Skip to content

Commit

Permalink
Merge pull request #2184 from input-output-hk/KtorZ/2180/address-insp…
Browse files Browse the repository at this point in the history
…ect-via-api

Allow address inspection via the API
  • Loading branch information
KtorZ authored Sep 25, 2020
2 parents d5d2898 + 49e5000 commit e324626
Show file tree
Hide file tree
Showing 13 changed files with 322 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import Test.Integration.Framework.TestData
( errMsg404NoWallet )

import qualified Cardano.Wallet.Api.Link as Link
import qualified Data.Aeson as Aeson
import qualified Data.Text as T
import qualified Network.HTTP.Types.Status as HTTP

Expand Down Expand Up @@ -224,3 +225,13 @@ spec = describe "SHELLEY_ADDRESSES" $ do
(Link.listAddresses @'Shelley w) Default Empty
expectResponseCode @IO HTTP.status404 r
expectErrorMessage (errMsg404NoWallet $ w ^. walletId) r

it "ADDRESS_INSPECT_01 - Address inspect OK" $ \ctx -> do
let str = "Ae2tdPwUPEYz6ExfbWubiXPB6daUuhJxikMEb4eXRp5oKZBKZwrbJ2k7EZe"
r <- request @Aeson.Value ctx (Link.inspectAddress str) Default Empty
expectResponseCode @IO HTTP.status200 r

it "ADDRESS_INSPECT_02 - Address inspect KO" $ \ctx -> do
let str = "patate"
r <- request @Aeson.Value ctx (Link.inspectAddress str) Default Empty
expectResponseCode @IO HTTP.status400 r
9 changes: 9 additions & 0 deletions lib/core/src/Cardano/Wallet/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module Cardano.Wallet.Api

, Addresses
, ListAddresses
, InspectAddress

, CoinSelections
, SelectCoins
Expand Down Expand Up @@ -105,6 +106,8 @@ import Cardano.Wallet
( WalletLayer (..), WalletLog )
import Cardano.Wallet.Api.Types
( ApiAddressIdT
, ApiAddressInspect
, ApiAddressInspectData
, ApiAddressT
, ApiByronWallet
, ApiCoinSelectionT
Expand Down Expand Up @@ -269,6 +272,7 @@ type GetUTxOsStatistics = "wallets"

type Addresses n =
ListAddresses n
:<|> InspectAddress

-- | https://input-output-hk.github.io/cardano-wallet/api/#operation/listAddresses
type ListAddresses n = "wallets"
Expand All @@ -277,6 +281,11 @@ type ListAddresses n = "wallets"
:> QueryParam "state" (ApiT AddressState)
:> Get '[JSON] [ApiAddressT n]

-- | https://input-output-hk.github.io/cardano-wallet/api/#operation/inspectAddress
type InspectAddress = "addresses"
:> Capture "addressId" ApiAddressInspectData
:> Get '[JSON] ApiAddressInspect

{-------------------------------------------------------------------------------
Coin Selections
Expand Down
18 changes: 17 additions & 1 deletion lib/core/src/Cardano/Wallet/Api/Client.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ import Cardano.Wallet.Api
)
import Cardano.Wallet.Api.Types
( ApiAddressIdT
, ApiAddressInspect (..)
, ApiAddressInspectData (..)
, ApiAddressT
, ApiByronWallet
, ApiCoinSelectionT
Expand Down Expand Up @@ -168,6 +170,9 @@ data AddressClient = AddressClient
:: ApiT WalletId
-> Maybe (ApiT AddressState)
-> ClientM [Aeson.Value]
, inspectAddress
:: Text
-> ClientM Aeson.Value
, postRandomAddress
:: ApiT WalletId
-> ApiPostRandomAddressData
Expand Down Expand Up @@ -311,21 +316,28 @@ addressClient
addressClient =
let
_listAddresses
:<|> _inspectAddress
= client (Proxy @("v2" :> Addresses Aeson.Value))
in
AddressClient
{ listAddresses = _listAddresses
, inspectAddress =
fmap unApiAddressInspect
. _inspectAddress
. ApiAddressInspectData
, postRandomAddress = \_ _ -> fail "feature unavailable."
, putRandomAddress = \_ _ -> fail "feature unavailable."
, putRandomAddresses = \_ _ -> fail "feature unavailable."
}


-- | Produces an 'AddressClient n' working against the /wallets API
byronAddressClient
:: AddressClient
byronAddressClient =
let
_ :<|> _inspectAddress
= client (Proxy @("v2" :> Addresses Aeson.Value))

_postRandomAddress
:<|> _putRandomAddress
:<|> _putRandomAddresses
Expand All @@ -334,6 +346,10 @@ byronAddressClient =
in
AddressClient
{ listAddresses = _listAddresses
, inspectAddress =
fmap unApiAddressInspect
. _inspectAddress
. ApiAddressInspectData
, postRandomAddress = _postRandomAddress
, putRandomAddress = _putRandomAddress
, putRandomAddresses = _putRandomAddresses
Expand Down
10 changes: 9 additions & 1 deletion lib/core/src/Cardano/Wallet/Api/Link.hs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ module Cardano.Wallet.Api.Link
, putRandomAddresses
, listAddresses
, listAddresses'
, inspectAddress

-- * CoinSelections
, selectCoins
Expand Down Expand Up @@ -88,7 +89,8 @@ module Cardano.Wallet.Api.Link
import Prelude

import Cardano.Wallet.Api.Types
( ApiPoolId (..)
( ApiAddressInspectData (..)
, ApiPoolId (..)
, ApiT (..)
, ApiTxId (ApiTxId)
, Iso8601Time
Expand Down Expand Up @@ -299,6 +301,12 @@ listAddresses' w mstate = discriminate @style
where
wid = w ^. typed @(ApiT WalletId)

inspectAddress
:: ApiAddressInspectData
-> (Method, Text)
inspectAddress addr =
endpoint @Api.InspectAddress (addr &)

--
-- Coin Selections
--
Expand Down
1 change: 0 additions & 1 deletion lib/core/src/Cardano/Wallet/Api/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,6 @@ listAddresses ctx normalize (ApiT wid) stateFilter = do
Just (ApiT s) -> (== s) . snd
coerceAddress (a, s) = ApiAddress (ApiT a, Proxy @n) (ApiT s)


{-------------------------------------------------------------------------------
Transactions
-------------------------------------------------------------------------------}
Expand Down
25 changes: 25 additions & 0 deletions lib/core/src/Cardano/Wallet/Api/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ module Cardano.Wallet.Api.Types
, ApiTxInput (..)
, ApiTxMetadata (..)
, AddressAmount (..)
, ApiAddressInspect (..)
, ApiAddressInspectData (..)
, ApiErrorCode (..)
, ApiNetworkInformation (..)
, ApiNtpStatus (..)
Expand Down Expand Up @@ -244,6 +246,8 @@ import Data.Proxy
( Proxy (..) )
import Data.Quantity
( Percentage, Quantity (..) )
import Data.String
( IsString )
import Data.Text
( Text, split )
import Data.Text.Class
Expand Down Expand Up @@ -638,6 +642,15 @@ data AddressAmount addr = AddressAmount
, amount :: !(Quantity "lovelace" Natural)
} deriving (Eq, Generic, Show)

newtype ApiAddressInspect = ApiAddressInspect
{ unApiAddressInspect :: Aeson.Value }
deriving (Eq, Generic, Show)

newtype ApiAddressInspectData = ApiAddressInspectData
{ unApiAddressInspectData :: Text }
deriving (Eq, Generic, Show)
deriving newtype (IsString)

data ApiTimeReference = ApiTimeReference
{ time :: !UTCTime
, block :: !ApiBlockReference
Expand Down Expand Up @@ -1530,6 +1543,12 @@ instance ToJSON ApiWalletDiscovery where
toJSON = genericToJSON $ Aeson.defaultOptions
{ constructorTagModifier = drop 1 . dropWhile (/= '_') . camelTo2 '_' }

instance ToJSON ApiAddressInspect where
toJSON = unApiAddressInspect

instance FromJSON ApiAddressInspect where
parseJSON = pure . ApiAddressInspect

{-------------------------------------------------------------------------------
FromText/ToText instances
-------------------------------------------------------------------------------}
Expand Down Expand Up @@ -1591,6 +1610,12 @@ instance ToHttpApiData ApiPoolId where
ApiPoolIdPlaceholder -> "*"
ApiPoolId pid -> encodePoolIdBech32 pid

instance FromHttpApiData ApiAddressInspectData where
parseUrlPiece = pure . ApiAddressInspectData

instance ToHttpApiData ApiAddressInspectData where
toUrlPiece = unApiAddressInspectData

{-------------------------------------------------------------------------------
Aeson Options
-------------------------------------------------------------------------------}
Expand Down
11 changes: 10 additions & 1 deletion lib/core/test/unit/Cardano/Wallet/Api/Malformed.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ module Cardano.Wallet.Api.Malformed
import Prelude

import Cardano.Wallet.Api.Types
( ApiNetworkTip
( ApiAddressInspectData
, ApiNetworkTip
, ApiPoolId
, ApiPostRandomAddressData
, ApiPutAddressesData
Expand Down Expand Up @@ -171,6 +172,14 @@ instance Wellformed (PathParam (ApiT Address, Proxy ('Testnet 0))) where
instance Malformed (PathParam (ApiT Address, Proxy ('Testnet 0))) where
malformed = []

instance Wellformed (PathParam ApiAddressInspectData) where
wellformed = PathParam <$>
[ "Ae2tdPwUPEYz6ExfbWubiXPB6daUuhJxikMEb4eXRp5oKZBKZwrbJ2k7EZe"
]

instance Malformed (PathParam ApiAddressInspectData) where
malformed = []

--
-- Class instances (BodyParam)
--
Expand Down
15 changes: 14 additions & 1 deletion lib/core/test/unit/Cardano/Wallet/Api/TypesSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import Cardano.Wallet.Api.Types
, ApiAddressDerivationPath (..)
, ApiAddressDerivationSegment (..)
, ApiAddressDerivationType (..)
, ApiAddressInspect (..)
, ApiBlockReference (..)
, ApiByronWallet (..)
, ApiByronWalletBalance (..)
Expand Down Expand Up @@ -173,7 +174,7 @@ import Control.Monad.IO.Class
import Crypto.Hash
( hash )
import Data.Aeson
( FromJSON (..), ToJSON (..) )
( FromJSON (..), ToJSON (..), (.=) )
import Data.Aeson.QQ
( aesonQQ )
import Data.Char
Expand Down Expand Up @@ -1456,6 +1457,15 @@ instance Arbitrary ApiPostRandomAddressData where
arbitrary = genericArbitrary
shrink = genericShrink

instance Arbitrary ApiAddressInspect where
arbitrary = do
style <- elements [ "Byron", "Icarus", "Shelley" ]
stake <- elements [ "none", "by value", "by pointer" ]
pure $ ApiAddressInspect $ Aeson.object
[ "address_style" .= Aeson.String style
, "stake_reference" .= Aeson.String stake
]

{-------------------------------------------------------------------------------
Specification / Servant-Swagger Machinery
Expand Down Expand Up @@ -1511,6 +1521,9 @@ specification =
instance ToSchema (ApiAddress t) where
declareNamedSchema _ = declareSchemaForDefinition "ApiAddress"

instance ToSchema ApiAddressInspect where
declareNamedSchema _ = declareSchemaForDefinition "ApiAddressInspect"

instance ToSchema (ApiPutAddressesData t) where
declareNamedSchema _ = declareSchemaForDefinition "ApiPutAddressesData"

Expand Down
4 changes: 2 additions & 2 deletions lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ server byron icarus jormungandr spl ntp =
:<|> getUTxOsStatistics jormungandr

addresses :: Server (Addresses n)
addresses = listAddresses jormungandr
(normalizeDelegationAddress @_ @JormungandrKey @n)
addresses = listAddresses jormungandr (normalizeDelegationAddress @_ @JormungandrKey @n)
:<|> (\_ -> throwError err501)

coinSelections :: Server (CoinSelections n)
coinSelections = selectCoins jormungandr (delegationAddress @n)
Expand Down
25 changes: 21 additions & 4 deletions lib/shelley/src/Cardano/Wallet/Shelley/Api/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ import Cardano.Wallet.Api.Server
, withLegacyLayer'
)
import Cardano.Wallet.Api.Types
( ApiErrorCode (..)
( ApiAddressInspect (..)
, ApiAddressInspectData (..)
, ApiErrorCode (..)
, ApiStakePool
, ApiT (..)
, SomeByronWalletPostData (..)
Expand All @@ -105,12 +107,14 @@ import Cardano.Wallet.Primitive.AddressDiscovery.Random
( RndState )
import Cardano.Wallet.Primitive.AddressDiscovery.Sequential
( SeqState )
import Cardano.Wallet.Shelley.Compatibility
( inspectAddress )
import Cardano.Wallet.Shelley.Pools
( StakePoolLayer (..) )
import Control.Applicative
( liftA2 )
import Control.Monad.Trans.Except
( throwE )
( except, throwE, withExceptT )
import Data.Coerce
( coerce )
import Data.Generics.Internal.VL.Lens
Expand All @@ -119,15 +123,21 @@ import Data.Generics.Labels
()
import Data.List
( sortOn )
import Data.Text.Class
( TextDecodingError (..) )
import Fmt
( Buildable )
import Network.Ntp
( NtpClient )
import Servant
( (:<|>) (..), Handler (..), Server, err400 )
import Servant.Server
( ServerError (..) )
import Type.Reflection
( Typeable )

import qualified Data.Text as T

server
:: forall t n.
( Buildable (ErrValidateSelection t)
Expand Down Expand Up @@ -167,8 +177,15 @@ server byron icarus shelley spl ntp =
:<|> getUTxOsStatistics shelley

addresses :: Server (Addresses n)
addresses = listAddresses shelley
(normalizeDelegationAddress @_ @ShelleyKey @n)
addresses = listAddresses shelley (normalizeDelegationAddress @_ @ShelleyKey @n)
:<|> (handler ApiAddressInspect . inspectAddress . unApiAddressInspectData)
where
toServerError :: TextDecodingError -> ServerError
toServerError = apiError err400 BadRequest . T.pack . getTextDecodingError

handler :: (a -> result) -> Either TextDecodingError a -> Handler result
handler transform =
Handler . withExceptT toServerError . except . fmap transform

coinSelections :: Server (CoinSelections n)
coinSelections = selectCoins shelley (delegationAddress @n)
Expand Down
Loading

0 comments on commit e324626

Please sign in to comment.