Skip to content

Commit

Permalink
support creating shared wallet from account xpub plus integration tes…
Browse files Browse the repository at this point in the history
…ting
  • Loading branch information
paweljakubas committed Apr 6, 2021
1 parent d5d78c7 commit f8f2c19
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 36 deletions.
Expand Up @@ -129,3 +129,65 @@ spec = describe "SHARED_WALLETS" $ do
, expectField #delegationScriptTemplate (`shouldBe` Nothing)
, expectField (#accountIndex . #getApiT) (`shouldBe` DerivationIndex 2147483678)
]

it "SHARED_WALLETS_CREATE_03 - Create an active shared wallet from account xpub" $ \ctx -> runResourceT $ do
let payload = Json [json| {
"name": "Shared Wallet",
"account_public_key": "1423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db11423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db1",
"account_index": "30H",
"payment_script_template":
{ "cosigners":
{ "cosigner#0": "1423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db11423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db1" },
"template":
{ "all":
[ "cosigner#0",
{ "active_from": 120 }
]
}
}
} |]
r <- postSharedWallet ctx Default payload
verify (fst r, (\(Right (ApiSharedWallet (Right res))) -> Right res) $ snd r)
[ expectResponseCode HTTP.status201
, expectField
(#name . #getApiT . #getWalletName) (`shouldBe` "Shared Wallet")
, expectField
(#addressPoolGap . #getApiT . #getAddressPoolGap) (`shouldBe` 20)
, expectField (#balance . #available) (`shouldBe` Quantity 0)
, expectField (#balance . #total) (`shouldBe` Quantity 0)
, expectField (#balance . #reward) (`shouldBe` Quantity 0)
, expectField (#assets . #total) (`shouldBe` mempty)
, expectField (#assets . #available) (`shouldBe` mempty)
, expectField #delegation (`shouldBe` notDelegating [])
, expectField #passphrase (`shouldBe` Nothing)
, expectField #delegationScriptTemplate (`shouldBe` Nothing)
, expectField (#accountIndex . #getApiT) (`shouldBe` DerivationIndex 2147483678)
]

it "SHARED_WALLETS_CREATE_04 - Create a pending shared wallet from account xpub" $ \ctx -> runResourceT $ do
let payload = Json [json| {
"name": "Shared Wallet",
"account_public_key": "1423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db11423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db2",
"account_index": "30H",
"payment_script_template":
{ "cosigners":
{ "cosigner#0": "1423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db11423856bc91c49e928f6f30f4e8d665d53eb4ab6028bd0ac971809d514c92db1" },
"template":
{ "all":
[ "cosigner#0",
"cosigner#1",
{ "active_from": 120 }
]
}
}
} |]
r <- postSharedWallet ctx Default payload
verify (fst r, (\(Right (ApiSharedWallet (Left res))) -> Right res) $ snd r)
[ expectResponseCode HTTP.status201
, expectField
(#name . #getApiT . #getWalletName) (`shouldBe` "Shared Wallet")
, expectField
(#addressPoolGap . #getApiT . #getAddressPoolGap) (`shouldBe` 20)
, expectField #delegationScriptTemplate (`shouldBe` Nothing)
, expectField (#accountIndex . #getApiT) (`shouldBe` DerivationIndex 2147483678)
]
114 changes: 78 additions & 36 deletions lib/core/src/Cardano/Wallet/Api/Server.hs
Expand Up @@ -200,6 +200,8 @@ import Cardano.Wallet.Api.Types
, ApiSelectCoinsPayments
, ApiSharedWallet (..)
, ApiSharedWalletPostData (..)
, ApiSharedWalletPostDataFromAccountPubX (..)
, ApiSharedWalletPostDataFromMnemonics (..)
, ApiSlotId (..)
, ApiSlotReference (..)
, ApiT (..)
Expand Down Expand Up @@ -296,7 +298,10 @@ import Cardano.Wallet.Primitive.AddressDiscovery.Sequential
, purposeCIP1852
)
import Cardano.Wallet.Primitive.AddressDiscovery.SharedState
( SharedState (..), mkSharedStateFromRootXPrv )
( SharedState (..)
, mkSharedStateFromAccountXPub
, mkSharedStateFromRootXPrv
)
import Cardano.Wallet.Primitive.CoinSelection.MA.RoundRobin
( SelectionError (..)
, SelectionInsufficientError (..)
Expand Down Expand Up @@ -782,17 +787,21 @@ mkShelleyWallet ctx wid cp meta pending progress = do
, state = ApiT progress
, tip = tip'
}
where
toApiWalletDelegation W.WalletDelegation{active,next} ti = do
apiNext <- forM next $ \W.WalletDelegationNext{status,changesAt} -> do
info <- interpretQuery ti $ toApiEpochInfo changesAt
return $ toApiWalletDelegationNext (Just info) status

return $ ApiWalletDelegation
{ active = toApiWalletDelegationNext Nothing active
, next = apiNext
}

toApiWalletDelegation
:: W.WalletDelegation
-> TimeInterpreter IO
-> IO ApiWalletDelegation
toApiWalletDelegation W.WalletDelegation{active,next} ti = do
apiNext <- forM next $ \W.WalletDelegationNext{status,changesAt} -> do
info <- interpretQuery ti $ toApiEpochInfo changesAt
return $ toApiWalletDelegationNext (Just info) status

return $ ApiWalletDelegation
{ active = toApiWalletDelegationNext Nothing active
, next = apiNext
}
where
toApiWalletDelegationNext mepochInfo = \case
W.Delegating pid -> ApiWalletDelegationNext
{ status = Delegating
Expand Down Expand Up @@ -826,7 +835,31 @@ postSharedWallet
-> (XPub -> k 'AccountK XPub)
-> ApiSharedWalletPostData
-> Handler ApiSharedWallet
postSharedWallet ctx generateKey _liftKey postData = do
postSharedWallet ctx generateKey liftKey postData =
case postData of
ApiSharedWalletPostData (Left body) ->
postSharedWalletFromRootXPrv ctx generateKey body
ApiSharedWalletPostData (Right body) ->
postSharedWalletFromAccountXPub ctx liftKey body

postSharedWalletFromRootXPrv
:: forall ctx s k n.
( s ~ SharedState n k
, ctx ~ ApiLayer s k
, SoftDerivation k
, MkKeyFingerprint k (Proxy n, k 'AddressK XPub)
, MkKeyFingerprint k Address
, WalletKey k
, HasDBFactory s k ctx
, HasWorkerRegistry s k ctx
, Typeable s
, Typeable n
)
=> ctx
-> ((SomeMnemonic, Maybe SomeMnemonic) -> Passphrase "encryption" -> k 'RootK XPrv)
-> ApiSharedWalletPostDataFromMnemonics
-> Handler ApiSharedWallet
postSharedWalletFromRootXPrv ctx generateKey body = do
let state = mkSharedStateFromRootXPrv (rootXPrv, pwd) accIx g pTemplate dTemplateM
void $ liftHandler $ initWorker @_ @s @k ctx wid
(\wrk -> W.createWallet @(WorkerCtx ctx) @s @k wrk wid wName state)
Expand All @@ -846,7 +879,39 @@ postSharedWallet ctx generateKey _liftKey postData = do
pTemplate = body ^. #paymentScriptTemplate
dTemplateM = body ^. #delegationScriptTemplate
wName = getApiT (body ^. #name)
(ApiSharedWalletPostData (Left body)) = postData

postSharedWalletFromAccountXPub
:: forall ctx s k n.
( s ~ SharedState n k
, ctx ~ ApiLayer s k
, SoftDerivation k
, MkKeyFingerprint k (Proxy n, k 'AddressK XPub)
, MkKeyFingerprint k Address
, WalletKey k
, HasDBFactory s k ctx
, HasWorkerRegistry s k ctx
, Typeable n
)
=> ctx
-> (XPub -> k 'AccountK XPub)
-> ApiSharedWalletPostDataFromAccountPubX
-> Handler ApiSharedWallet
postSharedWalletFromAccountXPub ctx liftKey body = do
let state = mkSharedStateFromAccountXPub (liftKey accXPub) accIx g pTemplate dTemplateM
void $ liftHandler $ initWorker @_ @s @k ctx wid
(\wrk -> W.createWallet @(WorkerCtx ctx) @s @k wrk wid wName state)
(\wrk -> W.restoreWallet @(WorkerCtx ctx) @s @k wrk wid)
(`idleWorker` wid)
fst <$> getWallet ctx (mkSharedWallet @_ @s @k state) (ApiT wid)
where
g = defaultAddressPoolGap
accIx = Index $ getDerivationIndex $ getApiT (body ^. #accountIndex)
pTemplate = body ^. #paymentScriptTemplate
dTemplateM = body ^. #delegationScriptTemplate
wName = getApiT (body ^. #name)
(ApiAccountPublicKey accXPubApiT) = body ^. #accountPublicKey
accXPub = getApiT accXPubApiT
wid = WalletId $ digest (liftKey accXPub)

mkSharedWallet
:: forall ctx s k n.
Expand Down Expand Up @@ -903,29 +968,6 @@ mkSharedWallet sharedState ctx wid cp meta pending progress = case sharedState o
, state = ApiT progress
, tip = tip'
}
where
toApiWalletDelegation W.WalletDelegation{active,next} ti = do
apiNext <- forM next $ \W.WalletDelegationNext{status,changesAt} -> do
info <- interpretQuery ti $ toApiEpochInfo changesAt
return $ toApiWalletDelegationNext (Just info) status

return $ ApiWalletDelegation
{ active = toApiWalletDelegationNext Nothing active
, next = apiNext
}

toApiWalletDelegationNext mepochInfo = \case
W.Delegating pid -> ApiWalletDelegationNext
{ status = Delegating
, target = Just (ApiT pid)
, changesAt = mepochInfo
}

W.NotDelegating -> ApiWalletDelegationNext
{ status = NotDelegating
, target = Nothing
, changesAt = mepochInfo
}

--------------------- Legacy

Expand Down

0 comments on commit f8f2c19

Please sign in to comment.