-
Notifications
You must be signed in to change notification settings - Fork 2
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
CLI deployment of Wst using Blockfrost #44
Changes from 1 commit
a166444
7450aff
b2418d6
4f4997a
1035988
e83ec79
f280bf8
0a6da4f
3949143
110b9ff
0f32d70
21a8743
234168c
32d12f9
88b78c6
242ce17
12db0da
69559e3
6f53e3c
8453053
796332c
89818f5
4c40704
0f2550e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ module Wst.Offchain.BuildTx.TransferLogic | |
seizeSmartTokens, | ||
initBlacklist, | ||
insertBlacklistNode, | ||
spendBlacklistOutput, | ||
paySmartTokensToDestination, | ||
registerTransferScripts, | ||
) | ||
|
@@ -17,6 +18,7 @@ where | |
import Cardano.Api qualified as C | ||
import Cardano.Api.Shelley qualified as C | ||
import Control.Lens (over, (^.)) | ||
import Control.Monad (when) | ||
import Control.Monad.Except (MonadError (throwError)) | ||
import Control.Monad.Reader (MonadReader, asks) | ||
import Convex.BuildTx (MonadBuildTx (addTxBuilder), TxBuilder (TxBuilder), | ||
|
@@ -44,7 +46,7 @@ import SmartTokens.Contracts.ExampleTransferLogic (BlacklistProof (..)) | |
import SmartTokens.Types.ProtocolParams | ||
import SmartTokens.Types.PTokenDirectory (BlacklistNode (..), | ||
DirectorySetNode (..)) | ||
import Wst.AppError (AppError (TransferBlacklistedCredential)) | ||
import Wst.AppError (AppError (DuplicateBlacklistNode, TransferBlacklistedCredential)) | ||
import Wst.Offchain.BuildTx.ProgrammableLogic (issueProgrammableToken, | ||
seizeProgrammableToken, | ||
transferProgrammableToken) | ||
|
@@ -91,7 +93,7 @@ initBlacklist = Utils.inBabbage @era $ do | |
opPkh <- asks (fst . Env.bteOperator . Env.operatorEnv) | ||
addRequiredSignature opPkh | ||
|
||
insertBlacklistNode :: forall era env m. (MonadReader env m, Env.HasOperatorEnv era env, Env.HasTransferLogicEnv env, C.IsBabbageBasedEra era, C.HasScriptLanguageInEra C.PlutusScriptV3 era, MonadBuildTx era m) => C.PaymentCredential -> [UTxODat era BlacklistNode]-> m () | ||
insertBlacklistNode :: forall era env m. (MonadReader env m, Env.HasOperatorEnv era env, Env.HasTransferLogicEnv env, C.IsBabbageBasedEra era, C.HasScriptLanguageInEra C.PlutusScriptV3 era, MonadBuildTx era m, MonadError (AppError era) m) => C.PaymentCredential -> [UTxODat era BlacklistNode]-> m () | ||
insertBlacklistNode cred blacklistNodes = Utils.inBabbage @era $ do | ||
-- mint new blacklist token | ||
mintingScript <- asks (Env.tleBlacklistMintingScript . Env.transferLogicEnv) | ||
|
@@ -102,7 +104,6 @@ insertBlacklistNode cred blacklistNodes = Utils.inBabbage @era $ do | |
mintPlutus mintingScript () newAssetName quantity | ||
|
||
let | ||
|
||
-- find the node to insert on | ||
UTxODat {uIn = prevNodeRef,uOut = (C.TxOut prevAddr prevVal _ _), uDatum = prevNode} = | ||
maximumBy (compare `on` (blnKey . uDatum)) $ | ||
|
@@ -119,6 +120,9 @@ insertBlacklistNode cred blacklistNodes = Utils.inBabbage @era $ do | |
newPrevNodeDatum = C.TxOutDatumInline C.babbageBasedEra $ C.toHashableScriptData newPrevNode | ||
newPrevNodeOutput = C.TxOut prevAddr prevVal newPrevNodeDatum C.ReferenceScriptNone | ||
|
||
when (blnKey prevNode == blnKey newNode) | ||
$ throwError DuplicateBlacklistNode | ||
|
||
-- spend previous node | ||
spendingScript <- asks (Env.tleBlacklistSpendingScript . Env.transferLogicEnv) | ||
spendPlutusInlineDatum prevNodeRef spendingScript () | ||
|
@@ -131,6 +135,13 @@ insertBlacklistNode cred blacklistNodes = Utils.inBabbage @era $ do | |
opPkh <- asks (fst . Env.bteOperator . Env.operatorEnv) | ||
addRequiredSignature opPkh | ||
|
||
spendBlacklistOutput :: forall era env m. (MonadReader env m, Env.HasOperatorEnv era env, Env.HasTransferLogicEnv env, C.IsBabbageBasedEra era, C.HasScriptLanguageInEra C.PlutusScriptV3 era, MonadBuildTx era m) => C.TxIn -> m () | ||
spendBlacklistOutput txin = Utils.inBabbage @era $ do | ||
spendingScript <- asks (Env.tleBlacklistSpendingScript . Env.transferLogicEnv) | ||
spendPlutusInlineDatum txin spendingScript () | ||
opPkh <- asks (fst . Env.bteOperator . Env.operatorEnv) | ||
addRequiredSignature opPkh | ||
|
||
{-| Add a smart token output that locks the given value, | ||
addressed to the payment credential | ||
-} | ||
|
@@ -330,6 +341,7 @@ registerTransferScripts = case C.babbageBasedEra @era of | |
C.BabbageEraOnwardsConway -> Utils.inConway @era $ do | ||
transferMintingScript <- asks (Env.tleMintingScript . Env.transferLogicEnv) | ||
transferSpendingScript <- asks (Env.tleTransferScript . Env.transferLogicEnv) | ||
transferSeizeSpendingScript <- asks (Env.tleIssuerScript . Env.transferLogicEnv) | ||
|
||
let | ||
hshMinting = C.hashScript $ C.PlutusScript C.plutusScriptVersion transferMintingScript | ||
|
@@ -338,5 +350,9 @@ registerTransferScripts = case C.babbageBasedEra @era of | |
hshSpending = C.hashScript $ C.PlutusScript C.plutusScriptVersion transferSpendingScript | ||
credSpending = C.StakeCredentialByScript hshSpending | ||
|
||
hshSeizeSpending = C.hashScript $ C.PlutusScript C.plutusScriptVersion transferSeizeSpendingScript | ||
credSeizeSpending = C.StakeCredentialByScript hshSeizeSpending | ||
|
||
addConwayStakeCredentialCertificate credMinting | ||
addConwayStakeCredentialCertificate credSpending | ||
addConwayStakeCredentialCertificate credSeizeSpending | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Registration step for transfer script was missing issuer spend (seize) stake script |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,16 +17,17 @@ module Wst.Offchain.Endpoints.Deployment( | |
import Cardano.Api (Quantity) | ||
import Cardano.Api.Shelley qualified as C | ||
import Control.Monad (when) | ||
import Control.Monad.Except (MonadError) | ||
import Control.Monad.Except (MonadError (..)) | ||
import Control.Monad.Reader (MonadReader, asks) | ||
import Convex.BuildTx qualified as BuildTx | ||
import Convex.Class (MonadBlockchain, MonadUtxoQuery) | ||
import Convex.CoinSelection qualified | ||
import Data.Foldable (maximumBy) | ||
import Data.Function (on) | ||
import GHC.IsList (IsList (..)) | ||
import SmartTokens.Core.Scripts (ScriptTarget (..)) | ||
import SmartTokens.Types.PTokenDirectory (DirectorySetNode (..)) | ||
import Wst.AppError (AppError) | ||
import Wst.AppError (AppError (NoTokensToSeize)) | ||
import Wst.Offchain.BuildTx.DirectorySet (InsertNodeArgs (inaNewKey)) | ||
import Wst.Offchain.BuildTx.DirectorySet qualified as BuildTx | ||
import Wst.Offchain.BuildTx.ProgrammableLogic qualified as BuildTx | ||
|
@@ -38,7 +39,6 @@ import Wst.Offchain.Query (UTxODat (..)) | |
import Wst.Offchain.Query qualified as Query | ||
|
||
|
||
|
||
{-| Build a transaction that deploys the directory and global params. Returns the | ||
transaction and the 'TxIn' that was selected for the one-shot NFTs. | ||
-} | ||
|
@@ -216,7 +216,17 @@ seizeCredentialAssetsTx :: forall era env m. | |
seizeCredentialAssetsTx sanctionedCred = do | ||
opPkh <- asks (fst . Env.bteOperator . Env.operatorEnv) | ||
directory <- Query.registryNodes @era | ||
seizeTxo <- head <$> Query.userProgrammableOutputs sanctionedCred | ||
let getTxOutValue (C.TxOut _a v _d _r) = v | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just selects the UTxO with the largest non ada asset quantities ignoring the asset names. |
||
-- simple fold to choose the UTxO with the most total assets | ||
nonAda v = foldl (\acc -> \case | ||
(C.AdaAssetId, _) -> acc | ||
(_aid, q) -> acc + q | ||
) 0 $ toList v | ||
|
||
getNonAdaTokens = nonAda . C.txOutValueToValue . getTxOutValue . uOut | ||
seizeTxo <- maximumBy (compare `on` getNonAdaTokens) <$> Query.userProgrammableOutputs sanctionedCred | ||
when (getNonAdaTokens seizeTxo == 0) $ | ||
throwError NoTokensToSeize | ||
paramsTxIn <- Query.globalParamsNode @era | ||
(tx, _) <- Env.balanceTxEnv_ $ do | ||
BuildTx.seizeSmartTokens paramsTxIn seizeTxo (C.PaymentCredentialByKey opPkh) directory | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
{-# LANGUAGE NamedFieldPuns #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
{-# LANGUAGE NamedFieldPuns #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
|
||
{-| servant server for stablecoin POC | ||
-} | ||
|
@@ -130,7 +131,8 @@ queryBlacklistedNodes _ (SerialiseAddress addr) = do | |
. P.fromBuiltin | ||
. blnKey | ||
. uDatum | ||
Env.withEnv $ Env.withTransfer transferLogic (fmap (fmap getHash) (Query.blacklistNodes @era)) | ||
nonHeadNodes (P.fromBuiltin . blnKey . uDatum -> hsh) = hsh /= "" | ||
Env.withEnv $ Env.withTransfer transferLogic (fmap getHash . filter nonHeadNodes <$> (Query.blacklistNodes @era)) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Desezialization would fail in the case of the head node with an empty payment credential |
||
txOutValue :: C.IsMaryBasedEra era => C.TxOut C.CtxUTxO era -> C.Value | ||
txOutValue = L.view (L._TxOut . L._2 . L._TxOutValue) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is currently unused in the endpoints. I only needed it to remove a duplicate blacklist node I accidentally pushed on preview. We could later cleanup the interface and add an endpoint if need be.