{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MonoLocalBinds #-}

module Cardano.Wasm.Api.Address
  ( AddressInfo (..)
  , inspectAddressImpl
  )
where

import Cardano.Api qualified as Api
import Cardano.Api.Ledger qualified as Ledger

import Data.Aeson (ToJSON (toJSON), (.=))
import Data.Aeson qualified as Aeson
import Data.Text (Text)
import Data.Text qualified as Text

-- | Information about a valid address, as returned by 'inspectAddressImpl'.
newtype AddressInfo = AddressInfo
  { AddressInfo -> Network
addressNetwork :: Ledger.Network
  -- ^ The network the address belongs to.
  }
  deriving (Int -> AddressInfo -> ShowS
[AddressInfo] -> ShowS
AddressInfo -> String
(Int -> AddressInfo -> ShowS)
-> (AddressInfo -> String)
-> ([AddressInfo] -> ShowS)
-> Show AddressInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AddressInfo -> ShowS
showsPrec :: Int -> AddressInfo -> ShowS
$cshow :: AddressInfo -> String
show :: AddressInfo -> String
$cshowList :: [AddressInfo] -> ShowS
showList :: [AddressInfo] -> ShowS
Show, AddressInfo -> AddressInfo -> Bool
(AddressInfo -> AddressInfo -> Bool)
-> (AddressInfo -> AddressInfo -> Bool) -> Eq AddressInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AddressInfo -> AddressInfo -> Bool
== :: AddressInfo -> AddressInfo -> Bool
$c/= :: AddressInfo -> AddressInfo -> Bool
/= :: AddressInfo -> AddressInfo -> Bool
Eq)

instance ToJSON AddressInfo where
  toJSON :: AddressInfo -> Aeson.Value
  toJSON :: AddressInfo -> Value
toJSON (AddressInfo Network
network) =
    [(Key, Value)] -> Value
Aeson.object
      [ Key
"network"
          Key -> Text -> (Key, Value)
forall v. ToJSON v => Key -> v -> (Key, Value)
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= case Network
network of
            Network
Ledger.Mainnet -> Text
"mainnet" :: Text
            Network
Ledger.Testnet -> Text
"testnet"
      ]

-- | Inspect an address given as a string. If the address is a well-formed
-- Shelley-era address (bech32, like @addr...@ or @addr_test...@), it returns
-- information about the address: currently, the network it belongs to.
-- Otherwise it returns 'Nothing' (serialised as @null@ in the JavaScript
-- API). It never throws.
--
-- Note that an address only encodes whether it belongs to mainnet or a
-- testnet: it is not possible to distinguish between different testnets
-- (like preprod and preview) from an address alone, because they only differ
-- in the network magic, which is not part of the address.
inspectAddressImpl :: String -> Maybe AddressInfo
inspectAddressImpl :: String -> Maybe AddressInfo
inspectAddressImpl String
addrStr =
  case AsType (Address ShelleyAddr) -> Text -> Maybe (Address ShelleyAddr)
forall addr.
SerialiseAddress addr =>
AsType addr -> Text -> Maybe addr
Api.deserialiseAddress (AsType ShelleyAddr -> AsType (Address ShelleyAddr)
forall addrtype. AsType addrtype -> AsType (Address addrtype)
Api.AsAddress AsType ShelleyAddr
Api.AsShelleyAddr) (String -> Text
Text.pack String
addrStr) of
    Just (Api.ShelleyAddress Network
network Credential Payment
_ StakeReference
_) -> AddressInfo -> Maybe AddressInfo
forall a. a -> Maybe a
Just (Network -> AddressInfo
AddressInfo Network
network)
    Maybe (Address ShelleyAddr)
Nothing -> Maybe AddressInfo
forall a. Maybe a
Nothing