diff --git a/package-lock.json b/package-lock.json index 1739f614..1d948190 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@harmoniclabs/bigint-utils": "^1.0.0", "@harmoniclabs/bytestring": "^1.0.0", "@harmoniclabs/cardano-costmodels-ts": "^1.1.0", - "@harmoniclabs/cardano-ledger-ts": "^0.2.0-dev5", + "@harmoniclabs/cardano-ledger-ts": "^0.2.1", "@harmoniclabs/cbor": "^1.3.0", "@harmoniclabs/crypto": "^0.2.4", "@harmoniclabs/obj-utils": "^1.0.0", @@ -1850,12 +1850,12 @@ } }, "node_modules/@harmoniclabs/cardano-ledger-ts": { - "version": "0.2.0-dev6", - "resolved": "https://registry.npmjs.org/@harmoniclabs/cardano-ledger-ts/-/cardano-ledger-ts-0.2.0-dev6.tgz", - "integrity": "sha512-vjKBfsV6isgBzNFeV35Fxr0BPOQktipw0UY8scrWAUU4OAOnWi5fgg+o64GxlfnNuCaVeKaDD2PaSJs+KNEoMA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@harmoniclabs/cardano-ledger-ts/-/cardano-ledger-ts-0.2.1.tgz", + "integrity": "sha512-27jzl1zehtKIQkYTHCM9EZ5azqdfEaK+uklloUhm+G1B94LWKqumM/C5ak+BpMVL30rLwsrPjGeGr8Jhx1HhlQ==", "dependencies": { "@harmoniclabs/bigint-utils": "^1.0.0", - "@harmoniclabs/crypto": "^0.1.0", + "@harmoniclabs/crypto": "^0.2.4", "@harmoniclabs/obj-utils": "^1.0.0", "@harmoniclabs/uint8array-utils": "^1.0.0" }, @@ -1871,15 +1871,6 @@ "@harmoniclabs/plutus-machine": "^2.0.0-dev0" } }, - "node_modules/@harmoniclabs/cardano-ledger-ts/node_modules/@harmoniclabs/crypto": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.1.0.tgz", - "integrity": "sha512-z3WGFpz5glQIzbo6qujRrfFjysLn73WXFyPuKFYeQwEkrLY+M8FzaGWXIWpKootWaITMepx39yloNHxwJZyA9Q==", - "dependencies": { - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.0" - } - }, "node_modules/@harmoniclabs/cbor": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/cbor/-/cbor-1.3.0.tgz", diff --git a/package.json b/package.json index 41dbca23..87da23d4 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "@harmoniclabs/cardano-costmodels-ts": "^1.1.0", "@harmoniclabs/plutus-machine": "^2.0.0-dev2", "@harmoniclabs/uplc": "^1.2.3", - "@harmoniclabs/cardano-ledger-ts": "^0.2.0-dev5", + "@harmoniclabs/cardano-ledger-ts": "^0.2.1", "@harmoniclabs/plu-ts-offchain": "0.1.13-dev4", "@harmoniclabs/plu-ts-onchain": "^0.3.0-dev2" }, diff --git a/packages/offchain/package-lock.json b/packages/offchain/package-lock.json index 2df6d2c7..e19a5fa1 100644 --- a/packages/offchain/package-lock.json +++ b/packages/offchain/package-lock.json @@ -32,7 +32,7 @@ "peerDependencies": { "@harmoniclabs/bytestring": "^1.0.0", "@harmoniclabs/cardano-costmodels-ts": "^1.1.0", - "@harmoniclabs/cardano-ledger-ts": "^0.2.0-dev6", + "@harmoniclabs/cardano-ledger-ts": "^0.2.1", "@harmoniclabs/cbor": "^1.3.0", "@harmoniclabs/pair": "^1.0.0", "@harmoniclabs/plutus-data": "^1.2.4", @@ -1854,13 +1854,13 @@ } }, "node_modules/@harmoniclabs/cardano-ledger-ts": { - "version": "0.2.0-dev6", - "resolved": "https://registry.npmjs.org/@harmoniclabs/cardano-ledger-ts/-/cardano-ledger-ts-0.2.0-dev6.tgz", - "integrity": "sha512-vjKBfsV6isgBzNFeV35Fxr0BPOQktipw0UY8scrWAUU4OAOnWi5fgg+o64GxlfnNuCaVeKaDD2PaSJs+KNEoMA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@harmoniclabs/cardano-ledger-ts/-/cardano-ledger-ts-0.2.1.tgz", + "integrity": "sha512-27jzl1zehtKIQkYTHCM9EZ5azqdfEaK+uklloUhm+G1B94LWKqumM/C5ak+BpMVL30rLwsrPjGeGr8Jhx1HhlQ==", "peer": true, "dependencies": { "@harmoniclabs/bigint-utils": "^1.0.0", - "@harmoniclabs/crypto": "^0.1.0", + "@harmoniclabs/crypto": "^0.2.4", "@harmoniclabs/obj-utils": "^1.0.0", "@harmoniclabs/uint8array-utils": "^1.0.0" }, @@ -1876,16 +1876,6 @@ "@harmoniclabs/plutus-machine": "^2.0.0-dev0" } }, - "node_modules/@harmoniclabs/cardano-ledger-ts/node_modules/@harmoniclabs/crypto": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.1.0.tgz", - "integrity": "sha512-z3WGFpz5glQIzbo6qujRrfFjysLn73WXFyPuKFYeQwEkrLY+M8FzaGWXIWpKootWaITMepx39yloNHxwJZyA9Q==", - "peer": true, - "dependencies": { - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.0" - } - }, "node_modules/@harmoniclabs/cbor": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/cbor/-/cbor-1.3.0.tgz", diff --git a/packages/offchain/package.json b/packages/offchain/package.json index b210a867..1e13a13d 100644 --- a/packages/offchain/package.json +++ b/packages/offchain/package.json @@ -66,7 +66,7 @@ "@harmoniclabs/cardano-costmodels-ts": "^1.1.0", "@harmoniclabs/plutus-machine": "^2.0.0-dev2", "@harmoniclabs/uplc": "^1.2.3", - "@harmoniclabs/cardano-ledger-ts": "^0.2.0-dev6" + "@harmoniclabs/cardano-ledger-ts": "^0.2.1" }, "devDependencies": { "@babel/preset-env": "^7.18.6", diff --git a/packages/offchain/src/TxBuilder/TxBuilder.ts b/packages/offchain/src/TxBuilder/TxBuilder.ts index 4a9dacd3..6929be09 100644 --- a/packages/offchain/src/TxBuilder/TxBuilder.ts +++ b/packages/offchain/src/TxBuilder/TxBuilder.ts @@ -15,7 +15,7 @@ import { freezeAll, defineReadOnlyProperty, definePropertyIfNotPresent, hasOwn, import { TxBuilderRunner } from "./TxBuilderRunner/TxBuilderRunner"; import { ITxRunnerProvider } from "./IProvider"; import { CanBeData, canBeData, forceData } from "../utils/CanBeData"; -import { getSpendingPurposeData } from "../toOnChain/getSpendingPurposeData"; +import { getScriptInfoData, getSpendingPurposeData } from "../toOnChain/getSpendingPurposeData"; import { TxBuilderProtocolParams, ValidatedTxBuilderProtocolParams, completeTxBuilderProtocolParams } from "./TxBuilderProtocolParams"; import { ChangeInfos } from "../txBuild/ChangeInfos/ChangeInfos"; import { scriptTypeToDataVersion } from "./utils"; @@ -363,12 +363,19 @@ export class TxBuilder const ctxData = getCtx( script.type, getSpendingPurposeData( rdmr, tx.body, expectedVersion ), + getScriptInfoData( rdmr, tx.body, expectedVersion ), + rdmrData, txInfosV1, txInfosV2, txInfosV3, ); const { result, budgetSpent, logs } = cek.eval( + script.type === ScriptType.PlutusV3 ? + new Application( + getScriptLikeUplc( script ), + UPLCConst.data( ctxData ) + ) : new Application( new Application( getScriptLikeUplc( script ), @@ -408,7 +415,9 @@ export class TxBuilder const { script, datum } = entry; - if( datum === undefined ) + const isV2OrLess = script.type === ScriptType.PlutusV1 || script.type === ScriptType.PlutusV2; + + if( datum === undefined && isV2OrLess ) throw new Error( "missing datum for spend redeemer " + index ); @@ -421,23 +430,30 @@ export class TxBuilder const ctxData = getCtx( script.type, getSpendingPurposeData( rdmr, tx.body, expectedVersion ), + getScriptInfoData( rdmr, tx.body, expectedVersion, datum ), + rdmrData, txInfosV1, txInfosV2, txInfosV3 ); const { result, budgetSpent, logs } = cek.eval( + isV2OrLess ? new Application( new Application( new Application( getScriptLikeUplc( script ), - UPLCConst.data( datum ) + UPLCConst.data( datum! ) ), UPLCConst.data( rdmrData ) ), UPLCConst.data( ctxData ) + ) : + new Application( + getScriptLikeUplc( script ), + UPLCConst.data( ctxData ) ) ); @@ -448,11 +464,11 @@ export class TxBuilder result, budgetSpent, logs, - [ - datum, + isV2OrLess ? [ + datum!, rdmrData, ctxData - ], + ] : [ ctxData ], rdmrs, onScriptResult, onScriptInvalid @@ -474,7 +490,7 @@ export class TxBuilder // bigint division truncates always towards 0; // we don't like that so we add `1n` for both divisions ( + 2n ) BigInt(2); - + if( fee === prevFee ) break; // return last transaciton // reset for next loop @@ -1021,9 +1037,10 @@ export class TxBuilder return withdrawal; }); + let i = 0; const _votingProcedures = Array.isArray( votingProcedures ) ? new VotingProcedures( - votingProcedures?.map(({ votingProcedure, script }, i) => { + votingProcedures?.map(({ votingProcedure, script }) => { if( script !== undef ) { @@ -1039,18 +1056,21 @@ export class TxBuilder const toExec = checkScriptAndPushIfInline( script ); pushScriptToExec( i, TxRedeemerTag.Voting, toExec ); + + i++; } return votingProcedure; }) ) : undef; + i = 0; const _proposalProcedures = Array.isArray( proposalProcedures ) ? - proposalProcedures.map(({ proposalProcedure, script }, i) => { + proposalProcedures.map(({ proposalProcedure, script }) => { if( script !== undef ) { - voteRedeemers.push( + proposeRedeemers.push( new TxRedeemer({ data: forceData( script.redeemer ), index: i, @@ -1062,11 +1082,15 @@ export class TxBuilder const toExec = checkScriptAndPushIfInline( script ); pushScriptToExec( i, TxRedeemerTag.Proposing, toExec ); + + i++; } return new ProposalProcedure( proposalProcedure ); }) : undef; + i = 0; + const auxData = metadata !== undefined? new AuxiliaryData({ metadata }) : undefined; const redeemers = @@ -1365,6 +1389,8 @@ function pushUniqueScript( arr: Script[], toPush: Scrip function getCtx( scriptType: ScriptType, spendingPurpose: DataConstr, + scriptInfo: DataConstr, + redeemerData: Data, txInfosV1: Data | undefined, txInfosV2: Data | undefined, txInfosV3: Data @@ -1375,7 +1401,8 @@ function getCtx( return new DataConstr( 0, [ txInfosV3, - spendingPurpose + redeemerData, + scriptInfo ] ) } @@ -1383,7 +1410,7 @@ function getCtx( { if( txInfosV2 === undefined ) throw new Error( - "plutus script v1 included in a v2 transaction" + "plutus script v2 included in a v3 transaction" ); return new DataConstr( @@ -1464,12 +1491,7 @@ function onEvaluationResult( `called with data arguments:\n${ callArgs .map( (d, i) => - ( - i === 0 ? ( rdmr.tag === TxRedeemerTag.Spend ? "datum" : "redeemer" ) : - i === 1 ? ( rdmr.tag === TxRedeemerTag.Spend ? "redeemer" : "script context" ) : - i === 2 ? ( rdmr.tag === TxRedeemerTag.Spend ? "script context" : i.toString() ) : - i.toString() - ) + ": " + dataToCbor( d ).toString() + i.toString() + ": " + dataToCbor( d ).toString() ) .join("\n") }\n\n` + diff --git a/packages/offchain/src/__tests__/docs/docs.v3.hello.test.ts b/packages/offchain/src/__tests__/docs/docs.v3.hello.test.ts new file mode 100644 index 00000000..1afd51da --- /dev/null +++ b/packages/offchain/src/__tests__/docs/docs.v3.hello.test.ts @@ -0,0 +1,66 @@ +import { Address, Credential, defaultProtocolParameters, forceTxOutRef, Script, ScriptType, TxOutRef, UTxO, Value } from "@harmoniclabs/cardano-ledger-ts"; +import { DataB } from "@harmoniclabs/plutus-data"; +import { fromAscii, fromHex } from "@harmoniclabs/uint8array-utils"; +import { defaultMainnetGenesisInfos, TxBuilder } from "../.."; +import { defaultV3Costs } from "@harmoniclabs/cardano-costmodels-ts" + +test("Hello plu-ts",() => { + + const script = new Script( + ScriptType.PlutusV3, + fromHex("01010032323232323232322323259800800c5268b2ae686644b3001002800c5282ae693001329800991aba1357446ae8800400a003001800c0064601800300148888888c8cc966002600290004400e2b300130014800a20091598009800a400910058acc004c005200688034566002600290044401e2b300130014802a20111655cd1573455cd1573455cd15734370e6aae74004d55cf0009baa007134928ca6002e3e664664600e46ae80c0080040052f588eb8dd6191aba1357446ae88d5d11aba2357446ae88d5d11aba2001300435742005375c6ae84005222330093003001002244464664b300130014800220071598009800a400510048b2ae68ab9a1b8735573a0026aae78004dd500184cdc79bae300a0014890c48656c6c6f20706c752d7473003002001235573c6ea800488cc01484008888cc014008c00c0048cc00c852811119802980200109801800912cc00400a2946002ab9a18011111194c004c0100066006003002401866008006004444b3001001801c4cc008d5d08009aba2001555cf88c8c0088cc0080080048c0088cc0080080048d5d09aba200101") + ); + + const scriptAddr = Address.mainnet( + Credential.script( script.hash ) + ); + + const myAddr = Address.fake; + const myPkh = myAddr.paymentCreds.hash; + + const scriptInput = new UTxO({ + utxoRef: { id: "aa".repeat( 32 ), index: 0 }, + resolved: { + address: scriptAddr, + value: Value.lovelaces( 5_000_000 ), + datum: new DataB( myPkh.toBuffer() ) + }, + }); + + const myInput = new UTxO({ + utxoRef: { id: "bb".repeat( 32 ), index: 0 }, + resolved: { + address: myAddr, + value: Value.lovelaces( 5_000_000_000_000_000_000_000 ), + } + }) + + // defaultProtocolParameters.costModels.PlutusScriptV3 = defaultV3Costs; + + const pps = { + ...defaultProtocolParameters, + costModels: { + ...defaultProtocolParameters.costModels, + PlutusScriptV3: defaultV3Costs + } + }; + + const txBuilder = new TxBuilder( pps, defaultMainnetGenesisInfos ); + + const tx = txBuilder.buildSync({ + inputs: [ + { + utxo: scriptInput, + inputScript: { + script: script, + datum: "inline", + redeemer: new DataB( fromAscii("Hello plu-ts") ) + } + }, + { utxo: myInput } + ], + requiredSigners: [ myPkh ], + changeAddress: myAddr + }); + +}) \ No newline at end of file diff --git a/packages/offchain/src/toOnChain/getSpendingPurposeData.ts b/packages/offchain/src/toOnChain/getSpendingPurposeData.ts index 303c68d0..5052a65a 100644 --- a/packages/offchain/src/toOnChain/getSpendingPurposeData.ts +++ b/packages/offchain/src/toOnChain/getSpendingPurposeData.ts @@ -1,4 +1,4 @@ -import { Hash28, StakeCredentials, StakeValidatorHash, Tx, TxBody, TxRedeemer, TxRedeemerTag } from "@harmoniclabs/cardano-ledger-ts"; +import { Hash28, StakeCredentials, StakeValidatorHash, Tx, TxBody, TxRedeemer, TxRedeemerTag, VoterKind } from "@harmoniclabs/cardano-ledger-ts"; import type { ToDataVersion } from "@harmoniclabs/cardano-ledger-ts/dist/toData/defaultToDataVersion"; import { Data, DataB, DataConstr, DataI, DataList, isData } from "@harmoniclabs/plutus-data"; import { lexCompare } from "@harmoniclabs/uint8array-utils"; @@ -124,7 +124,11 @@ export function getScriptInfoData( else if( tag === TxRedeemerTag.Voting ) { ctorIdx = 4; - const votingProcedure = tx.votingProcedures?.procedures[ rdmr.index ]; + const votingProcedure = tx.votingProcedures?.procedures + .filter( p => + p.voter.kind === VoterKind.ConstitutionalCommitteScript || + p.voter.kind === VoterKind.DRepScript + )[ rdmr.index ]; if( !votingProcedure ) { @@ -141,7 +145,22 @@ export function getScriptInfoData( else if( tag === TxRedeemerTag.Proposing ) { ctorIdx = 5; - + const proposalProcedure = tx.proposalProcedures?.filter( + p => p.rewardAccount.type === "script" + )[ rdmr.index ]; + + if( !proposalProcedure ) + { + throw new Error( + "mismatching proposal redeemer, couldn't find voting procedure at index " + + rdmr.index.toString() + ); + } + + purposeArgs = [ + new DataI( rdmr.index ), + proposalProcedure.toData( version ) + ]; } else throw new Error( "invalid redeemer tag" diff --git a/packages/onchain/package-lock.json b/packages/onchain/package-lock.json index 81cc8f49..1d3b0803 100644 --- a/packages/onchain/package-lock.json +++ b/packages/onchain/package-lock.json @@ -31,7 +31,7 @@ "peerDependencies": { "@harmoniclabs/bytestring": "^1.0.0", "@harmoniclabs/cardano-costmodels-ts": "^1.1.0", - "@harmoniclabs/cardano-ledger-ts": "^0.2.0-dev6", + "@harmoniclabs/cardano-ledger-ts": "^0.2.1", "@harmoniclabs/cbor": "^1.3.0", "@harmoniclabs/pair": "^1.0.0", "@harmoniclabs/plutus-data": "^1.2.4", @@ -1853,13 +1853,13 @@ } }, "node_modules/@harmoniclabs/cardano-ledger-ts": { - "version": "0.2.0-dev6", - "resolved": "https://registry.npmjs.org/@harmoniclabs/cardano-ledger-ts/-/cardano-ledger-ts-0.2.0-dev6.tgz", - "integrity": "sha512-vjKBfsV6isgBzNFeV35Fxr0BPOQktipw0UY8scrWAUU4OAOnWi5fgg+o64GxlfnNuCaVeKaDD2PaSJs+KNEoMA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@harmoniclabs/cardano-ledger-ts/-/cardano-ledger-ts-0.2.1.tgz", + "integrity": "sha512-27jzl1zehtKIQkYTHCM9EZ5azqdfEaK+uklloUhm+G1B94LWKqumM/C5ak+BpMVL30rLwsrPjGeGr8Jhx1HhlQ==", "peer": true, "dependencies": { "@harmoniclabs/bigint-utils": "^1.0.0", - "@harmoniclabs/crypto": "^0.1.0", + "@harmoniclabs/crypto": "^0.2.4", "@harmoniclabs/obj-utils": "^1.0.0", "@harmoniclabs/uint8array-utils": "^1.0.0" }, @@ -1875,16 +1875,6 @@ "@harmoniclabs/plutus-machine": "^2.0.0-dev0" } }, - "node_modules/@harmoniclabs/cardano-ledger-ts/node_modules/@harmoniclabs/crypto": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.1.0.tgz", - "integrity": "sha512-z3WGFpz5glQIzbo6qujRrfFjysLn73WXFyPuKFYeQwEkrLY+M8FzaGWXIWpKootWaITMepx39yloNHxwJZyA9Q==", - "peer": true, - "dependencies": { - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.0" - } - }, "node_modules/@harmoniclabs/cbor": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/cbor/-/cbor-1.3.0.tgz", @@ -3808,12 +3798,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4525,9 +4515,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -9218,9 +9208,9 @@ } }, "node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/packages/onchain/package.json b/packages/onchain/package.json index 92cc352d..8837b6ac 100644 --- a/packages/onchain/package.json +++ b/packages/onchain/package.json @@ -68,7 +68,7 @@ "@harmoniclabs/cardano-costmodels-ts": "^1.1.0", "@harmoniclabs/plutus-machine": "^2.0.0-dev3", "@harmoniclabs/uplc": "^1.2.4", - "@harmoniclabs/cardano-ledger-ts": "^0.2.0-dev6" + "@harmoniclabs/cardano-ledger-ts": "^0.2.1" }, "devDependencies": { "@babel/preset-env": "^7.18.6", diff --git a/packages/onchain/src/pluts/Script/getValidVersion.ts b/packages/onchain/src/pluts/Script/getValidVersion.ts index 5115ae2b..f9666a84 100644 --- a/packages/onchain/src/pluts/Script/getValidVersion.ts +++ b/packages/onchain/src/pluts/Script/getValidVersion.ts @@ -1,5 +1,5 @@ -export const defaultVersion: [ number, number, number ] = Object.freeze([ 1, 0, 0 ]) as any; +export const defaultVersion: [ number, number, number ] = Object.freeze([ 1, 1, 0 ]) as any; export function getValidVersion( version: Readonly<[number, number, number]> ): [number, number, number] { diff --git a/packages/onchain/src/pluts/__tests__/docs.v3.hello.test.ts b/packages/onchain/src/pluts/__tests__/docs.v3.hello.test.ts new file mode 100644 index 00000000..8756e852 --- /dev/null +++ b/packages/onchain/src/pluts/__tests__/docs.v3.hello.test.ts @@ -0,0 +1,37 @@ +import { toHex } from "@harmoniclabs/uint8array-utils"; +import { compile, data, passert, pBool, perror, pfn, plet, pmatch, PMaybe, PPubKeyHash, PScriptContext, punBData, unit } from ".." + +test("hello pluts", () => { + + const contract = pfn([ + PScriptContext.type + ], unit) + (({ redeemer, tx, purpose }) => { + + const message = plet( punBData.$( redeemer ) ); + + const maybeDatum = plet( + pmatch( purpose ) + .onSpending(({ datum }) => datum ) + ._(_ => perror( PMaybe( data ).type ) ) + ); + + const signedByOwner = plet( + pmatch( maybeDatum ) + .onNothing( _ => pBool( true ) ) // no owner, so we approve it + .onJust(({ val }) => + tx.signatories.includes( punBData.$( val ) ) + ) + ); + + const isBeingPolite = message.eq("Hello plu-ts"); + + return passert.$( + signedByOwner.and( isBeingPolite ) + ); + }); + + const compiled = compile( contract ); + + console.log( toHex( compiled ) ); +}); \ No newline at end of file diff --git a/packages/onchain/src/pluts/lib/std/PMaybe/PMaybe.ts b/packages/onchain/src/pluts/lib/std/PMaybe/PMaybe.ts index cbce1dbb..4f170e70 100644 --- a/packages/onchain/src/pluts/lib/std/PMaybe/PMaybe.ts +++ b/packages/onchain/src/pluts/lib/std/PMaybe/PMaybe.ts @@ -1,21 +1,48 @@ +import { pfn } from "../../pfn"; import { PDataRepresentable } from "../../../PType/PDataRepresentable"; import { PStruct, pstruct } from "../../../PTypes/PStruct/pstruct"; -import { StructT, TermType, FromPType } from "../../../type_system"; +import { StructT, TermType, FromPType, ToPType } from "../../../type_system"; +import { _fromData } from "../data/conversion/fromData_minimal"; +import { PFn, TermFn } from "../../../PTypes/PFn/PFn"; +import { pmatch } from "../../pmatch/pmatch"; export type MaybeT = StructT<{ Just: { val: T }, Nothing: {} +}, { + unwrap: TermFn<[ PMaybeRawT> ], ToPType>, + default: TermFn<[ PMaybeRawT>, ToPType ], ToPType>, }> +type PMaybeRawT = PStruct<{ + Just: { val: FromPType }, + Nothing: {} +}, {}> + export type PMaybeT = PStruct<{ Just: { val: FromPType }, Nothing: {} -}, any> +}, { + unwrap: TermFn<[ PMaybeRawT ], PTy>, + default: TermFn<[ PMaybeRawT, PTy ], PTy>, +}> export function PMaybe(tyArg: T) { return pstruct({ Just: { val: tyArg }, Nothing: {} + }, self_t => { + + return { + unwrap: pfn([ self_t ], tyArg) + ( self => _fromData( tyArg )( self.raw.fields.head ) ), + default: pfn([ self_t, tyArg ], tyArg) + (( self, defaultValue ) => + pmatch( self ) + .onJust(({ val }) => val) + .onNothing(_ => defaultValue ) + ) + }; }); } \ No newline at end of file