Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADP-3479] Add deposit wallet payment page #4837

Draft
wants to merge 23 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0a39092
Add XPrv mgmt in REST interface
paolino Nov 15, 2024
1509e26
Fix Menmonic vs Mnemonic typos
paolino Nov 15, 2024
72e25f4
Factor out address rendering into common pages lib
paolino Nov 8, 2024
769ae98
Expose lovelaceH html renderer from deposit html common module
paolino Nov 11, 2024
674906c
Add partial payments page to deposit wallet UI
paolino Nov 12, 2024
05df177
Add finer controls on the sseH component
paolino Nov 11, 2024
e3c28fb
Add available balance to payments page
paolino Nov 11, 2024
dd950cd
Return ResolvedTx from create payments operations
paolino Nov 12, 2024
c6e2075
Expose payment tx inspection from the REST api
paolino Nov 12, 2024
5608e74
Add read-only fields in the unsigned transaction component
paolino Nov 11, 2024
14e37c5
Add transaction balance to the inspection fields
paolino Nov 12, 2024
966a732
Move transaction balance in the new payment wallet balance component
paolino Nov 12, 2024
0431742
Report balancing error in the unsigned transaction box
paolino Nov 13, 2024
f8bf131
Remove bold typography from UI
paolino Nov 13, 2024
4172541
Reduce the overall spacing inside tables in the UI
paolino Nov 13, 2024
0d96f72
Add end-point for informative modal interaction
paolino Nov 13, 2024
d9ff30e
Add address and amount pre-validation in new receiver form
paolino Nov 13, 2024
f2c7e79
Change the export format for unsigned txs in the deposit UI
paolino Nov 14, 2024
57cbe24
Expose a way to resolve the txins of a transaction in the REST API
paolino Nov 14, 2024
c7f3afb
Add a restoration form to recover the receivers from a transaction in…
paolino Nov 14, 2024
f37f9e5
Add collapsability to transaction component in deposit UI
paolino Nov 15, 2024
1ef83bf
Add can-sign state observation to deposit state
paolino Nov 15, 2024
56e2f3b
Add signing controls to deposit payments UI page
paolino Nov 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/customer-deposit-wallet/customer-deposit-wallet.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ library
, async
, base
, base58-bytestring
, base16-bytestring
, bech32
, bech32-th
, bytestring
, cardano-addresses
, cardano-balance-tx
, cardano-crypto
, cardano-ledger-api
Expand Down Expand Up @@ -223,7 +225,9 @@ test-suite unit
, openapi3
, pretty-simple
, QuickCheck
, serialise
, temporary
, text
, time
, transformers
, with-utf8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import Cardano.Wallet.Deposit.HTTP.Types.JSON
import Cardano.Wallet.Deposit.IO
( WalletBootEnv
)
import Cardano.Wallet.Deposit.Pure.State.Creation
( credentialsFromEncodedXPub
, credentialsFromMnemonics
)
import Cardano.Wallet.Deposit.REST
( WalletResource
, WalletResourceM
Expand All @@ -32,10 +36,8 @@ import Cardano.Wallet.Deposit.REST.Catch
( catchRunWalletResourceM
)
import Cardano.Wallet.Deposit.REST.Wallet.Create
( PostWalletViaMenmonic (..)
( PostWalletViaMnemonic (..)
, PostWalletViaXPub (..)
, decodeXPub
, xpubFromMnemonics
)
import Control.Tracer
( Tracer
Expand Down Expand Up @@ -81,23 +83,23 @@ createWalletViaMnemonic
-> FilePath
-> WalletBootEnv IO
-> WalletResource
-> PostWalletViaMenmonic
-> PostWalletViaMnemonic
-> Handler NoContent
createWalletViaMnemonic
tracer
dir
boot
resource
(PostWalletViaMenmonic mnemonics' users') =
(PostWalletViaMnemonic mnemonics' passphrase' users') =
onlyOnWalletIntance resource initWallet $> NoContent
where
initWallet :: WalletResourceM ()
initWallet =
REST.initXPubWallet
REST.initWallet
tracer
boot
dir
(xpubFromMnemonics mnemonics')
(credentialsFromMnemonics mnemonics' passphrase')
(fromIntegral users')

createWalletViaXPub
Expand All @@ -119,17 +121,16 @@ createWalletViaXPub
Right () -> pure NoContent
where
initWallet :: WalletResourceM (Either String ())
initWallet = case decodeXPub xpubText of
Left e -> pure $ Left e
Right (Just xpub') ->
initWallet = case credentialsFromEncodedXPub xpubText of
Left e -> pure $ Left $ show e
Right credentials ->
Right
<$> REST.initXPubWallet
<$> REST.initWallet
tracer
boot
dir
xpub'
credentials
(fromIntegral users')
Right Nothing -> pure $ Left "Invalid XPub"

listCustomerH
:: WalletResource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import Cardano.Wallet.Deposit.HTTP.Types.JSON
, CustomerList
)
import Cardano.Wallet.Deposit.REST.Wallet.Create
( PostWalletViaMenmonic
( PostWalletViaMnemonic
, PostWalletViaXPub
)
import Servant.API
Expand All @@ -47,7 +47,7 @@ type API =
:> Capture "customerId" (ApiT Customer)
:> Put '[JSON] (ApiT Address)
:<|> "mnemonics"
:> ReqBody '[JSON] PostWalletViaMenmonic
:> ReqBody '[JSON] PostWalletViaMnemonic
:> PutNoContent
:<|> "xpub"
:> ReqBody '[JSON] PostWalletViaXPub
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import Cardano.Wallet.Deposit.Read
, ChainPoint (..)
)
import Cardano.Wallet.Deposit.REST.Wallet.Create
( PostWalletViaMenmonic
( PostWalletViaMnemonic
, PostWalletViaXPub
)
import Control.Applicative
Expand Down Expand Up @@ -223,6 +223,6 @@ instance ToSchema (ApiT ChainPoint) where
(Just "ApiT ChainPoint")
chainPointSchema

instance FromJSON PostWalletViaMenmonic
instance FromJSON PostWalletViaMnemonic

instance FromJSON PostWalletViaXPub
109 changes: 78 additions & 31 deletions lib/customer-deposit-wallet/rest/Cardano/Wallet/Deposit/REST.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -Wno-orphans #-}

-- |
-- Copyright: © 2024 Cardano Foundation
Expand All @@ -26,7 +27,7 @@ module Cardano.Wallet.Deposit.REST
-- * Operations

-- ** Initialization
, initXPubWallet
, initWallet
, loadWallet

-- ** Mapping between customers and addresses
Expand All @@ -49,19 +50,26 @@ module Cardano.Wallet.Deposit.REST
, walletPublicIdentity
, deleteWallet
, deleteTheDepositWalletOnDisk
, inspectTx
-- * Internals
, onWalletInstance
, resolveCurrentEraTx
, canSign

) where

import Prelude

import Cardano.Address.Derivation
( xpubFromBytes
, xpubToBytes
( xpubToBytes
)
import Cardano.Crypto.Wallet
( XPub (..)
( XPrv
, XPub (..)
, unXPrv
, unXPub
, xprv
, xpub
)
import Cardano.Wallet.Address.BIP32
( BIP32Path
Expand All @@ -74,20 +82,28 @@ import Cardano.Wallet.Deposit.IO.Resource
, ErrResourceMissing (..)
)
import Cardano.Wallet.Deposit.Pure
( Customer
( CanSign
, Credentials
, CurrentEraResolvedTx
, Customer
, ErrCreatePayment
, InspectTx
, Word31
, fromXPubAndGenesis
, fromCredentialsAndGenesis
)
import Cardano.Wallet.Deposit.Pure.API.TxHistory
( ByCustomer
, ByTime
)
import Cardano.Wallet.Deposit.Pure.State.Creation
( xpubFromCredentials
)
import Cardano.Wallet.Deposit.Read
( Address
)
import Codec.Serialise
( deserialise
( Serialise (..)
, deserialise
, serialise
)
import Control.DeepSeq
Expand Down Expand Up @@ -120,6 +136,9 @@ import Data.ByteArray.Encoding
( Base (..)
, convertToBase
)
import Data.ByteString
( ByteString
)
import Data.List
( isPrefixOf
)
Expand Down Expand Up @@ -245,52 +264,69 @@ findTheDepositWalletOnDisk dir action = do
ds <- scanDirectoryForDepositPrefix dir
case ds of
[d] -> do
(xpub, users) <- deserialise <$> BL.readFile (dir </> d)
case xpubFromBytes xpub of
Nothing -> action $ Left $ ErrDatabaseCorrupted (dir </> d)
Just identity -> do
let state =
fromXPubAndGenesis
identity
(fromIntegral @Int users)
Read.mockGenesisDataMainnet
store <- newStore
writeS store state
action $ Right store
(credentials, users) <-
deserialise <$> BL.readFile (dir </> d)
let state =
fromCredentialsAndGenesis
credentials
(fromIntegral @Int users)
Read.mockGenesisDataMainnet
store <- newStore
writeS store state
action $ Right store
[] -> action $ Left $ ErrDatabaseNotFound dir
ds' -> action $ Left $ ErrMultipleDatabases ((dir </>) <$> ds')

instance Serialise XPub where
encode = encode . unXPub
decode = do
b <- decode
case xpub b of
Right x -> pure x
Left e -> fail e

instance Serialise XPrv where
encode = encode . unXPrv
decode = do
b :: ByteString <- decode
case xprv b of
Right x -> pure x
Left e -> fail e

instance Serialise Credentials

-- | Try to create a new wallet
createTheDepositWalletOnDisk
:: Tracer IO String
-- ^ Tracer for logging
-> FilePath
-- ^ Path to the wallet database directory
-> XPub
-> Credentials
-- ^ Id of the wallet
-> Word31
-- ^ Max number of users ?
-> (Maybe WalletIO.WalletStore -> IO a)
-- ^ Action to run if the wallet is created
-> IO a
createTheDepositWalletOnDisk _tr dir identity users action = do
createTheDepositWalletOnDisk _tr dir credentials users action = do
ds <- scanDirectoryForDepositPrefix dir
case ds of
[] -> do
let fp = dir </> depositPrefix <> hashWalletId identity
let fp = dir </> depositPrefix <> hashWalletId credentials
BL.writeFile fp
$ serialise (xpubToBytes identity, fromIntegral users :: Int)
$ serialise (credentials, fromIntegral users :: Int)
store <- newStore
action $ Just store
_ -> do
action Nothing
where
hashWalletId :: XPub -> String
hashWalletId :: Credentials -> String
hashWalletId =
B8.unpack
. convertToBase Base16
. blake2b160
. xpubPublicKey
. xpubToBytes
. xpubFromCredentials

-- | Load an existing wallet from disk.
loadWallet
Expand All @@ -316,27 +352,27 @@ loadWallet bootEnv dir = do
<$> Resource.putResource action resource

-- | Initialize a new wallet from an 'XPub'.
initXPubWallet
initWallet
:: Tracer IO String
-- ^ Tracer for logging
-> WalletIO.WalletBootEnv IO
-- ^ Environment for the wallet
-> FilePath
-- ^ Path to the wallet database directory
-> XPub
-> Credentials
-- ^ Id of the wallet
-> Word31
-- ^ Max number of users ?
-> WalletResourceM ()
initXPubWallet tr bootEnv dir xpub users = do
initWallet tr bootEnv dir credentials users = do
let action
:: (WalletIO.WalletInstance -> IO b) -> IO (Either ErrDatabase b)
action f = createTheDepositWalletOnDisk tr dir xpub users $ \case
action f = createTheDepositWalletOnDisk tr dir credentials users $ \case
Just wallet -> do
fmap Right
$ WalletIO.withWalletInit
(WalletIO.WalletEnv bootEnv wallet)
xpub
credentials
users
$ \i -> do
addresses <- map snd <$> WalletIO.listCustomers i
Expand Down Expand Up @@ -409,7 +445,7 @@ getTxHistoryByTime = onWalletInstance WalletIO.getTxHistoryByTime

createPayment
:: [(Address, Read.Value)]
-> WalletResourceM (Either ErrCreatePayment Write.Tx)
-> WalletResourceM (Either ErrCreatePayment CurrentEraResolvedTx)
createPayment = onWalletInstance . WalletIO.createPayment

getBIP32PathsForOwnedInputs
Expand All @@ -418,7 +454,18 @@ getBIP32PathsForOwnedInputs
getBIP32PathsForOwnedInputs =
onWalletInstance . WalletIO.getBIP32PathsForOwnedInputs

canSign :: WalletResourceM CanSign
canSign = onWalletInstance WalletIO.canSign

signTx
:: Write.Tx
-> WalletResourceM (Maybe Write.Tx)
signTx = onWalletInstance . WalletIO.signTx

inspectTx
:: CurrentEraResolvedTx
-> WalletResourceM InspectTx
inspectTx = onWalletInstance . WalletIO.inspectTx

resolveCurrentEraTx :: Write.Tx -> WalletResourceM CurrentEraResolvedTx
resolveCurrentEraTx = onWalletInstance . WalletIO.resolveCurrentEraTx
Loading
Loading