|
| 1 | +package pv11 |
| 2 | + |
| 3 | +import scalus.* |
| 4 | +import scalus.uplc.builtin.{Data, BuiltinArray, BuiltinList} |
| 5 | +import scalus.uplc.builtin.Data.{FromData, ToData} |
| 6 | +import scalus.uplc.builtin.Builtins.* |
| 7 | +import scalus.cardano.onchain.plutus.prelude.* |
| 8 | +import scalus.cardano.onchain.plutus.v3.* |
| 9 | + |
| 10 | +/** CIP-138: Array Type validator Example |
| 11 | + * |
| 12 | + * Datum is a Plutus Data list of integers stored on-chain. |
| 13 | + * Redeemer specifies an index and expected value. |
| 14 | + * The validator converts the list to an array (O(1) access), |
| 15 | + * looks up the element at the given index, and asserts it |
| 16 | + * matches the expected value. |
| 17 | + * |
| 18 | + * Test case: Array [10, 20, 30, 40, 50], index 2, expect 30 |
| 19 | + * |
| 20 | + * Note: Array builtins (listToArray, indexArray) are PV11 features. |
| 21 | + */ |
| 22 | + |
| 23 | +case class ArrayRedeemer(index: BigInt, expectedValue: BigInt) derives FromData, ToData |
| 24 | + |
| 25 | +@Compile object ArrayRedeemer |
| 26 | + |
| 27 | +@Compile |
| 28 | +object ArrayValidator { |
| 29 | + inline def validate(scData: Data): Unit = { |
| 30 | + val ctx = scData.to[ScriptContext] |
| 31 | + ctx.scriptInfo match |
| 32 | + case ScriptInfo.SpendingScript(_, datum) => |
| 33 | + val d = datum.getOrFail("Missing datum") |
| 34 | + // Decode datum as a Plutus Data list of integers |
| 35 | + val dataList: BuiltinList[Data] = unListData(d) |
| 36 | + // Convert to array for O(1) indexed access (CIP-138) |
| 37 | + val arr: BuiltinArray[Data] = listToArray(dataList) |
| 38 | + // Decode redeemer |
| 39 | + val r = ctx.redeemer.to[ArrayRedeemer] |
| 40 | + // Look up element and verify |
| 41 | + val element: Data = indexArray(arr, r.index) |
| 42 | + val value: BigInt = unIData(element) |
| 43 | + require(value == r.expectedValue, "Array element does not match expected value") |
| 44 | + case _ => fail("Not a spending script") |
| 45 | + } |
| 46 | +} |
0 commit comments