diff --git a/cabal.project b/cabal.project index c8dec6d..812325c 100644 --- a/cabal.project +++ b/cabal.project @@ -31,3 +31,10 @@ source-repository-package . plutarch-ledger-api plutarch-extra + +source-repository-package + type: git + location: https://github.com/input-output-hk/catalyst-onchain-libs + tag: 25996ca26f1b33ffef611bc81423aae5841e297f + subdir: + src/plutarch-onchain-lib diff --git a/src/lib/Plutarch/Extra/Record.hs b/src/lib/Plutarch/Extra/Record.hs deleted file mode 100644 index 293c02e..0000000 --- a/src/lib/Plutarch/Extra/Record.hs +++ /dev/null @@ -1,148 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} -{-# LANGUAGE PartialTypeSignatures #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE QualifiedDo #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE ViewPatterns #-} - -module Plutarch.Extra.Record ( - mkRecord, - mkRecordConstr, - (.=), - (.&), - RecordMorphism, - FieldName, -) where - -import Control.Category (Category (id, (.))) -import Data.Coerce (coerce) -import Data.Kind (Type) -import Data.Type.Equality (type (~)) -import GHC.OverloadedLabels (IsLabel (fromLabel)) -import GHC.TypeLits (Symbol) -import Plutarch (PlutusType, S, Term, pcon, (#)) -import Plutarch.Builtin (PAsData) -import Plutarch.DataRepr (PDataRecord, PLabeledType ((:=)), pdcons, pdnil) -import Prelude (($)) - -{- | Like 'Data.Proxy.Proxy' but local to this module. - - @since 1.3.0 --} -data FieldName (sym :: Symbol) = FieldName - -{- | The use of two different 'Symbol's here allows unification to happen, - ensuring 'FieldName' has a fully inferred 'Symbol'. - - For example, @'mkRecord' (#foo .= 'pconstantData' (42 :: 'Integer'))@ gets - the correct type. Namely, @'Term' s ('PDataRecord' '["foo" ':= 'PInteger'])@. - - @since 1.3.0 --} -instance - forall (sym :: Symbol) (sym' :: Symbol). - (sym ~ sym') => - IsLabel sym (FieldName sym) - where - fromLabel = FieldName - -{- | Turn a constant 'RecordMorphism' into a fully built 'PDataRecord'. - - @since 1.3.0 --} -mkRecord :: forall (r :: [PLabeledType]) (s :: S). RecordMorphism s '[] r -> Term s (PDataRecord r) -mkRecord f = runRecordMorphism f pdnil - -{- | 'mkRecord' but for known data-types. - -This allows you to dynamically construct a record type constructor. - -=== Example: -@ -'mkRecordConstr' - 'PScriptContext' - ( #txInfo '.=' '(Your PTxInfo)' - '.&' #purpose '.=' '(Your PScriptPurpose)' - ) -@ -Is the same as - -@ -'pconstant' ('ScriptContext' '(Your TxInfo)' '(Your ScriptPurpose)') -@ - -@since 1.3.0 --} -mkRecordConstr :: - forall (r :: [PLabeledType]) (s :: S) (pt :: S -> Type). - (PlutusType pt) => - -- | The constructor. This is just the Haskell-level constructor for the type. - -- For 'Plutarch.Api.V2.Maybe.PMaybeData', this would - -- be 'Plutarch.Api.V2.Maybe.PDJust', or 'Plutarch.Api.V2.Maybe.PNothing'. - (forall s'. Term s' (PDataRecord r) -> pt s') -> - -- | The morphism that builds the record. - RecordMorphism s '[] r -> - Term s pt -mkRecordConstr ctr = pcon . ctr . mkRecord - -{- | A morphism from one 'PDataRecord' to another, representing some sort of consing of data. - - @since 1.3.0 --} -newtype RecordMorphism (s :: S) (as :: [PLabeledType]) (bs :: [PLabeledType]) - = RecordMorphism (Term s (PDataRecord as) -> Term s (PDataRecord bs)) - --- | @since 3.8.0 -runRecordMorphism :: - forall (s :: S) (as :: [PLabeledType]) (bs :: [PLabeledType]). - RecordMorphism s as bs -> - Term s (PDataRecord as) -> - Term s (PDataRecord bs) -runRecordMorphism (RecordMorphism f) = f - --- | @since 1.3.0 -instance Category (RecordMorphism s) where - id = RecordMorphism id - f . g = coerce $ runRecordMorphism f . runRecordMorphism g - -infix 7 .= - -{- | Cons a labeled type as a 'RecordMorphism'. - - @since 3.1.0 --} -(.=) :: - forall (sym :: Symbol) (a :: S -> Type) (as :: [PLabeledType]) (s :: S). - -- | The field name. You can use @-XOverloadedLabels@ to enable the syntax: - -- @#hello ~ 'FieldName' "hello"@ - FieldName sym -> - -- | The value at that field. This must be 'PAsData', because the underlying - -- type is @'PlutusCore.Data.Constr' 'Integer' ['PlutusCore.Data.Data']@. - Term s (PAsData a) -> - RecordMorphism s as ((sym ':= a) ': as) -_ .= x = RecordMorphism $ \rest -> pdcons # x # rest - -infixr 6 .& - -{- | Compose two 'RecordMorphism's. - - @since 1.3.0 --} -(.&) :: - forall - (s :: S) - (a :: [PLabeledType]) - (b :: [PLabeledType]) - (c :: [PLabeledType]). - RecordMorphism s b c -> - RecordMorphism s a b -> - RecordMorphism s a c -(.&) = (.) diff --git a/src/lib/Plutarch/Extra/Record.hs:Zone.Identifier b/src/lib/Plutarch/Extra/Record.hs:Zone.Identifier deleted file mode 100644 index e69de29..0000000 diff --git a/src/lib/SmartTokens/Contracts/ExampleTransferLogic.hs b/src/lib/SmartTokens/Contracts/ExampleTransferLogic.hs index 1daa010..e2cd3ba 100644 --- a/src/lib/SmartTokens/Contracts/ExampleTransferLogic.hs +++ b/src/lib/SmartTokens/Contracts/ExampleTransferLogic.hs @@ -48,7 +48,7 @@ import Plutarch.Prelude PListLike(pcons, ptail, pelimList, phead), PUnit, (#||) ) import Plutarch.Builtin ( pasByteStr, pasConstr, pforgetData ) -import SmartTokens.Core.Utils +import Plutarch.Core.Utils ( pisRewarding, phasDataCS, pelemAtFast, diff --git a/src/lib/SmartTokens/Contracts/Issuance.hs b/src/lib/SmartTokens/Contracts/Issuance.hs index dba0edb..519148d 100644 --- a/src/lib/SmartTokens/Contracts/Issuance.hs +++ b/src/lib/SmartTokens/Contracts/Issuance.hs @@ -7,7 +7,7 @@ import Plutarch.Monadic qualified as P import Plutarch.Prelude import Plutarch.Builtin import Plutarch.LedgerApi.Value -import SmartTokens.Core.Utils +import Plutarch.Core.Utils import Plutarch.Unsafe import Plutarch.Internal.PlutusType (PlutusType(pcon', pmatch')) --import SmartTokens.Types.PTokenDirectory (PDirectorySetNode) diff --git a/src/lib/SmartTokens/Contracts/ProgrammableLogicBase.hs b/src/lib/SmartTokens/Contracts/ProgrammableLogicBase.hs index fe9639a..604f42b 100644 --- a/src/lib/SmartTokens/Contracts/ProgrammableLogicBase.hs +++ b/src/lib/SmartTokens/Contracts/ProgrammableLogicBase.hs @@ -7,7 +7,7 @@ import Plutarch.LedgerApi.V3 import Plutarch.Monadic qualified as P import Plutarch.Prelude import Plutarch.Builtin -import SmartTokens.Core.Utils +import Plutarch.Core.Utils import Plutarch.Unsafe import PlutusLedgerApi.V1.Value import SmartTokens.Types.ProtocolParams (PProgrammableLogicGlobalParams) diff --git a/src/lib/SmartTokens/Contracts/ProgrammableLogicBase.txt b/src/lib/SmartTokens/Contracts/ProgrammableLogicBase.txt deleted file mode 100644 index 81bb239..0000000 --- a/src/lib/SmartTokens/Contracts/ProgrammableLogicBase.txt +++ /dev/null @@ -1,92 +0,0 @@ -module SmartTokens.Contracts.ProgrammableLogicBase ( - mkProgrammableLogicBase, -) where - -import Plutarch.LedgerApi.V3 -import Plutarch.Monadic qualified as P -import Plutarch.Unsafe (punsafeCoerce) -import Plutarch.Prelude -import Plutarch.Builtin -import Plutarch.LedgerApi.Value -import SmartTokens.Core.Utils -import SmartTokens.Core.List -import Plutarch.Evaluate (unsafeEvalTerm) -import Plutarch.Internal (Config(..)) -import PlutusCore qualified as PLC -import Plutarch.Unsafe -import SmartTokens.Types.ProtocolParams - -pprocessProgrammableLogicInput :: Term s PBuiltinList (PAsData PTxInInfo) -> Term s (PValue 'Sorted 'Positive) -> Term s (PAsData PTxInInfo) -> Term s (PValue 'Sorted 'Positive) -pprocessProgrammableLogicInput refIns accTotalValue progLogicInput = - perror - -pfoldProgrammableLogicInputs :: Term s (PBuiltinList (PAsData PTxInInfo)) -> Term s (PBuiltinList (PAsData PTxInInfo) :--> PValue 'Sorted 'Positive) -pfoldProgrammableLogicInputs refIns = - let go = pfix #$ plam $ \self acc -> - pelimList - (\x xs -> self # f refIns acc x # xs) - (pconstant @(PValue 'Sorted 'Positive) mempty) - in go - --- | Sum the values of the inputs from a given script credential --- pvalueFromScript :: --- forall (s :: S). --- Term s (PBuiltinList PTxInInfo :--> PValue 'Sorted 'Positive) --- pvalueFromScript = phoistAcyclic $ --- plam $ \inputs -> --- pfoldr --- # plam --- ( \txInInfo' v -> --- pmatch --- txInInfo' --- $ \(PTxInInfo txInInfo) -> --- pmatch --- (pfield @"resolved" # txInInfo) --- (\(PTxOut o) -> pfield @"value" # o) --- <> v --- ) --- -- TODO: This should be possible without coercions, but I can't figure out the types atm. --- # punsafeCoerce (pconstant mempty :: forall (s' :: S). Term s' (PValue 'Unsorted 'NonZero)) --- # inputs - - --- | Programmable logic base --- This validator forwards its validation logic to the programmable logic stake script --- using the withdraw-zero design pattern. -mkProgrammableLogicBase :: ClosedTerm (PAsData PCredential :--> PScriptContext :--> PUnit) -mkProgrammableLogicBase = plam $ \stakeCred ctx -> - plet (to $ pfromData $ pfield @"wdrl" # (pfield @"txInfo" # ctx)) $ \withdrawals -> - let firstWithdrawal = phead # withdrawals - hasCred = - pif (pfstBuiltin # firstWithdrawal #== stakeCred) - (pconstant True) - ( - pcanFind @PBuiltinList - # plam (\withdrawPair -> pfstBuiltin # withdrawPair #== stakeCred) - # (ptail # withdrawals) - ) - in pvalidateConditions [hasCred] - -type ProgrammableLogicGlobalRedeemer = PBuiltinList (PAsData PInteger) - -mkProgrammableLogicGlobal :: ClosedTerm (PAsData PCurrencySymbol :--> PScriptContext :--> PUnit) -mkProgrammableLogicGlobal = plam $ \nodeCS ctx -> P.do - ctxF <- pletFields @'["txInfo", "redeemer", "scriptInfo"] ctx - infoF <- pletFields @'["inputs", "referenceInputs", "outputs", "wdrl"] ctxF.txInfo - red <- plet $ pfromData $ punsafeCoerce @_ @_ @(PAsData ProgrammableLogicGlobalRedeemer) (pto ctxF.redeemer) - - let invokedScripts = pmap @PBuiltinList - # plam (\wdrlPair -> - let cred = pfstBuiltin # wdrlPair - in unsafeCoerce @_ @_ @(PAsData PByteString) $ pasByteStr $ psndBuiltin #$ pasConstr # pforgetData cred - ) - # pto pfromData infoF.wdrl - - let idxLength = phead # red - redeemerIdxs <- plet $ ptail # red - - pvalidateConditions - [ pisRewarding # ctxF.scriptInfo - -- No duplicate indices in the redeemer - , pisUniqueSet # idxLength # redeemerIdxs - ] \ No newline at end of file diff --git a/src/lib/SmartTokens/Contracts/ProtocolParams.hs b/src/lib/SmartTokens/Contracts/ProtocolParams.hs index 77fd6c4..60f7eee 100644 --- a/src/lib/SmartTokens/Contracts/ProtocolParams.hs +++ b/src/lib/SmartTokens/Contracts/ProtocolParams.hs @@ -22,7 +22,7 @@ import Plutarch.Prelude psndBuiltin, pletFields, PUnit, pfield ) -import SmartTokens.Core.Utils +import Plutarch.Core.Utils ( pheadSingleton, ptryLookupValue, phasUTxO, diff --git a/src/lib/SmartTokens/Core/Crypto.hs b/src/lib/SmartTokens/Core/Crypto.hs deleted file mode 100644 index 7b56b40..0000000 --- a/src/lib/SmartTokens/Core/Crypto.hs +++ /dev/null @@ -1,62 +0,0 @@ -module SmartTokens.Core.Crypto ( - pcardanoPubKeyToPubKeyHash, - pethereumPubKeyToPubKeyHash, - pcompressPublicKey, - scriptHashV3 -) where - -import Plutarch ( - Term, - type (:-->), - plet, - phoistAcyclic, - (#), - plam, - ) -import Plutarch.ByteString (PByteString, plengthBS, psliceBS, pindexBS) -import Plutarch.Crypto (pkeccak_256, pblake2b_224) -import Plutarch.Integer (PInteger, pmod) -import Plutarch.Lift (pconstant) -import Plutarch.Bool (pif, (#==)) -import PlutusCore.Crypto.Hash qualified as Hash -import PlutusLedgerApi.Common (serialiseUPLC) -import Data.ByteString.Short (fromShort) -import Plutarch.Script (Script(unScript)) -import Data.ByteString (ByteString) -import Data.ByteString qualified as BS -import Data.Word (Word8) - -scriptHashV3 :: Script -> ByteString -scriptHashV3 = hashScriptWithPrefix 0x3 - -hashScriptWithPrefix :: Word8 -> Script -> ByteString -hashScriptWithPrefix prefix scr = - Hash.blake2b_224 - $ BS.singleton prefix <> (fromShort . serialiseUPLC . unScript $ scr) - -pcardanoPubKeyToPubKeyHash :: Term s (PByteString :--> PByteString) -pcardanoPubKeyToPubKeyHash = phoistAcyclic $ plam $ \pubKey -> pblake2b_224 # pubKey - -pethereumPubKeyToPubKeyHash :: Term s (PByteString :--> PByteString) -pethereumPubKeyToPubKeyHash = phoistAcyclic $ plam $ \pubKey -> - plet (pkeccak_256 # pubKey) $ \fullHash -> - (pdropBS # (plengthBS # fullHash - 20) # fullHash) - -pcompressPublicKey :: Term s PByteString -> Term s PByteString -pcompressPublicKey pubKey = - plet (ptakeBS # 32 # pubKey) $ \xCoordinate -> - pif - (peven yCoordinate) - (pconstant "\x02" <> xCoordinate) - (pconstant "\x03" <> xCoordinate) - where - yCoordinate = pdropBS # 32 # pubKey - peven bs = (pmod # (pindexBS # bs # 31) # 2) #== 0 - -ptakeBS :: Term s (PInteger :--> PByteString :--> PByteString) -ptakeBS = phoistAcyclic $ plam $ \n bs -> - psliceBS # 0 # n # bs - -pdropBS :: Term s (PInteger :--> PByteString :--> PByteString) -pdropBS = phoistAcyclic $ plam $ \n bs -> - psliceBS # n # (plengthBS # bs - n) # bs \ No newline at end of file diff --git a/src/lib/SmartTokens/Core/List.hs b/src/lib/SmartTokens/Core/List.hs deleted file mode 100644 index d0fcd9e..0000000 --- a/src/lib/SmartTokens/Core/List.hs +++ /dev/null @@ -1,160 +0,0 @@ -{-# HLINT ignore "Use camelCase" #-} -{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} -module SmartTokens.Core.List ( - pdropFast, - pisUniqueSet, - phasNSetBits, - pbuiltinListLengthFast, - penforceNSpendRedeemers, - phasNUniqueElements, -) where -import Plutarch (ClosedTerm, Config (NoTracing), PType, S, Term, perror, pfix, - phoistAcyclic, plam, plet, pto, type (:-->), (#$), (#)) -import Plutarch.Bitwise (pcountSetBits, pwriteBits) -import Plutarch.Bool (PBool, PEq ((#==)), PPartialOrd ((#<), (#<=)), pif, pnot) -import Plutarch.Builtin (PAsData, PBuiltinList, PBuiltinPair, pasConstr, - pforgetData, pfstBuiltin) -import Plutarch.ByteString (PByteString, pconsBS, phexByteStr, pindexBS) -import SmartTokens.Core.Utils (pcond, ptails10, ptails20, ptails30, (#>)) -import Plutarch.Evaluate (unsafeEvalTerm) -import Plutarch.Integer (PInteger, PIntegral (pmod)) -import Plutarch.LedgerApi.AssocMap qualified as AssocMap -import Plutarch.LedgerApi.V3 (PRedeemer (..), PScriptPurpose (..)) -import Plutarch.Lift (pconstant) -import Plutarch.List (PIsListLike, - PListLike (PElemConstraint, pcons, pelimList, phead, pnil, ptail)) -import Plutarch.Monadic qualified as P -import Plutarch.Num ((#*)) -import Prelude - -pdropR :: forall (list :: PType -> PType) (a :: PType) (s :: S). - PIsListLike list a => - Term s (PInteger :--> list a :--> list a) -pdropR = phoistAcyclic $ - let go :: Term _ (PInteger :--> list a :--> list a) - go = pfix #$ plam $ \self n ys -> - pif (n #== 0) ys (self # (n - 1) # (ptail # ys)) - in go - -pdropFast :: PIsListLike PBuiltinList a => Term s (PInteger :--> PBuiltinList a :--> PBuiltinList a) -pdropFast = phoistAcyclic $ - let go = pfix #$ plam $ \self n ys -> - pcond - [ (30 #<= n, self # (n - 30) # (ptails30 # ys)) - , (20 #<= n, self # (n - 20) # (ptails20 # ys)) - , (10 #<= n, self # (n - 10) # (ptails10 # ys)) - ] - (pdropR # n # ys) - in go - -_byteBools :: ClosedTerm (PBuiltinList PBool) -_byteBools = unsafeEvalTerm NoTracing $ foldr (\h t -> pcons # pconstant h # t) pnil (replicate 255 True) - -emptyByteArray :: ClosedTerm PByteString -emptyByteArray = phexByteStr "0000000000000000000000000000000000000000000000000000000000000000" - -single_byte_powers :: ClosedTerm PByteString -single_byte_powers = foldr (\x acc -> pconsBS # pconstant x # acc) mempty [1,2,4,8,16,32,64,128] - --phexByteStr "0102040810204080" - -pcheckIndex :: Term s (PInteger :--> PInteger :--> PInteger) -pcheckIndex = phoistAcyclic $ plam $ \tagBits index -> P.do - bit <- plet $ pow2_trick # index - shifted_bit <- plet $ 2 * bit - set_bit <- plet $ tagBits + bit - pif (pmod # set_bit # shifted_bit #> pmod # tagBits # shifted_bit) - set_bit - perror - -pow2_trick :: Term s (PInteger :--> PInteger) -pow2_trick = plam $ \exponent' -> - pcond - [ (exponent' #< 8, pindexBS # single_byte_powers # exponent') - , (exponent' #< 16, 256 #* pindexBS # single_byte_powers # (exponent' - 8)) - , (exponent' #< 24, 65536 #* pindexBS # single_byte_powers # (exponent' - 16)) - , (exponent' #< 32, 16777216 #* pindexBS # single_byte_powers # (exponent' - 24)) - , (exponent' #< 40, 4294967296 #* pindexBS # single_byte_powers # (exponent' - 32)) - , (exponent' #< 48, 1099511627776 #* pindexBS # single_byte_powers # (exponent' - 40)) - , (exponent' #< 56, 281474976710656 #* pindexBS # single_byte_powers # (exponent' - 48)) - ] - (281474976710656 #* ppow2 # (exponent' - 48)) - -ppow2 :: Term s (PInteger :--> PInteger) -ppow2 = phoistAcyclic $ pfix #$ plam $ \self e -> - pif (e #< 8) - (pif (e #< 0) - 0 - (pindexBS # single_byte_powers # e) - ) - (pif (e #< 32) - (256 #* self # (e - 8)) - (4294967296 #* self # (e - 32)) - ) - -phasNSetBits :: Term s PInteger -> Term s PByteString -> Term s PBool -phasNSetBits n bs = - let setBits = pcountSetBits # bs - in setBits #== n - --- let (_, result2, _) = fromRight (error "") (evalTerm NoTracing (pisUniqueSet # 10 # pconstant [0..9]) --- TODO: Update CHaP and Plutarch -pisUniqueSet :: Term s (PInteger :--> PBuiltinList PInteger :--> PBool) -pisUniqueSet = phoistAcyclic $ plam $ \n xs -> - let flagUniqueBits = pwriteBits # emptyByteArray # xs # pconstant True - in (pcountSetBits # flagUniqueBits #== (pbuiltinListLengthFast # n # xs)) - -phasNUniqueElements :: Term s (PInteger :--> PBuiltinList PInteger :--> PBool) -phasNUniqueElements = phoistAcyclic $ plam $ \n xs -> - let flagUniqueBits = pwriteBits # emptyByteArray # xs # pconstant True - in (pcountSetBits # flagUniqueBits #== n) - --- exists to bench against pisUniqueSet -_pIsUnique :: Term s (PBuiltinList PInteger :--> PBool) -_pIsUnique = phoistAcyclic $ plam $ \list -> - let go :: Term _ (PInteger :--> PBuiltinList PInteger :--> PBool) - go = pfix #$ plam $ \self flag_bit xs -> - pelimList - (\y ys -> - self # (pcheckIndex # flag_bit # y) # ys - ) - (pconstant True) - xs - in go # 0 # list - -pbuiltinListLength :: forall s a. (PElemConstraint PBuiltinList a) => Term s PInteger -> Term s (PBuiltinList a :--> PInteger) -pbuiltinListLength acc = - (pfix #$ plam $ \self acc' l -> - pelimList - (\_ ys -> self # (acc' + 1) # ys) -- cons case - acc' -- nil case - l - ) - # acc - -pbuiltinListLengthFast :: forall (a :: PType) (s :: S). (PElemConstraint PBuiltinList a) => Term s (PInteger :--> PBuiltinList a :--> PInteger) -pbuiltinListLengthFast = phoistAcyclic $ plam $ \n elems -> - let go :: Term _ (PInteger :--> PInteger :--> PBuiltinList a :--> PInteger) - go = pfix #$ plam $ \self remainingExpected currentCount xs -> - pcond - [ (30 #<= remainingExpected, self # (remainingExpected - 30) # (currentCount + 30) # (ptails30 # xs)) - , (20 #<= remainingExpected, self # (remainingExpected - 20) # (currentCount + 20) # (ptails20 # xs)) - , (10 #<= remainingExpected, self # (remainingExpected - 10) # (currentCount + 10) # (ptails10 # xs)) - ] - (pbuiltinListLength 0 # xs) - in go # n # 0 # elems - -penforceNSpendRedeemers :: forall {s :: S}. Term s PInteger -> Term s (AssocMap.PMap 'AssocMap.Unsorted PScriptPurpose PRedeemer) -> Term s PBool -penforceNSpendRedeemers n rdmrs = - let isNonSpend :: Term _ (PAsData PScriptPurpose) -> Term _ PBool - isNonSpend red = pnot # (pfstBuiltin # (pasConstr # pforgetData red) #== 1) - - isLastSpend :: Term _ (PBuiltinList (PBuiltinPair (PAsData PScriptPurpose) (PAsData PRedeemer)) :--> PBool) - isLastSpend = plam $ \redeemers -> - let constrPair :: Term s (PAsData PScriptPurpose) - constrPair = pfstBuiltin # (phead # redeemers) - constrIdx = pfstBuiltin # (pasConstr # pforgetData constrPair) - in pif - (constrIdx #== 1) - (pelimList (\x _ -> isNonSpend (pfstBuiltin # x)) (pconstant True) (ptail # redeemers)) - perror - in isLastSpend # (pdropFast # (n - 1) # pto rdmrs) diff --git a/src/lib/SmartTokens/Core/PlutusDataList.hs b/src/lib/SmartTokens/Core/PlutusDataList.hs deleted file mode 100644 index 2037d31..0000000 --- a/src/lib/SmartTokens/Core/PlutusDataList.hs +++ /dev/null @@ -1,272 +0,0 @@ -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE QuantifiedConstraints #-} -{-# OPTIONS_GHC -Wno-unused-type-patterns #-} - -module SmartTokens.Core.PlutusDataList ( - -- * PlutusTx ToData/FromData derive-wrappers - ProductIsData (..), - unProductIsData, - - -- * Plutarch PIsData/PlutusType derive-wrappers - DerivePConstantViaDataList (..), - - -- * Plutarch deriving strategy - PlutusTypeDataList, - -) where - --------------------------------------------------------------------------------- - -import Data.Coerce (coerce) -import Data.Functor.Identity (Identity (Identity, runIdentity)) -import Data.Kind (Constraint) -import Data.Maybe (fromJust) -import Data.Proxy (Proxy (Proxy)) -import GHC.TypeLits (ErrorMessage (ShowType, Text, (:$$:), (:<>:)), TypeError) -import Generics.SOP ( - All, - IsProductType, - hcmap, - hcollapse, - hctraverse, - mapIK, - mapKI, - productTypeFrom, - productTypeTo, - unI, - ) -import Generics.SOP qualified as SOP -import Plutarch.Internal.Generic (PCode, PGeneric, gpfrom, gpto) -import Plutarch.Internal.PlutusType ( - PlutusTypeStrat (DerivedPInner, PlutusTypeStratConstraint, derivedPCon, derivedPMatch), - ) -import Plutarch.Lift (PConstantDecl (PConstantRepr, PConstanted, pconstantFromRepr, pconstantToRepr), PLifted) -import PlutusLedgerApi.V1 ( - BuiltinData (BuiltinData), - UnsafeFromData (unsafeFromBuiltinData), - ) -import PlutusTx ( - Data (List), - FromData (fromBuiltinData), - ToData (toBuiltinData), - fromData, - toData, - ) -import Plutarch -import Plutarch.Prelude --------------------------------------------------------------------------------- --- ProductIsData - -{- | Wrapper for deriving 'ToData', 'FromData' using the List - constructor of Data to represent a Product type. - - It is recommended to use 'PlutusTypeDataList' when deriving - 'PlutusType' as it provides some basic safety by ensuring - Plutarch types have an Inner type of 'PDataRecord'. - - Uses 'gProductToBuiltinData', 'gproductFromBuiltinData'. - - = Example -@ -import qualified Generics.SOP as SOP - -data Foo = - Foo Integer [Integer] - deriving stock (Generic) - deriving anyclass (SOP.Generic) - deriving (FromData, ToData) via (ProductIsData Foo) - deriving (PConstantDecl) via (DerivePConstantViaDataList Foo PFoo) - -instance PUnsafeLiftDecl PFoo where type PLifted PFoo = Foo - -newtype PFoo s - = PFoo - ( Term s - ( PDataRecord - '[ "abc" ':= PInteger - , "def" ':= PBuiltinList (PAsData PInteger) - ] - ) - ) - deriving stock (Generic) - deriving anyclass (SOP.Generic) - deriving anyclass (PlutusType, PIsData) - -instance DerivePlutusType PFoo where - type DPTStrat _ = PlutusTypeDataList -@ - - @since 3.8.0 --} -newtype ProductIsData (a :: Type) = ProductIsData a - --- | Variant of 'PConstantViaData' using the List repr from 'ProductIsData' -newtype DerivePConstantViaDataList (h :: Type) (p :: S -> Type) = DerivePConstantViaDataList h - -type family GetPRecord' (a :: [[S -> Type]]) :: [PLabeledType] where - GetPRecord' '[ '[PDataRecord a]] = a - -type family GetPRecord (a :: S -> Type) :: S -> Type where - GetPRecord a = PDataRecord (GetPRecord' (PCode a)) - -type family GetRecordTypes (n :: [[Type]]) :: [S -> Type] where - GetRecordTypes '[x ': xs] = PConstanted x ': GetRecordTypes '[xs] - GetRecordTypes '[ '[]] = '[] - -type family UD' (p :: S -> Type) :: S -> Type where - UD' (p x1 x2 x3 x4 x5) = p (UD' x1) (UD' x2) (UD' x3) (UD' x4) (UD' x5) - UD' (p x1 x2 x3 x4) = p (UD' x1) (UD' x2) (UD' x3) (UD' x4) - UD' (p x1 x2 x3) = p (UD' x1) (UD' x2) (UD' x3) - UD' (p x1 x2) = p (UD' x1) (UD' x2) - UD' (p x1) = p (PAsData (UD' x1)) - UD' p = p - -type family UD (p :: [S -> Type]) :: [S -> Type] where - UD (x ': xs) = UD' x ': UD xs - UD '[] = '[] - -type family PUnlabel (n :: [PLabeledType]) :: [S -> Type] where - PUnlabel ((_ ':= p) ': xs) = p ': PUnlabel xs - PUnlabel '[] = '[] - -type family MatchTypes' (n :: [S -> Type]) (m :: [S -> Type]) :: Bool where - MatchTypes' '[] '[] = 'True - MatchTypes' (x ': xs) (x ': ys) = MatchTypes' xs ys - MatchTypes' (x ': xs) (y ': ys) = 'False - MatchTypes' '[] ys = 'False - MatchTypes' xs '[] = 'False - -type family MatchTypesError (n :: [S -> Type]) (m :: [S -> Type]) (a :: Bool) :: Constraint where - MatchTypesError _ _ 'True = () - MatchTypesError n m 'False = - ( 'True ~ 'False - , TypeError - ( 'Text "Error when deriving 'PlutusTypeDataList':" - ':$$: 'Text "\tMismatch between constituent Haskell and Plutarch types" - ':$$: 'Text "Constituent Haskell Types: " - ':$$: 'Text "\t" - ':<>: 'ShowType n - ':$$: 'Text "Constituent Plutarch Types: " - ':$$: 'Text "\t" - ':<>: 'ShowType m - ) - ) - -type MatchTypes (n :: [S -> Type]) (m :: [S -> Type]) = - (MatchTypesError n m (MatchTypes' n m)) - -class - ( PGeneric p - , PCode p ~ '[ '[GetPRecord p]] - ) => - IsPlutusTypeDataList (p :: S -> Type) -instance - forall (p :: S -> Type). - ( PGeneric p - , PCode p ~ '[ '[GetPRecord p]] - , MatchTypes (UD (GetRecordTypes (SOP.Code (PLifted p)))) (PUnlabel (GetPRecord' (PCode p))) - ) => - IsPlutusTypeDataList p - --- | @since 3.5.0 -data PlutusTypeDataList - -instance PlutusTypeStrat PlutusTypeDataList where - type PlutusTypeStratConstraint PlutusTypeDataList = IsPlutusTypeDataList - type DerivedPInner PlutusTypeDataList a = GetPRecord a - derivedPCon x = case gpfrom x of - SOP.SOP (SOP.Z (x' SOP.:* SOP.Nil)) -> x' - SOP.SOP (SOP.S x') -> case x' of {} - derivedPMatch x f = f (gpto $ SOP.SOP $ SOP.Z $ x SOP.:* SOP.Nil) - --- | @since 3.8.0 -unProductIsData :: - forall (a :: Type). - ProductIsData a -> - a -unProductIsData = coerce - -{- | - Generically convert a Product-Type to 'BuiltinData' with the 'List' repr. - - @since 1.1.0 --} -gProductToBuiltinData :: - forall (a :: Type) (repr :: [Type]). - (IsProductType a repr, All ToData repr) => - a -> - BuiltinData -gProductToBuiltinData x = - BuiltinData $ List $ hcollapse $ hcmap (Proxy @ToData) (mapIK toData) $ productTypeFrom x - -{- | - Generically convert a Product-type from a 'BuiltinData' 'List' repr. - - @since 1.1.0 --} -gProductFromBuiltinData :: - forall (a :: Type) (repr :: [Type]). - (IsProductType a repr, All FromData repr) => - BuiltinData -> - Maybe a -gProductFromBuiltinData (BuiltinData (List xs)) = do - prod <- SOP.fromList @repr xs - productTypeTo <$> hctraverse (Proxy @FromData) (unI . mapKI fromData) prod -gProductFromBuiltinData _ = Nothing - -{- | - Unsafe version of 'gProductFromBuiltinData'. - - @since 1.1.0 --} -gProductFromBuiltinDataUnsafe :: - forall (a :: Type) (repr :: [Type]). - (IsProductType a repr, All UnsafeFromData repr) => - BuiltinData -> - a -gProductFromBuiltinDataUnsafe (BuiltinData (List xs)) = - let prod = fromJust $ SOP.fromList @repr xs - in productTypeTo $ - runIdentity $ - hctraverse - (Proxy @UnsafeFromData) - (unI . mapKI (Identity . unsafeFromBuiltinData . BuiltinData)) - prod -gProductFromBuiltinDataUnsafe _ = error "invalid representation" - --- | @since 1.1.0 -instance - forall (h :: Type) (p :: S -> Type). - (PlutusTx.FromData h, PlutusTx.ToData h, PLift p) => - PConstantDecl (DerivePConstantViaDataList h p) - where - type PConstantRepr (DerivePConstantViaDataList h p) = [PlutusTx.Data] - type PConstanted (DerivePConstantViaDataList h p) = p - pconstantToRepr (DerivePConstantViaDataList x) = case PlutusTx.toData x of - (PlutusTx.List xs) -> xs - _ -> error "ToData repr is not a List!" - pconstantFromRepr = coerce (PlutusTx.fromData @h . PlutusTx.List) - --- | @since 1.1.0 -instance - forall (a :: Type) (repr :: [Type]). - (IsProductType a repr, All ToData repr) => - ToData (ProductIsData a) - where - toBuiltinData = coerce (gProductToBuiltinData @a) - --- | @since 1.1.0 -instance - forall (a :: Type) (repr :: [Type]). - (IsProductType a repr, All UnsafeFromData repr) => - UnsafeFromData (ProductIsData a) - where - unsafeFromBuiltinData = coerce (gProductFromBuiltinDataUnsafe @a) - --- | @since 1.1.0 -instance - forall (a :: Type) (repr :: [Type]). - (IsProductType a repr, All FromData repr) => - FromData (ProductIsData a) - where - fromBuiltinData = coerce (gProductFromBuiltinData @a) \ No newline at end of file diff --git a/src/lib/SmartTokens/Core/Scripts.hs b/src/lib/SmartTokens/Core/Scripts.hs deleted file mode 100644 index 9046227..0000000 --- a/src/lib/SmartTokens/Core/Scripts.hs +++ /dev/null @@ -1,39 +0,0 @@ -module SmartTokens.Core.Scripts ( -tryCompile) where - -import Plutarch -import Plutarch.ByteString (PByteString, plengthBS, psliceBS, pindexBS) -import Plutarch.Crypto (pkeccak_256, pblake2b_224) -import Plutarch.Integer (PInteger, pmod) -import Plutarch.Lift (pconstant) -import Plutarch.Bool (pif, (#==)) -import PlutusCore.Crypto.Hash qualified as Hash -import PlutusLedgerApi.Common (serialiseUPLC) -import Data.ByteString.Short (fromShort) -import Plutarch.Script (Script(unScript)) -import Data.ByteString (ByteString) -import Data.ByteString qualified as BS -import Data.Word (Word8) -import PlutusLedgerApi.V2 ( - Data, - ExBudget, - ) -import Data.Text -import Plutarch.Evaluate -import Data.Bifunctor ( Bifunctor(first) ) - -tryCompile :: Config -> ClosedTerm a -> Script -tryCompile cfg x = case compile cfg x of - Left e -> error $ "Compilation failed: " <> show e - Right s -> s - -tryCompileTracingAndBinds :: ClosedTerm a -> Script -tryCompileTracingAndBinds = tryCompile (Tracing LogInfo DoTracingAndBinds) - -tryCompileNoTracing :: ClosedTerm a -> Script -tryCompileNoTracing = tryCompile NoTracing - - - - - diff --git a/src/lib/SmartTokens/Core/Utils.hs b/src/lib/SmartTokens/Core/Utils.hs deleted file mode 100644 index de978bb..0000000 --- a/src/lib/SmartTokens/Core/Utils.hs +++ /dev/null @@ -1,1102 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedRecordDot #-} -{-# LANGUAGE PartialTypeSignatures #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE QualifiedDo #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE ViewPatterns #-} - -{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-} -{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} -{-# HLINT ignore "Use newtype instead of data" #-} - -module SmartTokens.Core.Utils ( - PPosixTimeRange, - PCustomFiniteRange (..), - pletFieldsSpending, - -- pletFieldsRewarding, - pisRewarding, - pcountSpendRedeemers, - ptryFromInlineDatum, - pfromPDatum, - pnonew, - punnew, - ppair, - passert, - pcheck, - pfindCurrencySymbolsByTokenPrefix, - pcountScriptInputs, - pfoldl2, - pelemAtWithRest', - pmapIdxs, - pfindCurrencySymbolsByTokenName, - pmapFilter, - phasDataCS, - phasCS, - pcontainsCurrencySymbols, - pisPrefixedWith, - tcexpectJust, - paysToAddress, - paysValueToAddress, - paysAtleastValueToAddress, - paysToCredential, - pgetPubKeyHash, - pelemAt', - pelemAtFlipped', - pelemAtFast, - pmapMaybe, - paysToPubKey, - ptryOutputToAddress, - ptryOwnOutput, - ptryOwnInput, - pmustFind, - pcanFind, - pheadSingleton, - pisSingleton, - pisPrefixOf, - ptxSignedByPkh, - pcountOfUniqueTokens, - (#-), - pfindWithRest, - pcountCS, - pcountNonAdaCS, - pfirstTokenName, - ptryLookupValue, - pfilterCSFromValue, - psingletonOfCS, - pvalueOfOne, - pvalueOfOneScott, - pfirstTokenNameWithCS, - phasUTxO, - pvalueContains, - ponlyAsset, - pand'List, - pcond, - (#>=), - (#>), - (#/=), - pisFinite, - pmapAndConvertList, - pintToByteString, - pvalidityRangeStart, - ptoCustomFiniteRange, - ptoCustomFiniteRangeH, - punwrapPosixTime, - pwrapPosixTime, - pdivCeil, - pisScriptCredential, - pisPubKeyCredential, - nTails, - ptails10, - ptails20, - ptails30, - pconsAsData, - pmkBuiltinList, - ponlyLovelaceValueOf, - plovelaceValueOf, - pvalueSingleton, - pmapData, - ppairDataBuiltinRaw, - pmkBuiltinListAsData, - pvalidateConditions, - pfoldUTxOs, - pisMinting, - pisSpending, - pletFieldsMinting, - pcountInputsFromCred, -) where - -import Data.List (foldl') -import Data.Text qualified as T -import Plutarch.Bool (pand') -import Plutarch.Builtin (PAsData, PBuiltinList (..), PBuiltinPair, PData, - PDataNewtype (..), PIsData, pasConstr, pdata, - pforgetData, pfromData, pfstBuiltin, ppairDataBuiltin, - psndBuiltin) -import Plutarch.DataRepr.Internal.Field (HRec (..), Labeled (Labeled)) -import Plutarch.Internal (ClosedTerm, PType, S, Term, perror, phoistAcyclic, - plet, punsafeBuiltin, punsafeCoerce, type (:-->), - (#$), (#)) -import Plutarch.LedgerApi.AssocMap qualified as AssocMap -import Plutarch.LedgerApi.V3 (AmountGuarantees (NonZero, Positive), - KeyGuarantees (Sorted), PAddress, - PCredential (..), PCurrencySymbol, PDatum, - PExtended (PFinite), PInterval (..), - PLowerBound (PLowerBound), PMap (..), PMaybeData, - POutputDatum (POutputDatum), PPosixTime (..), - PPubKeyHash, PRedeemer, PScriptHash, PScriptInfo, - PScriptPurpose, PTokenName, PTxInInfo, PTxOut, - PTxOutRef, PUpperBound (PUpperBound), PValue (..)) -import Plutarch.LedgerApi.Value (padaSymbol, pnormalize, pvalueOf) -import Plutarch.LedgerApi.Value qualified as Value -import Plutarch.Monadic qualified as P -import Plutarch.Num (PNum) -import Plutarch.Prelude (DerivePlutusType (..), Generic, PBool (..), - PByteString, PEq (..), PInteger, - PIntegral (pdiv, pquot, prem), PIsListLike, - PListLike (..), PMaybe (..), POrd, PPair (..), - PPartialOrd ((#<), (#<=)), PShow, PTryFrom, - PlutusType (..), PlutusTypeScott, - TermCont (runTermCont), Type, pall, pany, pcon, - pconcat, pconstant, pelem, pfield, pfilter, pfix, - pfoldl, pif, plam, plength, plengthBS, pletFields, - pletFieldsC, pmap, pmatch, pmatchC, pnot, precList, - psliceBS, pto, ptraceInfoError, ptryFrom, tcont, (#&&), PUnit) -import PlutusCore qualified as PLC -import Prelude - -type PPosixTimeRange = PInterval PPosixTime - -type PScriptInfoHRec (s :: S) = - HRec - '[ '("_0", Term s (PAsData PTxOutRef)) - , '("_1", Term s (PAsData (PMaybeData PDatum))) - ] - -pletFieldsSpending :: forall {s :: S} {r :: PType}. Term s (PAsData PScriptInfo) -> (PScriptInfoHRec s -> Term s r) -> Term s r -pletFieldsSpending term = runTermCont $ do - constrPair <- tcont $ plet $ pasConstr # pforgetData term - fields <- tcont $ plet $ psndBuiltin # constrPair - checkedFields <- tcont $ plet $ pif ((pfstBuiltin # constrPair) #== 1) fields perror - let outRef = punsafeCoerce @_ @_ @(PAsData PTxOutRef) $ phead # checkedFields - datum = punsafeCoerce @_ @_ @(PAsData (PMaybeData PDatum)) $ phead # (ptail # checkedFields) - tcont $ \f -> f $ HCons (Labeled @"_0" outRef) (HCons (Labeled @"_1" datum) HNil) - -type PMintingScriptHRec (s :: S) = - HRec - '[ '("_0", Term s (PAsData PCurrencySymbol)) - ] - -pletFieldsMinting :: forall {s :: S} {r :: PType}. Term s (PAsData PScriptInfo) -> (PMintingScriptHRec s -> Term s r) -> Term s r -pletFieldsMinting term = runTermCont $ do - constrPair <- tcont $ plet $ pasConstr # pforgetData term - fields <- tcont $ plet $ psndBuiltin # constrPair - checkedFields <- tcont $ plet $ pif ((pfstBuiltin # constrPair) #== 0) fields perror - let mintCS = punsafeCoerce @_ @_ @(PAsData PCurrencySymbol) $ phead # checkedFields - tcont $ \f -> f $ HCons (Labeled @"_0" mintCS) HNil - --- pletFieldsRewarding :: forall {s :: S} {r :: PType}. Term s (PAsData PScriptInfo) -> (PScriptInfoHRec s -> Term s r) -> Term s r --- pletFieldsRewarding term = runTermCont $ do --- constrPair <- tcont $ plet $ pasConstr # pforgetData term --- fields <- tcont $ plet $ psndBuiltin # constrPair --- checkedFields <- tcont $ plet $ pif ((pfstBuiltin # constrPair) #== 2) fields perror --- let outRef = punsafeCoerce @_ @_ @(PAsData PTxOutRef) $ phead # checkedFields --- datum = punsafeCoerce @_ @_ @(PAsData (PMaybeData PDatum)) $ phead # (ptail # checkedFields) --- tcont $ \f -> f $ HCons (Labeled @"_0" outRef) (HCons (Labeled @"_1" datum) HNil) - -pisMinting :: Term s (PAsData PScriptInfo) -> Term s PBool -pisMinting term = (pfstBuiltin # (pasConstr # pforgetData term)) #== 0 - -pisSpending :: Term s (PAsData PScriptInfo) -> Term s PBool -pisSpending term = (pfstBuiltin # (pasConstr # pforgetData term)) #== 1 - -pisRewarding :: Term s (PAsData PScriptInfo) -> Term s PBool -pisRewarding term = (pfstBuiltin # (pasConstr # pforgetData term)) #== 2 - -{- | Count the number of spend plutus scripts executed in the transaction via the txInfoRedeemers list. - Assumes that the txInfoRedeemers list is sorted according to the ledger Ord instance for PlutusPurpose: - `deriving instance Ord (ConwayPlutusPurpose AsIx era)` -https://github.com/IntersectMBO/cardano-ledger/blob/d79d41e09da6ab93067acddf624d1a540a3e4e8d/eras/conway/impl/src/Cardano/Ledger/Conway/Scripts.hs#L188 --} -pcountSpendRedeemers :: forall {s :: S}. Term s (AssocMap.PMap 'AssocMap.Unsorted PScriptPurpose PRedeemer) -> Term s PInteger -pcountSpendRedeemers rdmrs = - let go :: Term _ (PInteger :--> PBuiltinList (PBuiltinPair (PAsData PScriptPurpose) (PAsData PRedeemer)) :--> PInteger) - go = pfix #$ plam $ \self n -> - pelimList - (\x xs -> - let constrPair :: Term _ (PAsData PScriptPurpose) - constrPair = pfstBuiltin # x - constrIdx = pfstBuiltin # (pasConstr # pforgetData constrPair) - in pif (constrIdx #== 1) (self # (n + 1) # xs) n - ) - n - in go # 0 # pto rdmrs - -ptryFromInlineDatum :: forall (s :: S). Term s (POutputDatum :--> PDatum) -ptryFromInlineDatum = phoistAcyclic $ - plam $ - flip pmatch $ \case - POutputDatum ((pfield @"outputDatum" #) -> datum) -> datum - _ -> ptraceInfoError "not an inline datum" - --- | Parse a Datum into a specific structure (specified by the type argument) --- and error if the datum does not decode to the expected structure. --- Note: This function is very inefficient and should typically not be used, especially if the UTxO --- in question has a state token that already enforces the correctness of the Datum structure. --- For outputs typically you should prefer to construct the expected output datum and compare it against the --- actual output datum thus entirely avoiding the need for decoding. -pfromPDatum :: - forall (a :: S -> Type) (s :: S). - PTryFrom PData a => - Term s (PDatum :--> a) -pfromPDatum = phoistAcyclic $ plam $ flip ptryFrom fst . pto - --- Extract the inner type from a type which contains a `DataNewtype` --- ex. PPosixTime -> PInteger --- PPubKeyHash -> PByteString -pnonew :: forall {a :: PType} {b :: PType} {s :: S}. - ((PInner a :: PType) ~ (PDataNewtype b :: PType), PIsData b) => - Term s a -> Term s b -pnonew nt = pmatch (pto nt) $ \(PDataNewtype bs) -> pfromData bs - --- Extract the inner type from a `PDataNewType` --- ex. PDataNewtype PInteger -> PInteger --- PDataNewtype PByteString -> PByteString -punnew :: forall {b :: PType} {s :: S}. - PIsData b => - Term s (PDataNewtype b) -> Term s b -punnew nt = pmatch nt $ \(PDataNewtype bs) -> pfromData bs - -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) - -{- | If the input is True then continue otherwise throw an error message. - Short trace is a sequence of first letters of long trace words. --} -passert :: - forall (s :: S) (a :: PType). - T.Text -> -- long trace - Term s PBool -> - Term s a -> - Term s a -passert longErrorMsg b inp = pif b inp $ ptraceInfoError (pconstant longErrorMsg) - --- | If the input is True then returns PJust otherwise PNothing -pcheck :: forall (s :: S) (a :: PType). Term s PBool -> Term s a -> Term s (PMaybe a) -pcheck b inp = pif b (pcon $ PJust inp) (pcon PNothing) - -{- | Finds the associated Currency symbols that contain token - names prefixed with the ByteString. --} -pfindCurrencySymbolsByTokenPrefix :: - forall - (anyOrder :: KeyGuarantees) - (anyAmount :: AmountGuarantees). - ClosedTerm - ( PValue anyOrder anyAmount - :--> PByteString - :--> PBuiltinList (PAsData PCurrencySymbol) - ) -pfindCurrencySymbolsByTokenPrefix = phoistAcyclic $ - plam $ \value prefix -> - plet (pisPrefixOf # prefix) $ \prefixCheck -> - let mapVal = pto (pto value) - isPrefixed = pfilter # plam (\csPair -> - pany # plam (\tkPair -> - pmatch (pto (pfromData $ pfstBuiltin # tkPair)) $ \(PDataNewtype tkn) -> - prefixCheck # pfromData tkn - ) # pto (pfromData (psndBuiltin # csPair)) - ) # mapVal - in pmap # pfstBuiltin # isPrefixed - -pcountScriptInputs :: Term s (PBuiltinList (PAsData PTxInInfo) :--> PInteger) -pcountScriptInputs = - phoistAcyclic $ - let go :: Term s (PInteger :--> PBuiltinList (PAsData 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 - -pcountInputsFromCred :: Term s (PAsData PCredential :--> PBuiltinList (PAsData PTxInInfo) :--> PInteger) -pcountInputsFromCred = - phoistAcyclic $ plam $ \cred txIns -> - let go :: Term _ (PInteger :--> PBuiltinList (PAsData PTxInInfo) :--> PInteger) - go = pfix #$ plam $ \self n -> - pelimList - (\x xs -> - let inputCred = pfield @"credential" # (pfield @"address" # (pfield @"resolved" # x)) - in pif (cred #== inputCred) (self # (n + 1) # xs) (self # n # xs) - ) - n - in go # 0 # txIns - -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 - -pfoldUTxOs :: (Term s (PAsData PTxOut) -> Term s (PAsData PTxOut) -> Term s PBool) -> Term s (PBuiltinList (PAsData PTxOut) :--> PBuiltinList (PAsData PTxOut) :--> PBool) -pfoldUTxOs func = - pfix #$ plam $ \self la lb -> - pelimList - (\a as -> - pelimList - (\b bs -> - pif (func a b) - (self # as # bs) - (pconstant False) - ) - perror - lb - ) - (pconstant True) - 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 - -pmapFilter :: - (PIsListLike list a, PElemConstraint list b) => Term s ((b :--> PBool) :--> (a :--> b) :--> list a :--> list b) -pmapFilter = - phoistAcyclic $ - plam $ \predicate f -> - precList - ( \self x' xs -> plet (f # x') $ \x -> - pif - (predicate # x) - (pcons # x # (self # xs)) - (self # xs) - ) - (const pnil) - --- | Checks if a Currency Symbol is held within a Value -phasDataCS :: - forall - (anyOrder :: KeyGuarantees) - (anyAmount :: AmountGuarantees). - ClosedTerm - (PAsData PCurrencySymbol :--> PValue anyOrder anyAmount :--> PBool) -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 -> - pmatch (pto tn) $ \(PDataNewtype tnBS) -> pisPrefixOf # prefix # pfromData tnBS - --- | Checks if the first ByteString is a prefix of the second -pisPrefixOf :: ClosedTerm (PByteString :--> PByteString :--> PBool) -pisPrefixOf = plam $ \prefix src -> - let prefixLength = plengthBS # prefix - 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) - - -pgetPubKeyHash :: Term s PAddress -> Term s (PAsData PPubKeyHash) -pgetPubKeyHash addr = - let cred = pfield @"credential" # addr - in pmatch cred $ \case - PScriptCredential _ -> perror - PPubKeyCredential pkh' -> pfield @"_0" # pkh' - -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)) - - -pelemAtFast :: (PIsListLike list a) => Term s (list a :--> PInteger :--> a) -pelemAtFast = phoistAcyclic $ - pfix #$ plam $ \self xs n -> - pif - (10 #< n) - ( self - # ( ptails10 # xs ) - # (n - 10) - ) - ( pif - (5 #< n) - (self # (ptail #$ ptail #$ ptail #$ ptail #$ ptail # xs) # (n - 5)) - (pelemAtFlipped' # xs # n) - ) - -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 :: Term s (PBuiltinList (PAsData 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) (pfromData txo) (self # txos) - ) - perror - xs - ) - # outs - -ptryOwnInput :: Term s (PBuiltinList (PAsData 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 - -pcanFind :: PIsListLike l a => Term s ((a :--> PBool) :--> l a :--> PBool) -pcanFind = - phoistAcyclic $ plam $ \f -> pfix #$ plam $ \self xs -> pelimList (\y ys -> pif (f # y) (pconstant True) (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 $ - plam $ \xs -> - pelimList - (pelimList (\_ _ -> ptraceInfoError "List contains more than one element.")) - (ptraceInfoError "List is empty.") - xs - -pisSingleton :: (PIsListLike list a) => Term s (list a) -> Term s PBool -pisSingleton = pelimList - (\_ ys -> pelimList (\_ _ -> pconstant False) (pconstant True) ys) - (pconstant False) - -ptxSignedByPkh :: - Term s (PAsData PPubKeyHash :--> PBuiltinList (PAsData PPubKeyHash) :--> PBool) -ptxSignedByPkh = pelem - --- | Probably more effective than `plength . pflattenValue` -pcountOfUniqueTokens :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term s (PValue keys amounts :--> PInteger) -pcountOfUniqueTokens = phoistAcyclic $ - plam $ \val -> - let tokensLength = plam (\pair -> pmatch (pfromData $ psndBuiltin # pair) $ \(PMap tokens) -> plength # tokens) - in pmatch val $ \(PValue val') -> - pmatch val' $ \(PMap csPairs) -> pfoldl # plam (\acc x -> acc + (tokensLength # x)) # 0 # csPairs - --- | Subtracts one Value from another -(#-) :: - forall - (amounts :: AmountGuarantees) - (s :: S). - Term s (PValue 'Sorted amounts) -> - Term s (PValue 'Sorted amounts) -> - Term s (PValue 'Sorted 'NonZero) -a #- b = pnormalize #$ Value.punionResolvingCollisionsWith AssocMap.NonCommutative # plam (-) # a # b - -pfindWithRest :: - forall (list :: PType -> PType) (a :: PType). - PListLike list => - PElemConstraint list a => - ClosedTerm - ( (a :--> PBool) - :--> list a - :--> PPair a (list a) - ) -pfindWithRest = phoistAcyclic $ - plam $ \f ys -> - let mcons self x xs = - pmatch (f # x) $ \case - PTrue -> P.do - acc <- plam - pcon $ PPair x (pconcat # acc # xs) - PFalse -> P.do - acc <- plam - self # xs #$ pcons # x # acc - mnil = const (ptraceInfoError "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' - -{- | Removes a currency symbol from a value --} -pfilterCSFromValue :: - forall - (anyOrder :: KeyGuarantees) - (anyAmount :: AmountGuarantees). - ClosedTerm - ( PValue anyOrder anyAmount - :--> PAsData PCurrencySymbol - :--> PValue anyOrder anyAmount - ) -pfilterCSFromValue = phoistAcyclic $ - plam $ \value policyId -> - let mapVal = pto (pto value) - go = pfix #$ plam $ \self ys -> - pelimList (\x xs -> pif (pfstBuiltin # x #== policyId) xs (pcons # x # (self # xs))) pnil ys - in pcon (PValue $ pcon $ PMap $ go # mapVal) - -psingletonOfCS :: - forall - (keys :: KeyGuarantees) - (amounts :: AmountGuarantees) - (s :: S). - Term - s - ( PAsData PCurrencySymbol - :--> PValue keys amounts - :--> PPair PTokenName PInteger - ) -psingletonOfCS = phoistAcyclic $ - plam $ \policyId val -> - pmatch val $ \(PValue val') -> - precList - ( \self x xs -> - pif - (pfstBuiltin # x #== policyId) - ( pmatch (pfromData (psndBuiltin # x)) $ \(PMap tokens) -> - let tkPair = pheadSingleton # tokens - in pcon (PPair (pfromData (pfstBuiltin # tkPair)) (pfromData (psndBuiltin # tkPair))) - ) - (self # xs) - ) - (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' - -{- | @phasUTxO # oref # inputs@ - ensures that in @inputs@ there is an input having @TxOutRef@ @oref@ . --} -phasUTxO :: - ClosedTerm - ( PAsData PTxOutRef - :--> PBuiltinList (PAsData PTxInInfo) - :--> PBool - ) -phasUTxO = phoistAcyclic $ - plam $ \oref inInputs -> - pany @PBuiltinList # plam (\input -> oref #== (pfield @"outRef" # input)) # inInputs - -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 - [] -> pconstant True - ts -> foldl1 (\res x -> pand' # res # x) ts - --- | Strictly evaluates a list of boolean expressions. --- If all the expressions evaluate to true, returns unit, otherwise throws an error. -pvalidateConditions :: [Term s PBool] -> Term s PUnit -pvalidateConditions conds = - pif (pand'List conds) - (pconstant ()) - perror - -pcond :: [(Term s PBool, Term s a)] -> Term s a -> Term s a -pcond [] def = def -pcond ((cond, x) : conds) def = pif cond x $ pcond conds def - -(#>) :: (POrd t) => Term s t -> Term s t -> Term s PBool -a #> b = b #< a -infix 4 #> - -(#>=) :: (POrd t) => Term s t -> Term s t -> Term s PBool -a #>= b = b #<= a -infix 4 #>= - -(#/=) :: (PEq t) => Term s t -> Term s t -> Term s PBool -a #/= b = pnot # (a #== b) -infix 4 #/= - -pisFinite :: Term s (PInterval PPosixTime :--> PBool) -pisFinite = plam $ \i -> - let isFiniteFrom = pmatch (pfield @"_0" # (pfield @"from" # i)) $ \case - PFinite _ -> pconstant True - _ -> pconstant False - isFiniteTo = pmatch (pfield @"_0" # (pfield @"to" # i)) $ \case - PFinite _ -> pconstant True - _ -> pconstant False - in pand' # isFiniteFrom # isFiniteTo - -pmapAndConvertList :: (PIsListLike listA a, PIsListLike listB b) => Term s ((a :--> b) :--> listA a :--> listB b) -pmapAndConvertList = phoistAcyclic $ - plam $ \f -> - pfix #$ plam $ \self xs -> pelimList (\y ys -> pcons # (f # y) # (self # ys)) pnil xs - -pintToByteString :: Term s (PInteger :--> PByteString) -pintToByteString = phoistAcyclic $ - pfix #$ plam $ \self n -> - plet - (pquot # abs n # 10) - ( \q -> - plet (prem # abs n # 10) $ \r -> - pif - (q #== 0) - (pshowDigit # r) - ( plet (self # q) $ \prefix -> - prefix <> pshowDigit # r - ) - ) - -pshowDigit :: Term s (PInteger :--> PByteString) -pshowDigit = phoistAcyclic $ - plam $ \digit -> - pcond - [ (digit #== 0, pconstant "0") - , (digit #== 1, pconstant "1") - , (digit #== 2, pconstant "2") - , (digit #== 3, pconstant "3") - , (digit #== 4, pconstant "4") - , (digit #== 5, pconstant "5") - , (digit #== 6, pconstant "6") - , (digit #== 7, pconstant "7") - , (digit #== 8, pconstant "8") - , (digit #== 9, pconstant "9") - ] - perror - -pvalidityRangeStart :: Term s (PPosixTimeRange :--> PAsData PInteger) -pvalidityRangeStart = phoistAcyclic $ plam $ \timeRange -> P.do - PInterval ((pfield @"from" #) -> startTime) <- pmatch timeRange - PLowerBound lb <- pmatch startTime - PFinite ((pfield @"_0" #) -> posixTime) <- pmatch (pfield @"_0" # lb) - pmatch posixTime $ \(PPosixTime pt) -> pmatch pt $ \(PDataNewtype t) -> t - -data PCustomFiniteRange (s :: S) = PCustomFiniteRange - { from :: Term s PPosixTime - , to :: Term s PPosixTime - } - deriving stock (Generic) - deriving anyclass - ( PlutusType - ) - -instance DerivePlutusType PCustomFiniteRange where - type DPTStrat _ = PlutusTypeScott - -ptoCustomFiniteRange :: Term s (PPosixTimeRange :--> PCustomFiniteRange) -ptoCustomFiniteRange = phoistAcyclic $ plam $ \timeRange -> P.do - timeRangeF <- pletFields @'["from", "to"] timeRange - PLowerBound lb <- pmatch timeRangeF.from - PFinite ((pfield @"_0" #) -> start) <- pmatch (pfield @"_0" # lb) - PUpperBound ub <- pmatch timeRangeF.to - PFinite ((pfield @"_0" #) -> end) <- pmatch (pfield @"_0" # ub) - pcon $ PCustomFiniteRange { from = start, to = end } - -ptoCustomFiniteRangeH :: Term s PPosixTimeRange -> TermCont @r s (Term s PInteger, Term s PInteger) -ptoCustomFiniteRangeH timeRange = do - timeRangeF <- pletFieldsC @'["from", "to"] timeRange - PLowerBound lb <- pmatchC timeRangeF.from - PFinite ((pfield @"_0" #) -> start) <- pmatchC (pfield @"_0" # lb) - PUpperBound ub <- pmatchC timeRangeF.to - PFinite ((pfield @"_0" #) -> end) <- pmatchC (pfield @"_0" # ub) - pure (pnonew $ pfromData start, pnonew $ pfromData end) - -punwrapPosixTime :: Term s (PAsData PPosixTime) -> Term s PInteger -punwrapPosixTime pt = pmatch (pfromData pt) $ \(PPosixTime pt') -> pmatch pt' $ \(PDataNewtype t) -> pfromData t - -pwrapPosixTime :: Term s PInteger -> Term s (PAsData PPosixTime) -pwrapPosixTime t = pdata $ pcon $ PPosixTime $ pcon $ PDataNewtype $ pdata t - -pdivCeil :: (PIntegral a, PNum a) => Term s (a :--> a :--> a) -pdivCeil = phoistAcyclic $ - plam $ - \x y -> 1 + pdiv # (x - 1) # y - -pisScriptCredential :: Term s (PAsData PCredential) -> Term s PBool -pisScriptCredential cred = (pfstBuiltin # (pasConstr # pforgetData cred)) #== 1 - -pisPubKeyCredential :: Term s (PAsData PCredential) -> Term s PBool -pisPubKeyCredential cred = (pfstBuiltin # (pasConstr # pforgetData cred)) #== 0 - -nTails :: PIsListLike list a => Integer -> Term s (list a) -> Term s (list a) -nTails n xs = foldl' (\acc _ -> ptail # acc) xs (replicate (fromIntegral n) ()) - -ptails10 :: PIsListLike list a => ClosedTerm (list a :--> list a) -ptails10 = phoistAcyclic $ plam (nTails 10) -ptails20 :: PIsListLike list a => ClosedTerm (list a :--> list a) -ptails20 = phoistAcyclic $ plam (\xs -> ptails10 # (ptails10 # xs)) -ptails30 :: PIsListLike list a => ClosedTerm (list a :--> list a) -ptails30 = phoistAcyclic $ plam (\xs -> ptails20 # (ptails10 # xs)) - -pconsAsData :: Term s (PAsData x) -> Term s (PBuiltinList PData) -> Term s (PBuiltinList PData) -pconsAsData x xs = pcon $ PCons (pforgetData x) xs - --- TODO: --- Can someone rewrite this function so that the list entries can all be different types --- with the only requirement that they are PAsData? Maybe this requires ExistentialTypes or GADTs? -pmkBuiltinListAsData :: [Term s (PAsData x)] -> Term s (PBuiltinList PData) -pmkBuiltinListAsData = foldr go (pcon PNil) - where - go :: Term s (PAsData x) -> Term s (PBuiltinList PData) -> Term s (PBuiltinList PData) - go = pconsAsData - -pmkBuiltinList :: [Term s PData] -> Term s (PBuiltinList PData) -pmkBuiltinList = foldr go (pcon PNil) - where - go :: Term s PData -> Term s (PBuiltinList PData) -> Term s (PBuiltinList PData) - go x xs = pcon $ PCons x xs - --- Returns the amount of Ada contained in a Value --- Errors if the Value contains tokens other than Ada --- --- This function assumes that the first entry in the Value is Ada --- The Cardano Ledger enforces that this invariant is maintained for all Values in the Script Context --- So we are guaranteed that this is safe to use for any Value inside the Script Context -ponlyLovelaceValueOf :: Term s (PValue 'Sorted 'Positive) -> Term s PInteger -ponlyLovelaceValueOf val = - let csPairs = pto $ pto val - adaEntry = pheadSingleton # csPairs - in pfromData (psndBuiltin #$ phead #$ pto $ pfromData $ psndBuiltin # adaEntry) - --- | Returns the amount of Ada contained in a Value --- --- The Cardano Ledger enforces that this invariant is maintained for all Values in the Script Context --- So we are guaranteed that this is safe to use for any Value inside the Script Context -plovelaceValueOf :: Term s (PValue 'Sorted 'Positive) -> Term s PInteger -plovelaceValueOf val = - let csPairs = pto $ pto val - adaEntry = phead # csPairs - in pfromData (psndBuiltin #$ phead #$ pto $ pfromData $ psndBuiltin # adaEntry) - - --- | Constructs a singleton `PValue` with the given currency symbol, token name, and amount. --- --- @param currencySymbol The currency symbol of the token. --- @param tokenName The name of the token. --- @param amount The amount of the token. --- --- @return A singleton `PValue` containing the specified currency symbol, token name, and amount. -pvalueSingleton :: Term s (PAsData PCurrencySymbol) -> Term s (PAsData PTokenName) -> Term s (PAsData PInteger) -> Term s (PAsData (PValue 'Sorted 'Positive)) -pvalueSingleton currencySymbol tokenName amount = - let innerValue = pcons @PBuiltinList # (ppairDataBuiltin # tokenName # amount) # pnil - in punsafeCoerce $ pmapData # (pcons @PBuiltinList # (ppairDataBuiltinRaw # pforgetData currencySymbol #$ pmapData # punsafeCoerce innerValue) # pnil) - --- Convert a BuiltinList of BuiltinPairs to a BuiltinMap -pmapData :: Term s (PBuiltinList (PBuiltinPair PData PData) :--> PData) -pmapData = punsafeBuiltin PLC.MapData - -ppairDataBuiltinRaw :: Term s (PData :--> PData :--> PBuiltinPair PData PData) -ppairDataBuiltinRaw = punsafeBuiltin PLC.MkPairData diff --git a/src/lib/SmartTokens/LinkedList/Common.hs b/src/lib/SmartTokens/LinkedList/Common.hs index 1ed952f..3b08ff4 100644 --- a/src/lib/SmartTokens/LinkedList/Common.hs +++ b/src/lib/SmartTokens/LinkedList/Common.hs @@ -15,7 +15,7 @@ import Plutarch.List (pconvertLists) import Plutarch.Monadic qualified as P import Plutarch.Prelude import Plutarch.Unsafe (punsafeCoerce) -import SmartTokens.Core.Utils ( +import Plutarch.Core.Utils ( pand'List, passert, paysToAddress, diff --git a/src/lib/SmartTokens/LinkedList/MintDirectory.hs b/src/lib/SmartTokens/LinkedList/MintDirectory.hs index 4de22a2..34bec7f 100644 --- a/src/lib/SmartTokens/LinkedList/MintDirectory.hs +++ b/src/lib/SmartTokens/LinkedList/MintDirectory.hs @@ -20,10 +20,10 @@ import SmartTokens.LinkedList.Common ( ) import Plutarch.Prelude -import SmartTokens.Core.Utils (pand'List, passert, pcond, pisFinite, phasUTxO, pintToByteString) +import Plutarch.Core.Utils (pand'List, passert, pcond, pisFinite, phasUTxO, pintToByteString) import SmartTokens.Types.PTokenDirectory import Types.Constants (claimRoot, airdropOperator) -import SmartTokens.Core.Crypto (pcardanoPubKeyToPubKeyHash, pethereumPubKeyToPubKeyHash, pcompressPublicKey) +import Plutarch.Core.Crypto (pcardanoPubKeyToPubKeyHash, pethereumPubKeyToPubKeyHash, pcompressPublicKey) import Plutarch.Builtin (pserialiseData, pforgetData, PDataNewtype(..)) import MerkleTree.MerklePatriciaForestry (phas) import Plutarch.Crypto (pverifyEcdsaSecp256k1Signature, pblake2b_256) diff --git a/src/lib/SmartTokens/Types/PTokenDirectory.hs b/src/lib/SmartTokens/Types/PTokenDirectory.hs index 4f38f80..5e89edd 100644 --- a/src/lib/SmartTokens/Types/PTokenDirectory.hs +++ b/src/lib/SmartTokens/Types/PTokenDirectory.hs @@ -28,7 +28,7 @@ module SmartTokens.Types.PTokenDirectory ( pisInsertedNode, ) where -import SmartTokens.Core.PlutusDataList +import Plutarch.Core.PlutusDataList ( DerivePConstantViaDataList(..), PlutusTypeDataList, ProductIsData(..) ) @@ -43,7 +43,7 @@ import PlutusLedgerApi.V3 (Credential, CurrencySymbol) import Plutarch.Lift (PConstantDecl, PUnsafeLiftDecl (PLifted)) import Plutarch.Evaluate (unsafeEvalTerm) import Plutarch (Config(NoTracing)) -import SmartTokens.Core.Utils (pmkBuiltinList) +import Plutarch.Core.Utils (pmkBuiltinList) import Plutarch.List import Plutarch.Prelude diff --git a/src/lib/SmartTokens/Types/ProtocolParams.hs b/src/lib/SmartTokens/Types/ProtocolParams.hs index f0afc5e..a7ee653 100644 --- a/src/lib/SmartTokens/Types/ProtocolParams.hs +++ b/src/lib/SmartTokens/Types/ProtocolParams.hs @@ -21,7 +21,7 @@ module SmartTokens.Types.ProtocolParams ( PProgrammableLogicGlobalParams (..), ) where -import SmartTokens.Core.PlutusDataList +import Plutarch.Core.PlutusDataList ( DerivePConstantViaDataList(..), PlutusTypeDataList, ProductIsData(..) ) diff --git a/src/lib/Types/Constants.hs b/src/lib/Types/Constants.hs index 6519340..fb79e8e 100644 --- a/src/lib/Types/Constants.hs +++ b/src/lib/Types/Constants.hs @@ -5,7 +5,7 @@ module Types.Constants where import Plutarch import Plutarch.LedgerApi.V1 (PTokenName (..)) import Plutarch.Prelude -import SmartTokens.Core.Utils +import Plutarch.Core.Utils import PlutusLedgerApi.V1 (TokenName(..)) import Plutarch.Builtin (PDataNewtype(..)) import qualified Plutarch.Monadic as P diff --git a/src/wst-poc.cabal b/src/wst-poc.cabal index fccbb6b..eb9c8df 100644 --- a/src/wst-poc.cabal +++ b/src/wst-poc.cabal @@ -182,10 +182,6 @@ library TypeFamilyDependencies exposed-modules: - SmartTokens.Core.Crypto - SmartTokens.Core.List - SmartTokens.Core.PlutusDataList - SmartTokens.Core.Utils SmartTokens.Contracts.Issuance SmartTokens.Contracts.ProgrammableLogicBase SmartTokens.Contracts.ExampleTransferLogic @@ -200,7 +196,6 @@ library Profile Types.Classes Types.Constants - Plutarch.Extra.Record -- Compile @@ -210,6 +205,7 @@ library , base16-bytestring , bytestring , cardano-binary + , plutarch-onchain-lib , data-default , generics-sop , plutarch