diff --git a/src/Plutarch/Constants.hs b/src/Plutarch/Constants.hs index 64b38a0..0503200 100644 --- a/src/Plutarch/Constants.hs +++ b/src/Plutarch/Constants.hs @@ -10,36 +10,12 @@ import Plutarch.Prelude import Plutarch.Utils (passert, pisPrefixOf) import PlutusLedgerApi.V1 (TokenName) -projectTokenHolderTN :: Term s PTokenName -projectTokenHolderTN = - let tn :: TokenName - tn = "PTHolder" - in pconstant tn - -commitFoldTN :: Term s PTokenName -commitFoldTN = - let tn :: TokenName - tn = "CFold" - in pconstant tn - -rewardFoldTN :: Term s PTokenName -rewardFoldTN = - let tn :: TokenName - tn = "RFold" - in pconstant tn - poriginNodeTN :: Term s PTokenName poriginNodeTN = let tn :: TokenName tn = "FSN" in pconstant tn -pcorrNodeTN :: Term s PTokenName -pcorrNodeTN = - let tn :: TokenName - tn = "FCN" - in pconstant tn - psetNodePrefix :: ClosedTerm PByteString psetNodePrefix = pconstant "FSN" @@ -57,12 +33,6 @@ pparseNodeKey = phoistAcyclic $ passert "incorrect node prefix" $ pisPrefixOf # psetNodePrefix # tn pif (prefixLength #< tnLength) (pcon $ PJust key) (pcon PNothing) -foldingFee :: Term s PInteger -foldingFee = pconstant 1_000_000 - -minAda :: Term s PInteger -minAda = pconstant 2_000_000 - nodeAda :: Term s PInteger nodeAda = pconstant 3_000_000 diff --git a/src/Plutarch/Helpers.hs b/src/Plutarch/Helpers.hs index e382153..965eda3 100644 --- a/src/Plutarch/Helpers.hs +++ b/src/Plutarch/Helpers.hs @@ -1,15 +1,11 @@ module Plutarch.Helpers ( - coversSeparators, coversKey, hasUtxoWithRef, - pseparatorsMintValue, - correctNodeTokensMinted, correctNodeTokenMinted, ) where import Plutarch.Api.V1.AssocMap qualified as AssocMap -import Plutarch.Api.V1.Value qualified as V import Plutarch.Api.V2 ( AmountGuarantees (NonZero), KeyGuarantees (Sorted), @@ -19,8 +15,6 @@ import Plutarch.Api.V2 ( PTxOutRef, PValue, ) -import Plutarch.Constants (pnodeKeyTN) -import Plutarch.Extra.Traversable (pfoldMap) import Plutarch.Monadic qualified as P import Plutarch.Prelude import Plutarch.Types (PDiscoverySetNode, PNodeKey (PEmpty, PKey)) @@ -38,19 +32,6 @@ coversKey = phoistAcyclic $ PKey (pfromData . (pfield @"_0" #) -> next) -> keyToCover #< next moreThanKey #&& lessThanNext --- | Checks that all the separators are covered by the node -coversSeparators :: ClosedTerm (PAsData PDiscoverySetNode :--> PBuiltinList PByteString :--> PBool) -coversSeparators = phoistAcyclic $ - plam $ \datum separators -> P.do - nodeDatum <- pletFields @'["key", "next"] datum - let moreThanKey = pmatch (nodeDatum.key) $ \case - PEmpty _ -> pcon PTrue - PKey (pfromData . (pfield @"_0" #) -> key) -> pall # plam (key #<) # separators - lessThanNext = pmatch (nodeDatum.next) $ \case - PEmpty _ -> pcon PTrue - PKey (pfromData . (pfield @"_0" #) -> next) -> pall # plam (#< next) # separators - moreThanKey #&& lessThanNext - {- | @hasUtxoWithRef # oref # inputs@ ensures that in @inputs@ there is an input having @TxOutRef@ @oref@ . -} @@ -64,38 +45,6 @@ hasUtxoWithRef = phoistAcyclic $ plam $ \oref inInputs -> pany # plam (\input -> oref #== (pfield @"outRef" # input)) # inInputs --- | Makes a Value from a list of separators keys -pseparatorsMintValue :: - ClosedTerm - ( PInteger - :--> PCurrencySymbol - :--> PBuiltinList PByteString - :--> PValue 'Sorted 'NonZero - ) -pseparatorsMintValue = phoistAcyclic $ - plam $ \amount nodeCS separators -> - let mkSeparatorToken = plam $ \key -> V.psingleton # nodeCS # (pnodeKeyTN # key) # amount - in pfoldMap # mkSeparatorToken # separators - -{- | Ensures that the minted amount of the FinSet CS is exactly the specified - list of tokenNames and amount --} -correctNodeTokensMinted :: - ClosedTerm - ( PCurrencySymbol - :--> PList PTokenName - :--> PInteger - :--> PValue 'Sorted 'NonZero - :--> PBool - ) -correctNodeTokensMinted = phoistAcyclic $ - plam $ \nodeCS tokenNames amount mint -> P.do - PJust nodeMint <- pmatch $ AssocMap.plookup # nodeCS # pto mint - let mkToken = plam $ \tn -> - AssocMap.pinsert # tn # amount - tokenMap = pfoldr # mkToken # AssocMap.pempty # tokenNames - tokenMap #== nodeMint - {- | Ensures that the minted amount of the FinSet CS is exactly the specified tokenName and amount -} diff --git a/src/Plutarch/Types.hs b/src/Plutarch/Types.hs index cb1e63d..3910b97 100644 --- a/src/Plutarch/Types.hs +++ b/src/Plutarch/Types.hs @@ -6,11 +6,7 @@ module Plutarch.Types ( PDiscoveryNodeAction (..), - PNodeValidatorAction (..), PDiscoveryConfig (..), - PDiscoveryLaunchConfig (..), - PSepNodeAction (..), - PSeparatorConfig (..), PDiscoverySetNode (..), PNodeKey (..), PNodeKeyState (..), @@ -33,7 +29,6 @@ import Plutarch.Api.V2 ( PAddress, PPOSIXTime, PPubKeyHash (PPubKeyHash), - PStakingCredential (..), PTxOutRef, ) import Plutarch.Classes @@ -47,52 +42,6 @@ import Plutarch.Prelude import PlutusLedgerApi.V2 (BuiltinByteString, PubKeyHash) import PlutusTx qualified -data NodeValidatorAction - = LinkedListAct - | ModifyCommitment - | RewardFoldAct - deriving stock (Generic, Show) - -PlutusTx.unstableMakeIsData ''NodeValidatorAction - -data PNodeValidatorAction (s :: S) - = PLinkedListAct (Term s (PDataRecord '[])) - | PModifyCommitment (Term s (PDataRecord '[])) - | PRewardFoldAct (Term s (PDataRecord '[])) - deriving stock (Generic) - deriving anyclass (PlutusType, PIsData, PShow) - -instance DerivePlutusType PNodeValidatorAction where - type DPTStrat _ = PlutusTypeData - -instance PUnsafeLiftDecl PNodeValidatorAction where - type PLifted PNodeValidatorAction = NodeValidatorAction - -deriving via - (DerivePConstantViaData NodeValidatorAction PNodeValidatorAction) - instance - (PConstantDecl NodeValidatorAction) - -instance PTryFrom PData (PAsData PNodeValidatorAction) - -instance PTryFrom PData PNodeValidatorAction - -newtype PDiscoveryLaunchConfig (s :: S) - = PDiscoveryLaunchConfig - ( Term - s - ( PDataRecord - '[ "discoveryDeadline" ':= PPOSIXTime - , "penaltyAddress" ':= PAddress - , "globalCred" ':= PStakingCredential - ] - ) - ) - deriving stock (Generic) - deriving anyclass (PlutusType, PIsData, PDataFields, PEq) - -instance DerivePlutusType PDiscoveryLaunchConfig where type DPTStrat _ = PlutusTypeData - newtype PDiscoveryConfig (s :: S) = PDiscoveryConfig ( Term @@ -122,19 +71,6 @@ data DiscoverySetNode = MkSetNode PlutusTx.unstableMakeIsData ''DiscoverySetNode -data SepNodeAction - = SepInit - | SepDeinit - | SepInsert PubKeyHash DiscoverySetNode - | SepRemove PubKeyHash DiscoverySetNode - | InsertSeps [BuiltinByteString] DiscoverySetNode - | -- | first arg is the key to insert, second arg is the covering node - RemoveSeps [BuiltinByteString] DiscoverySetNode - -- first arg is the key to remove, second arg is the covering node - deriving stock (Show, Eq, Generic) - -PlutusTx.unstableMakeIsData ''SepNodeAction - data DiscoveryNodeAction = Init | Deinit @@ -242,21 +178,6 @@ instance ScottConvertible PDiscoverySetNode where ) ) -newtype PSeparatorConfig (s :: S) - = PSeparatorConfig - ( Term - s - ( PDataRecord - '[ "signer" ':= PPubKeyHash - , "cutOff" ':= PPOSIXTime - ] - ) - ) - deriving stock (Generic) - deriving anyclass (PlutusType, PIsData, PDataFields, PEq) - -instance DerivePlutusType PSeparatorConfig where type DPTStrat _ = PlutusTypeData - mkNode :: Term s (PNodeKey :--> PNodeKey :--> PDiscoverySetNode) mkNode = phoistAcyclic $ plam $ \key next -> @@ -289,30 +210,6 @@ deriving via instance PConstantDecl DiscoveryNodeAction -data PSepNodeAction (s :: S) - = PSepInit (Term s (PDataRecord '[])) - | PSepDeinit (Term s (PDataRecord '[])) - | PSepInsert (Term s (PDataRecord '["keyToInsert" ':= PPubKeyHash, "coveringNode" ':= PDiscoverySetNode])) - | PSepRemove (Term s (PDataRecord '["keyToRemove" ':= PPubKeyHash, "coveringNode" ':= PDiscoverySetNode])) - | -- | separators must be sorted or validation will fail - PInsertSeps (Term s (PDataRecord '["separators" ':= PBuiltinList (PAsData PByteString), "coveringNode" ':= PDiscoverySetNode])) - | PRemoveSeps (Term s (PDataRecord '["separators" ':= PBuiltinList (PAsData PByteString), "coveringNode" ':= PDiscoverySetNode])) - deriving stock (Generic) - deriving anyclass (PlutusType, PIsData, PEq) - -instance DerivePlutusType PSepNodeAction where type DPTStrat _ = PlutusTypeData - -deriving anyclass instance - PTryFrom PData (PAsData PSepNodeAction) - -instance PUnsafeLiftDecl PSepNodeAction where - type PLifted PSepNodeAction = SepNodeAction - -deriving via - (DerivePConstantViaData SepNodeAction PSepNodeAction) - instance - PConstantDecl SepNodeAction - ----------------------------------------------- -- Helpers: diff --git a/src/Plutarch/Utils.hs b/src/Plutarch/Utils.hs index eaa6324..fafea45 100644 --- a/src/Plutarch/Utils.hs +++ b/src/Plutarch/Utils.hs @@ -4,33 +4,20 @@ module Plutarch.Utils where import Data.Text qualified as T -import Plutarch.Api.V1 (AmountGuarantees (..), KeyGuarantees (Sorted), PCredential (PPubKeyCredential, PScriptCredential)) -import Plutarch.Api.V1.Scripts (PScriptHash) -import Plutarch.Api.V1.Value (padaSymbol, pnormalize, pvalueOf) +import Plutarch.Api.V1 (AmountGuarantees (..), KeyGuarantees (Sorted)) +import Plutarch.Api.V1.Value (pnormalize) import Plutarch.Api.V1.Value qualified as Value import Plutarch.Api.V2 ( PAddress, PCurrencySymbol, PMap (PMap), - PPubKeyHash, PTokenName, - PTxInInfo, PTxOut, - PTxOutRef, PValue (..), ) import Plutarch.Bool (pand') import Plutarch.Monadic qualified as P import Plutarch.Prelude -import "liqwid-plutarch-extra" Plutarch.Extra.List (plookupAssoc) -import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (pmatchC) - -data PTriple (a :: PType) (b :: PType) (c :: PType) (s :: S) - = PTriple (Term s a) (Term s b) (Term s c) - deriving stock (Generic) - deriving anyclass (PlutusType, PEq, PShow) - -instance DerivePlutusType (PTriple a b c) where type DPTStrat _ = PlutusTypeScott ppair :: Term s a -> Term s b -> Term s (PPair a b) ppair a b = pcon (PPair a b) @@ -69,77 +56,6 @@ pfindCurrencySymbolsByTokenPrefix = phoistAcyclic $ isPrefixed = pfilter # plam (\csPair -> pany # plam (\tk -> prefixCheck # pto (pfromData (pfstBuiltin # tk))) # (pto $ pfromData (psndBuiltin # csPair))) # mapVal in pmap # pfstBuiltin # isPrefixed -pcountScriptInputs :: Term s (PBuiltinList PTxInInfo :--> PInteger) -pcountScriptInputs = - phoistAcyclic $ - let go :: Term s (PInteger :--> PBuiltinList PTxInInfo :--> PInteger) - go = pfix #$ plam $ \self n -> - pelimList - ( \x xs -> - let cred = pfield @"credential" # (pfield @"address" # (pfield @"resolved" # x)) - in pmatch cred $ \case - PScriptCredential _ -> self # (n + 1) # xs - _ -> self # n # xs - ) - n - in go # 0 - -pfoldl2 :: - (PListLike listA, PListLike listB, PElemConstraint listA a, PElemConstraint listB b) => - Term s ((acc :--> a :--> b :--> acc) :--> acc :--> listA a :--> listB b :--> acc) -pfoldl2 = - phoistAcyclic $ plam $ \func -> - pfix #$ plam $ \self acc la lb -> - pelimList - ( \a as -> - pelimList - (\b bs -> self # (func # acc # a # b) # as # bs) - perror - lb - ) - (pif (pnull # lb) acc perror) - la - -pelemAtWithRest' :: (PListLike list) => (PElemConstraint list a) => Term s (PInteger :--> list a :--> PPair a (list a)) -pelemAtWithRest' = phoistAcyclic $ - pfix #$ plam $ \self n xs -> - pif - (n #== 0) - (pcon $ PPair (phead # xs) (ptail # xs)) - (self # (n - 1) #$ ptail # xs) - -pmapIdxs :: - (PListLike listB, PElemConstraint listB b) => - Term s (PBuiltinList (PAsData PInteger) :--> listB b :--> listB b) -pmapIdxs = - phoistAcyclic $ - pfix #$ plam $ \self la lb -> - pelimList - ( \a as -> P.do - PPair foundEle xs <- pmatch $ pelemAtWithRest' # pfromData a # lb - (pcons # foundEle # (self # as # xs)) - ) - pnil - la - -{- | Finds the associated Currency symbols that contain the given token - name. --} -pfindCurrencySymbolsByTokenName :: - forall - (anyOrder :: KeyGuarantees) - (anyAmount :: AmountGuarantees). - ClosedTerm - ( PValue anyOrder anyAmount - :--> PTokenName - :--> PBuiltinList (PAsData PCurrencySymbol) - ) -pfindCurrencySymbolsByTokenName = phoistAcyclic $ - plam $ \value tn -> - let mapVal = pto (pto value) - hasTn = pfilter # plam (\csPair -> pany # plam (\tk -> tn #== (pfromData (pfstBuiltin # tk))) # (pto $ pfromData (psndBuiltin # csPair))) # mapVal - in pmap # pfstBuiltin # hasTn - -- | Checks if a Currency Symbol is held within a Value phasDataCS :: forall @@ -151,38 +67,6 @@ phasDataCS = phoistAcyclic $ plam $ \symbol value -> pany # plam (\tkPair -> (pfstBuiltin # tkPair) #== symbol) #$ pto (pto value) -phasCS :: - forall - (anyOrder :: KeyGuarantees) - (anyAmount :: AmountGuarantees). - ClosedTerm - (PValue anyOrder anyAmount :--> PCurrencySymbol :--> PBool) -phasCS = phoistAcyclic $ - plam $ \value symbol -> - pany # plam (\tkPair -> pfromData (pfstBuiltin # tkPair) #== symbol) #$ pto (pto value) - --- | Checks that a Value contains all the given CurrencySymbols. -pcontainsCurrencySymbols :: - forall - (anyOrder :: KeyGuarantees) - (anyAmount :: AmountGuarantees). - ClosedTerm - ( PValue anyOrder anyAmount - :--> PBuiltinList (PAsData PCurrencySymbol) - :--> PBool - ) -pcontainsCurrencySymbols = phoistAcyclic $ - plam $ \inValue symbols -> - let value = pmap # pfstBuiltin #$ pto $ pto inValue - containsCS = plam $ \cs -> pelem # cs # value - in pall # containsCS # symbols - --- | Checks if a tokenName is prefixed by a certain ByteString -pisPrefixedWith :: ClosedTerm (PTokenName :--> PByteString :--> PBool) -pisPrefixedWith = plam $ \tn prefix -> - let tnBS = pto tn - in pisPrefixOf # prefix # tnBS - -- | Checks if the first ByteString is a prefix of the second pisPrefixOf :: ClosedTerm (PByteString :--> PByteString :--> PBool) pisPrefixOf = plam $ \prefix src -> @@ -190,115 +74,9 @@ pisPrefixOf = plam $ \prefix src -> prefix' = psliceBS # 0 # prefixLength # src in prefix' #== prefix -tcexpectJust :: forall r (a :: PType) (s :: S). Term s r -> Term s (PMaybe a) -> TermCont @r s (Term s a) -tcexpectJust escape ma = tcont $ \f -> pmatch ma $ \case - PJust v -> f v - PNothing -> escape - paysToAddress :: Term s (PAddress :--> PTxOut :--> PBool) paysToAddress = phoistAcyclic $ plam $ \adr txOut -> adr #== (pfield @"address" # txOut) -paysValueToAddress :: - Term s (PValue 'Sorted 'Positive :--> PAddress :--> PTxOut :--> PBool) -paysValueToAddress = phoistAcyclic $ - plam $ \val adr txOut -> - pletFields @["address", "value"] txOut $ \txoFields -> - txoFields.address #== adr #&& txoFields.value #== val - -paysAtleastValueToAddress :: - Term s (PValue 'Sorted 'Positive :--> PAddress :--> PTxOut :--> PBool) -paysAtleastValueToAddress = phoistAcyclic $ - plam $ \val adr txOut -> - pletFields @["address", "value"] txOut $ \txoFields -> - txoFields.address #== adr #&& txoFields.value #<= val - -paysToCredential :: Term s (PScriptHash :--> PTxOut :--> PBool) -paysToCredential = phoistAcyclic $ - plam $ \valHash txOut -> - let txOutCred = pfield @"credential" # (pfield @"address" # txOut) - in pmatch txOutCred $ \case - PScriptCredential txOutValHash -> (pfield @"_0" # txOutValHash) #== valHash - PPubKeyCredential _ -> (pcon PFalse) - -pelemAt' :: (PIsListLike l a) => Term s (PInteger :--> l a :--> a) -pelemAt' = phoistAcyclic $ - pfix #$ plam $ \self n xs -> - pif - (n #== 0) - (phead # xs) - (self # (n - 1) #$ ptail # xs) - -pelemAtFlipped' :: (PIsListLike l a) => Term s (l a :--> PInteger :--> a) -pelemAtFlipped' = phoistAcyclic $ - pfix #$ plam $ \self xs n -> - pif - (n #== 0) - (phead # xs) - (self # (ptail # xs) # (n - 1)) - -pmapMaybe :: - forall (list :: PType -> PType) (a :: PType) (b :: PType). - (PListLike list) => - (PElemConstraint list a) => - (PElemConstraint list b) => - ClosedTerm ((a :--> PMaybe b) :--> list a :--> list b) -pmapMaybe = - phoistAcyclic $ - plam $ \func -> - precList - ( \self x xs -> - pmatch (func # x) $ \case - PJust y -> (pcons # y # (self # xs)) - PNothing -> (self # xs) - ) - (const pnil) - -paysToPubKey :: Term s (PPubKeyHash :--> PTxOut :--> PBool) -paysToPubKey = phoistAcyclic $ - plam $ \pkh txOut -> - let txOutCred = pfield @"credential" # (pfield @"address" # txOut) - in pmatch txOutCred $ \case - PScriptCredential _ -> pconstant False - PPubKeyCredential pkh' -> (pfield @"_0" # pkh') #== pkh - -ptryOutputToAddress :: (PIsListLike list PTxOut) => Term s (list PTxOut :--> PAddress :--> PTxOut) -ptryOutputToAddress = phoistAcyclic $ - plam $ \outs target -> - ( pfix #$ plam $ \self xs -> - pelimList - ( \txo txos -> - pif (target #== (pfield @"address" # txo)) txo (self # txos) - ) - perror - xs - ) - # outs - -ptryOwnOutput :: (PIsListLike list PTxOut) => Term s (list PTxOut :--> PScriptHash :--> PTxOut) -ptryOwnOutput = phoistAcyclic $ - plam $ \outs target -> - ( pfix #$ plam $ \self xs -> - pelimList - ( \txo txos -> - pmatch (pfield @"credential" # (pfield @"address" # txo)) $ \case - PPubKeyCredential _ -> (self # txos) - PScriptCredential ((pfield @"_0" #) -> vh) -> - pif (target #== vh) txo (self # txos) - ) - perror - xs - ) - # outs - -ptryOwnInput :: (PIsListLike list PTxInInfo) => Term s (list PTxInInfo :--> PTxOutRef :--> PTxOut) -ptryOwnInput = phoistAcyclic $ - plam $ \inputs ownRef -> - precList (\self x xs -> pletFields @'["outRef", "resolved"] x $ \txInFields -> pif (ownRef #== txInFields.outRef) txInFields.resolved (self # xs)) (const perror) # inputs - -pmustFind :: (PIsListLike l a) => Term s ((a :--> PBool) :--> l a :--> a) -pmustFind = - phoistAcyclic $ plam $ \f -> pfix #$ plam $ \self xs -> pelimList (\y ys -> pif (f # y) y (self # ys)) perror xs - -- Get the head of the list if the list contains exactly one element, otherwise error. pheadSingleton :: (PListLike list, PElemConstraint list a) => Term s (list a :--> a) pheadSingleton = phoistAcyclic $ @@ -308,69 +86,6 @@ pheadSingleton = phoistAcyclic $ (ptraceError "List is empty.") xs -ptxSignedByPkh :: - Term s (PAsData PPubKeyHash :--> PBuiltinList (PAsData PPubKeyHash) :--> PBool) -ptxSignedByPkh = pelem - -psymbolValueOfHelper :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term - s - ( (PInteger :--> PBool) - :--> PCurrencySymbol - :--> ( PValue keys amounts - :--> PInteger - ) - ) -psymbolValueOfHelper = - phoistAcyclic $ - plam $ \cond sym value'' -> unTermCont $ do - PValue value' <- pmatchC value'' - PMap value <- pmatchC value' - m' <- - tcexpectJust - 0 - ( plookupAssoc - # pfstBuiltin - # psndBuiltin - # pdata sym - # value - ) - PMap m <- pmatchC (pfromData m') - pure $ - pfoldr - # plam - ( \x v -> - plet (pfromData $ psndBuiltin # x) $ \q -> - pif - (cond # q) - (q + v) - v - ) - # 0 - # m - --- | @since 1.0.0 -ppositiveSymbolValueOf :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PCurrencySymbol :--> (PValue keys amounts :--> PInteger)) -ppositiveSymbolValueOf = phoistAcyclic $ psymbolValueOfHelper #$ plam (0 #<) - --- | @since 1.0.0 -pnegativeSymbolValueOf :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PCurrencySymbol :--> (PValue keys amounts :--> PInteger)) -pnegativeSymbolValueOf = phoistAcyclic $ psymbolValueOfHelper #$ plam (#< 0) - -- | Probably more effective than `plength . pflattenValue` pcountOfUniqueTokens :: forall @@ -416,74 +131,6 @@ pfindWithRest = phoistAcyclic $ mnil = const (ptraceError "Find") in precList mcons mnil # ys # pnil -pcountCS :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PValue keys amounts :--> PInteger) -pcountCS = phoistAcyclic $ - plam $ \val -> - pmatch val $ \(PValue val') -> - pmatch val' $ \(PMap csPairs) -> - plength # csPairs - -pcountNonAdaCS :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PValue keys amounts :--> PInteger) -pcountNonAdaCS = - phoistAcyclic $ - let go :: Term _ (PInteger :--> PBuiltinList (PBuiltinPair (PAsData PCurrencySymbol) (PAsData (PMap keys PTokenName PInteger))) :--> PInteger) - go = plet (pdata padaSymbol) $ \padaSymbolD -> - pfix #$ plam $ \self n -> - pelimList (\x xs -> pif (pfstBuiltin # x #== padaSymbolD) (self # n # xs) (self # (n + 1) # xs)) n - in plam $ \val -> - pmatch val $ \(PValue val') -> - pmatch val' $ \(PMap csPairs) -> - go # 0 # csPairs - -pfirstTokenName :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PValue keys amounts :--> PTokenName) -pfirstTokenName = phoistAcyclic $ - plam $ \val -> - pmatch val $ \(PValue val') -> - pmatch val' $ \(PMap csPairs) -> - pmatch (pfromData (psndBuiltin # (phead # csPairs))) $ \(PMap tokens) -> - pfromData $ pfstBuiltin # (phead # tokens) - -ptryLookupValue :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term - s - ( PAsData PCurrencySymbol - :--> PValue keys amounts - :--> PBuiltinList (PBuiltinPair (PAsData PTokenName) (PAsData PInteger)) - ) -ptryLookupValue = phoistAcyclic $ - plam $ \policyId val -> - pmatch val $ \(PValue val') -> - precList - ( \self x xs -> - pif - (pfstBuiltin # x #== policyId) - ( pmatch (pfromData (psndBuiltin # x)) $ \(PMap tokens) -> - tokens - ) - (self # xs) - ) - (const perror) - # pto val' - psingletonOfCS :: forall (keys :: KeyGuarantees) @@ -511,151 +158,6 @@ psingletonOfCS = phoistAcyclic $ (const perror) # pto val' -pvalueOfOne :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term - s - ( PAsData PCurrencySymbol - :--> PValue keys amounts - :--> PBool - ) -pvalueOfOne = phoistAcyclic $ - plam $ \policyId val -> - pmatch val $ \(PValue val') -> - precList - ( \self x xs -> - pif - (pfstBuiltin # x #== policyId) - ( pmatch (pfromData (psndBuiltin # x)) $ \(PMap tokens) -> - pfromData (psndBuiltin # (pheadSingleton # tokens)) #== 1 - ) - (self # xs) - ) - (const (pconstant False)) - # pto val' - -pvalueOfOneScott :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term - s - ( PCurrencySymbol - :--> PValue keys amounts - :--> PBool - ) -pvalueOfOneScott = phoistAcyclic $ - plam $ \policyId val -> - pmatch val $ \(PValue val') -> - precList - ( \self x xs -> - pif - (pfromData (pfstBuiltin # x) #== policyId) - ( pmatch (pfromData (psndBuiltin # x)) $ \(PMap tokens) -> - pfromData (psndBuiltin # (pheadSingleton # tokens)) #== 1 - ) - (self # xs) - ) - (const (pconstant False)) - # pto val' - -pfirstTokenNameWithCS :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PAsData PCurrencySymbol :--> PValue keys amounts :--> PTokenName) -pfirstTokenNameWithCS = phoistAcyclic $ - plam $ \policyId val -> - pmatch val $ \(PValue val') -> - precList - ( \self x xs -> - pif - (pfstBuiltin # x #== policyId) - ( pmatch (pfromData (psndBuiltin # x)) $ \(PMap tokens) -> - pfromData $ pfstBuiltin # (phead # tokens) - ) - (self # xs) - ) - (const perror) - # pto val' - --- | Finds amount of the first asset in a value that doesn't have ownPolicyId as its currency symbol. -ptryFindAmt :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PCurrencySymbol :--> PValue keys amounts :--> PInteger) -ptryFindAmt = phoistAcyclic $ - plam $ \ownPolicyId val -> - pmatch val $ \(PValue val') -> - pmatch val' $ \(PMap csPairs) -> - precList - ( \self x xs -> - pif - (pnot # (pfromData (pfstBuiltin # x) #== ownPolicyId)) - ( pmatch (pfromData (psndBuiltin # x)) $ \(PMap tokens) -> - pfoldr - # plam - ( \x acc -> - plet (pfromData $ psndBuiltin # x) $ \q -> - pif - (0 #< q) - (q + acc) - acc - ) - # 0 - # tokens - ) - (self # xs) - ) - (const $ ptraceError "ptryFindAmt") - # csPairs - -phasInput :: Term s (PBuiltinList PTxInInfo :--> PTxOutRef :--> PBool) -phasInput = phoistAcyclic $ plam $ \refs oref -> pany # plam (\oref' -> oref #== pfield @"outRef" # oref') # refs - -pvalueContains :: - ClosedTerm - ( PValue 'Sorted 'Positive - :--> PValue 'Sorted 'Positive - :--> PBool - ) -pvalueContains = phoistAcyclic $ - plam $ \superset subset -> - let forEachTN cs = plam $ \tnPair -> - let tn = pfromData $ pfstBuiltin # tnPair - amount = pfromData $ psndBuiltin # tnPair - in amount #<= pvalueOf # superset # cs # tn - forEachCS = plam $ \csPair -> - let cs = pfromData $ pfstBuiltin # csPair - tnMap = pto $ pfromData $ psndBuiltin # csPair - in pall # forEachTN cs # tnMap - in pall # forEachCS #$ pto $ pto subset - -{- | Extract the token name and the amount of the given currency symbol. -Throws when the token name is not found or more than one token name is involved -Plutarch level function. --} -ponlyAsset :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PValue keys amounts :--> PTriple PCurrencySymbol PTokenName PInteger) -ponlyAsset = phoistAcyclic $ - plam $ \val -> - pmatch val $ \(PValue val') -> - plet (pheadSingleton # pto val') $ \valuePair -> - pmatch (pfromData (psndBuiltin # valuePair)) $ \(PMap tokens) -> - plet (pheadSingleton # tokens) $ \tkPair -> - pcon (PTriple (pfromData (pfstBuiltin # valuePair)) (pfromData (pfstBuiltin # tkPair)) (pfromData (psndBuiltin # tkPair))) - pand'List :: [Term s PBool] -> Term s PBool pand'List ts' = case ts' of diff --git a/test/Spec.hs b/test/Spec.hs new file mode 100644 index 0000000..d5f9b19 --- /dev/null +++ b/test/Spec.hs @@ -0,0 +1,12 @@ +module Main (main) where + +import Spec.LinkedListSpec (unitTest) +import Test.Tasty (defaultMain, testGroup) + +main :: IO () +main = do + defaultMain $ + testGroup + "Unit Test Group" + [ unitTest + ] diff --git a/test/Spec/LinkedListSpec.hs b/test/Spec/LinkedListSpec.hs new file mode 100644 index 0000000..f7b2f53 --- /dev/null +++ b/test/Spec/LinkedListSpec.hs @@ -0,0 +1,90 @@ +{-# OPTIONS_GHC -Wno-redundant-constraints #-} +{-# OPTIONS_GHC -Wno-unused-imports #-} + +module Spec.LinkedListSpec ( + mkLiquidityNodeMP, + mkLiquidityNodeMPW, +) where +import Plutarch.Api.V2 ( + PMintingPolicy, + PScriptContext, + PTxOutRef, + ) +import Plutarch.Extra.Interval (pafter, pbefore) + +-- pRemoveAndDeinit, + +import Plutarch.Internal (Config (..)) +import Plutarch.Monadic qualified as P +import Plutarch.Unsafe (punsafeCoerce) +import Plutarch.LinkedList ( + PPriceDiscoveryCommon (mint, ownCS), + makeCommon, + pDeinit, + pInit, + pInsert, + pRemove, + pClaim + ) +import Plutarch.Helpers ( + hasUtxoWithRef, + ) + +import Plutarch.Prelude +import Plutarch.Utils (pand'List, passert, pcond) +import Plutarch.Types (PDiscoveryConfig (..), PDiscoveryNodeAction (..)) + +-------------------------------- +-- FinSet Node Minting Policy: +-------------------------------- + +mkDiscoveryNodeMP :: + Config -> + ClosedTerm + ( PDiscoveryConfig + :--> PDiscoveryNodeAction + :--> PScriptContext + :--> PUnit + ) +mkDiscoveryNodeMP cfg = plam $ \discConfig redm ctx -> P.do + configF <- pletFields @'["initUTxO"] discConfig + + (common, inputs, outs, sigs, vrange) <- + runTermCont $ + makeCommon cfg ctx + + pmatch redm $ \case + PInit _ -> P.do + passert "Init must consume TxOutRef" $ + hasUtxoWithRef # configF.initUTxO # inputs + pInit cfg common + PDeinit _ -> + -- TODO deinit must check that reward fold has been completed + pDeinit cfg common + PInsert action -> P.do + act <- pletFields @'["keyToInsert", "coveringNode"] action + let insertChecks = + pand'List + [ pafter # (pfield @"discoveryDeadline" # discConfig) # vrange + , pelem # act.keyToInsert # sigs + ] + pif insertChecks (pInsert cfg common # act.keyToInsert # act.coveringNode) perror + PRemove action -> P.do + configF <- pletFields @'["discoveryDeadline"] discConfig + act <- pletFields @'["keyToRemove", "coveringNode"] action + discDeadline <- plet configF.discoveryDeadline + pcond + [ ((pbefore # discDeadline # vrange), (pClaim cfg common outs sigs # act.keyToRemove)) + , ((pafter # discDeadline # vrange), (pRemove cfg common vrange discConfig outs sigs # act.keyToRemove # act.coveringNode)) + ] + perror + +mkDiscoveryNodeMPW :: + Config -> + ClosedTerm + ( PDiscoveryConfig + :--> PMintingPolicy + ) +mkDiscoveryNodeMPW cfg = phoistAcyclic $ plam $ \discConfig redm ctx -> + let red = punsafeCoerce @_ @_ @PDiscoveryNodeAction redm + in popaque $ mkDiscoveryNodeMP cfg # discConfig # red # ctx