|
9 | 9 |
|
10 | 10 | module ZkFold.Cardano.UPLC.RollupSimple ( |
11 | 11 | rollupSimple, |
| 12 | + rollupSimpleStake, |
12 | 13 | module ZkFold.Cardano.UPLC.RollupSimple.Types, |
13 | 14 | ) where |
| 15 | + |
14 | 16 | import Data.Function ((&)) |
15 | 17 | import PlutusLedgerApi.V1 (valueOf) |
16 | 18 | import PlutusLedgerApi.V3 |
| 19 | +import qualified PlutusTx.AssocMap as AssocMap |
17 | 20 | import qualified PlutusTx.Builtins.Internal as BI |
18 | | -import PlutusTx.Prelude hiding (toList, (*), (+)) |
| 21 | +import PlutusTx.Prelude hiding (toList) |
19 | 22 |
|
20 | 23 | import ZkFold.Cardano.OnChain.BLS12_381 (toF) |
21 | 24 | import ZkFold.Cardano.OnChain.Plonkup (PlonkupPlutus) |
22 | | -import ZkFold.Cardano.OnChain.Plonkup.Data (SetupBytes) |
23 | | -import ZkFold.Cardano.OnChain.Utils (findOwnInput') |
24 | | -import ZkFold.Cardano.UPLC.RollupSimple.Types (RollupSimpleRed, RollupState (..)) |
| 25 | +import ZkFold.Cardano.UPLC.RollupSimple.Types (BridgeUtxoInfo (..), BridgeUtxoStatus (..), |
| 26 | + RollupConfiguration (..), RollupSimpleRed (..), |
| 27 | + RollupState (..)) |
| 28 | +import ZkFold.Cardano.UPLC.RollupSimple.Utils |
25 | 29 | import ZkFold.Protocol.NonInteractiveProof (NonInteractiveProof (..)) |
26 | 30 |
|
27 | 31 | {-# INLINEABLE rollupSimple #-} |
28 | 32 | rollupSimple :: |
29 | | - -- | Setup bytes. |
| 33 | + -- | Script hash of the stake validator. |
30 | 34 | BuiltinData -> |
31 | | - -- | NFT Currency Symbol. |
| 35 | + -- | Script context. |
32 | 36 | BuiltinData -> |
33 | | - -- | NFT Token Name. |
| 37 | + BuiltinUnit |
| 38 | +rollupSimple (unsafeFromBuiltinData -> sh :: ScriptHash) scData = |
| 39 | + check |
| 40 | + $ AssocMap.member (toBuiltinData $ ScriptCredential sh) txInfoWrdl |
| 41 | + && trySpend |
| 42 | + == 1 -- Disallowing any other use-case for now to be on safe-side. |
| 43 | + where |
| 44 | + txInfoL = BI.unsafeDataAsConstr scData & BI.snd |
| 45 | + txInfo = txInfoL & BI.head & BI.unsafeDataAsConstr & BI.snd |
| 46 | + txInfoWrdl :: Map BuiltinData BuiltinData = |
| 47 | + txInfo |
| 48 | + & BI.tail |
| 49 | + & BI.tail |
| 50 | + & BI.tail |
| 51 | + & BI.tail |
| 52 | + & BI.tail |
| 53 | + & BI.tail |
| 54 | + & BI.head |
| 55 | + & unsafeFromBuiltinData |
| 56 | + redL = txInfoL & BI.tail |
| 57 | + scriptInfo = redL & BI.tail & BI.head & BI.unsafeDataAsConstr |
| 58 | + trySpend = BI.fst scriptInfo |
| 59 | + |
| 60 | +{-# INLINEABLE rollupSimpleStake #-} |
| 61 | +rollupSimpleStake :: |
| 62 | + -- | Rollup configuration. |
34 | 63 | BuiltinData -> |
35 | 64 | -- | Script context. |
36 | 65 | BuiltinData -> |
37 | 66 | BuiltinUnit |
38 | | -rollupSimple (unsafeFromBuiltinData -> (setupBytes :: SetupBytes)) (unsafeFromBuiltinData -> (nftCurrencySymbol :: CurrencySymbol)) (unsafeFromBuiltinData -> (nftTokenName :: TokenName)) scData = check $ |
39 | | - trySpend == 1 |
40 | | - && valueOf (txOutValue ownInputOutput) nftCurrencySymbol nftTokenName == 1 |
41 | | - && verify @PlonkupPlutus setupBytes (toF <$> [previousStateHash oldState, utxoTreeRoot oldState, chainLength oldState, bridgeInCommitment oldState, bridgeOutCommitment oldState, previousStateHash newState, utxoTreeRoot newState, chainLength newState, bridgeInCommitment newState, bridgeOutCommitment newState, 1]) proofBytes |
42 | | - where |
43 | | - |
44 | | - txInfoL = BI.unsafeDataAsConstr scData & BI.snd |
45 | | - txInfo = txInfoL & BI.head & BI.unsafeDataAsConstr & BI.snd |
46 | | - txInfoInputs = BI.head txInfo & unsafeFromBuiltinData @[TxInInfo] |
47 | | - txInfoOutputs = txInfo & BI.tail & BI.tail & BI.head & unsafeFromBuiltinData @[TxOut] |
48 | | - redL = txInfoL & BI.tail |
49 | | - proofBytes = redL & BI.head & unsafeFromBuiltinData |
50 | | - -- Extracting ScriptInfo |
51 | | - scriptInfo = redL & BI.tail & BI.head & BI.unsafeDataAsConstr |
52 | | - trySpend = BI.fst scriptInfo |
53 | | - spendFields = scriptInfo & BI.snd |
54 | | - spendRef = spendFields & BI.head & unsafeFromBuiltinData @TxOutRef |
55 | | - Just (unsafeFromBuiltinData . getDatum -> (oldState :: RollupState)) = spendFields & BI.tail & BI.head & unsafeFromBuiltinData @(Maybe Datum) |
56 | | - Just ownInput = findOwnInput' txInfoInputs spendRef |
57 | | - ownInputOutput = txInInfoResolved ownInput |
58 | | - Just continuingOutput = find (\txOut -> txOutAddress txOut == txOutAddress ownInputOutput && valueOf (txOutValue txOut) nftCurrencySymbol nftTokenName == 1) txInfoOutputs |
59 | | - OutputDatum (unsafeFromBuiltinData . getDatum -> (newState :: RollupState)) = txOutDatum continuingOutput |
| 67 | +rollupSimpleStake (unsafeFromBuiltinData -> RollupConfiguration {..}) scData = |
| 68 | + check |
| 69 | + $ if scriptInfoIx == 2 |
| 70 | + then |
| 71 | + -- Remaining funds are securely returned to the validator. |
| 72 | + traceIfFalse |
| 73 | + "rollupSimpleStake: availableBridgeVal mismatch" |
| 74 | + ( availableBridgeVal |
| 75 | + == (bridgeOutReqVal <> bridgeLeftoverVal) |
| 76 | + ) |
| 77 | + && traceIfFalse |
| 78 | + "rollupSimpleStake: proof verification failed" |
| 79 | + ( verify @PlonkupPlutus |
| 80 | + rcSetupBytes |
| 81 | + ( toF |
| 82 | + <$> [previousStateHash oldState, utxoTreeRoot oldState, chainLength oldState, bridgeInCommitment oldState, bridgeOutCommitment oldState, previousStateHash newState, utxoTreeRoot newState, chainLength newState, bridgeInCommitment newState, bridgeOutCommitment newState, 1] |
| 83 | + <> (bridgeInList <> fillWithZeros3WithAdd (rcMaxBridgeIn - quot (length bridgeInList)) rcMaxOutputAssets 3 []) |
| 84 | + <> (bridgeOutList <> fillWithZeros3WithAdd (rcMaxBridgeOut - quot (length bridgeOutList)) rcMaxOutputAssets 3 []) |
| 85 | + ) |
| 86 | + rsrProofBytes |
| 87 | + ) |
| 88 | + else |
| 89 | + scriptInfoIx |
| 90 | + == 3 |
| 91 | + && txCertIx |
| 92 | + == 0 -- Allow for registering of stake validator. |
| 93 | + where |
| 94 | + quot = (`quotient` (1 + 3 * rcMaxOutputAssets)) |
| 95 | + txInfoL = BI.unsafeDataAsConstr scData & BI.snd |
| 96 | + txInfo = txInfoL & BI.head & BI.unsafeDataAsConstr & BI.snd |
| 97 | + txInfoInputs = BI.head txInfo & unsafeFromBuiltinData @[TxInInfo] |
| 98 | + txInfoOutputs = txInfo & BI.tail & BI.tail & BI.head & unsafeFromBuiltinData @[TxOut] |
| 99 | + redL = txInfoL & BI.tail |
| 100 | + RollupSimpleRed {..} = redL & BI.head & unsafeFromBuiltinData |
| 101 | + scriptInfo = redL & BI.tail & BI.head & BI.unsafeDataAsConstr |
| 102 | + scriptInfoIx = BI.fst scriptInfo |
| 103 | + txCertIx = BI.snd scriptInfo & BI.tail & BI.head & BI.unsafeDataAsConstr & BI.fst |
| 104 | + toSymbolicValue' = toSymbolicValue rcMaxOutputAssets |
| 105 | + goInputs remInputs availableBridgeValAcc mownInput = |
| 106 | + case remInputs of |
| 107 | + [] -> (availableBridgeValAcc, mownInput) |
| 108 | + (i' : is) -> |
| 109 | + let i = txInInfoResolved i' |
| 110 | + in -- Input is relevant. |
| 111 | + if txOutAddress i == rsrAddress |
| 112 | + then |
| 113 | + -- Whether it is state input or an input given to satisfy bridge-out requirement. |
| 114 | + if valueOf (txOutValue i) rcNftCurrencySymbol rcNftTokenName == 1 |
| 115 | + then |
| 116 | + goInputs is availableBridgeValAcc (Just i') |
| 117 | + else goInputs is (availableBridgeValAcc <> txOutValue i) mownInput |
| 118 | + else goInputs is availableBridgeValAcc mownInput |
| 119 | + (availableBridgeVal, Just ownInputInfo) = goInputs txInfoInputs mempty Nothing |
| 120 | + ownInputOutput = txInInfoResolved ownInputInfo |
| 121 | + OutputDatum (unsafeFromBuiltinData . getDatum -> (oldState :: RollupState)) = txOutDatum ownInputOutput |
| 122 | + ownInputRef = txInInfoOutRef ownInputInfo |
| 123 | + goOutputs remOutputs bridgeOutReqValAcc bridgeLeftoverValAcc bridgeOutListAcc bridgeInListAcc mcontinuingOutput = |
| 124 | + case remOutputs of |
| 125 | + [] -> (bridgeOutReqValAcc, bridgeLeftoverValAcc, bridgeOutListAcc, bridgeInListAcc, mcontinuingOutput) |
| 126 | + (o : os) -> |
| 127 | + case txOutDatum o of |
| 128 | + NoOutputDatum -> goOutputs os bridgeOutReqValAcc bridgeLeftoverValAcc bridgeOutListAcc bridgeInListAcc mcontinuingOutput |
| 129 | + OutputDatumHash _ -> goOutputs os bridgeOutReqValAcc bridgeLeftoverValAcc bridgeOutListAcc bridgeInListAcc mcontinuingOutput |
| 130 | + OutputDatum (getDatum -> odatum) -> |
| 131 | + if txOutAddress o == rsrAddress |
| 132 | + then |
| 133 | + if valueOf (txOutValue o) rcNftCurrencySymbol rcNftTokenName == 1 |
| 134 | + then |
| 135 | + goOutputs os bridgeOutReqValAcc bridgeLeftoverValAcc bridgeOutListAcc bridgeInListAcc (Just o) |
| 136 | + else |
| 137 | + let odatum' :: BridgeUtxoInfo = unsafeFromBuiltinData odatum |
| 138 | + in if buiORef odatum' == ownInputRef |
| 139 | + then case buiStatus odatum' of |
| 140 | + BridgeIn layer2Address -> |
| 141 | + goOutputs os bridgeOutReqValAcc bridgeLeftoverValAcc bridgeOutListAcc ((layer2Address : toSymbolicValue' (txOutValue o)) <> bridgeInListAcc) mcontinuingOutput |
| 142 | + BridgeBalance -> |
| 143 | + goOutputs os bridgeOutReqValAcc (txOutValue o <> bridgeLeftoverValAcc) bridgeOutListAcc bridgeInListAcc mcontinuingOutput |
| 144 | + BridgeOut -> traceError "rollupSimpleStake: bridge-out output cannot be to the rollup validator" |
| 145 | + else |
| 146 | + traceError "rollupSimpleStake: output to rollup validator must be either a bridge-in, bridge-balance or state UTxO" |
| 147 | + else |
| 148 | + if odatum == toBuiltinData (BridgeUtxoInfo ownInputRef BridgeOut) |
| 149 | + then |
| 150 | + goOutputs os (bridgeOutReqValAcc <> txOutValue o) bridgeLeftoverValAcc ((byteStringToInteger' (addressToBS (txOutAddress o)) : toSymbolicValue' (txOutValue o)) <> bridgeOutListAcc) bridgeInListAcc mcontinuingOutput |
| 151 | + else goOutputs os bridgeOutReqValAcc bridgeLeftoverValAcc bridgeOutListAcc bridgeInListAcc mcontinuingOutput |
| 152 | + (bridgeOutReqVal, bridgeLeftoverVal, bridgeOutList, bridgeInList, Just continuingOutput) = goOutputs txInfoOutputs mempty mempty mempty mempty Nothing |
| 153 | + OutputDatum (unsafeFromBuiltinData . getDatum -> (newState :: RollupState)) = txOutDatum continuingOutput |
0 commit comments