From 9970db8eed35e583f5cee795d1a38225f283c755 Mon Sep 17 00:00:00 2001 From: Hongrui Fang Date: Fri, 25 Oct 2024 02:42:01 +0800 Subject: [PATCH 1/3] implement V3 types and their instances --- src/Lib/Ratio.ts | 98 ++ src/Lib/V1/Value.ts | 2 + src/Lib/V3.ts | 2 + src/Lib/V3/Contexts.ts | 3026 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 3128 insertions(+) create mode 100644 src/Lib/Ratio.ts create mode 100644 src/Lib/V3.ts create mode 100644 src/Lib/V3/Contexts.ts diff --git a/src/Lib/Ratio.ts b/src/Lib/Ratio.ts new file mode 100644 index 0000000..0e0680c --- /dev/null +++ b/src/Lib/Ratio.ts @@ -0,0 +1,98 @@ +/** + * TypeScript implementation for {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-tx/src/PlutusTx/Ratio.hs} + * + * @module plutus-ledger-api/Ratio.js + */ +import { + caseFieldWithValue, + type Eq, + eqInteger, + type Integer, + type Json, + jsonInteger, +} from "prelude"; +import type { IsPlutusData } from "./PlutusData.js"; +import { isPlutusDataInteger, isPlutusDataPairWithTag } from "./V1.js"; + +// TODO(chfanghr): Maintain the invariants + +/** + * {@link Rational} represents an arbitrary-precision ratio. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-tx/src/PlutusTx/Ratio.hs#L69} + */ +export type Rational = { + numerator: Integer; + denominator: Integer; +}; + +/** + * {@link Eq} instance for {@link Rational} + */ +export const eqRational: Eq = { + eq: (l, r) => { + return ( + eqInteger.eq(l.numerator, r.numerator) && + eqInteger.eq(l.denominator, r.denominator) + ); + }, + + neq: (l, r) => { + return ( + eqInteger.neq(l.numerator, r.numerator) || + eqInteger.neq(l.denominator, r.denominator) + ); + }, +}; + +/** + * {@link Json} instance for {@link Rational} + */ +export const jsonRational: Json = { + toJson: (rational) => { + return { + numerator: jsonInteger.toJson(rational.numerator), + denominator: jsonInteger.toJson(rational.denominator), + }; + }, + fromJson: (value) => { + const numerator = caseFieldWithValue( + "numerator", + jsonInteger.fromJson, + value, + ); + const denominator = caseFieldWithValue( + "denominator", + jsonInteger.fromJson, + value, + ); + + return { + numerator, + denominator, + }; + }, +}; + +/** + * {@link IsPlutusData} instance for {@link Rational} + */ +export const isPlutusDataRational: IsPlutusData = { + toData: (rational) => { + return isPlutusDataPairWithTag( + isPlutusDataInteger, + isPlutusDataInteger, + ).toData([rational.numerator, rational.denominator]); + }, + fromData: (value) => { + const [numerator, denominator] = isPlutusDataPairWithTag( + isPlutusDataInteger, + isPlutusDataInteger, + ).fromData(value); + + return { + numerator, + denominator, + }; + }, +}; diff --git a/src/Lib/V1/Value.ts b/src/Lib/V1/Value.ts index 3b5feb2..0e982a2 100644 --- a/src/Lib/V1/Value.ts +++ b/src/Lib/V1/Value.ts @@ -201,3 +201,5 @@ export const adaSymbol: CurrencySymbol = Uint8Array.from([]) as CurrencySymbol; * @see {@link https://github.com/input-output-hk/plutus/blob/1.16.0.0/plutus-ledger-api/src/PlutusLedgerApi/V1/Value.hs#L152-L155} */ export const adaToken: TokenName = Uint8Array.from([]) as TokenName; + +export type Lovelace = Integer; diff --git a/src/Lib/V3.ts b/src/Lib/V3.ts new file mode 100644 index 0000000..b4ded7c --- /dev/null +++ b/src/Lib/V3.ts @@ -0,0 +1,2 @@ +export * from "./V3/Contexts.js"; +export * from "./Prelude/Instances.js"; diff --git a/src/Lib/V3/Contexts.ts b/src/Lib/V3/Contexts.ts new file mode 100644 index 0000000..5d81dd3 --- /dev/null +++ b/src/Lib/V3/Contexts.ts @@ -0,0 +1,3026 @@ +import { + caseFieldWithValue, + caseJsonConstructor, + type Eq, + eqInteger, + eqList, + eqMaybe, + type Integer, + type Json, + jsonConstructor, + JsonError, + jsonInteger, + jsonList, + jsonMaybe, + type List, + type Maybe, +} from "prelude"; + +import type { Credential } from "../V1/Credential.js"; +import * as V1Credential from "../V1/Credential.js"; + +import type { Map } from "../AssocMap.js"; +import * as AssocMap from "../AssocMap.js"; + +import * as V1Scripts from "../V1/Scripts.js"; +import type { Datum, DatumHash, Redeemer, ScriptHash } from "../V1/Scripts.js"; + +import type { PubKeyHash } from "../V1/Crypto.js"; +import * as V1Crypto from "../V1/Crypto.js"; + +import type { CurrencySymbol, Lovelace, Value } from "../V1/Value.js"; +import * as V1Value from "../V1/Value.js"; + +import { + eqPlutusData, + type IsPlutusData, + IsPlutusDataError, + isPlutusDataPlutusData, + jsonPlutusData, + type PlutusData, +} from "../PlutusData.js"; +import { + eqRational, + isPlutusDataRational, + jsonRational, + type Rational, +} from "../Ratio.js"; + +import type { TxId, TxOutRef } from "../V1/Tx.js"; +import * as V1Tx from "../V1/Tx.js"; + +import { type TxInInfo } from "../V2/Contexts.js"; +import * as V2Contexts from "../V2/Contexts.js"; + +import type { TxOut } from "../V2/Tx.js"; +import * as V2Tx from "../V2/Tx.js"; + +import type { POSIXTimeRange } from "../V1/Time.js"; +import * as V1Time from "../V1/Time.js"; + +import { + isPlutusDataInteger, + isPlutusDataList, + isPlutusDataMaybe, +} from "../V1.js"; + +// import { isPlutusDataInteger, isPlutusDataMaybe } from "../V1.js"; + +export type ColdCommitteeCredential = Credential; + +export type HotCommitteeCredential = Credential; + +export type DRepCredential = Credential; + +export type DRep = + | { name: "DRep"; fields: DRepCredential } + | { name: "AlwaysAbstain" } + | { name: "AlwaysNoConfidence" }; + +export const eqDRep: Eq = { + eq: (l, r) => { + if (l.name === "DRep" && r.name === "DRep") { + return V1Credential.eqCredential.eq(l.fields, r.fields); + } else if (l.name == "AlwaysAbstain" && r.name == "AlwaysAbstain") { + return true; + } else if ( + l.name == "AlwaysNoConfidence" && + r.name == "AlwaysNoConfidence" + ) { + return true; + } else { + return false; + } + }, + neq: (l, r) => { + if (l.name == "DRep" && r.name == "DRep") { + return V1Credential.eqCredential.neq(l.fields, r.fields); + } else if (l.name === "AlwaysAbstain" && r.name === "AlwaysAbstain") { + return false; + } else if ( + l.name === "AlwaysNoConfidence" && + r.name === "AlwaysNoConfidence" + ) { + return false; + } else { + return true; + } + }, +}; + +export const jsonDRep: Json = { + toJson: (dRep) => { + switch (dRep.name) { + case "DRep": + return jsonConstructor(dRep.name, [ + V1Credential.jsonCredential.toJson(dRep.fields), + ]); + case "AlwaysAbstain": + return jsonConstructor(dRep.name, []); + case "AlwaysNoConfidence": + return jsonConstructor(dRep.name, []); + } + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus.V3.DRep", + { + DRep: (fields) => { + if (fields.length != 1) { + throw new JsonError(`Expected one field`); + } + return { + fields: V1Credential.jsonCredential.fromJson(fields[0]!), + name: "DRep", + }; + }, + AlwaysAbstain: (fields) => { + if (fields.length != 0) { + throw new JsonError(`Expected no field`); + } + return { + name: "AlwaysAbstain", + }; + }, + AlwaysNoConfidence: (fields) => { + if (fields.length != 0) { + throw new JsonError(`Expected no field`); + } + return { + name: "AlwaysNoConfidence", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataDRep: IsPlutusData = { + toData: (dRep) => { + switch (dRep.name) { + case "DRep": { + return { + fields: [ + 0n, + [V1Credential.isPlutusDataCredential.toData(dRep.fields)], + ], + name: "Constr", + }; + } + case "AlwaysAbstain": + return { + fields: [1n, []], + name: "Constr", + }; + case "AlwaysNoConfidence": + return { + fields: [2n, []], + name: "Constr", + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag === 0n && fields.length === 1) { + return { + fields: V1Credential.isPlutusDataCredential.fromData(fields[0]!), + name: "DRep", + }; + } else if (tag === 1n && fields.length === 0) { + return { + name: "AlwaysAbstain", + }; + } else if (tag === 2n && fields.length === 0) { + return { + name: "AlwaysNoConfidence", + }; + } else break; + } + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type Delegatee = + | { name: "Stake"; fields: PubKeyHash } + | { name: "Vote"; fields: DRep } + | { name: "StakeVote"; fields: [PubKeyHash, DRep] }; + +export const eqDelegatee: Eq = { + eq: (l, r) => { + if (l.name == "Stake" && r.name == "Stake") { + return V1Crypto.eqPubKeyHash.eq(l.fields, r.fields); + } else if (l.name == "Vote" && r.name == "Vote") { + return eqDRep.eq(l.fields, r.fields); + } else if (l.name == "StakeVote" && r.name == "StakeVote") { + return ( + V1Crypto.eqPubKeyHash.eq(l.fields[0], r.fields[0]) && + eqDRep.eq(l.fields[1], r.fields[1]) + ); + } else return false; + }, + neq: (l, r) => { + if (l.name == "Stake" && r.name == "Stake") { + return V1Crypto.eqPubKeyHash.neq(l.fields, r.fields); + } else if (l.name == "Vote" && r.name == "Vote") { + return eqDRep.neq(l.fields, r.fields); + } else if (l.name == "StakeVote" && r.name == "StakeVote") { + return ( + V1Crypto.eqPubKeyHash.neq(l.fields[0], r.fields[0]) || + eqDRep.neq(l.fields[1], r.fields[1]) + ); + } else return true; + }, +}; + +export const jsonDelegatee: Json = { + toJson: (delegatee) => { + switch (delegatee.name) { + case "Stake": + return jsonConstructor(delegatee.name, [ + V1Crypto.jsonPubKeyHash.toJson(delegatee.fields), + ]); + case "Vote": + return jsonConstructor(delegatee.name, [ + jsonDRep.toJson(delegatee.fields), + ]); + case "StakeVote": + return jsonConstructor(delegatee.name, [ + V1Crypto.jsonPubKeyHash.toJson(delegatee.fields[0]), + jsonDRep.toJson(delegatee.fields[1]!), + ]); + } + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus.V3.Delegatee", + { + Stake: (fields) => { + if (fields.length != 1) { + throw new JsonError(`Expected one field`); + } + return { + fields: V1Crypto.jsonPubKeyHash.fromJson(fields[0]!), + name: "Stake", + }; + }, + Vote: (fields) => { + if (fields.length != 1) { + throw new JsonError(`Expected one field`); + } + return { + fields: jsonDRep.fromJson(fields[0]!), + name: "Vote", + }; + }, + StakeVote: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + return { + fields: [ + V1Crypto.jsonPubKeyHash.fromJson(fields[0]!), + jsonDRep.fromJson(fields[1]!), + ], + name: "StakeVote", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataDelegatee: IsPlutusData = { + toData: (delegatee) => { + switch (delegatee.name) { + case "Stake": + return { + fields: [ + 0n, + [V1Crypto.isPlutusDataPubKeyHash.toData(delegatee.fields)], + ], + name: "Constr", + }; + case "Vote": + return { + fields: [1n, [isPlutusDataDRep.toData(delegatee.fields)]], + name: "Constr", + }; + case "StakeVote": + return { + fields: [ + 2n, + [ + V1Crypto.isPlutusDataPubKeyHash.toData(delegatee.fields[0]!), + isPlutusDataDRep.toData(delegatee.fields[1]!), + ], + ], + name: "Constr", + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + if (value.fields[0] === 0n && value.fields[1].length === 1) { + return { + fields: V1Crypto.isPlutusDataPubKeyHash.fromData( + value.fields[1][0]!, + ), + name: "Stake", + }; + } else if (value.fields[0] === 1n && value.fields[1].length === 1) { + return { + fields: isPlutusDataDRep.fromData(value.fields[1][0]!), + name: "Vote", + }; + } else if (value.fields[0] === 2n && value.fields[1].length === 2) { + return { + fields: [ + V1Crypto.isPlutusDataPubKeyHash.fromData(value.fields[1][0]!), + isPlutusDataDRep.fromData(value.fields[1][1]!), + ], + name: "StakeVote", + }; + } else { + break; + } + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type TxCert = + | { + name: "RegStaking"; + fields: [Credential, Maybe]; + } + | { + name: "UnRegStaking"; + fields: [Credential, Maybe]; + } + | { + name: "DelegStaking"; + fields: [Credential, Delegatee]; + } + | { + name: "RegDRep"; + fields: [DRepCredential, Delegatee, Lovelace]; + } + | { + name: "UpdateDRep"; + fields: DRepCredential; + } + | { + name: "UnRegDRep"; + fields: [DRepCredential, V1Value.Lovelace]; + } + | { + name: "PoolRegister"; + fields: [PubKeyHash, PubKeyHash]; + } + | { + name: "PoolRetire"; + fields: [PubKeyHash, Integer]; + } + | { + name: "AuthHotCommittee"; + fields: [ColdCommitteeCredential, HotCommitteeCredential]; + } + | { + name: "ResignColdCommittee"; + fields: ColdCommitteeCredential; + }; + +export const eqTxCert: Eq = { + eq: (l, r) => { + if (l.name === "RegStaking" && r.name === "RegStaking") { + return ( + V1Credential.eqCredential.eq(l.fields[0], r.fields[0]) && + eqMaybe(eqInteger).eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "UnRegStaking" && r.name === "UnRegStaking") { + return ( + V1Credential.eqCredential.eq(l.fields[0], r.fields[0]) && + eqMaybe(eqInteger).eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "DelegStaking" && r.name === "DelegStaking") { + return ( + V1Credential.eqCredential.eq(l.fields[0], r.fields[0]) && + eqDelegatee.eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "RegDRep" && r.name === "RegDRep") { + return ( + V1Credential.eqCredential.eq(l.fields[0], r.fields[0]) && + eqDelegatee.eq(l.fields[1], r.fields[1]) && + eqInteger.eq(l.fields[2], r.fields[2]) + ); + } else if (l.name === "UpdateDRep" && r.name === "UpdateDRep") { + return V1Credential.eqCredential.eq(l.fields, r.fields); + } else if (l.name === "UnRegDRep" && r.name === "UnRegDRep") { + return ( + V1Credential.eqCredential.eq(l.fields[0], r.fields[0]) && + eqInteger.eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "PoolRegister" && r.name === "PoolRegister") { + return ( + V1Crypto.eqPubKeyHash.eq(l.fields[0], r.fields[0]) && + V1Crypto.eqPubKeyHash.eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "AuthHotCommittee" && r.name === "AuthHotCommittee") { + return ( + V1Credential.eqCredential.eq(l.fields[0], r.fields[0]) && + V1Credential.eqCredential.eq(l.fields[1], r.fields[1]) + ); + } else if ( + l.name === "ResignColdCommittee" && + r.name === "ResignColdCommittee" + ) { + return V1Credential.eqCredential.eq(l.fields, r.fields); + } else { + return false; + } + }, + neq: (l, r) => { + if (l.name === "RegStaking" && r.name === "RegStaking") { + return ( + V1Credential.eqCredential.neq(l.fields[0], r.fields[0]) || + eqMaybe(eqInteger).neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "UnRegStaking" && r.name === "UnRegStaking") { + return ( + V1Credential.eqCredential.neq(l.fields[0], r.fields[0]) || + eqMaybe(eqInteger).neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "DelegStaking" && r.name === "DelegStaking") { + return ( + V1Credential.eqCredential.neq(l.fields[0], r.fields[0]) || + eqDelegatee.neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "RegDRep" && r.name === "RegDRep") { + return ( + V1Credential.eqCredential.neq(l.fields[0], r.fields[0]) || + eqDelegatee.neq(l.fields[1], r.fields[1]) || + eqInteger.neq(l.fields[2], r.fields[2]) + ); + } else if (l.name === "UpdateDRep" && r.name === "UpdateDRep") { + return V1Credential.eqCredential.neq(l.fields, r.fields); + } else if (l.name === "UnRegDRep" && r.name === "UnRegDRep") { + return ( + V1Credential.eqCredential.neq(l.fields[0], r.fields[0]) || + eqInteger.neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "PoolRegister" && r.name === "PoolRegister") { + return ( + V1Crypto.eqPubKeyHash.neq(l.fields[0], r.fields[0]) || + V1Crypto.eqPubKeyHash.neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "AuthHotCommittee" && r.name === "AuthHotCommittee") { + return ( + V1Credential.eqCredential.neq(l.fields[0], r.fields[0]) || + V1Credential.eqCredential.neq(l.fields[1], r.fields[1]) + ); + } else if ( + l.name === "ResignColdCommittee" && + r.name === "ResignColdCommittee" + ) { + return V1Credential.eqCredential.neq(l.fields, r.fields); + } else { + return true; + } + }, +}; + +export const jsonTxCert: Json = { + toJson: (txCert) => { + switch (txCert.name) { + case "RegStaking": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields[0]), + jsonMaybe(jsonInteger).toJson(txCert.fields[1]), + ]); + case "UnRegStaking": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields[0]), + jsonMaybe(jsonInteger).toJson(txCert.fields[1]), + ]); + case "DelegStaking": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields[0]), + jsonDelegatee.toJson(txCert.fields[1]), + ]); + case "RegDRep": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields[0]), + jsonDelegatee.toJson(txCert.fields[1]), + jsonInteger.toJson(txCert.fields[2]), + ]); + case "UpdateDRep": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields), + ]); + case "UnRegDRep": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields[0]), + jsonInteger.toJson(txCert.fields[1]), + ]); + case "PoolRegister": + return jsonConstructor(txCert.name, [ + V1Crypto.jsonPubKeyHash.toJson(txCert.fields[0]), + V1Crypto.jsonPubKeyHash.toJson(txCert.fields[1]), + ]); + case "PoolRetire": + return jsonConstructor(txCert.name, [ + V1Crypto.jsonPubKeyHash.toJson(txCert.fields[0]), + jsonInteger.toJson(txCert.fields[1]), + ]); + case "AuthHotCommittee": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields[0]), + V1Credential.jsonCredential.toJson(txCert.fields[1]), + ]); + case "ResignColdCommittee": + return jsonConstructor(txCert.name, [ + V1Credential.jsonCredential.toJson(txCert.fields), + ]); + } + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus.V3.TxCert", + { + RegStaking: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + + return { + fields: [ + V1Credential.jsonCredential.fromJson(fields[0]!), + jsonMaybe(jsonInteger).fromJson(fields[1]!), + ], + name: "RegStaking", + }; + }, + UnRegStaking: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + + return { + fields: [ + V1Credential.jsonCredential.fromJson(fields[0]!), + jsonMaybe(jsonInteger).fromJson(fields[1]!), + ], + name: "UnRegStaking", + }; + }, + DelegStaking: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + + return { + fields: [ + V1Credential.jsonCredential.fromJson(fields[0]!), + jsonDelegatee.fromJson(fields[1]!), + ], + name: "DelegStaking", + }; + }, + RegDRep: (fields) => { + if (fields.length != 3) { + throw new JsonError(`Expected three fields`); + } + + return { + fields: [ + V1Credential.jsonCredential.fromJson(fields[0]!), + jsonDelegatee.fromJson(fields[1]!), + jsonInteger.fromJson(fields[2]!), + ], + name: "RegDRep", + }; + }, + UpdateDRep: (fields) => { + if (fields.length != 1) { + throw new JsonError(`Expected one field`); + } + + return { + fields: V1Credential.jsonCredential.fromJson(fields[0]!), + name: "UpdateDRep", + }; + }, + UnRegDRep: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + + return { + fields: [ + V1Credential.jsonCredential.fromJson(fields[0]!), + jsonInteger.fromJson(fields[1]!), + ], + name: "UnRegDRep", + }; + }, + PoolRegister: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + + return { + fields: [ + V1Crypto.jsonPubKeyHash.fromJson(fields[0]!), + V1Crypto.jsonPubKeyHash.fromJson(fields[1]!), + ], + name: "PoolRegister", + }; + }, + PoolRetire: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + + return { + fields: [ + V1Crypto.jsonPubKeyHash.fromJson(fields[0]!), + jsonInteger.fromJson(fields[1]!), + ], + name: "PoolRetire", + }; + }, + AuthHotCommittee: (fields) => { + if (fields.length != 2) { + throw new JsonError(`Expected two fields`); + } + + return { + fields: [ + V1Credential.jsonCredential.fromJson(fields[0]!), + V1Credential.jsonCredential.fromJson(fields[1]!), + ], + name: "AuthHotCommittee", + }; + }, + ResignColdCommittee: (fields) => { + if (fields.length != 1) { + throw new JsonError(`Expected one field`); + } + + return { + fields: V1Credential.jsonCredential.fromJson(fields[0]!), + name: "ResignColdCommittee", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataTxCert: IsPlutusData = { + toData: (txCert) => { + switch (txCert.name) { + case "RegStaking": + return { + fields: [ + 0n, + [ + V1Credential.isPlutusDataCredential.toData(txCert.fields[0]), + isPlutusDataMaybe(isPlutusDataInteger).toData(txCert.fields[1]), + ], + ], + name: "Constr", + }; + case "UnRegStaking": + return { + fields: [ + 1n, + [ + V1Credential.isPlutusDataCredential.toData(txCert.fields[0]), + isPlutusDataMaybe(isPlutusDataInteger).toData(txCert.fields[1]), + ], + ], + name: "Constr", + }; + case "DelegStaking": + return { + fields: [ + 2n, + [ + V1Credential.isPlutusDataCredential.toData(txCert.fields[0]), + isPlutusDataDelegatee.toData(txCert.fields[1]), + ], + ], + name: "Constr", + }; + case "RegDRep": + return { + fields: [ + 3n, + [ + V1Credential.isPlutusDataCredential.toData(txCert.fields[0]), + isPlutusDataDelegatee.toData(txCert.fields[1]), + isPlutusDataInteger.toData(txCert.fields[2]), + ], + ], + name: "Constr", + }; + case "UpdateDRep": + return { + fields: [ + 4n, + [V1Credential.isPlutusDataCredential.toData(txCert.fields)], + ], + name: "Constr", + }; + case "UnRegDRep": + return { + fields: [ + 5n, + [ + V1Credential.isPlutusDataCredential.toData(txCert.fields[0]), + isPlutusDataInteger.toData(txCert.fields[1]), + ], + ], + name: "Constr", + }; + case "PoolRegister": + return { + fields: [ + 6n, + [ + V1Crypto.isPlutusDataPubKeyHash.toData(txCert.fields[0]), + V1Crypto.isPlutusDataPubKeyHash.toData(txCert.fields[1]), + ], + ], + name: "Constr", + }; + + case "PoolRetire": + return { + fields: [ + 7n, + [ + V1Crypto.isPlutusDataPubKeyHash.toData(txCert.fields[0]), + isPlutusDataInteger.toData(txCert.fields[1]), + ], + ], + name: "Constr", + }; + case "AuthHotCommittee": + return { + fields: [ + 8n, + [ + V1Credential.isPlutusDataCredential.toData(txCert.fields[0]), + V1Credential.isPlutusDataCredential.toData(txCert.fields[1]), + ], + ], + name: "Constr", + }; + case "ResignColdCommittee": + return { + fields: [ + 9n, + [V1Credential.isPlutusDataCredential.toData(txCert.fields)], + ], + name: "Constr", + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + if (tag === 0n && fields.length == 2) { + return { + fields: [ + V1Credential.isPlutusDataCredential.fromData(fields[0]!), + isPlutusDataMaybe(isPlutusDataInteger).fromData(fields[1]!), + ], + name: "RegStaking", + }; + } else if (tag === 1n && fields.length == 2) { + return { + fields: [ + V1Credential.isPlutusDataCredential.fromData(fields[0]!), + isPlutusDataMaybe(isPlutusDataInteger).fromData(fields[1]!), + ], + name: "UnRegStaking", + }; + } else if (tag === 2n && fields.length == 2) { + return { + fields: [ + V1Credential.isPlutusDataCredential.fromData(fields[0]!), + isPlutusDataDelegatee.fromData(fields[1]!), + ], + name: "DelegStaking", + }; + } else if (tag === 3n && fields.length == 3) { + return { + fields: [ + V1Credential.isPlutusDataCredential.fromData(fields[0]!), + isPlutusDataDelegatee.fromData(fields[1]!), + isPlutusDataInteger.fromData(fields[2]!), + ], + name: "RegDRep", + }; + } else if (tag === 4n && fields.length == 1) { + return { + fields: V1Credential.isPlutusDataCredential.fromData(fields[0]!), + name: "UpdateDRep", + }; + } else if (tag === 5n && fields.length == 2) { + return { + fields: [ + V1Credential.isPlutusDataCredential.fromData(fields[0]!), + isPlutusDataInteger.fromData(fields[1]!), + ], + name: "UnRegDRep", + }; + } else if (tag === 6n && fields.length == 2) { + return { + fields: [ + V1Crypto.isPlutusDataPubKeyHash.fromData(fields[0]!), + V1Crypto.isPlutusDataPubKeyHash.fromData(fields[1]!), + ], + name: "PoolRegister", + }; + } else if (tag === 7n && fields.length == 2) { + return { + fields: [ + V1Crypto.isPlutusDataPubKeyHash.fromData(fields[0]!), + isPlutusDataInteger.fromData(fields[1]!), + ], + name: "PoolRetire", + }; + } else if (tag === 8n && fields.length == 2) { + return { + fields: [ + V1Credential.isPlutusDataCredential.fromData(fields[0]!), + V1Credential.isPlutusDataCredential.fromData(fields[1]!), + ], + name: "AuthHotCommittee", + }; + } else if (tag === 9n && fields.length == 1) { + return { + fields: V1Credential.isPlutusDataCredential.fromData(fields[0]!), + name: "ResignColdCommittee", + }; + } else break; + } + default: + break; + } + + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type Voter = + | { name: "CommitteeVoter"; fields: HotCommitteeCredential } + | { name: "DRepVoter"; fields: DRepCredential } + | { name: "StakePoolVoter"; fields: PubKeyHash }; + +export const eqVoter: Eq = { + eq: (l, r) => { + if (l.name === "CommitteeVoter" && r.name === "CommitteeVoter") { + return V1Credential.eqCredential.eq(l.fields, r.fields); + } else if (l.name === "DRepVoter" && r.name === "DRepVoter") { + return V1Credential.eqCredential.eq(l.fields, r.fields); + } else if (l.name === "StakePoolVoter" && r.name === "StakePoolVoter") { + return V1Crypto.eqPubKeyHash.eq(l.fields, r.fields); + } else return false; + }, + neq: (l, r) => { + if (l.name === "CommitteeVoter" && r.name === "CommitteeVoter") { + return V1Credential.eqCredential.neq(l.fields, r.fields); + } else if (l.name === "DRepVoter" && r.name === "DRepVoter") { + return V1Credential.eqCredential.neq(l.fields, r.fields); + } else if (l.name === "StakePoolVoter" && r.name === "StakePoolVoter") { + return V1Crypto.eqPubKeyHash.neq(l.fields, r.fields); + } else return true; + }, +}; + +export const jsonVoter: Json = { + toJson: (voter) => { + switch (voter.name) { + case "CommitteeVoter": + return jsonConstructor(voter.name, [ + V1Credential.jsonCredential.toJson(voter.fields), + ]); + case "DRepVoter": + return jsonConstructor(voter.name, [ + V1Credential.jsonCredential.toJson(voter.fields), + ]); + case "StakePoolVoter": + return jsonConstructor(voter.name, [ + V1Crypto.jsonPubKeyHash.toJson(voter.fields), + ]); + } + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus.V3.Voter", + { + CommitteeVoter: (fields) => { + if (fields.length !== 1) { + throw new JsonError(`Expected one field`); + } + return { + fields: V1Credential.jsonCredential.fromJson(fields[0]!), + name: "CommitteeVoter", + }; + }, + DRepVoter: (fields) => { + if (fields.length !== 1) { + throw new JsonError(`Expected one field`); + } + return { + fields: V1Credential.jsonCredential.fromJson(fields[0]!), + name: "DRepVoter", + }; + }, + StakePoolVoter: (fields) => { + if (fields.length !== 1) { + throw new JsonError(`Expected one field`); + } + return { + fields: V1Crypto.jsonPubKeyHash.fromJson(fields[0]!), + name: "StakePoolVoter", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataVoter: IsPlutusData = { + toData: (voter) => { + switch (voter.name) { + case "CommitteeVoter": + return { + name: "Constr", + fields: [ + 0n, + [V1Credential.isPlutusDataCredential.toData(voter.fields)], + ], + }; + case "DRepVoter": + return { + name: "Constr", + fields: [ + 1n, + [V1Credential.isPlutusDataCredential.toData(voter.fields)], + ], + }; + case "StakePoolVoter": + return { + name: "Constr", + fields: [2n, [V1Crypto.isPlutusDataPubKeyHash.toData(voter.fields)]], + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + if (fields.length !== 1) break; + + if (tag == 0n) { + return { + fields: V1Credential.isPlutusDataCredential.fromData(fields[0]!), + name: "CommitteeVoter", + }; + } else if (tag == 1n) { + return { + fields: V1Credential.isPlutusDataCredential.fromData(fields[0]!), + name: "DRepVoter", + }; + } else if (tag == 2n) { + return { + fields: V1Crypto.isPlutusDataPubKeyHash.fromData(fields[0]!), + name: "StakePoolVoter", + }; + } else break; + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type Vote = + | { name: "VoteNo" } + | { name: "VoteYes" } + | { name: "Abstain" }; + +export const eqVote: Eq = { + eq: (l, r) => { + return l.name === r.name; + }, + neq: (l, r) => { + return l.name !== r.name; + }, +}; + +export const jsonVote: Json = { + toJson: (vote) => { + return jsonConstructor(vote.name, []); + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus.V3.Vote", + { + VoteNo: (fields) => { + if (fields.length !== 0) { + throw new JsonError("Expected no field"); + } + return { + name: "VoteNo", + }; + }, + VoteYes: (fields) => { + if (fields.length !== 0) { + throw new JsonError("Expected no field"); + } + return { + name: "VoteYes", + }; + }, + Abstain: (fields) => { + if (fields.length !== 0) { + throw new JsonError("Expected no field"); + } + return { + name: "Abstain", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataVote: IsPlutusData = { + toData: (vote) => { + switch (vote.name) { + case "VoteNo": + return { + fields: [0n, []], + name: "Constr", + }; + case "VoteYes": + return { + fields: [1n, []], + name: "Constr", + }; + case "Abstain": + return { + fields: [2n, []], + name: "Constr", + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (fields.length !== 0) break; + + if (tag === 0n) { + return { name: "VoteNo" }; + } + if (tag === 1n) { + return { name: "VoteYes" }; + } + if (tag === 2n) { + return { name: "Abstain" }; + } else break; + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type GovernanceActionId = { + gaidTxId: TxId; + gaidGovActionIx: Integer; +}; + +export const eqGovernanceActionId: Eq = { + eq: (l, r) => { + return ( + V1Tx.eqTxId.eq(l.gaidTxId, r.gaidTxId) && + eqInteger.eq(l.gaidGovActionIx, r.gaidGovActionIx) + ); + }, + neq: (l, r) => { + return ( + V1Tx.eqTxId.neq(l.gaidTxId, r.gaidTxId) || + eqInteger.neq(l.gaidGovActionIx, r.gaidGovActionIx) + ); + }, +}; + +export const jsonGovernanceActionId: Json = { + toJson: (governanceActionId) => { + return { + gaidGovActionIx: jsonInteger.toJson(governanceActionId.gaidGovActionIx), + gaidTxId: V1Tx.jsonTxId.toJson(governanceActionId.gaidTxId), + }; + }, + fromJson: (value) => { + const gaidGovActionIx = caseFieldWithValue( + "gaidGovActionIx", + jsonInteger.fromJson, + value, + ); + const gaidTxId = caseFieldWithValue( + "gaidTxId", + V1Tx.jsonTxId.fromJson, + value, + ); + + return { + gaidGovActionIx, + gaidTxId, + }; + }, +}; + +export const isPlutusDataGovernanceActionId: IsPlutusData = + { + toData: (governanceActionId) => { + return { + fields: [ + 0n, + [ + V1Tx.isPlutusDataTxId.toData(governanceActionId.gaidTxId), + isPlutusDataInteger.toData(governanceActionId.gaidGovActionIx), + ], + ], + name: "Constr", + }; + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag !== 0n) break; + if (fields.length !== 2) break; + + return { + gaidTxId: V1Tx.isPlutusDataTxId.fromData(fields[0]!), + gaidGovActionIx: isPlutusDataInteger.fromData(fields[1]!), + }; + } + } + + throw new IsPlutusDataError("Unexpected data"); + }, + }; + +export type Committee = { + committeeMembers: Map; + committeeQuorum: Integer; +}; + +export const eqCommittee: Eq = { + eq: (l, r) => { + return ( + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).eq( + l.committeeMembers, + r.committeeMembers, + ) && eqInteger.eq(l.committeeQuorum, r.committeeQuorum) + ); + }, + neq: (l, r) => { + return ( + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + l.committeeMembers, + r.committeeMembers, + ) || eqInteger.neq(l.committeeQuorum, r.committeeQuorum) + ); + }, +}; + +export const jsonCommittee: Json = { + toJson: (committee) => { + return { + committee_members: AssocMap.jsonMap( + V1Credential.jsonCredential, + jsonInteger, + ).toJson(committee.committeeMembers), + committee_quorum: jsonInteger.toJson(committee.committeeQuorum), + }; + }, + fromJson: (value) => { + const committeeMembers = caseFieldWithValue( + "members", + AssocMap.jsonMap(V1Credential.jsonCredential, jsonInteger).fromJson, + value, + ); + const committeeQuorum = caseFieldWithValue( + "quorum", + jsonInteger.fromJson, + value, + ); + return { + committeeMembers, + committeeQuorum, + }; + }, +}; + +export const isPlutusDataCommittee: IsPlutusData = { + toData: (committee) => { + return { + fields: [ + 0n, + [ + AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).toData(committee.committeeMembers), + isPlutusDataInteger.toData(committee.committeeQuorum), + ], + ], + name: "Constr", + }; + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag !== 0n) break; + if (fields.length !== 2) break; + + return { + committeeMembers: AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).fromData(fields[0]!), + committeeQuorum: isPlutusDataInteger.fromData(fields[1]!), + }; + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type Constitution = { + constitutionScript: Maybe; +}; + +export const eqConstitution: Eq = { + eq: (l, r) => { + return eqMaybe(V1Scripts.eqScriptHash).eq( + l.constitutionScript, + r.constitutionScript, + ); + }, + neq: (l, r) => { + return eqMaybe(V1Scripts.eqScriptHash).neq( + l.constitutionScript, + r.constitutionScript, + ); + }, +}; + +export const jsonConstitution: Json = { + toJson: (constitution) => { + return { + constitution_script: jsonMaybe(V1Scripts.jsonScriptHash).toJson( + constitution.constitutionScript, + ), + }; + }, + fromJson: (value) => { + const constitutionScript = caseFieldWithValue( + "script", + jsonMaybe(V1Scripts.jsonScriptHash).fromJson, + value, + ); + + return { + constitutionScript, + }; + }, +}; + +export const isPlutusDataConstitution: IsPlutusData = { + toData: (constitution) => { + return { + fields: [ + 0n, + [ + isPlutusDataMaybe(V1Scripts.isPlutusDataScriptHash).toData( + constitution.constitutionScript, + ), + ], + ], + name: "Constr", + }; + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag !== 0n) break; + if (fields.length !== 1) break; + + return { + constitutionScript: isPlutusDataMaybe( + V1Scripts.isPlutusDataScriptHash, + ).fromData(fields[0]!), + }; + } + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type ProtocolVersion = { + pvMajor: Integer; + pvMinor: Integer; +}; + +export const eqProtocolVersion: Eq = { + eq: (l, r) => { + return ( + eqInteger.eq(l.pvMajor, r.pvMajor) && eqInteger.eq(l.pvMinor, r.pvMinor) + ); + }, + neq: (l, r) => { + return ( + eqInteger.neq(l.pvMajor, r.pvMajor) || eqInteger.neq(l.pvMinor, r.pvMinor) + ); + }, +}; + +export const jsonProtocolVersion: Json = { + toJson: (protocolVersion) => { + return { + major: jsonInteger.toJson(protocolVersion.pvMajor), + minor: jsonInteger.toJson(protocolVersion.pvMinor), + }; + }, + fromJson: (value) => { + const pvMajor = caseFieldWithValue("major", jsonInteger.fromJson, value); + const pvMinor = caseFieldWithValue("minor", jsonInteger.fromJson, value); + return { + pvMajor, + pvMinor, + }; + }, +}; + +export const isPlutusDataProtocolVersion: IsPlutusData = { + toData: (protocolVersion) => { + return { + fields: [ + 0n, + [ + isPlutusDataInteger.toData(protocolVersion.pvMajor), + isPlutusDataInteger.toData(protocolVersion.pvMinor), + ], + ], + name: "Constr", + }; + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag !== 0n) break; + if (fields.length !== 2) break; + + return { + pvMajor: isPlutusDataInteger.fromData(fields[0]!), + pvMinor: isPlutusDataInteger.fromData(fields[1]!), + }; + } + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type ChangedParameters = PlutusData; + +export type GovernanceAction = + | { + name: "ParameterChange"; + fields: [Maybe, ChangedParameters, Maybe]; + } + | { + name: "HardForkInitiation"; + fields: [Maybe, ProtocolVersion]; + } + | { + name: "TreasuryWithdrawal"; + fields: [Map, Maybe]; + } + | { + name: "NoConfidence"; + fields: Maybe; + } + | { + name: "UpdateCommittee"; + fields: [ + Maybe, + List, + Map, + Rational, + ]; + } + | { + name: "NewConstitution"; + fields: [Maybe, Constitution]; + } + | { name: "InfoAction" }; + +export const eqGovernanceAction: Eq = { + eq: (l, r) => { + if (l.name === "ParameterChange" && r.name === "ParameterChange") { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqPlutusData.neq(l.fields[1], r.fields[1]) || + eqMaybe(V1Scripts.eqScriptHash).neq(l.fields[2], r.fields[2]) + ); + } else if ( + l.name === "HardForkInitiation" && + r.name === "HardForkInitiation" + ) { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqProtocolVersion.neq(l.fields[1], r.fields[1]) + ); + } else if ( + l.name === "TreasuryWithdrawal" && + r.name === "TreasuryWithdrawal" + ) { + return ( + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + l.fields[0], + r.fields[0], + ) || eqMaybe(V1Scripts.eqScriptHash).neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "NoConfidence" && r.name === "NoConfidence") { + return eqMaybe(eqGovernanceActionId).neq(l.fields, r.fields); + } else if (l.name === "UpdateCommittee" && r.name === "UpdateCommittee") { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqList(V1Credential.eqCredential).neq(l.fields[1], r.fields[1]) || + (AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + l.fields[2], + r.fields[2], + ) && + eqRational.eq(l.fields[3], r.fields[3])) + ); + } else if (l.name === "NewConstitution" && r.name === "NewConstitution") { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqConstitution.neq(l.fields[1], r.fields[1]) + ); + } else return false; + }, + neq: (l, r) => { + if (l.name === "ParameterChange" && r.name === "ParameterChange") { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqPlutusData.neq(l.fields[1], r.fields[1]) || + eqMaybe(V1Scripts.eqScriptHash).neq(l.fields[2], r.fields[2]) + ); + } else if ( + l.name === "HardForkInitiation" && + r.name === "HardForkInitiation" + ) { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqProtocolVersion.neq(l.fields[1], r.fields[1]) + ); + } else if ( + l.name === "TreasuryWithdrawal" && + r.name === "TreasuryWithdrawal" + ) { + return ( + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + l.fields[0], + r.fields[0], + ) || eqMaybe(V1Scripts.eqScriptHash).neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "NoConfidence" && r.name === "NoConfidence") { + return eqMaybe(eqGovernanceActionId).neq(l.fields, r.fields); + } else if (l.name === "UpdateCommittee" && r.name === "UpdateCommittee") { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqList(V1Credential.eqCredential).neq(l.fields[1], r.fields[1]) || + (AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + l.fields[2], + r.fields[2], + ) && + eqRational.neq(l.fields[3], r.fields[3])) + ); + } else if (l.name === "NewConstitution" && r.name === "NewConstitution") { + return ( + eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || + eqConstitution.neq(l.fields[1], r.fields[1]) + ); + } else return true; + }, +}; + +export const jsonGovernanceAction: Json = { + toJson: (governanceAction) => { + switch (governanceAction.name) { + case "ParameterChange": + return jsonConstructor(governanceAction.name, [ + jsonMaybe(jsonGovernanceActionId).toJson(governanceAction.fields[0]), + jsonPlutusData.toJson(governanceAction.fields[1]), + jsonMaybe(V1Scripts.jsonScriptHash).toJson( + governanceAction.fields[2], + ), + ]); + case "HardForkInitiation": + return jsonConstructor(governanceAction.name, [ + jsonMaybe(jsonGovernanceActionId).toJson(governanceAction.fields[0]), + jsonProtocolVersion.toJson(governanceAction.fields[1]), + ]); + case "TreasuryWithdrawal": + return jsonConstructor(governanceAction.name, [ + AssocMap.jsonMap(V1Credential.jsonCredential, jsonInteger).toJson( + governanceAction.fields[0], + ), + jsonMaybe(V1Scripts.jsonScriptHash).toJson( + governanceAction.fields[1], + ), + ]); + case "NoConfidence": + return jsonConstructor(governanceAction.name, [ + jsonMaybe(jsonGovernanceActionId).toJson(governanceAction.fields), + ]); + case "UpdateCommittee": + return jsonConstructor(governanceAction.name, [ + jsonMaybe(jsonGovernanceActionId).toJson(governanceAction.fields[0]), + jsonList(V1Credential.jsonCredential).toJson( + governanceAction.fields[1], + ), + AssocMap.jsonMap(V1Credential.jsonCredential, jsonInteger).toJson( + governanceAction.fields[2], + ), + jsonRational.toJson(governanceAction.fields[3]), + ]); + case "NewConstitution": + return jsonConstructor(governanceAction.name, [ + jsonMaybe(jsonGovernanceActionId).toJson(governanceAction.fields[0]), + jsonConstitution.toJson(governanceAction.fields[1]), + ]); + case "InfoAction": + return jsonConstructor(governanceAction.name, []); + } + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus.V3.GovernanceAction", + { + ParameterChange: (fields) => { + if (fields.length != 3) throw new JsonError("Expected three fields"); + + return { + fields: [ + jsonMaybe(jsonGovernanceActionId).fromJson(fields[0]!), + jsonPlutusData.fromJson(fields[1]!), + jsonMaybe(V1Scripts.jsonScriptHash).fromJson(fields[2]!), + ], + name: "ParameterChange", + }; + }, + HardForkInitiation: (fields) => { + if (fields.length != 2) throw new JsonError("Expected two fields"); + + return { + fields: [ + jsonMaybe(jsonGovernanceActionId).fromJson(fields[0]!), + jsonProtocolVersion.fromJson(fields[1]!), + ], + name: "HardForkInitiation", + }; + }, + TreasuryWithdrawal: (fields) => { + if (fields.length != 2) throw new JsonError("Expected two fields"); + + return { + fields: [ + AssocMap.jsonMap( + V1Credential.jsonCredential, + jsonInteger, + ).fromJson(fields[0]!), + jsonMaybe(V1Scripts.jsonScriptHash).fromJson(fields[1]!), + ], + name: "TreasuryWithdrawal", + }; + }, + NoConfidence: (fields) => { + if (fields.length != 1) throw new JsonError("Expected one field"); + + return { + fields: jsonMaybe(jsonGovernanceActionId).fromJson(fields[0]!), + name: "NoConfidence", + }; + }, + UpdateCommittee: (fields) => { + if (fields.length != 4) throw new JsonError("Expected four fields"); + + return { + fields: [ + jsonMaybe(jsonGovernanceActionId).fromJson(fields[0]!), + jsonList(V1Credential.jsonCredential).fromJson(fields[1]!), + AssocMap.jsonMap( + V1Credential.jsonCredential, + jsonInteger, + ).fromJson(fields[2]!), + jsonRational.fromJson(fields[3]!), + ], + name: "UpdateCommittee", + }; + }, + NewConstitution: (fields) => { + if (fields.length != 2) throw new JsonError("Expected two fields"); + + return { + fields: [ + jsonMaybe(jsonGovernanceActionId).fromJson(fields[0]!), + jsonConstitution.fromJson(fields[1]!), + ], + name: "NewConstitution", + }; + }, + InfoAction: (fields) => { + if (fields.length != 0) throw new JsonError("Expected no field"); + + return { + name: "InfoAction", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataGovernanceAction: IsPlutusData = { + toData: (governanceAction) => { + switch (governanceAction.name) { + case "ParameterChange": + return { + fields: [ + 0n, + [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).toData( + governanceAction.fields[0], + ), + isPlutusDataPlutusData.toData(governanceAction.fields[1]), + isPlutusDataMaybe(V1Scripts.isPlutusDataScriptHash).toData( + governanceAction.fields[2], + ), + ], + ], + name: "Constr", + }; + case "HardForkInitiation": + return { + fields: [ + 1n, + [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).toData( + governanceAction.fields[0], + ), + isPlutusDataProtocolVersion.toData(governanceAction.fields[1]), + ], + ], + name: "Constr", + }; + case "TreasuryWithdrawal": + return { + fields: [ + 2n, + [ + AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).toData(governanceAction.fields[0]), + isPlutusDataMaybe(V1Scripts.isPlutusDataScriptHash).toData( + governanceAction.fields[1], + ), + ], + ], + name: "Constr", + }; + case "NoConfidence": + return { + fields: [ + 3n, + [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).toData( + governanceAction.fields, + ), + ], + ], + name: "Constr", + }; + case "UpdateCommittee": + return { + fields: [ + 4n, + [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).toData( + governanceAction.fields[0], + ), + isPlutusDataList(V1Credential.isPlutusDataCredential).toData( + governanceAction.fields[1], + ), + AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).toData(governanceAction.fields[2]), + isPlutusDataRational.toData(governanceAction.fields[3]), + ], + ], + name: "Constr", + }; + case "NewConstitution": + return { + fields: [ + 5n, + [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).toData( + governanceAction.fields[0], + ), + isPlutusDataConstitution.toData(governanceAction.fields[1]), + ], + ], + name: "Constr", + }; + case "InfoAction": + return { + fields: [6n, []], + name: "Constr", + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag === 0n && fields.length === 3) { + return { + fields: [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).fromData( + fields[0]!, + ), + isPlutusDataPlutusData.fromData(fields[1]!), + isPlutusDataMaybe(V1Scripts.isPlutusDataScriptHash).fromData( + fields[2]!, + ), + ], + name: "ParameterChange", + }; + } else if (tag === 1n && fields.length === 2) { + return { + fields: [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).fromData( + fields[0]!, + ), + isPlutusDataProtocolVersion.fromData(fields[1]!), + ], + name: "HardForkInitiation", + }; + } else if (tag === 2n && fields.length === 2) { + return { + fields: [ + AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).fromData(fields[0]!), + isPlutusDataMaybe(V1Scripts.isPlutusDataScriptHash).fromData( + fields[1]!, + ), + ], + name: "TreasuryWithdrawal", + }; + } else if (tag === 3n && fields.length === 1) { + return { + fields: isPlutusDataMaybe(isPlutusDataGovernanceActionId).fromData( + fields[0]!, + ), + + name: "NoConfidence", + }; + } else if (tag === 4n && fields.length === 4) { + return { + fields: [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).fromData( + fields[0]!, + ), + isPlutusDataList(V1Credential.isPlutusDataCredential).fromData( + fields[1]!, + ), + AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).fromData(fields[2]!), + isPlutusDataRational.fromData(fields[3]!), + ], + name: "UpdateCommittee", + }; + } else if (tag === 5n && fields.length === 2) { + return { + fields: [ + isPlutusDataMaybe(isPlutusDataGovernanceActionId).fromData( + fields[0]!, + ), + isPlutusDataConstitution.fromData(fields[1]!), + ], + name: "NewConstitution", + }; + } else if (tag === 6n && fields.length === 0) { + return { + name: "InfoAction", + }; + } else break; + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type ProposalProcedure = { + ppDeposit: Lovelace; + ppReturnAddr: Credential; + ppGovernanceAction: GovernanceAction; +}; + +export const eqProposalProcedure: Eq = { + eq: (l, r) => { + return ( + eqInteger.eq(l.ppDeposit, r.ppDeposit) && + V1Credential.eqCredential.eq(l.ppReturnAddr, r.ppReturnAddr) && + eqGovernanceAction.eq(l.ppGovernanceAction, r.ppGovernanceAction) + ); + }, + neq: (l, r) => { + return ( + eqInteger.neq(l.ppDeposit, r.ppDeposit) || + V1Credential.eqCredential.neq(l.ppReturnAddr, r.ppReturnAddr) || + eqGovernanceAction.neq(l.ppGovernanceAction, r.ppGovernanceAction) + ); + }, +}; + +export const jsonProposalProcedure: Json = { + toJson: (proposalProcedure) => { + return { + deposit: jsonInteger.toJson(proposalProcedure.ppDeposit), + governance_action: jsonGovernanceAction.toJson( + proposalProcedure.ppGovernanceAction, + ), + return_addr: V1Credential.jsonCredential.toJson( + proposalProcedure.ppReturnAddr, + ), + }; + }, + fromJson: (value) => { + const ppDeposit = caseFieldWithValue( + "deposit", + jsonInteger.fromJson, + value, + ); + const ppGovernanceAction = caseFieldWithValue( + "governance_action", + jsonGovernanceAction.fromJson, + value, + ); + const ppReturnAddr = caseFieldWithValue( + "return_addr", + V1Credential.jsonCredential.fromJson, + value, + ); + + return { + ppDeposit, + ppGovernanceAction, + ppReturnAddr, + }; + }, +}; + +export const isPlutusDataProposalProcedure: IsPlutusData = { + toData: (protocolProcedure) => { + return { + fields: [ + 0n, + [ + isPlutusDataInteger.toData(protocolProcedure.ppDeposit), + V1Credential.isPlutusDataCredential.toData( + protocolProcedure.ppReturnAddr, + ), + isPlutusDataGovernanceAction.toData( + protocolProcedure.ppGovernanceAction, + ), + ], + ], + name: "Constr", + }; + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag !== 0n) break; + if (fields.length !== 3) break; + + return { + ppDeposit: isPlutusDataInteger.fromData(fields[0]!), + ppReturnAddr: V1Credential.isPlutusDataCredential.fromData( + fields[1]!, + ), + ppGovernanceAction: isPlutusDataGovernanceAction.fromData(fields[2]!), + }; + } + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type ScriptPurpose = + | { name: "Minting"; fields: CurrencySymbol } + | { name: "Spending"; fields: TxOutRef } + | { name: "Rewarding"; fields: Credential } + | { name: "Certifying"; fields: [Integer, TxCert] } + | { name: "Voting"; fields: Voter } + | { name: "Proposing"; fields: [Integer, ProposalProcedure] }; + +export const eqScriptPurpose: Eq = { + eq: (l, r) => { + if (l.name === "Minting" && r.name === "Minting") { + return V1Value.eqCurrencySymbol.eq(l.fields, r.fields); + } else if (l.name === "Spending" && r.name === "Spending") { + return V1Tx.eqTxOutRef.eq(l.fields, r.fields); + } else if (l.name === "Rewarding" && r.name === "Rewarding") { + return V1Credential.eqCredential.eq(l.fields, r.fields); + } else if (l.name === "Certifying" && r.name === "Certifying") { + return ( + eqInteger.eq(l.fields[0], r.fields[0]) && + eqTxCert.eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "Voting" && r.name === "Voting") { + return eqVoter.eq(l.fields, r.fields); + } else if (l.name === "Proposing" && r.name === "Proposing") { + return ( + eqInteger.eq(l.fields[0], r.fields[0]) && + eqProposalProcedure.eq(l.fields[1], r.fields[1]) + ); + } else return false; + }, + neq: (l, r) => { + if (l.name === "Minting" && r.name === "Minting") { + return V1Value.eqCurrencySymbol.neq(l.fields, r.fields); + } else if (l.name === "Spending" && r.name === "Spending") { + return V1Tx.eqTxOutRef.neq(l.fields, r.fields); + } else if (l.name === "Rewarding" && r.name === "Rewarding") { + return V1Credential.eqCredential.neq(l.fields, r.fields); + } else if (l.name === "Certifying" && r.name === "Certifying") { + return ( + eqInteger.neq(l.fields[0], r.fields[0]) || + eqTxCert.neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "Voting" && r.name === "Voting") { + return eqVoter.neq(l.fields, r.fields); + } else if (l.name === "Proposing" && r.name === "Proposing") { + return ( + eqInteger.neq(l.fields[0], r.fields[0]) || + eqProposalProcedure.neq(l.fields[1], r.fields[1]) + ); + } else return true; + }, +}; + +export const jsonScriptPurpose: Json = { + toJson: (scriptPurpose) => { + switch (scriptPurpose.name) { + case "Minting": + return jsonConstructor(scriptPurpose.name, [ + V1Value.jsonCurrencySymbol.toJson(scriptPurpose.fields), + ]); + case "Spending": + return jsonConstructor(scriptPurpose.name, [ + V1Tx.jsonTxOutRef.toJson(scriptPurpose.fields), + ]); + case "Rewarding": + return jsonConstructor(scriptPurpose.name, [ + V1Credential.jsonCredential.toJson(scriptPurpose.fields), + ]); + case "Certifying": + return jsonConstructor(scriptPurpose.name, [ + jsonInteger.toJson(scriptPurpose.fields[0]), + jsonTxCert.toJson(scriptPurpose.fields[1]), + ]); + case "Voting": + return jsonConstructor(scriptPurpose.name, [ + jsonVoter.toJson(scriptPurpose.fields), + ]); + case "Proposing": + return jsonConstructor(scriptPurpose.name, [ + jsonInteger.toJson(scriptPurpose.fields[0]), + jsonProposalProcedure.toJson(scriptPurpose.fields[1]), + ]); + } + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus,V3.ScriptPurpose", + { + Minting: (fields) => { + if (fields.length !== 1) { + throw new JsonError("Expected one field"); + } + return { + fields: V1Value.jsonCurrencySymbol.fromJson(fields[0]!), + name: "Minting", + }; + }, + Spending: (fields) => { + if (fields.length !== 1) { + throw new JsonError("Expected one field"); + } + return { + fields: V1Tx.jsonTxOutRef.fromJson(fields[0]!), + name: "Spending", + }; + }, + Rewarding: (fields) => { + if (fields.length !== 1) { + throw new JsonError("Expected one field"); + } + return { + fields: V1Credential.jsonCredential.fromJson(fields[0]!), + name: "Rewarding", + }; + }, + Certifying: (fields) => { + if (fields.length !== 2) { + throw new JsonError("Expected two fields"); + } + return { + fields: [ + jsonInteger.fromJson(fields[0]!), + jsonTxCert.fromJson(fields[1]!), + ], + name: "Certifying", + }; + }, + Voting: (fields) => { + if (fields.length !== 1) { + throw new JsonError("Expected one field"); + } + + return { + fields: jsonVoter.fromJson(fields[0]!), + name: "Voting", + }; + }, + Proposing: (fields) => { + if (fields.length !== 2) { + throw new JsonError("Expected two fields"); + } + + return { + fields: [ + jsonInteger.fromJson(fields[0]!), + jsonProposalProcedure.fromJson(fields[1]!), + ], + name: "Proposing", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataScriptPurpose: IsPlutusData = { + toData: (scriptPurpose) => { + switch (scriptPurpose.name) { + case "Minting": + return { + fields: [ + 0n, + [V1Value.isPlutusDataCurrencySymbol.toData(scriptPurpose.fields)], + ], + name: "Constr", + }; + case "Spending": + return { + fields: [ + 1n, + [V1Tx.isPlutusDataTxOutRef.toData(scriptPurpose.fields)], + ], + name: "Constr", + }; + case "Rewarding": + return { + fields: [ + 2n, + [V1Credential.isPlutusDataCredential.toData(scriptPurpose.fields)], + ], + name: "Constr", + }; + case "Certifying": + return { + fields: [ + 3n, + [ + isPlutusDataInteger.toData(scriptPurpose.fields[0]), + isPlutusDataTxCert.toData(scriptPurpose.fields[1]), + ], + ], + name: "Constr", + }; + case "Voting": + return { + fields: [4n, [isPlutusDataVoter.toData(scriptPurpose.fields)]], + name: "Constr", + }; + case "Proposing": + return { + fields: [ + 5n, + [ + isPlutusDataInteger.toData(scriptPurpose.fields[0]), + isPlutusDataProposalProcedure.toData(scriptPurpose.fields[1]), + ], + ], + name: "Constr", + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag === 0n && fields.length === 1) { + return { + fields: V1Value.isPlutusDataCurrencySymbol.fromData(fields[0]!), + name: "Minting", + }; + } else if (tag === 1n && fields.length === 1) { + return { + fields: V1Tx.isPlutusDataTxOutRef.fromData(fields[0]!), + name: "Spending", + }; + } else if (tag === 2n && fields.length === 1) { + return { + fields: V1Credential.isPlutusDataCredential.fromData(fields[0]!), + name: "Rewarding", + }; + } else if (tag === 3n && fields.length === 2) { + return { + fields: [ + isPlutusDataInteger.fromData(fields[0]!), + isPlutusDataTxCert.fromData(fields[1]!), + ], + name: "Certifying", + }; + } else if (tag === 4n && fields.length === 1) { + return { + fields: isPlutusDataVoter.fromData(fields[0]!), + name: "Voting", + }; + } else if (tag === 5n && fields.length === 2) { + return { + fields: [ + isPlutusDataInteger.fromData(fields[0]!), + isPlutusDataProposalProcedure.fromData(fields[1]!), + ], + name: "Proposing", + }; + } else break; + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type ScriptInfo = + | { name: "Minting"; fields: CurrencySymbol } + | { name: "Spending"; fields: [TxOutRef, Maybe] } + | { name: "Rewarding"; fields: Credential } + | { name: "Certifying"; fields: [Integer, TxCert] } + | { name: "Voting"; fields: Voter } + | { name: "Proposing"; fields: [Integer, ProposalProcedure] }; + +export const eqScriptInfo: Eq = { + eq: (l, r) => { + if (l.name === "Minting" && r.name === "Minting") { + return V1Value.eqCurrencySymbol.eq(l.fields, r.fields); + } else if (l.name === "Spending" && r.name === "Spending") { + return ( + V1Tx.eqTxOutRef.eq(l.fields[0], r.fields[0]) && + eqMaybe(V1Scripts.eqDatum).eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "Rewarding" && r.name === "Rewarding") { + return V1Credential.eqCredential.eq(l.fields, r.fields); + } else if (l.name === "Certifying" && r.name === "Certifying") { + return ( + eqInteger.eq(l.fields[0], r.fields[0]) && + eqTxCert.eq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "Voting" && r.name === "Voting") { + return eqVoter.eq(l.fields, r.fields); + } else if (l.name === "Proposing" && r.name === "Proposing") { + return ( + eqInteger.eq(l.fields[0], r.fields[0]) && + eqProposalProcedure.eq(l.fields[1], r.fields[1]) + ); + } else return false; + }, + neq: (l, r) => { + if (l.name === "Minting" && r.name === "Minting") { + return V1Value.eqCurrencySymbol.neq(l.fields, r.fields); + } else if (l.name === "Spending" && r.name === "Spending") { + return ( + V1Tx.eqTxOutRef.neq(l.fields[0], r.fields[0]) || + eqMaybe(V1Scripts.eqDatum).neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "Rewarding" && r.name === "Rewarding") { + return V1Credential.eqCredential.neq(l.fields, r.fields); + } else if (l.name === "Certifying" && r.name === "Certifying") { + return ( + eqInteger.neq(l.fields[0], r.fields[0]) || + eqTxCert.neq(l.fields[1], r.fields[1]) + ); + } else if (l.name === "Voting" && r.name === "Voting") { + return eqVoter.neq(l.fields, r.fields); + } else if (l.name === "Proposing" && r.name === "Proposing") { + return ( + eqInteger.neq(l.fields[0], r.fields[0]) || + eqProposalProcedure.neq(l.fields[1], r.fields[1]) + ); + } else return true; + }, +}; + +export const jsonScriptInfo: Json = { + toJson: (scriptPurpose) => { + switch (scriptPurpose.name) { + case "Minting": + return jsonConstructor(scriptPurpose.name, [ + V1Value.jsonCurrencySymbol.toJson(scriptPurpose.fields), + ]); + case "Spending": + return jsonConstructor(scriptPurpose.name, [ + V1Tx.jsonTxOutRef.toJson(scriptPurpose.fields[0]), + jsonMaybe(V1Scripts.jsonDatum).toJson(scriptPurpose.fields[1]), + ]); + case "Rewarding": + return jsonConstructor(scriptPurpose.name, [ + V1Credential.jsonCredential.toJson(scriptPurpose.fields), + ]); + case "Certifying": + return jsonConstructor(scriptPurpose.name, [ + jsonInteger.toJson(scriptPurpose.fields[0]), + jsonTxCert.toJson(scriptPurpose.fields[1]), + ]); + case "Voting": + return jsonConstructor(scriptPurpose.name, [ + jsonVoter.toJson(scriptPurpose.fields), + ]); + case "Proposing": + return jsonConstructor(scriptPurpose.name, [ + jsonInteger.toJson(scriptPurpose.fields[0]), + jsonProposalProcedure.toJson(scriptPurpose.fields[1]), + ]); + } + }, + fromJson: (value) => { + return caseJsonConstructor( + "Plutus,V3.ScriptPurpose", + { + Minting: (fields) => { + if (fields.length !== 1) { + throw new JsonError("Expected one field"); + } + return { + fields: V1Value.jsonCurrencySymbol.fromJson(fields[0]!), + name: "Minting", + }; + }, + Spending: (fields) => { + if (fields.length !== 2) { + throw new JsonError("Expected two fields"); + } + return { + fields: [ + V1Tx.jsonTxOutRef.fromJson(fields[0]!), + jsonMaybe(V1Scripts.jsonDatum).fromJson(fields[1]!), + ], + name: "Spending", + }; + }, + Rewarding: (fields) => { + if (fields.length !== 1) { + throw new JsonError("Expected one field"); + } + return { + fields: V1Credential.jsonCredential.fromJson(fields[0]!), + name: "Rewarding", + }; + }, + Certifying: (fields) => { + if (fields.length !== 2) { + throw new JsonError("Expected two fields"); + } + return { + fields: [ + jsonInteger.fromJson(fields[0]!), + jsonTxCert.fromJson(fields[1]!), + ], + name: "Certifying", + }; + }, + Voting: (fields) => { + if (fields.length !== 1) { + throw new JsonError("Expected one field"); + } + + return { + fields: jsonVoter.fromJson(fields[0]!), + name: "Voting", + }; + }, + Proposing: (fields) => { + if (fields.length !== 2) { + throw new JsonError("Expected two fields"); + } + + return { + fields: [ + jsonInteger.fromJson(fields[0]!), + jsonProposalProcedure.fromJson(fields[1]!), + ], + name: "Proposing", + }; + }, + }, + value, + ); + }, +}; + +export const isPlutusDataScriptInfo: IsPlutusData = { + toData: (scriptPurpose) => { + switch (scriptPurpose.name) { + case "Minting": + return { + fields: [ + 0n, + [V1Value.isPlutusDataCurrencySymbol.toData(scriptPurpose.fields)], + ], + name: "Constr", + }; + case "Spending": + return { + fields: [ + 1n, + [ + V1Tx.isPlutusDataTxOutRef.toData(scriptPurpose.fields[0]), + isPlutusDataMaybe(V1Scripts.isPlutusDataDatum).toData( + scriptPurpose.fields[1], + ), + ], + ], + name: "Constr", + }; + case "Rewarding": + return { + fields: [ + 2n, + [V1Credential.isPlutusDataCredential.toData(scriptPurpose.fields)], + ], + name: "Constr", + }; + case "Certifying": + return { + fields: [ + 3n, + [ + isPlutusDataInteger.toData(scriptPurpose.fields[0]), + isPlutusDataTxCert.toData(scriptPurpose.fields[1]), + ], + ], + name: "Constr", + }; + case "Voting": + return { + fields: [4n, [isPlutusDataVoter.toData(scriptPurpose.fields)]], + name: "Constr", + }; + case "Proposing": + return { + fields: [ + 5n, + [ + isPlutusDataInteger.toData(scriptPurpose.fields[0]), + isPlutusDataProposalProcedure.toData(scriptPurpose.fields[1]), + ], + ], + name: "Constr", + }; + } + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag === 0n && fields.length === 1) { + return { + fields: V1Value.isPlutusDataCurrencySymbol.fromData(fields[0]!), + name: "Minting", + }; + } else if (tag === 1n && fields.length === 2) { + return { + fields: [ + V1Tx.isPlutusDataTxOutRef.fromData(fields[0]!), + isPlutusDataMaybe(V1Scripts.isPlutusDataDatum).fromData( + fields[1]!, + ), + ], + name: "Spending", + }; + } else if (tag === 2n && fields.length === 1) { + return { + fields: V1Credential.isPlutusDataCredential.fromData(fields[0]!), + name: "Rewarding", + }; + } else if (tag === 3n && fields.length === 2) { + return { + fields: [ + isPlutusDataInteger.fromData(fields[0]!), + isPlutusDataTxCert.fromData(fields[1]!), + ], + name: "Certifying", + }; + } else if (tag === 4n && fields.length === 1) { + return { + fields: isPlutusDataVoter.fromData(fields[0]!), + name: "Voting", + }; + } else if (tag === 5n && fields.length === 2) { + return { + fields: [ + isPlutusDataInteger.fromData(fields[0]!), + isPlutusDataProposalProcedure.fromData(fields[1]!), + ], + name: "Proposing", + }; + } else break; + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type TxInfo = { + txInfoInputs: TxInInfo[]; + txInfoReferenceInputs: TxInInfo[]; + txInfoOutputs: TxOut[]; + txInfoFee: Lovelace; + txInfoMint: Value; + txInfoTxCerts: TxCert[]; + txInfoWdrl: Map; + txInfoValidRange: POSIXTimeRange; + txInfoSignatories: PubKeyHash[]; + txInfoRedeemers: Map; + txInfoData: Map; + txInfoId: TxId; + txInfoVotes: Map>; + txInfoProposalProcedures: ProposalProcedure[]; + txInfoCurrentTreasuryAmount: Maybe; + txInfoTreasuryDonation: Maybe; +}; + +export const eqTxInfo: Eq = { + eq: (l, r) => { + return ( + eqList(V2Contexts.eqTxInInfo).eq(l.txInfoInputs, r.txInfoInputs) && + eqList(V2Contexts.eqTxInInfo).eq( + l.txInfoReferenceInputs, + r.txInfoReferenceInputs, + ) && + eqList(V2Tx.eqTxOut).eq(l.txInfoOutputs, r.txInfoOutputs) && + eqInteger.eq(l.txInfoFee, r.txInfoFee) && + V1Value.eqValue.eq(l.txInfoMint, r.txInfoMint) && + eqList(eqTxCert).eq(l.txInfoTxCerts, r.txInfoTxCerts) && + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).eq( + l.txInfoWdrl, + r.txInfoWdrl, + ) && + V1Time.eqPOSIXTimeRange.eq(l.txInfoValidRange, r.txInfoValidRange) && + eqList(V1Crypto.eqPubKeyHash).eq( + l.txInfoSignatories, + r.txInfoSignatories, + ) && + AssocMap.eqMap(eqScriptPurpose, V1Scripts.eqRedeemer).eq( + l.txInfoRedeemers, + r.txInfoRedeemers, + ) && + AssocMap.eqMap(V1Scripts.eqDatumHash, V1Scripts.eqDatum).eq( + l.txInfoData, + r.txInfoData, + ) && + V1Tx.eqTxId.eq(l.txInfoId, r.txInfoId) && + AssocMap.eqMap(eqVoter, AssocMap.eqMap(eqGovernanceActionId, eqVote)).eq( + l.txInfoVotes, + r.txInfoVotes, + ) && + eqList(eqProposalProcedure).eq( + l.txInfoProposalProcedures, + r.txInfoProposalProcedures, + ) && + eqMaybe(eqInteger).eq( + l.txInfoCurrentTreasuryAmount, + r.txInfoCurrentTreasuryAmount, + ) && + eqMaybe(eqInteger).eq(l.txInfoTreasuryDonation, r.txInfoTreasuryDonation) + ); + }, + neq: (l, r) => { + return ( + eqList(V2Contexts.eqTxInInfo).neq(l.txInfoInputs, r.txInfoInputs) || + eqList(V2Contexts.eqTxInInfo).neq( + l.txInfoReferenceInputs, + r.txInfoReferenceInputs, + ) || + eqList(V2Tx.eqTxOut).neq(l.txInfoOutputs, r.txInfoOutputs) || + eqInteger.neq(l.txInfoFee, r.txInfoFee) || + V1Value.eqValue.neq(l.txInfoMint, r.txInfoMint) || + eqList(eqTxCert).neq(l.txInfoTxCerts, r.txInfoTxCerts) || + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + l.txInfoWdrl, + r.txInfoWdrl, + ) || + V1Time.eqPOSIXTimeRange.neq(l.txInfoValidRange, r.txInfoValidRange) || + eqList(V1Crypto.eqPubKeyHash).neq( + l.txInfoSignatories, + r.txInfoSignatories, + ) || + AssocMap.eqMap(eqScriptPurpose, V1Scripts.eqRedeemer).neq( + l.txInfoRedeemers, + r.txInfoRedeemers, + ) || + AssocMap.eqMap(V1Scripts.eqDatumHash, V1Scripts.eqDatum).neq( + l.txInfoData, + r.txInfoData, + ) || + V1Tx.eqTxId.neq(l.txInfoId, r.txInfoId) || + AssocMap.eqMap(eqVoter, AssocMap.eqMap(eqGovernanceActionId, eqVote)).neq( + l.txInfoVotes, + r.txInfoVotes, + ) || + eqList(eqProposalProcedure).neq( + l.txInfoProposalProcedures, + r.txInfoProposalProcedures, + ) || + eqMaybe(eqInteger).neq( + l.txInfoCurrentTreasuryAmount, + r.txInfoCurrentTreasuryAmount, + ) || + eqMaybe(eqInteger).neq(l.txInfoTreasuryDonation, r.txInfoTreasuryDonation) + ); + }, +}; + +export const jsonTxInfo: Json = { + toJson: (txInfo) => { + return { + current_treasury_amount: jsonMaybe(jsonInteger).toJson( + txInfo.txInfoCurrentTreasuryAmount, + ), + datums: AssocMap.jsonMap( + V1Scripts.jsonDatumHash, + V1Scripts.jsonDatum, + ).toJson(txInfo.txInfoData), + fee: jsonInteger.toJson(txInfo.txInfoFee), + id: V1Tx.jsonTxId.toJson(txInfo.txInfoId), + inputs: jsonList(V2Contexts.jsonTxInInfo).toJson(txInfo.txInfoInputs), + mint: V1Value.jsonValue.toJson(txInfo.txInfoMint), + outputs: jsonList(V2Tx.jsonTxOut).toJson(txInfo.txInfoOutputs), + proposal_procedures: jsonList(jsonProposalProcedure).toJson( + txInfo.txInfoProposalProcedures, + ), + redeemers: AssocMap.jsonMap( + jsonScriptPurpose, + V1Scripts.jsonRedeemer, + ).toJson(txInfo.txInfoRedeemers), + reference_inputs: jsonList(V2Contexts.jsonTxInInfo).toJson( + txInfo.txInfoReferenceInputs, + ), + signatories: jsonList(V1Crypto.jsonPubKeyHash).toJson( + txInfo.txInfoSignatories, + ), + treasury_donation: jsonMaybe(jsonInteger).toJson( + txInfo.txInfoTreasuryDonation, + ), + tx_certs: jsonList(jsonTxCert).toJson(txInfo.txInfoTxCerts), + valid_range: V1Time.jsonPOSIXTimeRange.toJson(txInfo.txInfoValidRange), + wdrl: AssocMap.jsonMap(V1Credential.jsonCredential, jsonInteger).toJson( + txInfo.txInfoWdrl, + ), + }; + }, + fromJson: (value) => { + const txInfoInputs = caseFieldWithValue( + "inputs", + jsonList(V2Contexts.jsonTxInInfo).fromJson, + value, + ); + const txInfoReferenceInputs = caseFieldWithValue( + "reference_inputs", + jsonList(V2Contexts.jsonTxInInfo).fromJson, + value, + ); + const txInfoOutputs = caseFieldWithValue( + "outputs", + jsonList(V2Tx.jsonTxOut).fromJson, + value, + ); + const txInfoFee = caseFieldWithValue("fee", jsonInteger.fromJson, value); + const txInfoMint = caseFieldWithValue( + "mint", + V1Value.jsonValue.fromJson, + value, + ); + const txInfoTxCerts = caseFieldWithValue( + "tx_cert", + jsonList(jsonTxCert).fromJson, + value, + ); + const txInfoWdrl = caseFieldWithValue( + "wdrl", + AssocMap.jsonMap(V1Credential.jsonCredential, jsonInteger).fromJson, + value, + ); + const txInfoValidRange = caseFieldWithValue( + "valid_range", + V1Time.jsonPOSIXTimeRange.fromJson, + value, + ); + + const txInfoSignatories = caseFieldWithValue( + "signatories", + jsonList(V1Crypto.jsonPubKeyHash).fromJson, + value, + ); + + const txInfoRedeemers = caseFieldWithValue( + "redeemers", + AssocMap.jsonMap(jsonScriptPurpose, V1Scripts.jsonRedeemer).fromJson, + value, + ); + + const txInfoData = caseFieldWithValue( + "datums", + AssocMap.jsonMap(V1Scripts.jsonDatumHash, V1Scripts.jsonDatum).fromJson, + value, + ); + + const txInfoId = caseFieldWithValue("id", V1Tx.jsonTxId.fromJson, value); + + const txInfoVotes = caseFieldWithValue( + "votes", + AssocMap.jsonMap( + jsonVoter, + AssocMap.jsonMap(jsonGovernanceActionId, jsonVote), + ).fromJson, + value, + ); + + const txInfoProposalProcedures = caseFieldWithValue( + "protocol_procedure", + jsonList(jsonProposalProcedure).fromJson, + value, + ); + + const txInfoCurrentTreasuryAmount = caseFieldWithValue( + "current_treasury_amount", + jsonMaybe(jsonInteger).fromJson, + value, + ); + + const txInfoTreasuryDonation = caseFieldWithValue( + "treasury_donation", + jsonMaybe(jsonInteger).fromJson, + value, + ); + + return { + txInfoInputs, + txInfoReferenceInputs, + txInfoOutputs, + txInfoFee, + txInfoMint, + txInfoTxCerts, + txInfoWdrl, + txInfoValidRange, + txInfoSignatories, + txInfoRedeemers, + txInfoData, + txInfoId, + txInfoVotes, + txInfoProposalProcedures, + txInfoCurrentTreasuryAmount, + txInfoTreasuryDonation, + }; + }, +}; + +export const isPlutusDataTxInfo: IsPlutusData = { + toData: (txInfo) => { + return { + fields: [ + 0n, + [ + isPlutusDataList(V2Contexts.isPlutusDataTxInInfo).toData( + txInfo.txInfoInputs, + ), + isPlutusDataList(V2Contexts.isPlutusDataTxInInfo).toData( + txInfo.txInfoReferenceInputs, + ), + isPlutusDataList(V2Tx.isPlutusDataTxOut).toData(txInfo.txInfoOutputs), + isPlutusDataInteger.toData(txInfo.txInfoFee), + V1Value.isPlutusDataValue.toData(txInfo.txInfoMint), + isPlutusDataList(isPlutusDataTxCert).toData(txInfo.txInfoTxCerts), + AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).toData(txInfo.txInfoWdrl), + V1Time.isPlutusDataPOSIXTimeRange.toData(txInfo.txInfoValidRange), + isPlutusDataList(V1Crypto.isPlutusDataPubKeyHash).toData( + txInfo.txInfoSignatories, + ), + AssocMap.isPlutusDataMap( + isPlutusDataScriptPurpose, + V1Scripts.isPlutusDataRedeemer, + ).toData(txInfo.txInfoRedeemers), + AssocMap.isPlutusDataMap( + V1Scripts.isPlutusDataDatumHash, + V1Scripts.isPlutusDataDatum, + ).toData(txInfo.txInfoData), + V1Tx.isPlutusDataTxId.toData(txInfo.txInfoId), + AssocMap.isPlutusDataMap( + isPlutusDataVoter, + AssocMap.isPlutusDataMap( + isPlutusDataGovernanceActionId, + isPlutusDataVote, + ), + ).toData(txInfo.txInfoVotes), + isPlutusDataList(isPlutusDataProposalProcedure).toData( + txInfo.txInfoProposalProcedures, + ), + isPlutusDataMaybe(isPlutusDataInteger).toData( + txInfo.txInfoCurrentTreasuryAmount, + ), + isPlutusDataMaybe(isPlutusDataInteger).toData( + txInfo.txInfoTreasuryDonation, + ), + ], + ], + name: "Constr", + }; + }, + + fromData: (plutusData) => { + switch (plutusData.name) { + case "Constr": { + if (plutusData.fields[0] === 0n && plutusData.fields[1].length === 16) { + const txInfoInputs = isPlutusDataList( + V2Contexts.isPlutusDataTxInInfo, + ).fromData(plutusData.fields[1][0]!); + const txInfoReferenceInputs = isPlutusDataList( + V2Contexts.isPlutusDataTxInInfo, + ).fromData(plutusData.fields[1][1]!); + const txInfoOutputs = isPlutusDataList( + V2Tx.isPlutusDataTxOut, + ).fromData(plutusData.fields[1][2]!); + const txInfoFee = isPlutusDataInteger.fromData( + plutusData.fields[1][3]!, + ); + const txInfoMint = V1Value.isPlutusDataValue.fromData( + plutusData.fields[1][4]!, + ); + const txInfoTxCerts = isPlutusDataList(isPlutusDataTxCert).fromData( + plutusData.fields[1][5]!, + ); + const txInfoWdrl = AssocMap.isPlutusDataMap( + V1Credential.isPlutusDataCredential, + isPlutusDataInteger, + ).fromData(plutusData.fields[1][6]!); + const txInfoValidRange = V1Time.isPlutusDataPOSIXTimeRange.fromData( + plutusData.fields[1][7]!, + ); + const txInfoSignatories = isPlutusDataList( + V1Crypto.isPlutusDataPubKeyHash, + ).fromData(plutusData.fields[1][8]!); + const txInfoRedeemers = AssocMap.isPlutusDataMap( + isPlutusDataScriptPurpose, + V1Scripts.isPlutusDataRedeemer, + ).fromData(plutusData.fields[1][9]!); + const txInfoData = AssocMap.isPlutusDataMap( + V1Scripts.isPlutusDataDatumHash, + V1Scripts.isPlutusDataDatum, + ).fromData(plutusData.fields[1][10]!); + const txInfoId = V1Tx.isPlutusDataTxId.fromData( + plutusData.fields[1][11]!, + ); + const txInfoVotes = AssocMap.isPlutusDataMap( + isPlutusDataVoter, + AssocMap.isPlutusDataMap( + isPlutusDataGovernanceActionId, + isPlutusDataVote, + ), + ).fromData(plutusData.fields[1][12]!); + const txInfoProposalProcedures = isPlutusDataList( + isPlutusDataProposalProcedure, + ).fromData(plutusData.fields[1][13]!); + const txInfoCurrentTreasuryAmount = isPlutusDataMaybe( + isPlutusDataInteger, + ).fromData(plutusData.fields[1][14]!); + const txInfoTreasuryDonation = isPlutusDataMaybe( + isPlutusDataInteger, + ).fromData(plutusData.fields[1][15]!); + + return { + txInfoInputs, + txInfoReferenceInputs, + txInfoOutputs, + txInfoFee, + txInfoMint, + txInfoTxCerts, + txInfoWdrl, + txInfoValidRange, + txInfoSignatories, + txInfoRedeemers, + txInfoData, + txInfoId, + txInfoVotes, + txInfoProposalProcedures, + txInfoCurrentTreasuryAmount, + txInfoTreasuryDonation, + }; + } else { + break; + } + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; + +export type ScriptContext = { + scriptContextTxInfo: TxInfo; + scriptContextRedeemer: V1Scripts.Redeemer; + scriptContextScriptInfo: ScriptInfo; +}; + +export const eqScriptContext: Eq = { + eq: (l, r) => { + return ( + eqTxInfo.eq(l.scriptContextTxInfo, r.scriptContextTxInfo) && + V1Scripts.eqRedeemer.eq( + l.scriptContextRedeemer, + r.scriptContextRedeemer, + ) && + eqScriptInfo.eq(l.scriptContextScriptInfo, r.scriptContextScriptInfo) + ); + }, + neq: (l, r) => { + return ( + eqTxInfo.neq(l.scriptContextTxInfo, r.scriptContextTxInfo) || + V1Scripts.eqRedeemer.neq( + l.scriptContextRedeemer, + r.scriptContextRedeemer, + ) || + eqScriptInfo.neq(l.scriptContextScriptInfo, r.scriptContextScriptInfo) + ); + }, +}; + +export const jsonScriptContext: Json = { + toJson: (scriptContext) => { + return { + redeemer: V1Scripts.jsonRedeemer.toJson( + scriptContext.scriptContextRedeemer, + ), + script_info: jsonScriptInfo.toJson(scriptContext.scriptContextScriptInfo), + tx_info: jsonTxInfo.toJson(scriptContext.scriptContextTxInfo), + }; + }, + fromJson: (value) => { + const scriptContextTxInfo = caseFieldWithValue( + "tx_info", + jsonTxInfo.fromJson, + value, + ); + const scriptContextRedeemer = caseFieldWithValue( + "redeemer", + V1Scripts.jsonRedeemer.fromJson, + value, + ); + const scriptContextScriptInfo = caseFieldWithValue( + "script_info", + jsonScriptInfo.fromJson, + value, + ); + + return { + scriptContextTxInfo, + scriptContextRedeemer, + scriptContextScriptInfo, + }; + }, +}; + +export const isPlutusDataScriptContext: IsPlutusData = { + toData: (scriptContext) => { + return { + fields: [ + 0n, + [ + isPlutusDataTxInfo.toData(scriptContext.scriptContextTxInfo), + V1Scripts.isPlutusDataRedeemer.toData( + scriptContext.scriptContextRedeemer, + ), + isPlutusDataScriptInfo.toData(scriptContext.scriptContextScriptInfo), + ], + ], + name: "Constr", + }; + }, + fromData: (value) => { + switch (value.name) { + case "Constr": { + const [tag, fields] = value.fields; + + if (tag !== 0n) break; + if (fields.length != 3) break; + + return { + scriptContextTxInfo: isPlutusDataTxInfo.fromData(fields[0]!), + scriptContextRedeemer: V1Scripts.isPlutusDataRedeemer.fromData( + fields[1]!, + ), + scriptContextScriptInfo: isPlutusDataScriptInfo.fromData(fields[2]!), + }; + } + default: + break; + } + throw new IsPlutusDataError("Unexpected data"); + }, +}; From ba074489a8d8f7f06dedbd17efb7ea07f9448cef Mon Sep 17 00:00:00 2001 From: Hongrui Fang Date: Wed, 30 Oct 2024 22:02:01 +0800 Subject: [PATCH 2/3] add doc strings for new types --- src/Lib/V1/Value.ts | 3 + src/Lib/V3.ts | 13 +++ src/Lib/V3/Contexts.ts | 220 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 234 insertions(+), 2 deletions(-) diff --git a/src/Lib/V1/Value.ts b/src/Lib/V1/Value.ts index 0e982a2..d6cf12e 100644 --- a/src/Lib/V1/Value.ts +++ b/src/Lib/V1/Value.ts @@ -202,4 +202,7 @@ export const adaSymbol: CurrencySymbol = Uint8Array.from([]) as CurrencySymbol; */ export const adaToken: TokenName = Uint8Array.from([]) as TokenName; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V1/Value.hs#L598} + */ export type Lovelace = Integer; diff --git a/src/Lib/V3.ts b/src/Lib/V3.ts index b4ded7c..da4fbfe 100644 --- a/src/Lib/V3.ts +++ b/src/Lib/V3.ts @@ -1,2 +1,15 @@ +/** + * TypeScript types for {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/} + * + * @example + * ```ts + * import * as PlaV3 from 'plutus-ledger-api/V3.js' + * + * // ... + * ``` + * + * @module plutus-ledger-api/V3.js + */ + export * from "./V3/Contexts.js"; export * from "./Prelude/Instances.js"; diff --git a/src/Lib/V3/Contexts.ts b/src/Lib/V3/Contexts.ts index 5d81dd3..6953ad4 100644 --- a/src/Lib/V3/Contexts.ts +++ b/src/Lib/V3/Contexts.ts @@ -1,3 +1,6 @@ +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs} + */ import { caseFieldWithValue, caseJsonConstructor, @@ -64,19 +67,40 @@ import { isPlutusDataMaybe, } from "../V1.js"; -// import { isPlutusDataInteger, isPlutusDataMaybe } from "../V1.js"; - +/** + * Cold credential of a constitutional committee. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L78} + */ export type ColdCommitteeCredential = Credential; +/** + * Hot credential of a constitutional committee. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L102} + */ export type HotCommitteeCredential = Credential; +/** + * Credential of a delegated representative. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L126} + */ export type DRepCredential = Credential; +/** + * Delegated representative, or the two predefined voting options. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L150-L153} + */ export type DRep = | { name: "DRep"; fields: DRepCredential } | { name: "AlwaysAbstain" } | { name: "AlwaysNoConfidence" }; +/** + * {@link Eq} instance for {@link DRep} + */ export const eqDRep: Eq = { eq: (l, r) => { if (l.name === "DRep" && r.name === "DRep") { @@ -108,6 +132,9 @@ export const eqDRep: Eq = { }, }; +/** + * {@link Json} instance for {@link DRep} + */ export const jsonDRep: Json = { toJson: (dRep) => { switch (dRep.name) { @@ -156,6 +183,9 @@ export const jsonDRep: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link DRep} + */ export const isPlutusDataDRep: IsPlutusData = { toData: (dRep) => { switch (dRep.name) { @@ -205,11 +235,17 @@ export const isPlutusDataDRep: IsPlutusData = { }, }; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L165-L168} + */ export type Delegatee = | { name: "Stake"; fields: PubKeyHash } | { name: "Vote"; fields: DRep } | { name: "StakeVote"; fields: [PubKeyHash, DRep] }; +/** + * {@link Eq} instance for {@link Delegatee} + */ export const eqDelegatee: Eq = { eq: (l, r) => { if (l.name == "Stake" && r.name == "Stake") { @@ -237,6 +273,9 @@ export const eqDelegatee: Eq = { }, }; +/** + * {@link Json} instance for {@link Delegatee} + */ export const jsonDelegatee: Json = { toJson: (delegatee) => { switch (delegatee.name) { @@ -295,6 +334,9 @@ export const jsonDelegatee: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link Delegatee} + */ export const isPlutusDataDelegatee: IsPlutusData = { toData: (delegatee) => { switch (delegatee.name) { @@ -358,6 +400,9 @@ export const isPlutusDataDelegatee: IsPlutusData = { }, }; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L181-L207} + */ export type TxCert = | { name: "RegStaking"; @@ -400,6 +445,9 @@ export type TxCert = fields: ColdCommitteeCredential; }; +/** + * {@link Eq} instance for {@link TxCert} + */ export const eqTxCert: Eq = { eq: (l, r) => { if (l.name === "RegStaking" && r.name === "RegStaking") { @@ -499,6 +547,9 @@ export const eqTxCert: Eq = { }, }; +/** + * {@link Json} instance for {@link TxCert} + */ export const jsonTxCert: Json = { toJson: (txCert) => { switch (txCert.name) { @@ -688,6 +739,9 @@ export const jsonTxCert: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link TxCert} + */ export const isPlutusDataTxCert: IsPlutusData = { toData: (txCert) => { switch (txCert.name) { @@ -888,11 +942,19 @@ export const isPlutusDataTxCert: IsPlutusData = { }, }; +/** + * {@link Voter} represents a body with voting power. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L234-L237} + */ export type Voter = | { name: "CommitteeVoter"; fields: HotCommitteeCredential } | { name: "DRepVoter"; fields: DRepCredential } | { name: "StakePoolVoter"; fields: PubKeyHash }; +/** + * {@link Eq} instance for {@link Voter} + */ export const eqVoter: Eq = { eq: (l, r) => { if (l.name === "CommitteeVoter" && r.name === "CommitteeVoter") { @@ -914,6 +976,9 @@ export const eqVoter: Eq = { }, }; +/** + * {@link Json} instance for {@link Voter} + */ export const jsonVoter: Json = { toJson: (voter) => { switch (voter.name) { @@ -968,6 +1033,9 @@ export const jsonVoter: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link Voter} + */ export const isPlutusDataVoter: IsPlutusData = { toData: (voter) => { switch (voter.name) { @@ -1024,11 +1092,19 @@ export const isPlutusDataVoter: IsPlutusData = { }, }; +/** + * {@link Voter} represents the different voting options: yes, no or abstain. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L234-L237} + */ export type Vote = | { name: "VoteNo" } | { name: "VoteYes" } | { name: "Abstain" }; +/** + * {@link Eq} instance for {@link Vote} + */ export const eqVote: Eq = { eq: (l, r) => { return l.name === r.name; @@ -1038,6 +1114,9 @@ export const eqVote: Eq = { }, }; +/** + * {@link Json} instance for {@link Vote} + */ export const jsonVote: Json = { toJson: (vote) => { return jsonConstructor(vote.name, []); @@ -1076,6 +1155,9 @@ export const jsonVote: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link Vote} + */ export const isPlutusDataVote: IsPlutusData = { toData: (vote) => { switch (vote.name) { @@ -1120,11 +1202,17 @@ export const isPlutusDataVote: IsPlutusData = { }, }; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L269-L272} + */ export type GovernanceActionId = { gaidTxId: TxId; gaidGovActionIx: Integer; }; +/** + * {@link Eq} instance for {@link GovernanceActionId} + */ export const eqGovernanceActionId: Eq = { eq: (l, r) => { return ( @@ -1140,6 +1228,9 @@ export const eqGovernanceActionId: Eq = { }, }; +/** + * {@link Json} instance for {@link GovernanceActionId} + */ export const jsonGovernanceActionId: Json = { toJson: (governanceActionId) => { return { @@ -1166,6 +1257,9 @@ export const jsonGovernanceActionId: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link GovernanceActionId} + */ export const isPlutusDataGovernanceActionId: IsPlutusData = { toData: (governanceActionId) => { @@ -1199,11 +1293,17 @@ export const isPlutusDataGovernanceActionId: IsPlutusData = }, }; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L288-L293} + */ export type Committee = { committeeMembers: Map; committeeQuorum: Integer; }; +/** + * {@link Eq} instance for {@link Committee} + */ export const eqCommittee: Eq = { eq: (l, r) => { return ( @@ -1223,6 +1323,9 @@ export const eqCommittee: Eq = { }, }; +/** + * {@link Json} instance for {@link Committee} + */ export const jsonCommittee: Json = { toJson: (committee) => { return { @@ -1251,6 +1354,9 @@ export const jsonCommittee: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link Committee} + */ export const isPlutusDataCommittee: IsPlutusData = { toData: (committee) => { return { @@ -1290,10 +1396,16 @@ export const isPlutusDataCommittee: IsPlutusData = { }, }; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L305} + */ export type Constitution = { constitutionScript: Maybe; }; +/** + * {@link Eq} instance for {@link Constitution} + */ export const eqConstitution: Eq = { eq: (l, r) => { return eqMaybe(V1Scripts.eqScriptHash).eq( @@ -1309,6 +1421,9 @@ export const eqConstitution: Eq = { }, }; +/** + * {@link Json} instance for {@link Constitution} + */ export const jsonConstitution: Json = { toJson: (constitution) => { return { @@ -1330,6 +1445,9 @@ export const jsonConstitution: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link Constitution} + */ export const isPlutusDataConstitution: IsPlutusData = { toData: (constitution) => { return { @@ -1363,11 +1481,17 @@ export const isPlutusDataConstitution: IsPlutusData = { }, }; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L319-L322} + */ export type ProtocolVersion = { pvMajor: Integer; pvMinor: Integer; }; +/** + * {@link Eq} instance for {@link ProtocolVersion} + */ export const eqProtocolVersion: Eq = { eq: (l, r) => { return ( @@ -1381,6 +1505,9 @@ export const eqProtocolVersion: Eq = { }, }; +/** + * {@link Json} instance for {@link ProtocolVersion} + */ export const jsonProtocolVersion: Json = { toJson: (protocolVersion) => { return { @@ -1398,6 +1525,9 @@ export const jsonProtocolVersion: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link ProtocolVersion} + */ export const isPlutusDataProtocolVersion: IsPlutusData = { toData: (protocolVersion) => { return { @@ -1429,8 +1559,16 @@ export const isPlutusDataProtocolVersion: IsPlutusData = { }, }; +/** + * {@link ChangedParameters} is a Plutus Data object containing proposed parameter changes. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L365} + */ export type ChangedParameters = PlutusData; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L381-L403} + */ export type GovernanceAction = | { name: "ParameterChange"; @@ -1463,6 +1601,9 @@ export type GovernanceAction = } | { name: "InfoAction" }; +/** + * {@link Eq} instance for {@link GovernanceAction} + */ export const eqGovernanceAction: Eq = { eq: (l, r) => { if (l.name === "ParameterChange" && r.name === "ParameterChange") { @@ -1554,6 +1695,9 @@ export const eqGovernanceAction: Eq = { }, }; +/** + * {@link Json} instance for {@link GovernanceAction} + */ export const jsonGovernanceAction: Json = { toJson: (governanceAction) => { switch (governanceAction.name) { @@ -1692,6 +1836,9 @@ export const jsonGovernanceAction: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link GovernanceAction} + */ export const isPlutusDataGovernanceAction: IsPlutusData = { toData: (governanceAction) => { switch (governanceAction.name) { @@ -1881,12 +2028,18 @@ export const isPlutusDataGovernanceAction: IsPlutusData = { }, }; +/** + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L409-L413} + */ export type ProposalProcedure = { ppDeposit: Lovelace; ppReturnAddr: Credential; ppGovernanceAction: GovernanceAction; }; +/** + * {@link Eq} instance for {@link ProposalProcedure} + */ export const eqProposalProcedure: Eq = { eq: (l, r) => { return ( @@ -1904,6 +2057,9 @@ export const eqProposalProcedure: Eq = { }, }; +/** + * {@link Json} instance for {@link ProposalProcedure} + */ export const jsonProposalProcedure: Json = { toJson: (proposalProcedure) => { return { @@ -1941,6 +2097,9 @@ export const jsonProposalProcedure: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link ProposalProcedure} + */ export const isPlutusDataProposalProcedure: IsPlutusData = { toData: (protocolProcedure) => { return { @@ -1980,6 +2139,11 @@ export const isPlutusDataProposalProcedure: IsPlutusData = { }, }; +/** + * {@link ScriptPurpose} uniquely identifies a Plutus script within a transaction. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L426-L438} + */ export type ScriptPurpose = | { name: "Minting"; fields: CurrencySymbol } | { name: "Spending"; fields: TxOutRef } @@ -1988,6 +2152,9 @@ export type ScriptPurpose = | { name: "Voting"; fields: Voter } | { name: "Proposing"; fields: [Integer, ProposalProcedure] }; +/** + * {@link Eq} instance for {@link ScriptPurpose} + */ export const eqScriptPurpose: Eq = { eq: (l, r) => { if (l.name === "Minting" && r.name === "Minting") { @@ -2033,6 +2200,9 @@ export const eqScriptPurpose: Eq = { }, }; +/** + * {@link Json} instance for {@link ScriptPurpose} + */ export const jsonScriptPurpose: Json = { toJson: (scriptPurpose) => { switch (scriptPurpose.name) { @@ -2136,6 +2306,9 @@ export const jsonScriptPurpose: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link ScriptPurpose} + */ export const isPlutusDataScriptPurpose: IsPlutusData = { toData: (scriptPurpose) => { switch (scriptPurpose.name) { @@ -2242,6 +2415,11 @@ export const isPlutusDataScriptPurpose: IsPlutusData = { }, }; +/** + * {@link ScriptInfo} is like {@link ScriptPurpose} but with an optional datum for spending scripts. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L444-L456} + */ export type ScriptInfo = | { name: "Minting"; fields: CurrencySymbol } | { name: "Spending"; fields: [TxOutRef, Maybe] } @@ -2250,6 +2428,9 @@ export type ScriptInfo = | { name: "Voting"; fields: Voter } | { name: "Proposing"; fields: [Integer, ProposalProcedure] }; +/** + * {@link Eq} instance for {@link ScriptInfo} + */ export const eqScriptInfo: Eq = { eq: (l, r) => { if (l.name === "Minting" && r.name === "Minting") { @@ -2301,6 +2482,9 @@ export const eqScriptInfo: Eq = { }, }; +/** + * {@link Json} instance for {@link ScriptInfo} + */ export const jsonScriptInfo: Json = { toJson: (scriptPurpose) => { switch (scriptPurpose.name) { @@ -2408,6 +2592,9 @@ export const jsonScriptInfo: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link ScriptInfo} + */ export const isPlutusDataScriptInfo: IsPlutusData = { toData: (scriptPurpose) => { switch (scriptPurpose.name) { @@ -2524,6 +2711,12 @@ export const isPlutusDataScriptInfo: IsPlutusData = { }, }; +/** + * {@link TxInfo} represents a pending transaction. This is the view as seen by + * validator scripts, so some details are stripped out. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L478-L499} + */ export type TxInfo = { txInfoInputs: TxInInfo[]; txInfoReferenceInputs: TxInInfo[]; @@ -2543,6 +2736,9 @@ export type TxInfo = { txInfoTreasuryDonation: Maybe; }; +/** + * {@link Eq} instance for {@link TxInfo} + */ export const eqTxInfo: Eq = { eq: (l, r) => { return ( @@ -2634,6 +2830,9 @@ export const eqTxInfo: Eq = { }, }; +/** + * {@link Json} instance for {@link TxInfo} + */ export const jsonTxInfo: Json = { toJson: (txInfo) => { return { @@ -2778,6 +2977,9 @@ export const jsonTxInfo: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link TxInfo} + */ export const isPlutusDataTxInfo: IsPlutusData = { toData: (txInfo) => { return { @@ -2922,12 +3124,20 @@ export const isPlutusDataTxInfo: IsPlutusData = { }, }; +/** + * The context that the currently-executing script can access. + * + * @see {@link https://github.com/IntersectMBO/plutus/blob/1.36.0.0/plutus-ledger-api/src/PlutusLedgerApi/V3/Contexts.hs#L525-L533} + */ export type ScriptContext = { scriptContextTxInfo: TxInfo; scriptContextRedeemer: V1Scripts.Redeemer; scriptContextScriptInfo: ScriptInfo; }; +/** + * {@link Eq} instance for {@link ScriptContext} + */ export const eqScriptContext: Eq = { eq: (l, r) => { return ( @@ -2951,6 +3161,9 @@ export const eqScriptContext: Eq = { }, }; +/** + * {@link Json} instance for {@link ScriptContext} + */ export const jsonScriptContext: Json = { toJson: (scriptContext) => { return { @@ -2986,6 +3199,9 @@ export const jsonScriptContext: Json = { }, }; +/** + * {@link IsPlutusData} instance for {@link ScriptContext} + */ export const isPlutusDataScriptContext: IsPlutusData = { toData: (scriptContext) => { return { From d5ce426dd0a462aef97653f0a19f4ed47409612b Mon Sep 17 00:00:00 2001 From: Hongrui Fang Date: Fri, 1 Nov 2024 19:10:08 +0800 Subject: [PATCH 3/3] add property tests for newly added types --- src/Lib/V3/Contexts.ts | 42 +++---- src/Tests/RatioInstances-test.ts | 46 ++++++++ src/Tests/V3/CommitteeInstances-test.ts | 45 ++++++++ src/Tests/V3/ConstitutionInstances-test.ts | 45 ++++++++ src/Tests/V3/DRepInstances-test.ts | 61 ++++++++++ src/Tests/V3/DelegateeInstatnces-test.ts | 59 ++++++++++ .../V3/GovernanceActionIdInstances-test.ts | 48 ++++++++ .../V3/GovernanceActionInstances-test.ts | 104 ++++++++++++++++++ .../V3/ProposalProcedureInstances-test.ts | 50 +++++++++ src/Tests/V3/ProtocolInstances-test.ts | 41 +++++++ src/Tests/V3/ScriptContextInstances-test.ts | 45 ++++++++ src/Tests/V3/ScriptInfoInstances-test.ts | 82 ++++++++++++++ src/Tests/V3/ScriptPpurposeInstances-test.ts | 80 ++++++++++++++ src/Tests/V3/TxCertInstances-test.ts | 101 +++++++++++++++++ src/Tests/V3/TxInfoInstances-test.ts | 83 ++++++++++++++ src/Tests/V3/VoteInstances-test.ts | 51 +++++++++ src/Tests/V3/VoterInstatnces-test.ts | 64 +++++++++++ 17 files changed, 1028 insertions(+), 19 deletions(-) create mode 100644 src/Tests/RatioInstances-test.ts create mode 100644 src/Tests/V3/CommitteeInstances-test.ts create mode 100644 src/Tests/V3/ConstitutionInstances-test.ts create mode 100644 src/Tests/V3/DRepInstances-test.ts create mode 100644 src/Tests/V3/DelegateeInstatnces-test.ts create mode 100644 src/Tests/V3/GovernanceActionIdInstances-test.ts create mode 100644 src/Tests/V3/GovernanceActionInstances-test.ts create mode 100644 src/Tests/V3/ProposalProcedureInstances-test.ts create mode 100644 src/Tests/V3/ProtocolInstances-test.ts create mode 100644 src/Tests/V3/ScriptContextInstances-test.ts create mode 100644 src/Tests/V3/ScriptInfoInstances-test.ts create mode 100644 src/Tests/V3/ScriptPpurposeInstances-test.ts create mode 100644 src/Tests/V3/TxCertInstances-test.ts create mode 100644 src/Tests/V3/TxInfoInstances-test.ts create mode 100644 src/Tests/V3/VoteInstances-test.ts create mode 100644 src/Tests/V3/VoterInstatnces-test.ts diff --git a/src/Lib/V3/Contexts.ts b/src/Lib/V3/Contexts.ts index 6953ad4..fcaca2d 100644 --- a/src/Lib/V3/Contexts.ts +++ b/src/Lib/V3/Contexts.ts @@ -1329,11 +1329,11 @@ export const eqCommittee: Eq = { export const jsonCommittee: Json = { toJson: (committee) => { return { - committee_members: AssocMap.jsonMap( + members: AssocMap.jsonMap( V1Credential.jsonCredential, jsonInteger, ).toJson(committee.committeeMembers), - committee_quorum: jsonInteger.toJson(committee.committeeQuorum), + quorum: jsonInteger.toJson(committee.committeeQuorum), }; }, fromJson: (value) => { @@ -1427,7 +1427,7 @@ export const eqConstitution: Eq = { export const jsonConstitution: Json = { toJson: (constitution) => { return { - constitution_script: jsonMaybe(V1Scripts.jsonScriptHash).toJson( + script: jsonMaybe(V1Scripts.jsonScriptHash).toJson( constitution.constitutionScript, ), }; @@ -1608,44 +1608,44 @@ export const eqGovernanceAction: Eq = { eq: (l, r) => { if (l.name === "ParameterChange" && r.name === "ParameterChange") { return ( - eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || - eqPlutusData.neq(l.fields[1], r.fields[1]) || - eqMaybe(V1Scripts.eqScriptHash).neq(l.fields[2], r.fields[2]) + eqMaybe(eqGovernanceActionId).eq(l.fields[0], r.fields[0]) && + eqPlutusData.eq(l.fields[1], r.fields[1]) && + eqMaybe(V1Scripts.eqScriptHash).eq(l.fields[2], r.fields[2]) ); } else if ( l.name === "HardForkInitiation" && r.name === "HardForkInitiation" ) { return ( - eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || - eqProtocolVersion.neq(l.fields[1], r.fields[1]) + eqMaybe(eqGovernanceActionId).eq(l.fields[0], r.fields[0]) && + eqProtocolVersion.eq(l.fields[1], r.fields[1]) ); } else if ( l.name === "TreasuryWithdrawal" && r.name === "TreasuryWithdrawal" ) { return ( - AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).eq( l.fields[0], r.fields[0], - ) || eqMaybe(V1Scripts.eqScriptHash).neq(l.fields[1], r.fields[1]) + ) && eqMaybe(V1Scripts.eqScriptHash).eq(l.fields[1], r.fields[1]) ); } else if (l.name === "NoConfidence" && r.name === "NoConfidence") { - return eqMaybe(eqGovernanceActionId).neq(l.fields, r.fields); + return eqMaybe(eqGovernanceActionId).eq(l.fields, r.fields); } else if (l.name === "UpdateCommittee" && r.name === "UpdateCommittee") { return ( - eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || - eqList(V1Credential.eqCredential).neq(l.fields[1], r.fields[1]) || - (AssocMap.eqMap(V1Credential.eqCredential, eqInteger).neq( + eqMaybe(eqGovernanceActionId).eq(l.fields[0], r.fields[0]) && + eqList(V1Credential.eqCredential).eq(l.fields[1], r.fields[1]) && + AssocMap.eqMap(V1Credential.eqCredential, eqInteger).eq( l.fields[2], r.fields[2], ) && - eqRational.eq(l.fields[3], r.fields[3])) + eqRational.eq(l.fields[3], r.fields[3]) ); } else if (l.name === "NewConstitution" && r.name === "NewConstitution") { return ( - eqMaybe(eqGovernanceActionId).neq(l.fields[0], r.fields[0]) || - eqConstitution.neq(l.fields[1], r.fields[1]) + eqMaybe(eqGovernanceActionId).eq(l.fields[0], r.fields[0]) && + eqConstitution.eq(l.fields[1], r.fields[1]) ); } else return false; }, @@ -2866,6 +2866,10 @@ export const jsonTxInfo: Json = { ), tx_certs: jsonList(jsonTxCert).toJson(txInfo.txInfoTxCerts), valid_range: V1Time.jsonPOSIXTimeRange.toJson(txInfo.txInfoValidRange), + votes: AssocMap.jsonMap( + jsonVoter, + AssocMap.jsonMap(jsonGovernanceActionId, jsonVote), + ).toJson(txInfo.txInfoVotes), wdrl: AssocMap.jsonMap(V1Credential.jsonCredential, jsonInteger).toJson( txInfo.txInfoWdrl, ), @@ -2894,7 +2898,7 @@ export const jsonTxInfo: Json = { value, ); const txInfoTxCerts = caseFieldWithValue( - "tx_cert", + "tx_certs", jsonList(jsonTxCert).fromJson, value, ); @@ -2939,7 +2943,7 @@ export const jsonTxInfo: Json = { ); const txInfoProposalProcedures = caseFieldWithValue( - "protocol_procedure", + "proposal_procedures", jsonList(jsonProposalProcedure).fromJson, value, ); diff --git a/src/Tests/RatioInstances-test.ts b/src/Tests/RatioInstances-test.ts new file mode 100644 index 0000000..afa593e --- /dev/null +++ b/src/Tests/RatioInstances-test.ts @@ -0,0 +1,46 @@ +import * as LbRatio from "../Lib/Ratio.js"; + +import { describe, it } from "node:test"; +import * as TestUtils from "./TestUtils.js"; + +import fc from "fast-check"; + +export function fcRational(): fc.Arbitrary { + return fc.record({ + numerator: fc.bigInt(), + denominator: fc.bigInt().filter((n) => n !== 0n), + }); +} + +describe("Ratio tests", () => { + describe("Eq Rational tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcRational(), fcRational(), (l, r) => { + TestUtils.negationTest(LbRatio.eqRational, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json Rational tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcRational(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(LbRatio.jsonRational, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData Rational tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcRational(), (data) => { + TestUtils.isPlutusDataRoundTrip(LbRatio.isPlutusDataRational, data); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/CommitteeInstances-test.ts b/src/Tests/V3/CommitteeInstances-test.ts new file mode 100644 index 0000000..3d3ea19 --- /dev/null +++ b/src/Tests/V3/CommitteeInstances-test.ts @@ -0,0 +1,45 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcAssocMap } from "../AssocMap-test.js"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; +import { eqCredential } from "../../Lib/V1.js"; + +export function fcCommittee(): fc.Arbitrary { + return fc.record({ + committeeMembers: fcAssocMap(eqCredential, fcCredential(), fc.bigUint()), + committeeQuorum: fc.bigUint(), + }); +} + +describe("Eq Committee tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcCommittee(), fcCommittee(), (l, r) => { + TestUtils.negationTest(V3.eqCommittee, l, r); + }), + { examples: [] }, + ); + }); +}); +describe("Json Committee tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcCommittee(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonCommittee, data); + }), + { examples: [] }, + ); + }); +}); +describe("IsPlutusData Committee tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcCommittee(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataCommittee, data); + }), + { examples: [] }, + ); + }); +}); diff --git a/src/Tests/V3/ConstitutionInstances-test.ts b/src/Tests/V3/ConstitutionInstances-test.ts new file mode 100644 index 0000000..c29ae60 --- /dev/null +++ b/src/Tests/V3/ConstitutionInstances-test.ts @@ -0,0 +1,45 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcMaybe } from "../Prelude/MaybeInstances-test.js"; +import { fcScriptHash } from "../V1/ScriptHashInstances-test.js"; + +export function fcConstitution(): fc.Arbitrary { + return fc.record({ + constitutionScript: fcMaybe(fcScriptHash()), + }); +} + +describe("Constitution tests", () => { + describe("Eq Constitution tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcConstitution(), fcConstitution(), (l, r) => { + TestUtils.negationTest(V3.eqConstitution, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json Constitution tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcConstitution(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonConstitution, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData GovernanceActionId tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcConstitution(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataConstitution, data); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/DRepInstances-test.ts b/src/Tests/V3/DRepInstances-test.ts new file mode 100644 index 0000000..f6a6a62 --- /dev/null +++ b/src/Tests/V3/DRepInstances-test.ts @@ -0,0 +1,61 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; + +export function fcDRep(): fc.Arbitrary { + const { dRep } = fc.letrec((tie) => ({ + dRep: fc.oneof( + {}, + tie("DRep"), + tie("AlwaysAbstain"), + tie("AlwaysNoConfidence"), + ), + DRep: fc.record({ + name: fc.constant("DRep"), + fields: fcCredential(), + }), + AlwaysAbstain: fc.record({ + name: fc.constant("AlwaysAbstain"), + }), + AlwaysNoConfidence: fc.record({ + name: fc.constant("AlwaysNoConfidence"), + }), + })); + + return dRep as fc.Arbitrary; +} + +describe("DRep tests", () => { + describe("Eq DRep tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcDRep(), fcDRep(), (l, r) => { + TestUtils.negationTest(V3.eqDRep, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json Rational tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcDRep(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonDRep, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData DRep tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcDRep(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataDRep, data); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/DelegateeInstatnces-test.ts b/src/Tests/V3/DelegateeInstatnces-test.ts new file mode 100644 index 0000000..2e57a35 --- /dev/null +++ b/src/Tests/V3/DelegateeInstatnces-test.ts @@ -0,0 +1,59 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcPubKeyHash } from "../V1/PubKeyHashInstances-test.js"; +import { fcDRep } from "./DRepInstances-test.js"; + +export function fcDelegatee(): fc.Arbitrary { + const { delegatee } = fc.letrec((tie) => ({ + delegatee: fc.oneof({}, tie("Stake"), tie("Vote"), tie("StakeVote")), + Stake: fc.record({ + name: fc.constant("Stake"), + fields: fcPubKeyHash(), + }), + Vote: fc.record({ + name: fc.constant("Vote"), + fields: fcDRep(), + }), + StakeVote: fc.record({ + name: fc.constant("StakeVote"), + fields: fc.tuple(fcPubKeyHash(), fcDRep()), + }), + })); + + return delegatee as fc.Arbitrary; +} + +describe("Delegatee tests", () => { + describe("Eq Delegatee tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcDelegatee(), fcDelegatee(), (l, r) => { + TestUtils.negationTest(V3.eqDelegatee, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json Delegatee tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcDelegatee(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonDelegatee, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData Delegatee tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcDelegatee(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataDelegatee, data); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/GovernanceActionIdInstances-test.ts b/src/Tests/V3/GovernanceActionIdInstances-test.ts new file mode 100644 index 0000000..a688cf8 --- /dev/null +++ b/src/Tests/V3/GovernanceActionIdInstances-test.ts @@ -0,0 +1,48 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcTxId } from "../V1/TxIdInstances-test.js"; + +export function fcGovernanceActionId(): fc.Arbitrary { + return fc.record({ + gaidTxId: fcTxId(), + gaidGovActionIx: fc.bigUint(), + }); +} + +describe("GovernanceActionId tests", () => { + describe("Eq GovernanceActionId tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcGovernanceActionId(), fcGovernanceActionId(), (l, r) => { + TestUtils.negationTest(V3.eqGovernanceActionId, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json GovernanceActionId tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcGovernanceActionId(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonGovernanceActionId, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData GovernanceActionId tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcGovernanceActionId(), (data) => { + TestUtils.isPlutusDataRoundTrip( + V3.isPlutusDataGovernanceActionId, + data, + ); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/GovernanceActionInstances-test.ts b/src/Tests/V3/GovernanceActionInstances-test.ts new file mode 100644 index 0000000..a1bc67e --- /dev/null +++ b/src/Tests/V3/GovernanceActionInstances-test.ts @@ -0,0 +1,104 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcGovernanceActionId } from "./GovernanceActionIdInstances-test.js"; +import { fcMaybe } from "../Prelude/MaybeInstances-test.js"; +import { fcPlutusData } from "../PlutusDataInstances-test.js"; +import { fcScriptHash } from "../V1/ScriptHashInstances-test.js"; +import { fcProtocolVersion } from "./ProtocolInstances-test.js"; +import { fcAssocMap } from "../AssocMap-test.js"; +import { eqCredential } from "../../Lib/V1.js"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; +import { fcConstitution } from "./ConstitutionInstances-test.js"; +import { fcRational } from "../RatioInstances-test.js"; + +export function fcGovernanceAction(): fc.Arbitrary { + const { governanceAction } = fc.letrec((tie) => ({ + governanceAction: fc.oneof( + {}, + tie("ParameterChange"), + tie("HardForkInitiation"), + tie("TreasuryWithdrawal"), + tie("NoConfidence"), + tie("UpdateCommittee"), + tie("NewConstitution"), + tie("InfoAction"), + ), + ParameterChange: fc.record({ + name: fc.constant("ParameterChange"), + fields: fc.tuple( + fcMaybe(fcGovernanceActionId()), + fcPlutusData(), + fcMaybe(fcScriptHash()), + ), + }), + HardForkInitiation: fc.record({ + name: fc.constant("HardForkInitiation"), + fields: fc.tuple(fcMaybe(fcGovernanceActionId()), fcProtocolVersion()), + }), + TreasuryWithdrawal: fc.record({ + name: fc.constant("TreasuryWithdrawal"), + fields: fc.tuple( + fcAssocMap(eqCredential, fcCredential(), fc.bigInt()), + fcMaybe(fcScriptHash()), + ), + }), + NoConfidence: fc.record({ + name: fc.constant("NoConfidence"), + fields: fcMaybe(fcGovernanceActionId()), + }), + UpdateCommittee: fc.record({ + name: fc.constant("UpdateCommittee"), + fields: fc.tuple( + fcMaybe(fcGovernanceActionId()), + fc.array(fcCredential()), + fcAssocMap(eqCredential, fcCredential(), fc.bigUint()), + fcRational(), + ), + }), + NewConstitution: fc.record({ + name: fc.constant("NewConstitution"), + fields: fc.tuple(fcMaybe(fcGovernanceActionId()), fcConstitution()), + }), + InfoAction: fc.record({ name: fc.constant("InfoAction") }), + })); + + return governanceAction as fc.Arbitrary; +} + +describe("GovernanceAction tests", () => { + describe("Eq GovernanceAction tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcGovernanceAction(), fcGovernanceAction(), (l, r) => { + TestUtils.negationTest(V3.eqGovernanceAction, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json GovernanceAction tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcGovernanceAction(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonGovernanceAction, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData GovernanceAction tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcGovernanceAction(), (data) => { + TestUtils.isPlutusDataRoundTrip( + V3.isPlutusDataGovernanceAction, + data, + ); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/ProposalProcedureInstances-test.ts b/src/Tests/V3/ProposalProcedureInstances-test.ts new file mode 100644 index 0000000..ebbccb3 --- /dev/null +++ b/src/Tests/V3/ProposalProcedureInstances-test.ts @@ -0,0 +1,50 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; +import { fcGovernanceAction } from "./GovernanceActionInstances-test.js"; + +export function fcProposalProcedure(): fc.Arbitrary { + return fc.record({ + ppDeposit: fc.bigUint(), + ppReturnAddr: fcCredential(), + ppGovernanceAction: fcGovernanceAction(), + }); +} + +describe("ProposalProcedure tests", () => { + describe("Eq Delegatee tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcProposalProcedure(), fcProposalProcedure(), (l, r) => { + TestUtils.negationTest(V3.eqProposalProcedure, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json ProposalProcedure tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcProposalProcedure(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonProposalProcedure, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData ProposalProcedure tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcProposalProcedure(), (data) => { + TestUtils.isPlutusDataRoundTrip( + V3.isPlutusDataProposalProcedure, + data, + ); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/ProtocolInstances-test.ts b/src/Tests/V3/ProtocolInstances-test.ts new file mode 100644 index 0000000..4cd0c04 --- /dev/null +++ b/src/Tests/V3/ProtocolInstances-test.ts @@ -0,0 +1,41 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; + +export function fcProtocolVersion(): fc.Arbitrary { + return fc.record({ pvMajor: fc.bigInt(), pvMinor: fc.bigInt() }); +} + +describe("ProtocolVersion tests", () => { + describe("Eq Constitution tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcProtocolVersion(), fcProtocolVersion(), (l, r) => { + TestUtils.negationTest(V3.eqProtocolVersion, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json ProtocolVersion tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcProtocolVersion(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonProtocolVersion, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData ProtocolVersion tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcProtocolVersion(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataProtocolVersion, data); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/ScriptContextInstances-test.ts b/src/Tests/V3/ScriptContextInstances-test.ts new file mode 100644 index 0000000..205d500 --- /dev/null +++ b/src/Tests/V3/ScriptContextInstances-test.ts @@ -0,0 +1,45 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcTxInfo } from "./TxInfoInstances-test.js"; +import { fcRedeemer } from "../V1/RedeemerInstances-test.js"; +import { fcScriptInfo } from "./ScriptInfoInstances-test.js"; + +export function fcScriptContext(): fc.Arbitrary { + return fc.record({ + scriptContextTxInfo: fcTxInfo(), + scriptContextRedeemer: fcRedeemer(), + scriptContextScriptInfo: fcScriptInfo(), + }); +} + +describe("ScriptContext tests", () => { + describe("Eq ScriptContext tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcScriptContext(), fcScriptContext(), (l, r) => { + TestUtils.negationTest(V3.eqScriptContext, l, r); + }), + ); + }); + }); + describe("Json ScriptContext tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcScriptContext(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonScriptContext, data); + }), + ); + }); + }); + describe("IsPlutusData ScriptContext tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcScriptContext(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataScriptContext, data); + }), + ); + }); + }); +}); diff --git a/src/Tests/V3/ScriptInfoInstances-test.ts b/src/Tests/V3/ScriptInfoInstances-test.ts new file mode 100644 index 0000000..7ee86c4 --- /dev/null +++ b/src/Tests/V3/ScriptInfoInstances-test.ts @@ -0,0 +1,82 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcCurrencySymbol } from "../V1/ValueInstances-test.js"; +import { fcTxOutRef } from "../V1/TxOutRefInstances-test.js"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; +import { fcVoter } from "./VoterInstatnces-test.js"; +import { fcMaybe } from "../Prelude/MaybeInstances-test.js"; +import { fcDatum } from "../V1/DatumInstances-test.js"; +import { fcProposalProcedure } from "./ProposalProcedureInstances-test.js"; +import { fcTxCert } from "./TxCertInstances-test.js"; + +export function fcScriptInfo(): fc.Arbitrary { + const { scriptPurpose } = fc.letrec((tie) => ({ + scriptPurpose: fc.oneof( + {}, + tie("Minting"), + tie("Spending"), + tie("Rewarding"), + tie("Certifying"), + tie("Voting"), + tie("Proposing"), + ), + Minting: fc.record({ + name: fc.constant("Minting"), + fields: fcCurrencySymbol(), + }), + Spending: fc.record({ + name: fc.constant("Spending"), + fields: fc.tuple(fcTxOutRef(), fcMaybe(fcDatum())), + }), + Rewarding: fc.record({ + name: fc.constant("Rewarding"), + fields: fcCredential(), + }), + Certifying: fc.record({ + name: fc.constant("Certifying"), + fields: fc.tuple(fc.bigUint(), fcTxCert()), + }), + Voting: fc.record({ + name: fc.constant("Voting"), + fields: fcVoter(), + }), + Proposing: fc.record({ + name: fc.constant("Proposing"), + fields: fc.tuple(fc.bigUint(), fcProposalProcedure()), + }), + })); + + return scriptPurpose as fc.Arbitrary; +} + +describe("ScriptInfo tests", () => { + describe("Eq ScriptInfo tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcScriptInfo(), fcScriptInfo(), (l, r) => { + TestUtils.negationTest(V3.eqScriptInfo, l, r); + }), + ); + }); + }); + describe("Json ScriptInfo tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcScriptInfo(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonScriptInfo, data); + }), + ); + }); + }); + describe("IsPlutusData ScriptInfo tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcScriptInfo(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataScriptInfo, data); + }), + ); + }); + }); +}); diff --git a/src/Tests/V3/ScriptPpurposeInstances-test.ts b/src/Tests/V3/ScriptPpurposeInstances-test.ts new file mode 100644 index 0000000..1f75ffa --- /dev/null +++ b/src/Tests/V3/ScriptPpurposeInstances-test.ts @@ -0,0 +1,80 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcCurrencySymbol } from "../V1/ValueInstances-test.js"; +import { fcTxOutRef } from "../V1/TxOutRefInstances-test.js"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; +import { fcVoter } from "./VoterInstatnces-test.js"; +import { fcProposalProcedure } from "./ProposalProcedureInstances-test.js"; +import { fcTxCert } from "./TxCertInstances-test.js"; + +export function fcScriptPurpose(): fc.Arbitrary { + const { scriptPurpose } = fc.letrec((tie) => ({ + scriptPurpose: fc.oneof( + {}, + tie("Minting"), + tie("Spending"), + tie("Rewarding"), + tie("Certifying"), + tie("Voting"), + tie("Proposing"), + ), + Minting: fc.record({ + name: fc.constant("Minting"), + fields: fcCurrencySymbol(), + }), + Spending: fc.record({ + name: fc.constant("Spending"), + fields: fcTxOutRef(), + }), + Rewarding: fc.record({ + name: fc.constant("Rewarding"), + fields: fcCredential(), + }), + Certifying: fc.record({ + name: fc.constant("Certifying"), + fields: fc.tuple(fc.bigUint(), fcTxCert()), + }), + Voting: fc.record({ + name: fc.constant("Voting"), + fields: fcVoter(), + }), + Proposing: fc.record({ + name: fc.constant("Proposing"), + fields: fc.tuple(fc.bigUint(), fcProposalProcedure()), + }), + })); + + return scriptPurpose as fc.Arbitrary; +} + +describe("ScriptPurpose tests", () => { + describe("Eq ScriptPurpose tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcScriptPurpose(), fcScriptPurpose(), (l, r) => { + TestUtils.negationTest(V3.eqScriptPurpose, l, r); + }), + ); + }); + }); + describe("Json ScriptPurpose tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcScriptPurpose(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonScriptPurpose, data); + }), + ); + }); + }); + describe("IsPlutusData ScriptPurpose tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcScriptPurpose(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataScriptPurpose, data); + }), + ); + }); + }); +}); diff --git a/src/Tests/V3/TxCertInstances-test.ts b/src/Tests/V3/TxCertInstances-test.ts new file mode 100644 index 0000000..6f7f5a6 --- /dev/null +++ b/src/Tests/V3/TxCertInstances-test.ts @@ -0,0 +1,101 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcPubKeyHash } from "../V1/PubKeyHashInstances-test.js"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; +import { fcMaybe } from "../Prelude/MaybeInstances-test.js"; +import { fcDelegatee } from "./DelegateeInstatnces-test.js"; + +export function fcTxCert(): fc.Arbitrary { + const { txCert } = fc.letrec((tie) => ({ + txCert: fc.oneof( + {}, + tie("RegStaking"), + tie("UnRegStaking"), + tie("DelegStaking"), + tie("RegDRep"), + tie("UpdateDRep"), + tie("UnRegDRep"), + tie("PoolRegister"), + tie("PoolRetire"), + tie("AuthHotCommittee"), + tie("ResignColdCommittee"), + ), + RegStaking: fc.record({ + name: fc.constant("RegStaking"), + fields: fc.tuple(fcCredential(), fcMaybe(fc.bigUint())), + }), + UnRegStaking: fc.record({ + name: fc.constant("UnRegStaking"), + fields: fc.tuple(fcCredential(), fcMaybe(fc.bigUint())), + }), + DelegStaking: fc.record({ + name: fc.constant("DelegStaking"), + fields: fc.tuple(fcCredential(), fcDelegatee()), + }), + RegDRep: fc.record({ + name: fc.constant("RegDRep"), + fields: fc.tuple(fcCredential(), fcDelegatee(), fc.bigInt()), + }), + UpdateDRep: fc.record({ + name: fc.constant("UpdateDRep"), + fields: fcCredential(), + }), + UnRegDRep: fc.record({ + name: fc.constant("UnRegDRep"), + fields: fc.tuple(fcCredential(), fc.bigInt()), + }), + PoolRegister: fc.record({ + name: fc.constant("PoolRegister"), + fields: fc.tuple(fcPubKeyHash(), fcPubKeyHash()), + }), + PoolRetire: fc.record({ + name: fc.constant("PoolRetire"), + fields: fc.tuple(fcPubKeyHash(), fc.bigInt()), + }), + AuthHotCommittee: fc.record({ + name: fc.constant("AuthHotCommittee"), + fields: fc.tuple(fcCredential(), fcCredential()), + }), + ResignColdCommittee: fc.record({ + name: fc.constant("ResignColdCommittee"), + fields: fcCredential(), + }), + })); + + return txCert as fc.Arbitrary; +} + +describe("TxCert tests", () => { + describe("Eq TxCert tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcTxCert(), fcTxCert(), (l, r) => { + TestUtils.negationTest(V3.eqTxCert, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json TxCert tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcTxCert(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonTxCert, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData TxCert tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcTxCert(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataTxCert, data); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/TxInfoInstances-test.ts b/src/Tests/V3/TxInfoInstances-test.ts new file mode 100644 index 0000000..a824dd8 --- /dev/null +++ b/src/Tests/V3/TxInfoInstances-test.ts @@ -0,0 +1,83 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcValue } from "../V1/ValueInstances-test.js"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; +import { fcVoter } from "./VoterInstatnces-test.js"; +import { fcProposalProcedure } from "./ProposalProcedureInstances-test.js"; +import { fcTxCert } from "./TxCertInstances-test.js"; +import { fcTxInInfo } from "../V2/TxInInfoInstances-test.js"; +import { fcTxOut } from "../V2/TxOutInstances-test.js"; +import { fcAssocMap } from "../AssocMap-test.js"; +import { eqCredential } from "../../Lib/V1/Credential.js"; +import { fcInterval } from "../V1/IntervalInstances-test.js"; +import { fcPubKeyHash } from "../V1/PubKeyHashInstances-test.js"; +import { fcScriptPurpose } from "./ScriptPpurposeInstances-test.js"; +import { fcRedeemer } from "../V1/RedeemerInstances-test.js"; +import { eqDatumHash } from "../../Lib/V1/Scripts.js"; +import { fcDatumHash } from "../V1/DatumHashInstances-test.js"; +import { fcDatum } from "../V1/DatumInstances-test.js"; +import { fcTxId } from "../V1/TxIdInstances-test.js"; +import { fcGovernanceActionId } from "./GovernanceActionIdInstances-test.js"; +import { fcVote } from "./VoteInstances-test.js"; +import { fcMaybe } from "../Prelude/MaybeInstances-test.js"; + +export function fcTxInfo(): fc.Arbitrary { + return fc.record({ + txInfoInputs: fc.array(fcTxInInfo()), + txInfoReferenceInputs: fc.array(fcTxInInfo()), + txInfoOutputs: fc.array(fcTxOut()), + txInfoFee: fc.bigUint(), + txInfoMint: fcValue(), + txInfoTxCerts: fc.array(fcTxCert()), + txInfoWdrl: fcAssocMap(eqCredential, fcCredential(), fc.bigInt()), + txInfoValidRange: fcInterval(fc.bigInt()), + txInfoSignatories: fc.array(fcPubKeyHash()), + txInfoRedeemers: fcAssocMap( + V3.eqScriptPurpose, + fcScriptPurpose(), + fcRedeemer(), + ), + txInfoData: fcAssocMap(eqDatumHash, fcDatumHash(), fcDatum()), + txInfoId: fcTxId(), + txInfoVotes: fcAssocMap( + V3.eqVoter, + fcVoter(), + fcAssocMap(V3.eqGovernanceActionId, fcGovernanceActionId(), fcVote()), + ), + txInfoProposalProcedures: fc.array(fcProposalProcedure()), + txInfoCurrentTreasuryAmount: fcMaybe(fc.bigUint()), + txInfoTreasuryDonation: fcMaybe(fc.bigUint()), + }); +} + +describe("TxInfo tests", () => { + describe("Eq TxInfo tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcTxInfo(), fcTxInfo(), (l, r) => { + TestUtils.negationTest(V3.eqTxInfo, l, r); + }), + ); + }); + }); + describe("Json TxInfo tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcTxInfo(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonTxInfo, data); + }), + ); + }); + }); + describe("IsPlutusData TxInfo tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcTxInfo(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataTxInfo, data); + }), + ); + }); + }); +}); diff --git a/src/Tests/V3/VoteInstances-test.ts b/src/Tests/V3/VoteInstances-test.ts new file mode 100644 index 0000000..ea7a96a --- /dev/null +++ b/src/Tests/V3/VoteInstances-test.ts @@ -0,0 +1,51 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; + +export function fcVote(): fc.Arbitrary { + return fc.oneof( + fc.record({ + name: fc.constant("VoteNo"), + }), + fc.record({ + name: fc.constant("VoteYes"), + }), + fc.record({ + name: fc.constant("Abstain"), + }), + ) as fc.Arbitrary; +} + +describe("Vote tests", () => { + describe("Eq Vote tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcVote(), fcVote(), (l, r) => { + TestUtils.negationTest(V3.eqVote, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json Vote tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcVote(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonVote, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData Vote tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcVote(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataVote, data); + }), + { examples: [] }, + ); + }); + }); +}); diff --git a/src/Tests/V3/VoterInstatnces-test.ts b/src/Tests/V3/VoterInstatnces-test.ts new file mode 100644 index 0000000..095d513 --- /dev/null +++ b/src/Tests/V3/VoterInstatnces-test.ts @@ -0,0 +1,64 @@ +import * as V3 from "../../Lib/V3.js"; +import { describe, it } from "node:test"; +import * as TestUtils from "../TestUtils.js"; +import fc from "fast-check"; +import { fcPubKeyHash } from "../V1/PubKeyHashInstances-test.js"; +import { fcCredential } from "../V1/CredentialInstances-test.js"; + +export function fcVoter(): fc.Arbitrary { + const { voter } = fc.letrec((tie) => ({ + voter: fc.oneof( + {}, + tie("CommitteeVoter"), + tie("DRepVoter"), + tie("DRepVoter"), + ), + CommitteeVoter: fc.record({ + name: fc.constant("CommitteeVoter"), + fields: fcCredential(), + }), + DRepVoter: fc.record({ + name: fc.constant("DRepVoter"), + fields: fcCredential(), + }), + StakePoolVoter: fc.record({ + name: fc.constant("DRepVoter"), + fields: fcPubKeyHash(), + }), + })); + + return voter as fc.Arbitrary; +} + +describe("Voter tests", () => { + describe("Eq Voter tests", () => { + it(`eq is not neq property based tests`, () => { + fc.assert( + fc.property(fcVoter(), fcVoter(), (l, r) => { + TestUtils.negationTest(V3.eqVoter, l, r); + }), + { examples: [] }, + ); + }); + }); + describe("Json Voter tests", () => { + it(`toJson/fromJson property based tests`, () => { + fc.assert( + fc.property(fcVoter(), (data) => { + TestUtils.toJsonFromJsonRoundTrip(V3.jsonVoter, data); + }), + { examples: [] }, + ); + }); + }); + describe("IsPlutusData Voter tests", () => { + it(`toData/fromData property based tests`, () => { + fc.assert( + fc.property(fcVoter(), (data) => { + TestUtils.isPlutusDataRoundTrip(V3.isPlutusDataVoter, data); + }), + { examples: [] }, + ); + }); + }); +});