From 2c7fa7e3461ca9ca40e631a028b02fe32beecdd6 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Mon, 23 Jun 2025 14:07:44 +0800 Subject: [PATCH 01/19] added: spec --- .../aiken-crowdfund/README.md | 1 + .../aiken-crowdfund/aiken.lock | 26 +++++ .../aiken-crowdfund/aiken.toml | 23 ++++ .../aiken-crowdfund/plutus.json | 101 ++++++++++++++++++ .../aiken-crowdfund/specs/1_auth_token.md | 15 +++ .../aiken-crowdfund/specs/2_shares.md | 15 +++ .../aiken-crowdfund/specs/3_crowdfund.md | 50 +++++++++ .../aiken-crowdfund/specs/_scripts.md | 24 +++++ .../aiken-crowdfund/validators/placeholder.ak | 41 +++++++ .../workflows/continuous-integration.yml | 18 ++++ .../gov-crowdfund/.gitignore | 6 ++ .../gov-crowdfund/README.md | 1 + .../gov-crowdfund/aiken.toml | 18 ++++ .../gov-crowdfund/specs/1_spend.md | 69 ++++++++++++ .../gov-crowdfund/specs/2_stake.md | 15 +++ .../gov-crowdfund/specs/3_start.md | 25 +++++ .../gov-crowdfund/specs/_scripts.md | 24 +++++ .../gov-crowdfund/validators/placeholder.ak | 41 +++++++ 18 files changed, 513 insertions(+) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/README.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.lock create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.toml create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/1_auth_token.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/2_shares.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.github/workflows/continuous-integration.yml create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.gitignore create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/README.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/README.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/README.md new file mode 100644 index 000000000..e76d22490 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/README.md @@ -0,0 +1 @@ +Implement in core mesh repo `mesh-contract` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.lock b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.lock new file mode 100644 index 000000000..2e65bd164 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.lock @@ -0,0 +1,26 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +[[requirements]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +source = "github" + +[[requirements]] +name = "sidan-lab/vodka" +version = "0.1.13" +source = "github" + +[[packages]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +requirements = [] +source = "github" + +[[packages]] +name = "sidan-lab/vodka" +version = "0.1.13" +requirements = [] +source = "github" + +[etags] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.toml new file mode 100644 index 000000000..62cb1af77 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.toml @@ -0,0 +1,23 @@ +name = "sidan-lab/crowdfund" +version = "0.0.0" +compiler = "v1.1.16" +plutus = "v3" +license = "Apache-2.0" +description = "Aiken contracts for project 'sidan-lab/crowdfund'" + +[repository] +user = "sidan-lab" +project = "crowdfund" +platform = "github" + +[[dependencies]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +source = "github" + +[[dependencies]] +name = "sidan-lab/vodka" +version = "0.1.13" +source = "github" + +[config] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json new file mode 100644 index 000000000..67ed61785 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json @@ -0,0 +1,101 @@ +{ + "preamble": { + "title": "sidan-lab/crowdfund", + "description": "Aiken contracts for project 'sidan-lab/crowdfund'", + "version": "0.0.0", + "plutusVersion": "v3", + "compiler": { + "name": "Aiken", + "version": "v1.1.16+23061c0" + }, + "license": "Apache-2.0" + }, + "validators": [ + { + "title": "placeholder.placeholder.mint", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", + "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + }, + { + "title": "placeholder.placeholder.spend", + "datum": { + "title": "_datum", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", + "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + }, + { + "title": "placeholder.placeholder.withdraw", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", + "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + }, + { + "title": "placeholder.placeholder.publish", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", + "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + }, + { + "title": "placeholder.placeholder.vote", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", + "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + }, + { + "title": "placeholder.placeholder.propose", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", + "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + }, + { + "title": "placeholder.placeholder.else", + "redeemer": { + "schema": {} + }, + "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", + "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + } + ], + "definitions": { + "Data": { + "title": "Data", + "description": "Any Plutus data." + } + } +} \ No newline at end of file diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/1_auth_token.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/1_auth_token.md new file mode 100644 index 000000000..86a689cd0 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/1_auth_token.md @@ -0,0 +1,15 @@ +# Auth Token - One Shot + +## Parameter + +- `utxo_ref`: UTxO to be spent at minting + +## User Action + +1. Mint - Redeemer `RMint` + + - Transaction hash as parameterized is included in input + +2. Burn - Redeemer `RBurn` + + - The current policy id only has negative minting value in transaction body. diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/2_shares.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/2_shares.md new file mode 100644 index 000000000..4492912d7 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/2_shares.md @@ -0,0 +1,15 @@ +# Share Token + +## Parameter + +- `auth_token`: The policy id of `AuthToken` + +## User Action + +1. Mint - Redeemer `RMint` + + - There is input with `auth_token` with redeemer `ContributeFund` + +2. Burn - Redeemer `RBurn` + + - The current policy id only has negative minting value in transaction body. diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md new file mode 100644 index 000000000..df78c76fe --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md @@ -0,0 +1,50 @@ +# Specification - Crowdfund + +## Parameter + +- `auth_token`: The policy id of `AuthToken` + +## Datum + +- `completion_script`: ByteArray +- `share_token`: ByteArray +- `crowdfund_address`: Address +- `fundraise_target`: Int +- `current_fundraised_amount`: Int +- `allow_over_subscription`: Bool +- `deadline`: Int +- `expiry_buffer`: Int +- `fee_address`: Address +- `min_charge`: Int + +## User Action + +1. ContributeFund + + - There is only 1 input with `auth_token` from current address, and 1 output with `auth_token` and to current_address + - Not allowed other token deposit in output. Min contribution 2 ADA + - The value increase in current respending utxo equal to the increase in `current_fundraised_amount`, comparing input output datum + - If `allow_over_scription` is False, check whether `current_fundraised_amount` <= `fundraise_target` + - `deadline` is not passed + - `Shares` - Minted exactly the amount of `share_token` that lovelave contributed, with token name of `completion_script` + +2. CompleteCrowdfund + + - Any value in the current utxos - (`current_fundraised_amount` + `min_charge`) goes to `fee_address` + - `current_fundraised_amount` >= `fundraise_target` + - `completion_script` withdrawal script is exeuted + - `auth_token` from current input is burnt + +3. ContributorWithdrawal + + - Either one of below conditions + - `deadline` + `expiry_buffer` is passed + - `current_fundraised_amount` <= `fundraise_target` + - There is only 1 input with `auth_token` from current address, and 1 output with `auth_token` and to current_address + - The lovelace unlocking from `crowdfund_address` equal exactly the amount that the `share_token` with token name of `completion_script` is burnt + +4. RemoveEmptyInstance + + - `deadline` is passed + - share token with token name `completion_script` burning in current tx == `current_fundraised_amount` + - `auth_token` from current input is burnt diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md new file mode 100644 index 000000000..21e4621a5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md @@ -0,0 +1,24 @@ +# Aiken Crowdfunding + +## 1. Auth Token + +The token that represent distinct crowdfunding campaign, attaching with distinct `completion_script` + +## 2. Shares + +The token that represents lovelace contributed to current crowdfunding campaign + +## 3. Crowdfund + +The validator that handles the crowdfunding campaign + +## Param dependency tree + +1. First layer + + - `auth_token` - no param + +2. Second layer + + - `shares` - param `auth_token` + - `crowdfund` - param `auth_token` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak new file mode 100644 index 000000000..bbf9d47d4 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak @@ -0,0 +1,41 @@ +use cardano/address.{Credential} +use cardano/assets.{PolicyId} +use cardano/certificate.{Certificate} +use cardano/governance.{ProposalProcedure, Voter} +use cardano/transaction.{Transaction, OutputReference} + +validator placeholder { + mint(_redeemer: Data, _policy_id: PolicyId, _self: Transaction) { + todo @"mint logic goes here" + } + + spend(_datum: Option, _redeemer: Data, _utxo: OutputReference, _self: Transaction) { + todo @"spend logic goes here" + } + + withdraw(_redeemer: Data, _account: Credential, _self: Transaction) { + todo @"withdraw logic goes here" + } + + publish(_redeemer: Data, _certificate: Certificate, _self: Transaction) { + todo @"publish logic goes here" + } + + vote(_redeemer: Data, _voter: Voter, _self: Transaction) { + todo @"vote logic goes here" + } + + propose(_redeemer: Data, _proposal: ProposalProcedure, _self: Transaction) { + todo @"propose logic goes here" + } + + // // If needs be, remove any of unneeded handlers above, and use: + // + // else(_ctx: ScriptContext) { + // todo @"fallback logic if none of the other purposes match" + // } + // + // // You will also need an additional import: + // // + // // use cardano/script_context.{ScriptContext} +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.github/workflows/continuous-integration.yml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.github/workflows/continuous-integration.yml new file mode 100644 index 000000000..ba419b4a2 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.github/workflows/continuous-integration.yml @@ -0,0 +1,18 @@ +name: Continuous Integration + +on: + push: + branches: ["main"] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: aiken-lang/setup-aiken@v1 + with: + version: v1.1.16 + - run: aiken fmt --check + - run: aiken check -D + - run: aiken build diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.gitignore b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.gitignore new file mode 100644 index 000000000..ff7811b15 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.gitignore @@ -0,0 +1,6 @@ +# Aiken compilation artifacts +artifacts/ +# Aiken's project working directory +build/ +# Aiken's default documentation export +docs/ diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/README.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/README.md new file mode 100644 index 000000000..de5ef005b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/README.md @@ -0,0 +1 @@ +Implement separately & publish SDK diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml new file mode 100644 index 000000000..fba837145 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml @@ -0,0 +1,18 @@ +name = "sidan-lab/gov-crowdfund" +version = "0.0.0" +compiler = "v1.1.16" +plutus = "v3" +license = "Apache-2.0" +description = "Aiken contracts for project 'sidan-lab/gov-crowdfund'" + +[repository] +user = "sidan-lab" +project = "gov-crowdfund" +platform = "github" + +[[dependencies]] +name = "aiken-lang/stdlib" +version = "1.5.0" +source = "github" + +[config] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md new file mode 100644 index 000000000..e403685c1 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md @@ -0,0 +1,69 @@ +# Specification - Spend + +## Parameter + +- `delegate_pool_id`: ByteArray +- `gov_action`: GovernanceAction +- `proposer_key_hash`: ByteArray + +## Datum + +```rs +pub type Datum { + Init { + completion_script: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + Proposed { + completion_script: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + Refundable { + completion_script: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } +} +``` + +## User Action + +1. RegisterCerts + + - Only one input and output from current address + - Input datum in state of `Init` + - Output datum in state of `Proposed` + - fields exactly the same + - Registering stake cert + - Registering DRep cert + - Delegate to current own DRep + stake pool `delegate_pool_id` + - Propose gov action + - Vote on same proposal? -> if cant, create one more separate state + +2. DeregisterCerts + + - deadline is passed + - Only one input and output from current address + - Input datum in state of `Proposed` + - Output datum in state of `Refundable` + - fields exactly the same + - Deregistering both certs + - Refunds go into the output + +3. ContributorWithdrawal + + - Input datum in state of Refundable + - `deadline` is passed + - The lovelace unlocking from current equal exactly the amount that the `share_token` with token name of `completion_script` is burnt + +4. RemoveEmptyInstance + + - Input datum in state of Refundable + - `deadline` is passed + - share token with token name `completion_script` burning in current tx == `current_fundraised_amount` + - signed by `proposer_key_hash` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md new file mode 100644 index 000000000..a6b11130c --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md @@ -0,0 +1,15 @@ +# Specification - Stake + +## Parameter + +- `spend_script_hash`: The script hash of the spending part + +## User Action + +1. Register + + - Only 1 input from `spend_script_hash` with redeemer of `RegisterCerts` + +2. Deregister + + - Only 1 input from `spend_script_hash` with redeemer of `DeregisterCerts` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md new file mode 100644 index 000000000..b07a65114 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md @@ -0,0 +1,25 @@ +# Specification - Start + +## Parameter + +- `auth_token`: The policy ID of crowdfunding token +- `spend`: The script hash of the spending part of the gov system +- `stake`: The script hash of the staking part of the gov system +- `gov_action_period`: The buffer since crowdfund deadline to complete entire gov process + +## User Action + +1. Validate completion of crowdfunding + + - Only one input with `auth_token`, with inline datum + `completion_script` same as current crendential hash + - All `fundraise_target` amount of ADA is sent to address composed of `spend` and `stake` (both script hash) + - With datum: + + ```rs + Init { + completion_script: , + share_token: , + funds_controlled: , + deadline: , + } + ``` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md new file mode 100644 index 000000000..cb2f26cb4 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md @@ -0,0 +1,24 @@ +# Aiken Gov Crowdfunding + +## 1. Spend + +The spending validator that guarding the crowdfunded + +## 2. Stake + +The token that represents lovelace contributed to current crowdfunding campaign + +## 3. Start + +The withdrawal script that oversight the completion of crowdfunding (i.e. `completion_script` at crowdfunding script) + +## Param dependency tree + +1. First layer + + - `spend` - no param + - `stake` - no param + +2. Second layer + + - `start` - param `spend` and `stake` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak new file mode 100644 index 000000000..bbf9d47d4 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak @@ -0,0 +1,41 @@ +use cardano/address.{Credential} +use cardano/assets.{PolicyId} +use cardano/certificate.{Certificate} +use cardano/governance.{ProposalProcedure, Voter} +use cardano/transaction.{Transaction, OutputReference} + +validator placeholder { + mint(_redeemer: Data, _policy_id: PolicyId, _self: Transaction) { + todo @"mint logic goes here" + } + + spend(_datum: Option, _redeemer: Data, _utxo: OutputReference, _self: Transaction) { + todo @"spend logic goes here" + } + + withdraw(_redeemer: Data, _account: Credential, _self: Transaction) { + todo @"withdraw logic goes here" + } + + publish(_redeemer: Data, _certificate: Certificate, _self: Transaction) { + todo @"publish logic goes here" + } + + vote(_redeemer: Data, _voter: Voter, _self: Transaction) { + todo @"vote logic goes here" + } + + propose(_redeemer: Data, _proposal: ProposalProcedure, _self: Transaction) { + todo @"propose logic goes here" + } + + // // If needs be, remove any of unneeded handlers above, and use: + // + // else(_ctx: ScriptContext) { + // todo @"fallback logic if none of the other purposes match" + // } + // + // // You will also need an additional import: + // // + // // use cardano/script_context.{ScriptContext} +} From b3c7f36558deea19bcb1a2115319bc462ae4b346 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Mon, 23 Jun 2025 14:38:17 +0800 Subject: [PATCH 02/19] added: auth token --- .../aiken-crowdfund/lib/types.ak | 4 ++ .../aiken-crowdfund/specs/_scripts.md | 2 +- .../validators/auth_token/mint.ak | 27 ++++++++ .../aiken-crowdfund/validators/placeholder.ak | 41 ------------ .../validators/tests/auth_token/mint.ak | 63 +++++++++++++++++++ .../aiken-crowdfund/validators/tests/utils.ak | 3 + 6 files changed, 98 insertions(+), 42 deletions(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/auth_token/mint.ak delete mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak new file mode 100644 index 000000000..a23a4479f --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak @@ -0,0 +1,4 @@ +pub type MintPolarity { + RMint + RBurn +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md index 21e4621a5..72da5bb9a 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md @@ -16,7 +16,7 @@ The validator that handles the crowdfunding campaign 1. First layer - - `auth_token` - no param + - `auth_token` - `utxo_ref` 2. Second layer diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/auth_token/mint.ak new file mode 100644 index 000000000..57706664d --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/auth_token/mint.ak @@ -0,0 +1,27 @@ +use aiken/collection/dict +use aiken/collection/list +use cardano/assets.{PolicyId} +use cardano/transaction.{OutputReference, Transaction} +use types.{MintPolarity, RBurn, RMint} + +validator auth_token(utxo_ref: OutputReference) { + mint(redeemer: MintPolarity, policy_id: PolicyId, self: Transaction) { + expect [Pair(_asset_name, quantity)] = + self.mint + |> assets.tokens(policy_id) + |> dict.to_pairs() + let Transaction { inputs, .. } = self + when redeemer is { + RMint -> { + let is_output_consumed = + list.any(inputs, fn(input) { input.output_reference == utxo_ref }) + is_output_consumed? && quantity == 1 + } + RBurn -> quantity == -1 + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak deleted file mode 100644 index bbf9d47d4..000000000 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/placeholder.ak +++ /dev/null @@ -1,41 +0,0 @@ -use cardano/address.{Credential} -use cardano/assets.{PolicyId} -use cardano/certificate.{Certificate} -use cardano/governance.{ProposalProcedure, Voter} -use cardano/transaction.{Transaction, OutputReference} - -validator placeholder { - mint(_redeemer: Data, _policy_id: PolicyId, _self: Transaction) { - todo @"mint logic goes here" - } - - spend(_datum: Option, _redeemer: Data, _utxo: OutputReference, _self: Transaction) { - todo @"spend logic goes here" - } - - withdraw(_redeemer: Data, _account: Credential, _self: Transaction) { - todo @"withdraw logic goes here" - } - - publish(_redeemer: Data, _certificate: Certificate, _self: Transaction) { - todo @"publish logic goes here" - } - - vote(_redeemer: Data, _voter: Voter, _self: Transaction) { - todo @"vote logic goes here" - } - - propose(_redeemer: Data, _proposal: ProposalProcedure, _self: Transaction) { - todo @"propose logic goes here" - } - - // // If needs be, remove any of unneeded handlers above, and use: - // - // else(_ctx: ScriptContext) { - // todo @"fallback logic if none of the other purposes match" - // } - // - // // You will also need an additional import: - // // - // // use cardano/script_context.{ScriptContext} -} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak new file mode 100644 index 000000000..47de07ed7 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak @@ -0,0 +1,63 @@ +use auth_token/mint as auth_token_mint +use cardano/assets.{add, from_asset, zero} +use cardano/transaction.{Transaction, placeholder} +use mocktail.{ + complete, mint, mock_policy_id, mock_pub_key_address, mock_tx_hash, + mock_utxo_ref, mocktail_tx, tx_in, +} +use tests/utils.{mock_auth_token} +use types.{RBurn, RMint} + +test s0_mint_success_mint() { + let redeemer = RMint + let input_utxo = mock_utxo_ref(0, 1) + let policy_id = mock_auth_token + + let tx = + mocktail_tx() + |> mint(True, 1, policy_id, "") + |> tx_in(True, mock_tx_hash(0), 1, zero, mock_pub_key_address(0, None)) + |> complete() + + auth_token_mint.auth_token.mint(input_utxo, redeemer, policy_id, tx) +} + +test s0_mint_fail_mint_no_utxo_ref_supply() { + let redeemer = RMint + let policy_id = mock_auth_token + + let tx = + mocktail_tx() + |> mint(True, 1, policy_id, "") + |> tx_in(True, mock_tx_hash(0), 1, zero, mock_pub_key_address(0, None)) + |> complete() + !auth_token_mint.auth_token.mint(mock_utxo_ref(0, 0), redeemer, policy_id, tx) +} + +test s0_mint_success_burn() { + let redeemer = RBurn + let policy_id = mock_auth_token + + let tx = Transaction { ..placeholder, mint: from_asset(policy_id, "", -1) } + auth_token_mint.auth_token.mint(mock_utxo_ref(0, 0), redeemer, policy_id, tx) +} + +test s0_mint_success_burn_with_other_minting() { + let redeemer = RBurn + let policy_id = mock_auth_token + + let tx = + Transaction { + ..placeholder, + mint: from_asset(policy_id, "", -1) |> add(mock_policy_id(999), "", 1), + } + auth_token_mint.auth_token.mint(mock_utxo_ref(0, 0), redeemer, policy_id, tx) +} + +test s0_mint_fail_burn_with_mint() { + let redeemer = RBurn + let policy_id = mock_auth_token + + let tx = Transaction { ..placeholder, mint: from_asset(policy_id, "", 1) } + !auth_token_mint.auth_token.mint(mock_utxo_ref(0, 0), redeemer, policy_id, tx) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak new file mode 100644 index 000000000..c81269154 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak @@ -0,0 +1,3 @@ +use mocktail.{mock_policy_id} + +pub const mock_auth_token = mock_policy_id(0) From eace8eec7c39d4c0d8106704a3941bf25d538cf2 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Mon, 23 Jun 2025 16:08:41 +0800 Subject: [PATCH 03/19] added: share token --- .../aiken-crowdfund/lib/types.ak | 7 ++ .../aiken-crowdfund/lib/utils.ak | 10 ++ .../validators/share_token/mint.ak | 35 +++++++ .../validators/tests/share_token/mint.ak | 93 +++++++++++++++++++ .../aiken-crowdfund/validators/tests/utils.ak | 13 ++- 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/share_token/mint.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak index a23a4479f..a2bb650b8 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak @@ -2,3 +2,10 @@ pub type MintPolarity { RMint RBurn } + +pub type CrowdfundRedeemer { + ContributeFund + CompleteCrowdfund + ContributorWithdrawal + RemoveEmptyInstance +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak new file mode 100644 index 000000000..ab263997e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak @@ -0,0 +1,10 @@ +use aiken/collection/pairs +use cardano/transaction.{Input, Redeemer, ScriptPurpose, Spend} + +pub fn redeemer_with_input( + redeemers: Pairs, + input: Input, +) -> Option { + let output_reference = input.output_reference + redeemers |> pairs.get_first(Spend(output_reference)) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/share_token/mint.ak new file mode 100644 index 000000000..01bad7385 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/share_token/mint.ak @@ -0,0 +1,35 @@ +use aiken/collection/dict +use cardano/assets.{PolicyId} +use cardano/transaction.{Transaction} +use cocktail.{inputs_with_policy} +use types.{ContributeFund, CrowdfundRedeemer, MintPolarity, RBurn, RMint} +use utils.{redeemer_with_input} + +validator share_token(auth_token: PolicyId) { + mint(redeemer: MintPolarity, policy_id: PolicyId, self: Transaction) { + expect [Pair(_asset_name, quantity)] = + self.mint + |> assets.tokens(policy_id) + |> dict.to_pairs() + let Transaction { inputs, redeemers, .. } = self + when redeemer is { + RMint -> { + expect [auth_token_input] = inputs_with_policy(inputs, auth_token) + + expect Some(auth_token_redeemer_data) = + redeemer_with_input(redeemers, auth_token_input) + + expect auth_token_redeemer: CrowdfundRedeemer = auth_token_redeemer_data + + let redeemer_check = auth_token_redeemer == ContributeFund + + redeemer_check? + } + RBurn -> quantity == -1 + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak new file mode 100644 index 000000000..e623afb0a --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak @@ -0,0 +1,93 @@ +use cardano/assets.{add, from_asset, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction, placeholder} +use mocktail.{ + add_redeemer, complete, mint, mock_policy_id, mock_tx_hash, mocktail_tx, tx_in, +} +use share_token/mint as share_token_mint +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_share_token, +} +use types.{ContributeFund, RBurn, RMint} + +test s1_mint_success_mint() { + let redeemer = RMint + let auth_input = + from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) + + let policy_id = mock_share_token + + let auth_token_redeemer: Data = ContributeFund + let tx = + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, auth_input, mock_crowdfund_address) + |> mint(True, 1, policy_id, mock_completion_script) + |> complete() + |> add_redeemer( + True, + Pair( + Spend( + OutputReference { + transaction_id: mock_tx_hash(0), + output_index: 0, + }, + ), + auth_token_redeemer, + ), + ) + + share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) +} + +test s1_mint_fail_mint_no_auth_token_input() fail { + let redeemer = RMint + let policy_id = mock_share_token + + let tx = + mocktail_tx() + |> mint(True, 1, policy_id, mock_completion_script) + |> complete() + share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) +} + +test s1_mint_fail_mint_no_auth_token_redeemer() fail { + let redeemer = RMint + let auth_input = + from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) + let policy_id = mock_share_token + + let tx = + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, auth_input, mock_crowdfund_address) + |> mint(True, 1, policy_id, mock_completion_script) + |> complete() + share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) +} + +test s1_mint_success_burn() { + let redeemer = RBurn + let policy_id = mock_share_token + + let tx = Transaction { ..placeholder, mint: from_asset(policy_id, "", -1) } + share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) +} + +test s1_mint_success_burn_with_other_minting() { + let redeemer = RBurn + let policy_id = mock_share_token + + let tx = + Transaction { + ..placeholder, + mint: from_asset(policy_id, "", -1) |> add(mock_policy_id(999), "", 1), + } + share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) +} + +test s1_mint_fail_burn_with_mint() { + let redeemer = RBurn + let policy_id = mock_share_token + + let tx = Transaction { ..placeholder, mint: from_asset(policy_id, "", 1) } + !share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak index c81269154..2ed469108 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak @@ -1,3 +1,14 @@ -use mocktail.{mock_policy_id} +use cardano/address.{from_script} +use mocktail.{mock_policy_id, mock_script_hash, mock_script_stake_key_hash} pub const mock_auth_token = mock_policy_id(0) + +pub const mock_share_token = mock_policy_id(1) + +pub const mock_completion_script = mock_script_hash(0) + +pub const mock_crowdfund_spend_script_hash = mock_script_hash(1) + +pub const mock_crowdfund_stake_script_hash = mock_script_stake_key_hash(0) + +pub const mock_crowdfund_address = from_script(mock_crowdfund_spend_script_hash) From 1af92993ca6e17c2b3bac835a27486a9b886921a Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Mon, 23 Jun 2025 18:21:10 +0800 Subject: [PATCH 04/19] added: crowdfund script todo: crowdfund test case added : crowdfund test --- .../aiken-crowdfund/lib/types.ak | 15 + .../aiken-crowdfund/lib/utils.ak | 31 +- .../validators/crowdfund/spend.ak | 182 +++ .../validators/tests/crowdfund/spend.ak | 1139 +++++++++++++++++ .../aiken-crowdfund/validators/tests/utils.ak | 45 + 5 files changed, 1411 insertions(+), 1 deletion(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak index a2bb650b8..0232fc7aa 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak @@ -1,3 +1,5 @@ +use cardano/address.{Address} + pub type MintPolarity { RMint RBurn @@ -9,3 +11,16 @@ pub type CrowdfundRedeemer { ContributorWithdrawal RemoveEmptyInstance } + +pub type CrowdfundDatum { + completion_script: ByteArray, + share_token: ByteArray, + crowdfund_address: Address, + fundraise_target: Int, + current_fundraised_amount: Int, + allow_over_subscription: Bool, + deadline: Int, + expiry_buffer: Int, + fee_address: Address, + min_charge: Int, +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak index ab263997e..9216d4927 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak @@ -1,5 +1,8 @@ +use aiken/collection/list use aiken/collection/pairs -use cardano/transaction.{Input, Redeemer, ScriptPurpose, Spend} +use cardano/address.{Address} +use cardano/assets.{Value} +use cardano/transaction.{Input, Output, Redeemer, ScriptPurpose, Spend} pub fn redeemer_with_input( redeemers: Pairs, @@ -8,3 +11,29 @@ pub fn redeemer_with_input( let output_reference = input.output_reference redeemers |> pairs.get_first(Spend(output_reference)) } + +pub fn check_fundraise_target( + allow_over_subscription: Bool, + fundraise_target: Int, + current_fundraised_amount: Int, +) -> Bool { + if allow_over_subscription { + True + } else { + current_fundraised_amount <= fundraise_target + } +} + +pub fn output_at_with_value( + outputs: List, + address: Address, + value: Value, +) -> List { + list.filter( + outputs, + fn(output) { + let are_values_equal = output.value == value + are_values_equal && output.address == address + }, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak new file mode 100644 index 000000000..827b8cf86 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak @@ -0,0 +1,182 @@ +use aiken/collection/list.{delete} +use aiken/collection/pairs.{has_key} +use cardano/address.{Credential, Script} +use cardano/assets.{ + PolicyId, from_lovelace, lovelace_of, merge, policies, restricted_to, +} +use cardano/transaction.{OutputReference, Transaction, find_input} +use cocktail.{ + inputs_at_with_policy, only_minted_token, output_inline_datum, + outputs_at_with_policy, policy_only_minted_token, valid_after, valid_before, + value_length, +} +use types.{ + CompleteCrowdfund, ContributeFund, ContributorWithdrawal, CrowdfundDatum, + CrowdfundRedeemer, RemoveEmptyInstance, +} +use utils.{check_fundraise_target, output_at_with_value} + +validator crowdfund(auth_token: PolicyId) { + spend( + datum_opt: Option, + redeemer: CrowdfundRedeemer, + input: OutputReference, + self: Transaction, + ) { + let Transaction { inputs, validity_range, mint, outputs, withdrawals, .. } = + self + + expect Some(own_input) = find_input(inputs, input) + expect Some(auth_input_datum) = datum_opt + + let current_address = own_input.output.address + + // check only 1 auth toke input from current address + expect [auth_input] = + inputs_at_with_policy(inputs, current_address, auth_token) + + let CrowdfundDatum { + current_fundraised_amount, + fundraise_target, + allow_over_subscription, + deadline, + completion_script, + share_token, + min_charge, + fee_address, + expiry_buffer, + .. + } = auth_input_datum + when redeemer is { + ContributeFund -> { + expect [auth_output] = + outputs_at_with_policy(outputs, current_address, auth_token) + + let lovelace_from_auth_input = auth_input.output.value |> lovelace_of() + let lovelace_from_auth_output = auth_output.value |> lovelace_of() + expect auth_output_datum: CrowdfundDatum = + output_inline_datum(auth_output) + + let fundraise_added = + lovelace_from_auth_output - lovelace_from_auth_input + let fundraise_check = + (fundraise_added == auth_output_datum.current_fundraised_amount - current_fundraised_amount)? && (fundraise_added >= 2000000)? + + let fundraise_target_check = + check_fundraise_target( + allow_over_subscription, + fundraise_target, + auth_output_datum.current_fundraised_amount, + ) + + let validity_check = valid_before(validity_range, deadline) + + let output_datum_check = + auth_output_datum == CrowdfundDatum { + ..auth_input_datum, + current_fundraised_amount: current_fundraised_amount + fundraise_added, + } + + let is_auth_output_value_clean = value_length(auth_output.value) == 2 + fundraise_check? && fundraise_target_check? && validity_check? && output_datum_check? && is_auth_output_value_clean? && only_minted_token( + mint, + share_token, + completion_script, + fundraise_added, + )? + } + + CompleteCrowdfund -> { + let fee_value = + from_lovelace( + lovelace_of(auth_input.output.value) - current_fundraised_amount - min_charge, + ) + + let other_policy = + policies(auth_input.output.value) + |> delete(auth_token) + |> delete("") + let other_value = restricted_to(auth_input.output.value, other_policy) + + expect [_] = + output_at_with_value( + outputs, + fee_address, + merge(other_value, fee_value), + ) + + let fundraise_check = current_fundraised_amount >= fundraise_target + let completion_script_withdrawal_credential: Credential = + Script(completion_script) + let withdrawal_script_check = + withdrawals + |> has_key(completion_script_withdrawal_credential) + fundraise_check? && withdrawal_script_check? && only_minted_token( + mint, + auth_token, + completion_script, + -1, + )? + } + + ContributorWithdrawal -> { + let validity_check = + valid_after(validity_range, deadline + expiry_buffer) + let fund_check = current_fundraised_amount <= fundraise_target + + expect [auth_output] = + outputs_at_with_policy(outputs, current_address, auth_token) + + let lovelace_from_auth_input = auth_input.output.value |> lovelace_of() + let lovelace_from_auth_output = auth_output.value |> lovelace_of() + + let lovelace_withdrawn = + lovelace_from_auth_output - lovelace_from_auth_input + + let lovelace_withdrawn_check = lovelace_withdrawn < 0 + + expect auth_output_datum: CrowdfundDatum = + output_inline_datum(auth_output) + let output_datum_check = + auth_output_datum == CrowdfundDatum { + ..auth_input_datum, + current_fundraised_amount: current_fundraised_amount + lovelace_withdrawn, + } + + let is_auth_output_value_clean = value_length(auth_output.value) == 2 + (validity_check || fund_check)? && lovelace_withdrawn_check? && output_datum_check? && is_auth_output_value_clean? && only_minted_token( + mint, + share_token, + completion_script, + lovelace_withdrawn, + )? + } + + RemoveEmptyInstance -> { + let validity_check = valid_after(validity_range, deadline) + + let token_burnt_check = + if current_fundraised_amount > 0 { + policy_only_minted_token( + mint, + share_token, + completion_script, + -current_fundraised_amount, + )? && policy_only_minted_token( + mint, + auth_token, + completion_script, + -1, + )? + } else { + only_minted_token(mint, auth_token, completion_script, -1)? + } + validity_check? && token_burnt_check? + } + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak new file mode 100644 index 000000000..d1f3d7577 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak @@ -0,0 +1,1139 @@ +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{Transaction} +use crowdfund/spend as crowdfund_spend +use mocktail.{ + complete, invalid_before, invalid_hereafter, mint, mock_policy_id, + mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, + script_withdrawal, tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, +} +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_contribute_min_fundraised_amount, + mock_contribute_over_fundraised_amount, mock_crowdfund_address, + mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, + mock_expiry_buffer, mock_extra_fundraised_amount, mock_fee_address, + mock_fundraise_target, mock_min_charge, mock_share_token, +} +use types.{ + CompleteCrowdfund, ContributeFund, ContributorWithdrawal, RemoveEmptyInstance, +} + +type ContributeFundTestCase { + is_only_one_auth_inputed: Bool, + is_only_one_auth_outputed: Bool, + is_auth_output_datum_correct: Bool, + is_auth_output_value_clean: Bool, + is_deadline_not_passed: Bool, + is_shares_minted: Bool, +} + +fn mock_contribute_fund_tx( + test_case: ContributeFundTestCase, + current_fundraised_amount: Int, + contribute_amount: Int, + allow_over_subscription: Bool, +) -> Transaction { + let ContributeFundTestCase { + is_only_one_auth_inputed, + is_only_one_auth_outputed, + is_auth_output_datum_correct, + is_auth_output_value_clean, + is_deadline_not_passed, + is_shares_minted, + } = test_case + + let input_value = + from_lovelace(current_fundraised_amount) + |> add(mock_auth_token, mock_completion_script, 1) + + let output_value = + from_lovelace(current_fundraised_amount + contribute_amount) + |> add(mock_auth_token, mock_completion_script, 1) + + let auth_correct_output_datum = + mock_crowdfund_datum( + current_fundraised_amount + contribute_amount, + allow_over_subscription, + ) + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(current_fundraised_amount, allow_over_subscription), + ) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_crowdfund_address, + ) + |> tx_in( + True, + mock_tx_hash(1), + 0, + from_lovelace(contribute_amount), + mock_pub_key_address(0, None), + ) + |> tx_out(is_auth_output_value_clean, mock_crowdfund_address, output_value) + |> tx_out( + !is_auth_output_value_clean, + mock_crowdfund_address, + output_value |> add(mock_policy_id(999), mock_completion_script, 1), + ) + |> tx_out_inline_datum(is_auth_output_datum_correct, auth_correct_output_datum) + |> tx_out_inline_datum( + !is_auth_output_datum_correct, + mock_crowdfund_datum( + current_fundraised_amount + contribute_amount + 9999999, + allow_over_subscription, + ), + ) + |> tx_out(!is_only_one_auth_outputed, mock_crowdfund_address, output_value) + |> invalid_hereafter(is_deadline_not_passed, mock_deadline - 3600 * 24) + |> invalid_hereafter(!is_deadline_not_passed, mock_deadline + 3600 * 24) + |> mint( + is_shares_minted, + contribute_amount, + mock_share_token, + mock_completion_script, + ) + |> mint( + !is_shares_minted, + contribute_amount + 9999999, + mock_share_token, + mock_completion_script, + ) + |> complete() +} + +test s2_spend_success_contribute_fund_with_not_allow_over_subscription() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_success_contribute_fund_with_allow_over_subscription() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + True, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, True)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_success_contribute_fund_with_allow_over_subscription_and_over_fundraised() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_over_fundraised_amount, + True, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, True)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_not_allow_over_subscription_but_over_fundraised() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_over_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_over_current_fundraised() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_more_than_one_auth_inputed() fail { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: False, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_more_than_one_auth_outputed() fail { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: False, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_incorrect_auth_output_datum() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: False, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_auth_output_not_clean() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: False, + is_deadline_not_passed: True, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_deadline_passed() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: False, + is_shares_minted: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contribute_fund_with_wrong_shares_minted() { + let tx = + mock_contribute_fund_tx( + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: False, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +type CompleteCrowdfundTestCase { + is_only_one_auth_inputed: Bool, + is_output_to_fee_address_correct: Bool, + is_auth_burnt: Bool, + is_completion_script_executed: Bool, +} + +fn mock_complete_crowdfund_tx( + test_case: CompleteCrowdfundTestCase, + current_fundraised_amount: Int, + allow_over_subscription: Bool, +) -> Transaction { + let CompleteCrowdfundTestCase { + is_only_one_auth_inputed, + is_output_to_fee_address_correct, + is_auth_burnt, + is_completion_script_executed, + } = test_case + + let input_value = + from_lovelace( + current_fundraised_amount + mock_min_charge + mock_extra_fundraised_amount, + ) + |> add(mock_auth_token, mock_completion_script, 1) + |> add(mock_policy_id(999), mock_completion_script, 10) + + let output_value = + from_lovelace(mock_extra_fundraised_amount) + |> add(mock_policy_id(999), mock_completion_script, 10) + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(current_fundraised_amount, allow_over_subscription), + ) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_crowdfund_address, + ) + |> tx_out(is_output_to_fee_address_correct, mock_fee_address, output_value) + |> tx_out( + !is_output_to_fee_address_correct, + mock_fee_address, + from_lovelace(mock_extra_fundraised_amount - 10) + |> add(mock_policy_id(999), mock_completion_script, 10), + ) + |> script_withdrawal( + is_completion_script_executed, + mock_completion_script, + 2_000_000, + ) + |> mint(is_auth_burnt, -1, mock_auth_token, mock_completion_script) + |> complete() +} + +test s2_spend_success_complete_crowdfund_with_amount_equal_to_target() { + let tx = + mock_complete_crowdfund_tx( + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + }, + mock_fundraise_target, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_success_complete_crowdfund_with_amount_larger_than_target() { + let tx = + mock_complete_crowdfund_tx( + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + }, + mock_contribute_over_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_complete_crowdfund_with_amount_less_than_target() { + let tx = + mock_complete_crowdfund_tx( + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + }, + mock_fundraise_target - 1, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_fundraise_target - 1, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_complete_crowdfund_with_more_than_one_auth_inputed() fail { + let tx = + mock_complete_crowdfund_tx( + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: False, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + }, + mock_fundraise_target, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_complete_crowdfund_with_incorrect_fee_output() fail { + let tx = + mock_complete_crowdfund_tx( + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: False, + is_auth_burnt: True, + is_completion_script_executed: True, + }, + mock_fundraise_target, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_complete_crowdfund_with_no_auth_burnt() { + let tx = + mock_complete_crowdfund_tx( + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: False, + is_completion_script_executed: True, + }, + mock_fundraise_target, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_complete_crowdfund_with_no_completion_script_executed() { + let tx = + mock_complete_crowdfund_tx( + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: False, + }, + mock_fundraise_target, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +type ContributorWithdrawalTestCase { + is_only_one_auth_inputed: Bool, + is_only_one_auth_outputed: Bool, + is_auth_output_datum_correct: Bool, + is_auth_output_value_clean: Bool, + is_auth_unlock_value_correct: Bool, + is_deadline_passed: Bool, + is_shares_burnt: Bool, +} + +fn mock_contributor_withdrawal_tx( + test_case: ContributorWithdrawalTestCase, + current_fundraised_amount: Int, + withdraw_amount: Int, + allow_over_subscription: Bool, +) -> Transaction { + let ContributorWithdrawalTestCase { + is_only_one_auth_inputed, + is_only_one_auth_outputed, + is_auth_output_datum_correct, + is_auth_output_value_clean, + is_auth_unlock_value_correct, + is_deadline_passed, + is_shares_burnt, + } = test_case + + let input_value = + from_lovelace(current_fundraised_amount) + |> add(mock_auth_token, mock_completion_script, 1) + + let output_value = + if is_auth_unlock_value_correct { + from_lovelace(current_fundraised_amount - withdraw_amount) + |> add(mock_auth_token, mock_completion_script, 1) + } else { + from_lovelace(current_fundraised_amount - withdraw_amount + 10) + |> add(mock_auth_token, mock_completion_script, 1) + } + + let auth_correct_output_datum = + mock_crowdfund_datum( + current_fundraised_amount - withdraw_amount, + allow_over_subscription, + ) + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(current_fundraised_amount, allow_over_subscription), + ) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_crowdfund_address, + ) + |> tx_out(True, mock_pub_key_address(0, None), from_lovelace(withdraw_amount)) + |> tx_out(is_auth_output_value_clean, mock_crowdfund_address, output_value) + |> tx_out( + !is_auth_output_value_clean, + mock_crowdfund_address, + output_value |> add(mock_policy_id(999), mock_completion_script, 1), + ) + |> tx_out_inline_datum(is_auth_output_datum_correct, auth_correct_output_datum) + |> tx_out_inline_datum( + !is_auth_output_datum_correct, + mock_crowdfund_datum( + current_fundraised_amount - withdraw_amount + 9999999, + allow_over_subscription, + ), + ) + |> tx_out(!is_only_one_auth_outputed, mock_crowdfund_address, output_value) + |> invalid_before( + is_deadline_passed, + mock_deadline + mock_expiry_buffer + 3600 * 24, + ) + |> invalid_before( + !is_deadline_passed, + mock_deadline + mock_expiry_buffer - 3600 * 24, + ) + |> mint( + is_shares_burnt, + -withdraw_amount, + mock_share_token, + mock_completion_script, + ) + |> mint( + !is_shares_burnt, + -withdraw_amount + 9999999, + mock_share_token, + mock_completion_script, + ) + |> complete() +} + +test s2_spend_success_contributor_withdraw_with_deadline_passed_but_fundraised_reach_target() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_success_contributor_withdraw_with_deadline_passed_and_fundraised_less_than_target() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount * 2, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount * 2, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_success_contributor_withdraw_with_deadline_not_passed_but_fundraised_less_than_target() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: False, + is_shares_burnt: True, + }, + mock_current_fundraised_amount * 2, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount * 2, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contributor_withdraw_with_deadline_not_passed_and_fundraised_reached_target() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: False, + is_shares_burnt: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contributor_withdraw_with_more_thanone_auth_inputed() fail { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: False, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contributor_withdraw_with_more_thanone_auth_outputed() fail { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: False, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contributor_withdraw_with_incorrect_output_datum() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: False, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: False, + is_auth_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: False, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_auth_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: False, + }, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +type RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed: Bool, + is_deadline_passed: Bool, + is_shares_burnt: Bool, + is_auth_burnt: Bool, +} + +fn mock_remove_empty_instance_tx( + test_case: RemoveEmptyInstanceTestCase, + current_fundraised_amount: Int, + allow_over_subscription: Bool, +) -> Transaction { + let RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed, + is_deadline_passed, + is_shares_burnt, + is_auth_burnt, + } = test_case + + let input_value = + from_lovelace(current_fundraised_amount) + |> add(mock_auth_token, mock_completion_script, 1) + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(current_fundraised_amount, allow_over_subscription), + ) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_crowdfund_address, + ) + |> invalid_before(is_deadline_passed, mock_deadline + 3600 * 24) + |> invalid_before(!is_deadline_passed, mock_deadline - 3600 * 24) + |> mint( + is_shares_burnt, + -current_fundraised_amount, + mock_share_token, + mock_completion_script, + ) + |> mint( + !is_shares_burnt, + -current_fundraised_amount + 9999999, + mock_share_token, + mock_completion_script, + ) + |> mint(is_auth_burnt, -1, mock_auth_token, mock_completion_script) + |> complete() +} + +test s2_spend_success_remove_empty_instance_wih_zero_fund() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_auth_burnt: True, + }, + 0, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(0, False)), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_success_remove_empty_instance_wih_some_fund() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_auth_burnt: True, + }, + mock_current_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed: False, + is_deadline_passed: True, + is_shares_burnt: True, + is_auth_burnt: True, + }, + mock_current_fundraised_amount, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_remove_empty_instance_wih_deadline_not_passed() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed: True, + is_deadline_passed: False, + is_shares_burnt: True, + is_auth_burnt: True, + }, + mock_current_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_remove_empty_instance_wih_share_not_burnt() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed: True, + is_deadline_passed: True, + is_shares_burnt: False, + is_auth_burnt: True, + }, + mock_current_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s2_spend_fail_remove_empty_instance_wih_authe_not_burnt() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_auth_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_auth_burnt: False, + }, + mock_current_fundraised_amount, + False, + ) + + !crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak index 2ed469108..a752a80c8 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak @@ -1,5 +1,6 @@ use cardano/address.{from_script} use mocktail.{mock_policy_id, mock_script_hash, mock_script_stake_key_hash} +use types.{CrowdfundDatum} pub const mock_auth_token = mock_policy_id(0) @@ -12,3 +13,47 @@ pub const mock_crowdfund_spend_script_hash = mock_script_hash(1) pub const mock_crowdfund_stake_script_hash = mock_script_stake_key_hash(0) pub const mock_crowdfund_address = from_script(mock_crowdfund_spend_script_hash) + +pub const mock_fee_address = from_script("fee_address") + +pub const mock_fundraise_target = 100000000000 + +pub const mock_deadline = 1750735607 + +pub const mock_expiry_buffer = 3600 * 24 + +pub const mock_min_charge = 0 + +pub fn mock_crowdfund_datum( + current_fundraised_amount: Int, + allow_over_subscription: Bool, +) { + CrowdfundDatum { + completion_script: mock_completion_script, + share_token: mock_share_token, + crowdfund_address: mock_crowdfund_address, + fundraise_target: mock_fundraise_target, + current_fundraised_amount, + allow_over_subscription, + deadline: mock_deadline, + expiry_buffer: mock_expiry_buffer, + fee_address: mock_fee_address, + min_charge: mock_min_charge, + } +} + +pub const mock_current_fundraised_amount = 2000000 + +pub const mock_extra_fundraised_amount = 4000000 + +pub const mock_contribute_less_than_min_fundraised_amount = 1999999 + +pub const mock_contribute_min_fundraised_amount = 2000000 + +pub const mock_contribute_over_fundraised_amount = 100000000001 + +pub const auth_allow_over_subscription = + mock_crowdfund_datum(mock_current_fundraised_amount, True) + +pub const auth_not_allow_over_subscription = + mock_crowdfund_datum(mock_current_fundraised_amount, False) From 608ce463668f315b09377b7e173acc6ea8c0ae59 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Wed, 25 Jun 2025 14:04:32 +0800 Subject: [PATCH 05/19] added: stake --- .../aiken-crowdfund/specs/3_crowdfund.md | 2 +- .../validators/tests/auth_token/mint.ak | 10 +- .../validators/tests/crowdfund/spend.ak | 68 ++++---- .../validators/tests/share_token/mint.ak | 12 +- .../gov-crowdfund/aiken.lock | 26 +++ .../gov-crowdfund/aiken.toml | 7 +- .../gov-crowdfund/lib/types.ak | 32 ++++ .../gov-crowdfund/lib/utils.ak | 10 ++ .../gov-crowdfund/specs/1_spend.md | 1 + .../gov-crowdfund/validators/placeholder.ak | 41 ----- .../gov-crowdfund/validators/spend.ak | 0 .../gov-crowdfund/validators/stake.ak | 36 +++++ .../gov-crowdfund/validators/start.ak | 0 .../gov-crowdfund/validators/tests/stake.ak | 151 ++++++++++++++++++ .../gov-crowdfund/validators/tests/utils.ak | 10 ++ 15 files changed, 318 insertions(+), 88 deletions(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.lock create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak delete mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md index df78c76fe..d63202f8e 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md @@ -32,7 +32,7 @@ - Any value in the current utxos - (`current_fundraised_amount` + `min_charge`) goes to `fee_address` - `current_fundraised_amount` >= `fundraise_target` - - `completion_script` withdrawal script is exeuted + - `completion_script` withdrawal script is executed - `auth_token` from current input is burnt 3. ContributorWithdrawal diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak index 47de07ed7..b113dd1c5 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak @@ -8,7 +8,7 @@ use mocktail.{ use tests/utils.{mock_auth_token} use types.{RBurn, RMint} -test s0_mint_success_mint() { +test s1_mint_success_mint() { let redeemer = RMint let input_utxo = mock_utxo_ref(0, 1) let policy_id = mock_auth_token @@ -22,7 +22,7 @@ test s0_mint_success_mint() { auth_token_mint.auth_token.mint(input_utxo, redeemer, policy_id, tx) } -test s0_mint_fail_mint_no_utxo_ref_supply() { +test s1_mint_fail_mint_no_utxo_ref_supply() { let redeemer = RMint let policy_id = mock_auth_token @@ -34,7 +34,7 @@ test s0_mint_fail_mint_no_utxo_ref_supply() { !auth_token_mint.auth_token.mint(mock_utxo_ref(0, 0), redeemer, policy_id, tx) } -test s0_mint_success_burn() { +test s1_mint_success_burn() { let redeemer = RBurn let policy_id = mock_auth_token @@ -42,7 +42,7 @@ test s0_mint_success_burn() { auth_token_mint.auth_token.mint(mock_utxo_ref(0, 0), redeemer, policy_id, tx) } -test s0_mint_success_burn_with_other_minting() { +test s1_mint_success_burn_with_other_minting() { let redeemer = RBurn let policy_id = mock_auth_token @@ -54,7 +54,7 @@ test s0_mint_success_burn_with_other_minting() { auth_token_mint.auth_token.mint(mock_utxo_ref(0, 0), redeemer, policy_id, tx) } -test s0_mint_fail_burn_with_mint() { +test s1_mint_fail_burn_with_mint() { let redeemer = RBurn let policy_id = mock_auth_token diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak index d1f3d7577..30acf36bc 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak @@ -107,7 +107,7 @@ fn mock_contribute_fund_tx( |> complete() } -test s2_spend_success_contribute_fund_with_not_allow_over_subscription() { +test s3_spend_success_contribute_fund_with_not_allow_over_subscription() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -132,7 +132,7 @@ test s2_spend_success_contribute_fund_with_not_allow_over_subscription() { ) } -test s2_spend_success_contribute_fund_with_allow_over_subscription() { +test s3_spend_success_contribute_fund_with_allow_over_subscription() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -157,7 +157,7 @@ test s2_spend_success_contribute_fund_with_allow_over_subscription() { ) } -test s2_spend_success_contribute_fund_with_allow_over_subscription_and_over_fundraised() { +test s3_spend_success_contribute_fund_with_allow_over_subscription_and_over_fundraised() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -182,7 +182,7 @@ test s2_spend_success_contribute_fund_with_allow_over_subscription_and_over_fund ) } -test s2_spend_fail_contribute_fund_with_not_allow_over_subscription_but_over_fundraised() { +test s3_spend_fail_contribute_fund_with_not_allow_over_subscription_but_over_fundraised() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -207,7 +207,7 @@ test s2_spend_fail_contribute_fund_with_not_allow_over_subscription_but_over_fun ) } -test s2_spend_fail_contribute_fund_with_over_current_fundraised() { +test s3_spend_fail_contribute_fund_with_over_current_fundraised() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -232,7 +232,7 @@ test s2_spend_fail_contribute_fund_with_over_current_fundraised() { ) } -test s2_spend_fail_contribute_fund_with_more_than_one_auth_inputed() fail { +test s3_spend_fail_contribute_fund_with_more_than_one_auth_inputed() fail { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -257,7 +257,7 @@ test s2_spend_fail_contribute_fund_with_more_than_one_auth_inputed() fail { ) } -test s2_spend_fail_contribute_fund_with_more_than_one_auth_outputed() fail { +test s3_spend_fail_contribute_fund_with_more_than_one_auth_outputed() fail { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -282,7 +282,7 @@ test s2_spend_fail_contribute_fund_with_more_than_one_auth_outputed() fail { ) } -test s2_spend_fail_contribute_fund_with_incorrect_auth_output_datum() { +test s3_spend_fail_contribute_fund_with_incorrect_auth_output_datum() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -307,7 +307,7 @@ test s2_spend_fail_contribute_fund_with_incorrect_auth_output_datum() { ) } -test s2_spend_fail_contribute_fund_with_auth_output_not_clean() { +test s3_spend_fail_contribute_fund_with_auth_output_not_clean() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -332,7 +332,7 @@ test s2_spend_fail_contribute_fund_with_auth_output_not_clean() { ) } -test s2_spend_fail_contribute_fund_with_deadline_passed() { +test s3_spend_fail_contribute_fund_with_deadline_passed() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -357,7 +357,7 @@ test s2_spend_fail_contribute_fund_with_deadline_passed() { ) } -test s2_spend_fail_contribute_fund_with_wrong_shares_minted() { +test s3_spend_fail_contribute_fund_with_wrong_shares_minted() { let tx = mock_contribute_fund_tx( ContributeFundTestCase { @@ -441,7 +441,7 @@ fn mock_complete_crowdfund_tx( |> complete() } -test s2_spend_success_complete_crowdfund_with_amount_equal_to_target() { +test s3_spend_success_complete_crowdfund_with_amount_equal_to_target() { let tx = mock_complete_crowdfund_tx( CompleteCrowdfundTestCase { @@ -463,7 +463,7 @@ test s2_spend_success_complete_crowdfund_with_amount_equal_to_target() { ) } -test s2_spend_success_complete_crowdfund_with_amount_larger_than_target() { +test s3_spend_success_complete_crowdfund_with_amount_larger_than_target() { let tx = mock_complete_crowdfund_tx( CompleteCrowdfundTestCase { @@ -485,7 +485,7 @@ test s2_spend_success_complete_crowdfund_with_amount_larger_than_target() { ) } -test s2_spend_fail_complete_crowdfund_with_amount_less_than_target() { +test s3_spend_fail_complete_crowdfund_with_amount_less_than_target() { let tx = mock_complete_crowdfund_tx( CompleteCrowdfundTestCase { @@ -507,7 +507,7 @@ test s2_spend_fail_complete_crowdfund_with_amount_less_than_target() { ) } -test s2_spend_fail_complete_crowdfund_with_more_than_one_auth_inputed() fail { +test s3_spend_fail_complete_crowdfund_with_more_than_one_auth_inputed() fail { let tx = mock_complete_crowdfund_tx( CompleteCrowdfundTestCase { @@ -529,7 +529,7 @@ test s2_spend_fail_complete_crowdfund_with_more_than_one_auth_inputed() fail { ) } -test s2_spend_fail_complete_crowdfund_with_incorrect_fee_output() fail { +test s3_spend_fail_complete_crowdfund_with_incorrect_fee_output() fail { let tx = mock_complete_crowdfund_tx( CompleteCrowdfundTestCase { @@ -551,7 +551,7 @@ test s2_spend_fail_complete_crowdfund_with_incorrect_fee_output() fail { ) } -test s2_spend_fail_complete_crowdfund_with_no_auth_burnt() { +test s3_spend_fail_complete_crowdfund_with_no_auth_burnt() { let tx = mock_complete_crowdfund_tx( CompleteCrowdfundTestCase { @@ -573,7 +573,7 @@ test s2_spend_fail_complete_crowdfund_with_no_auth_burnt() { ) } -test s2_spend_fail_complete_crowdfund_with_no_completion_script_executed() { +test s3_spend_fail_complete_crowdfund_with_no_completion_script_executed() { let tx = mock_complete_crowdfund_tx( CompleteCrowdfundTestCase { @@ -692,7 +692,7 @@ fn mock_contributor_withdrawal_tx( |> complete() } -test s2_spend_success_contributor_withdraw_with_deadline_passed_but_fundraised_reach_target() { +test s3_spend_success_contributor_withdraw_with_deadline_passed_but_fundraised_reach_target() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -718,7 +718,7 @@ test s2_spend_success_contributor_withdraw_with_deadline_passed_but_fundraised_r ) } -test s2_spend_success_contributor_withdraw_with_deadline_passed_and_fundraised_less_than_target() { +test s3_spend_success_contributor_withdraw_with_deadline_passed_and_fundraised_less_than_target() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -744,7 +744,7 @@ test s2_spend_success_contributor_withdraw_with_deadline_passed_and_fundraised_l ) } -test s2_spend_success_contributor_withdraw_with_deadline_not_passed_but_fundraised_less_than_target() { +test s3_spend_success_contributor_withdraw_with_deadline_not_passed_but_fundraised_less_than_target() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -770,7 +770,7 @@ test s2_spend_success_contributor_withdraw_with_deadline_not_passed_but_fundrais ) } -test s2_spend_fail_contributor_withdraw_with_deadline_not_passed_and_fundraised_reached_target() { +test s3_spend_fail_contributor_withdraw_with_deadline_not_passed_and_fundraised_reached_target() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -796,7 +796,7 @@ test s2_spend_fail_contributor_withdraw_with_deadline_not_passed_and_fundraised_ ) } -test s2_spend_fail_contributor_withdraw_with_more_thanone_auth_inputed() fail { +test s3_spend_fail_contributor_withdraw_with_more_thanone_auth_inputed() fail { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -822,7 +822,7 @@ test s2_spend_fail_contributor_withdraw_with_more_thanone_auth_inputed() fail { ) } -test s2_spend_fail_contributor_withdraw_with_more_thanone_auth_outputed() fail { +test s3_spend_fail_contributor_withdraw_with_more_thanone_auth_outputed() fail { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -848,7 +848,7 @@ test s2_spend_fail_contributor_withdraw_with_more_thanone_auth_outputed() fail { ) } -test s2_spend_fail_contributor_withdraw_with_incorrect_output_datum() { +test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -874,7 +874,7 @@ test s2_spend_fail_contributor_withdraw_with_incorrect_output_datum() { ) } -test s2_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { +test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -900,7 +900,7 @@ test s2_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { ) } -test s2_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { +test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -926,7 +926,7 @@ test s2_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { ) } -test s2_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { +test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1006,7 +1006,7 @@ fn mock_remove_empty_instance_tx( |> complete() } -test s2_spend_success_remove_empty_instance_wih_zero_fund() { +test s3_spend_success_remove_empty_instance_wih_zero_fund() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1028,7 +1028,7 @@ test s2_spend_success_remove_empty_instance_wih_zero_fund() { ) } -test s2_spend_success_remove_empty_instance_wih_some_fund() { +test s3_spend_success_remove_empty_instance_wih_some_fund() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1050,7 +1050,7 @@ test s2_spend_success_remove_empty_instance_wih_some_fund() { ) } -test s2_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { +test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1072,7 +1072,7 @@ test s2_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { ) } -test s2_spend_fail_remove_empty_instance_wih_deadline_not_passed() { +test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1094,7 +1094,7 @@ test s2_spend_fail_remove_empty_instance_wih_deadline_not_passed() { ) } -test s2_spend_fail_remove_empty_instance_wih_share_not_burnt() { +test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1116,7 +1116,7 @@ test s2_spend_fail_remove_empty_instance_wih_share_not_burnt() { ) } -test s2_spend_fail_remove_empty_instance_wih_authe_not_burnt() { +test s3_spend_fail_remove_empty_instance_wih_authe_not_burnt() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak index e623afb0a..6ad5a815e 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak @@ -10,7 +10,7 @@ use tests/utils.{ } use types.{ContributeFund, RBurn, RMint} -test s1_mint_success_mint() { +test s2_mint_success_mint() { let redeemer = RMint let auth_input = from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) @@ -39,7 +39,7 @@ test s1_mint_success_mint() { share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) } -test s1_mint_fail_mint_no_auth_token_input() fail { +test s2_mint_fail_mint_no_auth_token_input() fail { let redeemer = RMint let policy_id = mock_share_token @@ -50,7 +50,7 @@ test s1_mint_fail_mint_no_auth_token_input() fail { share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) } -test s1_mint_fail_mint_no_auth_token_redeemer() fail { +test s2_mint_fail_mint_no_auth_token_redeemer() fail { let redeemer = RMint let auth_input = from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) @@ -64,7 +64,7 @@ test s1_mint_fail_mint_no_auth_token_redeemer() fail { share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) } -test s1_mint_success_burn() { +test s2_mint_success_burn() { let redeemer = RBurn let policy_id = mock_share_token @@ -72,7 +72,7 @@ test s1_mint_success_burn() { share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) } -test s1_mint_success_burn_with_other_minting() { +test s2_mint_success_burn_with_other_minting() { let redeemer = RBurn let policy_id = mock_share_token @@ -84,7 +84,7 @@ test s1_mint_success_burn_with_other_minting() { share_token_mint.share_token.mint(mock_auth_token, redeemer, policy_id, tx) } -test s1_mint_fail_burn_with_mint() { +test s2_mint_fail_burn_with_mint() { let redeemer = RBurn let policy_id = mock_share_token diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.lock b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.lock new file mode 100644 index 000000000..2e65bd164 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.lock @@ -0,0 +1,26 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +[[requirements]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +source = "github" + +[[requirements]] +name = "sidan-lab/vodka" +version = "0.1.13" +source = "github" + +[[packages]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +requirements = [] +source = "github" + +[[packages]] +name = "sidan-lab/vodka" +version = "0.1.13" +requirements = [] +source = "github" + +[etags] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml index fba837145..bff202272 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml @@ -12,7 +12,12 @@ platform = "github" [[dependencies]] name = "aiken-lang/stdlib" -version = "1.5.0" +version = "v2.2.0" +source = "github" + +[[dependencies]] +name = "sidan-lab/vodka" +version = "0.1.13" source = "github" [config] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak new file mode 100644 index 000000000..04220021f --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak @@ -0,0 +1,32 @@ +pub type CrowdfundRedeemer { + RegisterCerts + DeregisterCerts + ContributorWithdrawal + RemoveEmptyInstance +} + +pub type CrowdfundDatum { + Init { + completion_script: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + Proposed { + completion_script: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + Refundable { + completion_script: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } +} + +pub type StakeRedeemer { + Register + Deregister +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak new file mode 100644 index 000000000..ab263997e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak @@ -0,0 +1,10 @@ +use aiken/collection/pairs +use cardano/transaction.{Input, Redeemer, ScriptPurpose, Spend} + +pub fn redeemer_with_input( + redeemers: Pairs, + input: Input, +) -> Option { + let output_reference = input.output_reference + redeemers |> pairs.get_first(Spend(output_reference)) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md index e403685c1..4ad76c581 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md @@ -44,6 +44,7 @@ pub type Datum { - Delegate to current own DRep + stake pool `delegate_pool_id` - Propose gov action - Vote on same proposal? -> if cant, create one more separate state + - todo: check 100k lock before retification correctly 2. DeregisterCerts diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak deleted file mode 100644 index bbf9d47d4..000000000 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/placeholder.ak +++ /dev/null @@ -1,41 +0,0 @@ -use cardano/address.{Credential} -use cardano/assets.{PolicyId} -use cardano/certificate.{Certificate} -use cardano/governance.{ProposalProcedure, Voter} -use cardano/transaction.{Transaction, OutputReference} - -validator placeholder { - mint(_redeemer: Data, _policy_id: PolicyId, _self: Transaction) { - todo @"mint logic goes here" - } - - spend(_datum: Option, _redeemer: Data, _utxo: OutputReference, _self: Transaction) { - todo @"spend logic goes here" - } - - withdraw(_redeemer: Data, _account: Credential, _self: Transaction) { - todo @"withdraw logic goes here" - } - - publish(_redeemer: Data, _certificate: Certificate, _self: Transaction) { - todo @"publish logic goes here" - } - - vote(_redeemer: Data, _voter: Voter, _self: Transaction) { - todo @"vote logic goes here" - } - - propose(_redeemer: Data, _proposal: ProposalProcedure, _self: Transaction) { - todo @"propose logic goes here" - } - - // // If needs be, remove any of unneeded handlers above, and use: - // - // else(_ctx: ScriptContext) { - // todo @"fallback logic if none of the other purposes match" - // } - // - // // You will also need an additional import: - // // - // // use cardano/script_context.{ScriptContext} -} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak new file mode 100644 index 000000000..e69de29bb diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak new file mode 100644 index 000000000..969dd4024 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak @@ -0,0 +1,36 @@ +use cardano/address.{from_script} +use cardano/script_context.{ScriptContext} +use cardano/transaction.{Transaction} +use cocktail.{inputs_at} +use types.{ + CrowdfundRedeemer, Deregister, DeregisterCerts, Register, RegisterCerts, + StakeRedeemer, +} +use utils.{redeemer_with_input} + +validator stake(spend_script_hash: ByteArray) { + else(ctx: ScriptContext) { + let ScriptContext { transaction, redeemer, .. } = ctx + expect stake_redeemer: StakeRedeemer = redeemer + let Transaction { inputs, redeemers, .. } = transaction + let spend_address = from_script(spend_script_hash) + expect [only_input] = inputs_at(inputs, spend_address) + expect Some(only_inpuy_redeemer_data) = + redeemer_with_input(redeemers, only_input) + + expect only_input_redeemer: CrowdfundRedeemer = only_inpuy_redeemer_data + + when stake_redeemer is { + Register -> { + let redeemer_check = only_input_redeemer == RegisterCerts + + redeemer_check? + } + Deregister -> { + let redeemer_check = only_input_redeemer == DeregisterCerts + + redeemer_check? + } + } + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak new file mode 100644 index 000000000..e69de29bb diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak new file mode 100644 index 000000000..5d5410a07 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak @@ -0,0 +1,151 @@ +use cardano/assets.{add, from_lovelace} +use cardano/certificate.{RegisterCredential} +use cardano/script_context.{Publishing, ScriptContext} +use cardano/transaction.{OutputReference, Spend, Transaction} +use mocktail.{ + add_redeemer, complete, mock_script_credential, mock_tx_hash, mocktail_tx, + tx_in, +} +use stake +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_spend_script_hash, +} +use types.{Deregister, DeregisterCerts, Register, RegisterCerts} + +type StakeTestCase { + is_only_one_auth_inputed: Bool, +} + +fn mock_stake_tx( + test_case: StakeTestCase, + only_input_redeemer: Data, +) -> Transaction { + let StakeTestCase { is_only_one_auth_inputed } = test_case + let only_input = + from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_address) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + only_input, + mock_crowdfund_address, + ) + |> complete() + |> add_redeemer( + True, + Pair( + Spend( + OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, + ), + only_input_redeemer, + ), + ) +} + +test s2_success_stake_with_reg() { + let only_input_redeemer: Data = RegisterCerts + + let ctx = + ScriptContext { + transaction: mock_stake_tx( + StakeTestCase { is_only_one_auth_inputed: True }, + only_input_redeemer, + ), + redeemer: Register, + info: Publishing { + at: 0, + certificate: RegisterCredential { + credential: mock_script_credential(0), + deposit: Never, + }, + }, + } + stake.stake.else(mock_spend_script_hash, ctx) +} + +test s2_success_stake_with_dereg() { + let only_input_redeemer: Data = DeregisterCerts + + let ctx = + ScriptContext { + transaction: mock_stake_tx( + StakeTestCase { is_only_one_auth_inputed: True }, + only_input_redeemer, + ), + redeemer: Deregister, + info: Publishing { + at: 0, + certificate: RegisterCredential { + credential: mock_script_credential(0), + deposit: Never, + }, + }, + } + stake.stake.else(mock_spend_script_hash, ctx) +} + +test s2_fail_stake_with_reg_but_deregister_cert() { + let only_input_redeemer: Data = DeregisterCerts + + let ctx = + ScriptContext { + transaction: mock_stake_tx( + StakeTestCase { is_only_one_auth_inputed: True }, + only_input_redeemer, + ), + redeemer: Register, + info: Publishing { + at: 0, + certificate: RegisterCredential { + credential: mock_script_credential(0), + deposit: Never, + }, + }, + } + !stake.stake.else(mock_spend_script_hash, ctx) +} + +test s2_fail_stake_with_dereg_but_register_cert() { + let only_input_redeemer: Data = RegisterCerts + + let ctx = + ScriptContext { + transaction: mock_stake_tx( + StakeTestCase { is_only_one_auth_inputed: True }, + only_input_redeemer, + ), + redeemer: Deregister, + info: Publishing { + at: 0, + certificate: RegisterCredential { + credential: mock_script_credential(0), + deposit: Never, + }, + }, + } + !stake.stake.else(mock_spend_script_hash, ctx) +} + +test s2_fail_stake_with_more_than_one_input_from_hash() fail { + let only_input_redeemer: Data = RegisterCerts + + let ctx = + ScriptContext { + transaction: mock_stake_tx( + StakeTestCase { is_only_one_auth_inputed: False }, + only_input_redeemer, + ), + redeemer: Register, + info: Publishing { + at: 0, + certificate: RegisterCredential { + credential: mock_script_credential(0), + deposit: Never, + }, + }, + } + stake.stake.else(mock_spend_script_hash, ctx) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak new file mode 100644 index 000000000..f3c5c63af --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -0,0 +1,10 @@ +use cardano/address.{from_script} +use mocktail.{mock_policy_id, mock_script_hash} + +pub const mock_auth_token = mock_policy_id(0) + +pub const mock_completion_script = mock_script_hash(0) + +pub const mock_spend_script_hash = mock_script_hash(1) + +pub const mock_crowdfund_address = from_script(mock_spend_script_hash) From a9c5cc6d3cba720837132dcfbf690b3ad68aeadc Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Wed, 25 Jun 2025 15:27:11 +0800 Subject: [PATCH 06/19] added: start added: check completion script --- .../gov-crowdfund/lib/types.ak | 15 ++ .../gov-crowdfund/validators/start.ak | 57 +++++ .../gov-crowdfund/validators/tests/stake.ak | 6 +- .../gov-crowdfund/validators/tests/start.ak | 206 ++++++++++++++++++ .../gov-crowdfund/validators/tests/utils.ak | 55 ++++- 5 files changed, 333 insertions(+), 6 deletions(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak index 04220021f..948ee8a32 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak @@ -1,3 +1,5 @@ +use cardano/address.{Address} + pub type CrowdfundRedeemer { RegisterCerts DeregisterCerts @@ -6,6 +8,19 @@ pub type CrowdfundRedeemer { } pub type CrowdfundDatum { + completion_script: ByteArray, + share_token: ByteArray, + crowdfund_address: Address, + fundraise_target: Int, + current_fundraised_amount: Int, + allow_over_subscription: Bool, + deadline: Int, + expiry_buffer: Int, + fee_address: Address, + min_charge: Int, +} + +pub type CrowdfundGovDatum { Init { completion_script: ByteArray, share_token: ByteArray, diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak index e69de29bb..ce4fff784 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak @@ -0,0 +1,57 @@ +use cardano/address.{Address, Credential, Inline, Script} +use cardano/assets.{PolicyId, lovelace_of} +use cardano/transaction.{Transaction} +use cocktail.{ + input_inline_datum, inputs_with_policy, output_inline_datum, outputs_at, +} +use types.{CrowdfundDatum, CrowdfundGovDatum, Init} + +validator start( + auth_token: PolicyId, + spend: ByteArray, + stake: ByteArray, + gov_action_period: Int, +) { + withdraw(_r, account: Credential, self: Transaction) { + let Transaction { inputs, outputs, .. } = self + + expect [auth_token_input] = inputs_with_policy(inputs, auth_token) + expect auth_input_datum: CrowdfundDatum = + input_inline_datum(auth_token_input) + + let CrowdfundDatum { + completion_script, + share_token, + fundraise_target, + deadline, + current_fundraised_amount, + .. + } = auth_input_datum + + let completion_script_check = Script(completion_script) == account + let gov_address = + Address { + payment_credential: Script(spend), + stake_credential: Some(Inline(Script(stake))), + } + + expect [fundraise_target_output] = outputs_at(outputs, gov_address) + + let fundraise_output_lovelace_check = + lovelace_of(fundraise_target_output.value) == fundraise_target + expect fundraise_output_datum: CrowdfundGovDatum = + output_inline_datum(fundraise_target_output) + let fundraise_output_datum_check = + fundraise_output_datum == Init { + completion_script, + share_token, + funds_controlled: current_fundraised_amount, + deadline: deadline + gov_action_period, + } + completion_script_check? && fundraise_output_lovelace_check? && fundraise_output_datum_check? + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak index 5d5410a07..18284ec4b 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak @@ -8,7 +8,7 @@ use mocktail.{ } use stake use tests/utils.{ - mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_auth_token, mock_completion_script, mock_crowdfund_gov_address, mock_spend_script_hash, } use types.{Deregister, DeregisterCerts, Register, RegisterCerts} @@ -25,13 +25,13 @@ fn mock_stake_tx( let only_input = from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) mocktail_tx() - |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_address) + |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_gov_address) |> tx_in( !is_only_one_auth_inputed, mock_tx_hash(0), 1, only_input, - mock_crowdfund_address, + mock_crowdfund_gov_address, ) |> complete() |> add_redeemer( diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak new file mode 100644 index 000000000..c1215bfab --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak @@ -0,0 +1,206 @@ +use cardano/address.{Script} +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{Transaction} +use mocktail.{ + complete, mock_script_hash, mock_tx_hash, mocktail_tx, tx_in, + tx_in_inline_datum, tx_out, tx_out_inline_datum, +} +use start +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, + mock_fundraise_target, mock_gov_action_period, mock_gov_address, + mock_share_token, mock_spend_script_hash, mock_stake_script_hash, +} +use types.{Init} + +type StartTestCase { + is_only_one_auth_inputed: Bool, + is_fundraise_target_sent: Bool, + is_fundraise_target_amount_correct: Bool, + is_fundraise_output_datum_correct: Bool, +} + +fn mock_stake_tx(test_case: StartTestCase) -> Transaction { + let StartTestCase { + is_only_one_auth_inputed, + is_fundraise_target_sent, + is_fundraise_target_amount_correct, + is_fundraise_output_datum_correct, + } = test_case + let auth_input = + from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) + + let fundraise_output = + if is_fundraise_target_amount_correct { + from_lovelace(mock_fundraise_target) + } else { + from_lovelace(mock_fundraise_target - 1000000) + } + + let fundraise_output_datum = + if is_fundraise_output_datum_correct { + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + } + } else { + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount + 1000000, + deadline: mock_deadline + mock_gov_action_period, + } + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, auth_input, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(mock_current_fundraised_amount, True), + ) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + auth_input, + mock_crowdfund_address, + ) + |> tx_out(is_fundraise_target_sent, mock_gov_address, fundraise_output) + |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) + |> complete() +} + +test s3_withdraw_success() { + let tx = + mock_stake_tx( + StartTestCase { + is_only_one_auth_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + }, + ) + + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_stake_script_hash, + mock_gov_action_period, + None, + Script(mock_completion_script), + tx, + ) +} + +test s3_withdraw_fail_with_more_than_one_auth_inputed() fail { + let tx = + mock_stake_tx( + StartTestCase { + is_only_one_auth_inputed: False, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + }, + ) + + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_stake_script_hash, + mock_gov_action_period, + None, + Script(mock_completion_script), + tx, + ) +} + +test s3_withdraw_fail_with_fundraise_target_not_sent() fail { + let tx = + mock_stake_tx( + StartTestCase { + is_only_one_auth_inputed: True, + is_fundraise_target_sent: False, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + }, + ) + + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_stake_script_hash, + mock_gov_action_period, + None, + Script(mock_completion_script), + tx, + ) +} + +test s3_withdraw_fail_with_incorrect_fundraise_target_output_amount() { + let tx = + mock_stake_tx( + StartTestCase { + is_only_one_auth_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: False, + is_fundraise_output_datum_correct: True, + }, + ) + + !start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_stake_script_hash, + mock_gov_action_period, + None, + Script(mock_completion_script), + tx, + ) +} + +test s3_withdraw_fail_with_incorrect_fundraise_target_output_datum() { + let tx = + mock_stake_tx( + StartTestCase { + is_only_one_auth_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: False, + }, + ) + + !start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_stake_script_hash, + mock_gov_action_period, + None, + Script(mock_completion_script), + tx, + ) +} + +test s3_withdraw_fail_with_different_completion_script() { + let tx = + mock_stake_tx( + StartTestCase { + is_only_one_auth_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: False, + }, + ) + + !start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_stake_script_hash, + mock_gov_action_period, + None, + Script(mock_script_hash(999)), + tx, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak index f3c5c63af..d26e19c0e 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -1,10 +1,59 @@ -use cardano/address.{from_script} -use mocktail.{mock_policy_id, mock_script_hash} +use cardano/address.{Address, Inline, Script, from_script} +use mocktail.{mock_policy_id, mock_script_hash, mock_script_stake_key_hash} +use types.{CrowdfundDatum} pub const mock_auth_token = mock_policy_id(0) +pub const mock_share_token = mock_policy_id(1) + pub const mock_completion_script = mock_script_hash(0) +pub const mock_crowdfund_spend_script_hash = mock_script_hash(1) + +pub const mock_crowdfund_stake_script_hash = mock_script_stake_key_hash(0) + +pub const mock_crowdfund_address = from_script(mock_crowdfund_spend_script_hash) + +pub const mock_fee_address = from_script("fee_address") + +pub const mock_fundraise_target = 100000000000 + +pub const mock_current_fundraised_amount = mock_fundraise_target + 1000000 + +pub const mock_deadline = 1750735607 + +pub const mock_expiry_buffer = 3600 * 24 + +pub const mock_min_charge = 0 + +pub fn mock_crowdfund_datum( + current_fundraised_amount: Int, + allow_over_subscription: Bool, +) { + CrowdfundDatum { + completion_script: mock_completion_script, + share_token: mock_share_token, + crowdfund_address: mock_crowdfund_address, + fundraise_target: mock_fundraise_target, + current_fundraised_amount, + allow_over_subscription, + deadline: mock_deadline, + expiry_buffer: mock_expiry_buffer, + fee_address: mock_fee_address, + min_charge: mock_min_charge, + } +} + pub const mock_spend_script_hash = mock_script_hash(1) -pub const mock_crowdfund_address = from_script(mock_spend_script_hash) +pub const mock_stake_script_hash = mock_script_hash(2) + +pub const mock_crowdfund_gov_address = from_script(mock_spend_script_hash) + +pub const mock_gov_address = + Address { + payment_credential: Script(mock_spend_script_hash), + stake_credential: Some(Inline(Script(mock_stake_script_hash))), + } + +pub const mock_gov_action_period = 3600 From 36418e774fe4c365016c72fd731b33868a32bdb2 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Thu, 26 Jun 2025 13:32:18 +0800 Subject: [PATCH 07/19] added: gov spend added: gov spend test case --- .../gov-crowdfund/lib/gov.ak | 95 ++ .../gov-crowdfund/lib/utils.ak | 103 +- .../gov-crowdfund/specs/1_spend.md | 4 +- .../gov-crowdfund/validators/spend.ak | 251 +++ .../gov-crowdfund/validators/tests/spend.ak | 1369 +++++++++++++++++ .../gov-crowdfund/validators/tests/stake.ak | 8 +- .../gov-crowdfund/validators/tests/utils.ak | 39 +- 7 files changed, 1861 insertions(+), 8 deletions(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak new file mode 100644 index 000000000..215e09f88 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak @@ -0,0 +1,95 @@ +// use aiken/cbor +// use aiken/crypto.{ScriptHash} +// use aiken/math/rational.{Rational} +// use cardano/address.{Credential} +// use cardano/assets.{Lovelace} +// use cardano/governance.{ +// Constitution, GovernanceAction, GovernanceActionId, Mandate, +// ProtocolParameters, ProtocolVersion, +// } +// use cardano/governance/protocol_parameters.{ProtocolParametersUpdate} + +// pub fn to_aiken_gov_action(gov_action: VGovernanceAction) -> GovernanceAction { +// // let raw = cbor.serialise(gov_action) +// // expect Some(output): Option = cbor.deserialise(raw) +// // expect gov: GovernanceAction = output +// when gov_action is { +// VProtocolParameters { ancestor, new_parameters, guardrails } -> +// ProtocolParameters { +// ancestor, +// new_parameters: ProtocolParametersUpdate { inner: new_parameters.inner }, +// guardrails, +// } +// _ -> gov_action +// } +// } + +// type ProtocolParametersIndex = +// Int + +// pub type VProtocolParametersUpdate { +// inner: Pairs, +// } + +// pub type VGovernanceAction { +// VProtocolParameters { +// /// The last governance action of type 'ProtocolParameters'. They must all +// /// form a chain. +// ancestor: Option, +// /// The new proposed protocol parameters. Only values set to `Some` are relevant. +// new_parameters: VProtocolParametersUpdate, +// /// The optional guardrails script defined in the constitution. The script +// /// is executed by the ledger in addition to the hard-coded ledger rules. +// /// +// /// It must pass for the new protocol parameters to be deemed valid. +// guardrails: Option, +// } +// HardFork { +// /// The last governance action of type `HardFork`. They must all +// /// form a chain. +// ancestor: Option, +// /// The new proposed version. Few rules apply to proposing new versions: +// /// +// /// - The `major` component, if incremented, must be exactly one more than the current. +// /// - The `minor` component, if incremented, must be exactly one more than the current. +// /// - If the `major` component is incremented, `minor` must be set to `0`. +// /// - Neither `minor` nor `major` can be decremented. +// new_version: ProtocolVersion, +// } +// TreasuryWithdrawal { +// /// A collection of beneficiaries, which can be plain verification key +// /// hashes or script hashes (e.g. DAO). +// beneficiaries: Pairs, +// /// The optional guardrails script defined in the constitution. The script +// /// is executed by the ledger in addition to the hard-coded ledger rules. +// /// +// /// It must pass for the withdrawals to be authorized. +// guardrails: Option, +// } +// NoConfidence { +// /// The last governance action of type `NoConfidence` or +// /// `ConstitutionalCommittee`. They must all / form a chain. +// ancestor: Option, +// } +// ConstitutionalCommittee { +// /// The last governance action of type `NoConfidence` or +// /// `ConstitutionalCommittee`. They must all / form a chain. +// ancestor: Option, +// /// Constitutional members to be removed. +// evicted_members: List, +// /// Constitutional members to be added. +// added_members: Pairs, +// /// The new quorum value, as a ratio of a numerator and a denominator. The +// /// quorum specifies the threshold of 'Yes' votes necessary for the +// /// constitutional committee to accept a proposal procedure. +// quorum: Rational, +// } +// NewConstitution { +// /// The last governance action of type `Constitution` or +// /// `ConstitutionalCommittee`. They must all / form a chain. +// ancestor: Option, +// /// The new proposed constitution. +// constitution: Constitution, +// } +// NicePoll +// } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak index ab263997e..2b72369a7 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak @@ -1,5 +1,14 @@ +use aiken/collection/list use aiken/collection/pairs -use cardano/transaction.{Input, Redeemer, ScriptPurpose, Spend} +use cardano/address.{Credential} +use cardano/assets.{Lovelace, lovelace_of} +use cardano/certificate.{ + Certificate, DelegateBlockProduction, DelegateBoth, DelegateCredential, + DelegateRepresentative, DelegateVote, RegisterCredential, + RegisterDelegateRepresentative, StakePoolId, UnregisterCredential, + UnregisterDelegateRepresentative, +} +use cardano/transaction.{Input, Output, Redeemer, ScriptPurpose, Spend} pub fn redeemer_with_input( redeemers: Pairs, @@ -8,3 +17,95 @@ pub fn redeemer_with_input( let output_reference = input.output_reference redeemers |> pairs.get_first(Spend(output_reference)) } + +pub fn register_stake_certificate( + certificates: List, + credential: Credential, +) { + list.has(certificates, RegisterCredential { credential, deposit: Never }) +} + +pub fn unregister_stake_certificate( + certificates: List, + credential: Credential, +) { + list.has(certificates, UnregisterCredential { credential, refund: Never }) +} + +pub fn register_drep_certificate( + certificates: List, + credential: Credential, + deposit: Lovelace, +) { + list.has( + certificates, + RegisterDelegateRepresentative { + delegate_representative: credential, + deposit, + }, + ) +} + +pub fn unregister_drep_certificate( + certificates: List, + credential: Credential, + refund: Lovelace, +) { + list.has( + certificates, + UnregisterDelegateRepresentative { + delegate_representative: credential, + refund, + }, + ) +} + +pub fn delegate_vote_certificate( + certificates: List, + credential: Credential, + delegate_representative: DelegateRepresentative, +) { + list.has( + certificates, + DelegateCredential { + credential, + delegate: DelegateVote { delegate_representative }, + }, + ) +} + +pub fn delegate_stake_certificate( + certificates: List, + credential: Credential, + stake_pool: StakePoolId, +) { + list.has( + certificates, + DelegateCredential { + credential, + delegate: DelegateBlockProduction { stake_pool }, + }, + ) +} + +pub fn delegate_stake_and_vote_certificate( + certificates: List, + credential: Credential, + stake_pool: StakePoolId, + delegate_representative: DelegateRepresentative, +) { + list.has( + certificates, + DelegateCredential { + credential, + delegate: DelegateBoth { stake_pool, delegate_representative }, + }, + ) +} + +pub fn check_lovelace_diff(input: Input, output: Output, diff: Lovelace) { + let lovelace_from_input_output = input.output.value |> lovelace_of() + let lovelace_from_output = output.value |> lovelace_of() + + lovelace_from_output - lovelace_from_input_output == diff +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md index 4ad76c581..09e4a1977 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md @@ -5,6 +5,8 @@ - `delegate_pool_id`: ByteArray - `gov_action`: GovernanceAction - `proposer_key_hash`: ByteArray +- `stake_register_deposit`: Int +- `drep_register_deposti`: Int ## Datum @@ -44,7 +46,7 @@ pub type Datum { - Delegate to current own DRep + stake pool `delegate_pool_id` - Propose gov action - Vote on same proposal? -> if cant, create one more separate state - - todo: check 100k lock before retification correctly + - todo: check 100k lock before ratification correctly 2. DeregisterCerts diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak index e69de29bb..2c2fc36e3 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak @@ -0,0 +1,251 @@ +use aiken/collection/list +use cardano/address.{Inline} +use cardano/assets.{Lovelace, lovelace_of} +use cardano/certificate.{Registered} +use cardano/governance.{GovernanceAction, ProposalProcedure} +use cardano/transaction.{OutputReference, Transaction, find_input} +use cocktail.{ + inputs_at, key_signed, only_minted_token, output_inline_datum, outputs_at, + valid_after, value_length, +} +use types.{ + ContributorWithdrawal, CrowdfundGovDatum, CrowdfundRedeemer, DeregisterCerts, + Init, Proposed, Refundable, RegisterCerts, RemoveEmptyInstance, +} +use utils.{ + check_lovelace_diff, delegate_stake_and_vote_certificate, + delegate_stake_certificate, delegate_vote_certificate, + register_drep_certificate, register_stake_certificate, + unregister_drep_certificate, unregister_stake_certificate, +} + +validator spend( + delegate_pool_id: ByteArray, + gov_action: GovernanceAction, + proposer_key_hash: ByteArray, + stake_register_deposit: Lovelace, + drep_register_deposit: Lovelace, +) { + spend( + datum_opt: Option, + redeemer: CrowdfundRedeemer, + input: OutputReference, + self: Transaction, + ) { + let Transaction { + inputs, + validity_range, + mint, + outputs, + extra_signatories, + certificates, + proposal_procedures, + .. + } = self + + expect Some(own_input) = find_input(inputs, input) + expect Some(only_input_datum) = datum_opt + + let current_address = own_input.output.address + + // check only 1 input from current address + expect [only_input] = inputs_at(inputs, current_address) + + when redeemer is { + RegisterCerts -> + when only_input_datum is { + Init { share_token, deadline, funds_controlled, completion_script } -> { + expect Some(current_stake_credential) = + current_address.stake_credential + + expect Inline(current_credential) = current_stake_credential + + expect [only_output] = outputs_at(outputs, current_address) + + let lovelace_from_only_input = + only_input.output.value |> lovelace_of() + + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + -(stake_register_deposit + drep_register_deposit), + ) + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Proposed { + completion_script, + share_token, + funds_controlled, + deadline, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 1 + + let reg_stake_cert_check = + register_stake_certificate(certificates, current_credential) + + let reg_drep_cert_check = + register_drep_certificate( + certificates, + current_credential, + drep_register_deposit, + ) + + let delegate_check = + delegate_vote_certificate( + certificates, + current_credential, + Registered(current_credential), + ) && delegate_stake_certificate( + certificates, + current_credential, + delegate_pool_id, + ) || delegate_stake_and_vote_certificate( + certificates, + current_credential, + delegate_pool_id, + Registered(current_credential), + ) + + let proposal_check = + list.has( + proposal_procedures, + ProposalProcedure { + deposit: lovelace_from_only_input - stake_register_deposit - drep_register_deposit, + return_address: current_address.payment_credential, + governance_action: gov_action, + }, + ) + lovelace_check? && output_datum_check? && is_only_output_value_clean? && reg_stake_cert_check? && reg_drep_cert_check? && delegate_check? && proposal_check? + } + _ -> False + } + + DeregisterCerts -> + when only_input_datum is { + Refundable { + share_token, + deadline, + funds_controlled, + completion_script, + } -> { + expect Some(current_stake_credential) = + current_address.stake_credential + + expect Inline(current_credential) = current_stake_credential + let validity_check = valid_after(validity_range, deadline) + expect [only_output] = outputs_at(outputs, current_address) + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + stake_register_deposit + drep_register_deposit, + ) + + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Refundable { + completion_script, + share_token, + funds_controlled, + deadline, + } + + let unreg_stake_cert_check = + unregister_stake_certificate(certificates, current_credential) + + let unreg_drep_cert_check = + unregister_drep_certificate( + certificates, + current_credential, + drep_register_deposit, + ) + validity_check? && lovelace_check? && output_datum_check? && unreg_stake_cert_check? && unreg_drep_cert_check? + } + + _ -> False + } + + ContributorWithdrawal -> + when only_input_datum is { + Refundable { + share_token, + deadline, + funds_controlled, + completion_script, + } -> { + let validity_check = valid_after(validity_range, deadline) + + expect [only_output] = outputs_at(outputs, current_address) + + let lovelace_from_only_input = + only_input.output.value |> lovelace_of() + let lovelace_from_only_output = only_output.value |> lovelace_of() + + let lovelace_withdrawn = + lovelace_from_only_output - lovelace_from_only_input + + let lovelace_withdrawn_check = lovelace_withdrawn < 0 + + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Refundable { + completion_script, + share_token, + funds_controlled: funds_controlled + lovelace_withdrawn, + deadline, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 1 + + validity_check? && lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( + mint, + share_token, + completion_script, + lovelace_withdrawn, + )? + } + _ -> False + } + + RemoveEmptyInstance -> + when only_input_datum is { + Refundable { + share_token, + deadline, + funds_controlled, + completion_script, + } -> { + let validity_check = valid_after(validity_range, deadline) + + let token_burnt_check = + if funds_controlled > 0 { + only_minted_token( + mint, + share_token, + completion_script, + -funds_controlled, + ) + } else { + True + } + + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + validity_check? && token_burnt_check? && proposer_key_signed_check? + } + _ -> False + } + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak new file mode 100644 index 000000000..1e5e6e438 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak @@ -0,0 +1,1369 @@ +use cardano/address.{Script} +use cardano/assets.{add, from_lovelace} +use cardano/certificate.{ + DelegateBlockProduction, DelegateCredential, DelegateVote, RegisterCredential, + RegisterDelegateRepresentative, Registered, UnregisterCredential, + UnregisterDelegateRepresentative, +} +use cardano/governance.{ProposalProcedure} +use cardano/transaction.{Transaction} +use mocktail.{ + add_certificate, add_extra_signatory, complete, invalid_before, mint, + mock_policy_id, mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, + tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, +} +use spend +use tests/utils.{ + add_proposal_procedure, mock_completion_script, + mock_contribute_min_fundraised_amount, mock_current_fundraised_amount, + mock_deadline, mock_delegate_pool_id, mock_drep_register_deposit, + mock_funds_controlled, mock_gov_action, mock_gov_action_period, + mock_gov_address, mock_proposer_key_hash, mock_share_token, + mock_spend_script_hash, mock_stake_register_deposit, mock_stake_script_hash, +} +use types.{ + ContributorWithdrawal, Init, Proposed, Refundable, RegisterCerts, + RemoveEmptyInstance, +} + +type RegisterCertsTestCase { + is_only_one_inputed: Bool, + is_only_one_outputed: Bool, + is_output_datum_correct: Bool, + is_output_value_clean: Bool, + is_output_value_correct: Bool, + is_stake_cert_register: Bool, + is_drep_cert_register: Bool, + is_drep_deposit_correct: Bool, + is_stake_delegated: Bool, + is_vote_delegated: Bool, + is_gov_proposed: Bool, +} + +fn mock_register_cert_tx(test_case: RegisterCertsTestCase) -> Transaction { + let RegisterCertsTestCase { + is_only_one_inputed, + is_only_one_outputed, + is_output_datum_correct, + is_output_value_clean, + is_output_value_correct, + is_stake_cert_register, + is_drep_cert_register, + is_drep_deposit_correct, + is_stake_delegated, + is_vote_delegated, + is_gov_proposed, + } = test_case + + let input_value = from_lovelace(mock_funds_controlled) + + let input_datum = + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + } + let output_value = + if is_output_value_correct { + from_lovelace( + mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, + ) + } else { + from_lovelace( + mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit + 10, + ) + } + + let output_datum = + if is_output_datum_correct { + Proposed { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + } + } else { + Proposed { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled + 10, + deadline: mock_deadline + mock_gov_action_period, + } + } + + let drep_deposit = + if is_drep_deposit_correct { + mock_drep_register_deposit + } else { + mock_drep_register_deposit - 1000000 + } + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out(is_output_value_clean, mock_gov_address, output_value) + |> tx_out( + !is_output_value_clean, + mock_gov_address, + output_value |> add(mock_policy_id(999), mock_completion_script, 1), + ) + |> tx_out_inline_datum(True, output_datum) + |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) + |> complete() + |> add_certificate( + is_stake_cert_register, + RegisterCredential { + credential: Script(mock_stake_script_hash), + deposit: Never, + }, + ) + |> add_certificate( + is_drep_cert_register, + RegisterDelegateRepresentative { + delegate_representative: Script(mock_stake_script_hash), + deposit: drep_deposit, + }, + ) + |> add_certificate( + is_stake_delegated, + DelegateCredential { + credential: Script(mock_stake_script_hash), + delegate: DelegateBlockProduction { + stake_pool: mock_delegate_pool_id, + }, + }, + ) + |> add_certificate( + is_vote_delegated, + DelegateCredential { + credential: Script(mock_stake_script_hash), + delegate: DelegateVote { + delegate_representative: Registered(Script(mock_stake_script_hash)), + }, + }, + ) + |> add_proposal_procedure( + is_gov_proposed, + ProposalProcedure { + deposit: mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, + return_address: Script(mock_spend_script_hash), + governance_action: mock_gov_action, + }, + ) +} + +test s3_spend_success_reg_cert() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_not_init_state() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_more_than_one_input() fail { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: False, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_more_than_one_output() fail { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: False, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_incorrect_output_datum() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: False, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_output_value_not_clean() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: False, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_incorrect_output_value() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: False, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_stake_cert_not_reg() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: False, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_drep_cert_not_reg() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: False, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_drep_deposit_incorrect() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: False, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_stake_not_delegated() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: False, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_vote_not_delegated() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: False, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_gov_not_proposed() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: False, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +type ContributorWithdrawalTestCase { + is_only_one_inputed: Bool, + is_only_one_outputed: Bool, + is_output_datum_correct: Bool, + is_output_value_clean: Bool, + is_unlock_value_correct: Bool, + is_deadline_passed: Bool, + is_shares_burnt: Bool, +} + +fn mock_contributor_withdrawal_tx( + test_case: ContributorWithdrawalTestCase, + current_fundraised_amount: Int, + withdraw_amount: Int, +) -> Transaction { + let ContributorWithdrawalTestCase { + is_only_one_inputed, + is_only_one_outputed, + is_output_datum_correct, + is_output_value_clean, + is_unlock_value_correct, + is_deadline_passed, + is_shares_burnt, + } = test_case + + let input_value = from_lovelace(current_fundraised_amount) + + let input_datum = + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + } + let output_value = + if is_unlock_value_correct { + from_lovelace(current_fundraised_amount - withdraw_amount) + } else { + from_lovelace(current_fundraised_amount - withdraw_amount + 10) + } + + let output_datum = + if is_output_datum_correct { + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount - withdraw_amount, + deadline: mock_deadline + mock_gov_action_period, + } + } else { + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount - withdraw_amount + 10, + deadline: mock_deadline + mock_gov_action_period, + } + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out(True, mock_pub_key_address(0, None), from_lovelace(withdraw_amount)) + |> tx_out(is_output_value_clean, mock_gov_address, output_value) + |> tx_out( + !is_output_value_clean, + mock_gov_address, + output_value |> add(mock_policy_id(999), mock_completion_script, 1), + ) + |> tx_out_inline_datum(True, output_datum) + |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) + |> invalid_before( + is_deadline_passed, + mock_deadline + mock_gov_action_period + 3600 * 24, + ) + |> invalid_before( + !is_deadline_passed, + mock_deadline + mock_gov_action_period - 3600 * 24, + ) + |> mint( + is_shares_burnt, + -withdraw_amount, + mock_share_token, + mock_completion_script, + ) + |> mint( + !is_shares_burnt, + -withdraw_amount + 9999999, + mock_share_token, + mock_completion_script, + ) + |> complete() +} + +test s3_spend_success_contributor_withdraw() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_state_not_refundable() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: False, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: False, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: False, + is_output_value_clean: True, + is_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: False, + is_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: False, + is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_deadline_not_passed() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + is_deadline_passed: False, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + is_deadline_passed: True, + is_shares_burnt: False, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +type RemoveEmptyInstanceTestCase { + is_only_one_inputed: Bool, + is_deadline_passed: Bool, + is_shares_burnt: Bool, + is_proposer_signed: Bool, +} + +fn mock_remove_empty_instance_tx( + test_case: RemoveEmptyInstanceTestCase, + current_fundraised_amount: Int, +) -> Transaction { + let RemoveEmptyInstanceTestCase { + is_only_one_inputed, + is_deadline_passed, + is_shares_burnt, + is_proposer_signed, + } = test_case + + let input_value = from_lovelace(current_fundraised_amount) + + let input_datum = + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out( + True, + mock_pub_key_address(0, None), + from_lovelace(current_fundraised_amount), + ) + |> invalid_before( + is_deadline_passed, + mock_deadline + mock_gov_action_period + 3600 * 24, + ) + |> invalid_before( + !is_deadline_passed, + mock_deadline + mock_gov_action_period - 3600 * 24, + ) + |> mint( + is_shares_burnt, + -current_fundraised_amount, + mock_share_token, + mock_completion_script, + ) + |> mint( + !is_shares_burnt, + -current_fundraised_amount + 9999999, + mock_share_token, + mock_completion_script, + ) + |> complete() + |> add_extra_signatory(is_proposer_signed, mock_proposer_key_hash) +} + +test s3_spend_success_remove_empty_instance_wih_zero_fund() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_proposer_signed: True, + }, + 0, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: 0, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_success_remove_empty_instance_wih_some_fund() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_state_not_refundable() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: False, + is_deadline_passed: True, + is_shares_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + is_deadline_passed: False, + is_shares_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + is_deadline_passed: True, + is_shares_burnt: False, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_proposer_not_signed() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_proposer_signed: False, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + completion_script: mock_completion_script, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak index 18284ec4b..e7188fa6a 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak @@ -1,4 +1,4 @@ -use cardano/assets.{add, from_lovelace} +use cardano/assets.{from_lovelace} use cardano/certificate.{RegisterCredential} use cardano/script_context.{Publishing, ScriptContext} use cardano/transaction.{OutputReference, Spend, Transaction} @@ -8,8 +8,7 @@ use mocktail.{ } use stake use tests/utils.{ - mock_auth_token, mock_completion_script, mock_crowdfund_gov_address, - mock_spend_script_hash, + mock_crowdfund_gov_address, mock_fundraise_target, mock_spend_script_hash, } use types.{Deregister, DeregisterCerts, Register, RegisterCerts} @@ -22,8 +21,7 @@ fn mock_stake_tx( only_input_redeemer: Data, ) -> Transaction { let StakeTestCase { is_only_one_auth_inputed } = test_case - let only_input = - from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) + let only_input = from_lovelace(mock_fundraise_target) mocktail_tx() |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_gov_address) |> tx_in( diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak index d26e19c0e..5278a3af4 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -1,5 +1,11 @@ +use aiken/collection/list use cardano/address.{Address, Inline, Script, from_script} -use mocktail.{mock_policy_id, mock_script_hash, mock_script_stake_key_hash} +use cardano/governance.{NoConfidence, ProposalProcedure} +use cardano/transaction.{Transaction} +use mocktail.{ + mock_policy_id, mock_pub_key_hash, mock_script_hash, + mock_script_stake_key_hash, +} use types.{CrowdfundDatum} pub const mock_auth_token = mock_policy_id(0) @@ -20,6 +26,8 @@ pub const mock_fundraise_target = 100000000000 pub const mock_current_fundraised_amount = mock_fundraise_target + 1000000 +pub const mock_contribute_min_fundraised_amount = 2000000 + pub const mock_deadline = 1750735607 pub const mock_expiry_buffer = 3600 * 24 @@ -57,3 +65,32 @@ pub const mock_gov_address = } pub const mock_gov_action_period = 3600 + +pub const mock_delegate_pool_id = mock_script_hash(3) + +pub const mock_gov_action = NoConfidence { ancestor: None } + +pub const mock_proposer_key_hash = mock_pub_key_hash(0) + +pub const mock_stake_register_deposit = 2000000 + +pub const mock_drep_register_deposit = 500000000 + +pub const mock_funds_controlled = + mock_fundraise_target + mock_stake_register_deposit + mock_drep_register_deposit + +pub fn add_proposal_procedure( + tx: Transaction, + condition: Bool, + proposal_procedure: ProposalProcedure, +) -> Transaction { + if !condition { + tx + } else { + Transaction { + ..tx, + proposal_procedures: tx.proposal_procedures + |> list.concat([proposal_procedure]), + } + } +} From 9ecbd4bed6402e6e941536faf15969c3f787df0a Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Thu, 26 Jun 2025 18:19:41 +0800 Subject: [PATCH 08/19] updated: spec --- .../gov-crowdfund/specs/1_spend.md | 40 ++++++++----- .../gov-crowdfund/specs/2_stake.md | 15 ----- .../gov-crowdfund/specs/2_start.md | 57 +++++++++++++++++++ .../gov-crowdfund/specs/3_start.md | 25 -------- .../gov-crowdfund/specs/_scripts.md | 11 +--- 5 files changed, 87 insertions(+), 61 deletions(-) delete mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md delete mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md index 09e4a1977..4e92d5944 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md @@ -5,27 +5,34 @@ - `delegate_pool_id`: ByteArray - `gov_action`: GovernanceAction - `proposer_key_hash`: ByteArray -- `stake_register_deposit`: Int -- `drep_register_deposti`: Int +- `stake_register_deposit`: Lovelace +- `drep_register_deposit`: Lovelace ## Datum ```rs pub type Datum { Init { - completion_script: ByteArray, + start_hash: ByteArray, share_token: ByteArray, funds_controlled: Int, deadline: Int, } Proposed { - completion_script: ByteArray, + start_hash: ByteArray, share_token: ByteArray, funds_controlled: Int, deadline: Int, } + Voted { + start_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + gov_tx_id: GovernanceActionId + deadline: Int, + } Refundable { - completion_script: ByteArray, + start_hash: ByteArray, share_token: ByteArray, funds_controlled: Int, deadline: Int, @@ -39,32 +46,39 @@ pub type Datum { - Only one input and output from current address - Input datum in state of `Init` + - Output value has deducted with 502 ADA exactly - Output datum in state of `Proposed` - fields exactly the same - Registering stake cert - - Registering DRep cert + - Registering DRep cert with drep_register_deposit - Delegate to current own DRep + stake pool `delegate_pool_id` - Propose gov action - - Vote on same proposal? -> if cant, create one more separate state - - todo: check 100k lock before ratification correctly -2. DeregisterCerts +2. VoteOnGovAction - - deadline is passed - Only one input and output from current address - Input datum in state of `Proposed` + - Check output value (deducted by 100k ADA exactly) + - Output datum in state of `Voted`, with `gov_tx_id` composed by own's input `TransactionId` + `proposal_procedure` as 0 + - fields exactly the same + +3. DeregisterCerts + + - deadline is passed + - Only one input and output from current address + - Input datum in state of `Voted` - Output datum in state of `Refundable` - fields exactly the same - Deregistering both certs - - Refunds go into the output + - Refunds (502ADA) go into the output -3. ContributorWithdrawal +4. ContributorWithdrawal - Input datum in state of Refundable - `deadline` is passed - The lovelace unlocking from current equal exactly the amount that the `share_token` with token name of `completion_script` is burnt -4. RemoveEmptyInstance +5. RemoveEmptyInstance - Input datum in state of Refundable - `deadline` is passed diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md deleted file mode 100644 index a6b11130c..000000000 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_stake.md +++ /dev/null @@ -1,15 +0,0 @@ -# Specification - Stake - -## Parameter - -- `spend_script_hash`: The script hash of the spending part - -## User Action - -1. Register - - - Only 1 input from `spend_script_hash` with redeemer of `RegisterCerts` - -2. Deregister - - - Only 1 input from `spend_script_hash` with redeemer of `DeregisterCerts` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md new file mode 100644 index 000000000..3471a3568 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md @@ -0,0 +1,57 @@ +# Specification - Start + +## Parameter + +- `auth_token`: The policy ID of crowdfunding token +- `spend`: The script hash of the spending part of the gov system +- `gov_action_period`: The buffer since crowdfund deadline to complete entire gov process + +## User Action - Withdraw + +1. Validate completion of crowdfunding + + - Only one input with `auth_token`, with inline datum + `completion_script` same as current crendential hash + - Exactly 1 token with `current_script_hash` policy is minted + - All `fundraise_target` amount of ADA + currently minted token is sent to address composed of `spend` and `current_script_hash` (both script hash) + - With datum: + + ```rs + Init { + start_hash: , + share_token: , + funds_controlled: , + deadline: , + } + ``` + +## User Action - Mint + +1. Mint - Redeemer `RMint` + + - The current token policy's equivalent withdrawal script is validated + +2. Burn - Redeemer `RBurn` + + - Only 1 input from `spend_script_hash` with redeemer of `RemoveEmptyInstance` + +## User Action - Publish + +1. Redeemer 1 - Register + + - Only 1 input from `spend_script_hash` with redeemer of `RegisterCerts` + +2. Redeemer 2 - Deregister + + - Only 1 input from `spend_script_hash` with redeemer of `DeregisterCerts` + +## User Action - Propose + +1. Propose gov action + + - Only 1 input from `spend_script_hash` with redeemer of `RegisterCerts` + +## User Action - Vote + +1. Propose gov action + + - Only 1 input from `spend_script_hash` with redeemer of `VoteOnGovAction` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md deleted file mode 100644 index b07a65114..000000000 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/3_start.md +++ /dev/null @@ -1,25 +0,0 @@ -# Specification - Start - -## Parameter - -- `auth_token`: The policy ID of crowdfunding token -- `spend`: The script hash of the spending part of the gov system -- `stake`: The script hash of the staking part of the gov system -- `gov_action_period`: The buffer since crowdfund deadline to complete entire gov process - -## User Action - -1. Validate completion of crowdfunding - - - Only one input with `auth_token`, with inline datum + `completion_script` same as current crendential hash - - All `fundraise_target` amount of ADA is sent to address composed of `spend` and `stake` (both script hash) - - With datum: - - ```rs - Init { - completion_script: , - share_token: , - funds_controlled: , - deadline: , - } - ``` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md index cb2f26cb4..94cedaeca 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md @@ -4,21 +4,16 @@ The spending validator that guarding the crowdfunded -## 2. Stake +## 2. Start -The token that represents lovelace contributed to current crowdfunding campaign - -## 3. Start - -The withdrawal script that oversight the completion of crowdfunding (i.e. `completion_script` at crowdfunding script) +The withdrawal script that oversight the completion of crowdfunding (i.e. `completion_script` at crowdfunding script). Also as the script for current campaign auth token + all gov power. ## Param dependency tree 1. First layer - `spend` - no param - - `stake` - no param 2. Second layer - - `start` - param `spend` and `stake` + - `start` - param `spend` From a615279633fa293d0cfa0159c32c49d3344fc8df Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Thu, 26 Jun 2025 19:08:45 +0800 Subject: [PATCH 09/19] updated: start todo: start test todo: spend --- .../validators/crowdfund/spend.ak | 2 +- .../gov-crowdfund/lib/types.ak | 22 +- .../gov-crowdfund/lib/utils.ak | 20 +- .../gov-crowdfund/plutus.json | 248 ++ .../gov-crowdfund/validators/spend.ak | 502 +-- .../gov-crowdfund/validators/stake.ak | 36 - .../gov-crowdfund/validators/start.ak | 85 +- .../gov-crowdfund/validators/tests/spend.ak | 2738 ++++++++--------- .../gov-crowdfund/validators/tests/stake.ak | 274 +- .../gov-crowdfund/validators/tests/start.ak | 412 +-- .../gov-crowdfund/validators/tests/utils.ak | 140 +- 11 files changed, 2394 insertions(+), 2085 deletions(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json delete mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak index 827b8cf86..017f07a62 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak @@ -111,7 +111,7 @@ validator crowdfund(auth_token: PolicyId) { let withdrawal_script_check = withdrawals |> has_key(completion_script_withdrawal_credential) - fundraise_check? && withdrawal_script_check? && only_minted_token( + fundraise_check? && withdrawal_script_check? && policy_only_minted_token( mint, auth_token, completion_script, diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak index 948ee8a32..4d53cd0de 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak @@ -1,8 +1,10 @@ use cardano/address.{Address} +use cardano/governance.{GovernanceActionId} pub type CrowdfundRedeemer { RegisterCerts DeregisterCerts + VoteOnGovAction ContributorWithdrawal RemoveEmptyInstance } @@ -22,26 +24,38 @@ pub type CrowdfundDatum { pub type CrowdfundGovDatum { Init { - completion_script: ByteArray, + start_hash: ByteArray, share_token: ByteArray, funds_controlled: Int, deadline: Int, } Proposed { - completion_script: ByteArray, + start_hash: ByteArray, share_token: ByteArray, funds_controlled: Int, deadline: Int, } + Voted { + start_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + gov_tx_id: GovernanceActionId, + deadline: Int, + } Refundable { - completion_script: ByteArray, + start_hash: ByteArray, share_token: ByteArray, funds_controlled: Int, deadline: Int, } } -pub type StakeRedeemer { +pub type MintPolarity { + RMint + RBurn +} + +pub type PublishRedeemer { Register Deregister } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak index 2b72369a7..e9d0491e3 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak @@ -1,6 +1,6 @@ use aiken/collection/list use aiken/collection/pairs -use cardano/address.{Credential} +use cardano/address.{Credential, from_script} use cardano/assets.{Lovelace, lovelace_of} use cardano/certificate.{ Certificate, DelegateBlockProduction, DelegateBoth, DelegateCredential, @@ -9,6 +9,8 @@ use cardano/certificate.{ UnregisterDelegateRepresentative, } use cardano/transaction.{Input, Output, Redeemer, ScriptPurpose, Spend} +use cocktail.{inputs_at} +use types.{CrowdfundRedeemer} pub fn redeemer_with_input( redeemers: Pairs, @@ -109,3 +111,19 @@ pub fn check_lovelace_diff(input: Input, output: Output, diff: Lovelace) { lovelace_from_output - lovelace_from_input_output == diff } + +pub fn check_spend_script_input_redeemer( + spend: ByteArray, + inputs: List, + redeemers: Pairs, + redeemer: CrowdfundRedeemer, +) { + let spend_address = from_script(spend) + expect [only_input] = inputs_at(inputs, spend_address) + expect Some(only_inpuy_redeemer_data) = + redeemer_with_input(redeemers, only_input) + + expect only_input_redeemer: CrowdfundRedeemer = only_inpuy_redeemer_data + + only_input_redeemer == redeemer +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json new file mode 100644 index 000000000..4f4bf0764 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json @@ -0,0 +1,248 @@ +{ + "preamble": { + "title": "sidan-lab/gov-crowdfund", + "description": "Aiken contracts for project 'sidan-lab/gov-crowdfund'", + "version": "0.0.0", + "plutusVersion": "v3", + "compiler": { + "name": "Aiken", + "version": "v1.1.7+e2fb28b" + }, + "license": "Apache-2.0" + }, + "validators": [ + { + "title": "start.start.withdraw", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + }, + { + "title": "start.start.mint", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1MintPolarity" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + }, + { + "title": "start.start.publish", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1PublishRedeemer" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + }, + { + "title": "start.start.propose", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + }, + { + "title": "start.start.vote", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + }, + { + "title": "start.start.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + } + ], + "definitions": { + "ByteArray": { + "dataType": "bytes" + }, + "Data": { + "title": "Data", + "description": "Any Plutus data." + }, + "Int": { + "dataType": "integer" + }, + "PolicyId": { + "title": "PolicyId", + "dataType": "bytes" + }, + "types/MintPolarity": { + "title": "MintPolarity", + "anyOf": [ + { + "title": "RMint", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "RBurn", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "types/PublishRedeemer": { + "title": "PublishRedeemer", + "anyOf": [ + { + "title": "Register", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "Deregister", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + } + } +} \ No newline at end of file diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak index 2c2fc36e3..33648a5f7 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak @@ -1,251 +1,251 @@ -use aiken/collection/list -use cardano/address.{Inline} -use cardano/assets.{Lovelace, lovelace_of} -use cardano/certificate.{Registered} -use cardano/governance.{GovernanceAction, ProposalProcedure} -use cardano/transaction.{OutputReference, Transaction, find_input} -use cocktail.{ - inputs_at, key_signed, only_minted_token, output_inline_datum, outputs_at, - valid_after, value_length, -} -use types.{ - ContributorWithdrawal, CrowdfundGovDatum, CrowdfundRedeemer, DeregisterCerts, - Init, Proposed, Refundable, RegisterCerts, RemoveEmptyInstance, -} -use utils.{ - check_lovelace_diff, delegate_stake_and_vote_certificate, - delegate_stake_certificate, delegate_vote_certificate, - register_drep_certificate, register_stake_certificate, - unregister_drep_certificate, unregister_stake_certificate, -} - -validator spend( - delegate_pool_id: ByteArray, - gov_action: GovernanceAction, - proposer_key_hash: ByteArray, - stake_register_deposit: Lovelace, - drep_register_deposit: Lovelace, -) { - spend( - datum_opt: Option, - redeemer: CrowdfundRedeemer, - input: OutputReference, - self: Transaction, - ) { - let Transaction { - inputs, - validity_range, - mint, - outputs, - extra_signatories, - certificates, - proposal_procedures, - .. - } = self - - expect Some(own_input) = find_input(inputs, input) - expect Some(only_input_datum) = datum_opt - - let current_address = own_input.output.address - - // check only 1 input from current address - expect [only_input] = inputs_at(inputs, current_address) - - when redeemer is { - RegisterCerts -> - when only_input_datum is { - Init { share_token, deadline, funds_controlled, completion_script } -> { - expect Some(current_stake_credential) = - current_address.stake_credential - - expect Inline(current_credential) = current_stake_credential - - expect [only_output] = outputs_at(outputs, current_address) - - let lovelace_from_only_input = - only_input.output.value |> lovelace_of() - - let lovelace_check = - check_lovelace_diff( - only_input, - only_output, - -(stake_register_deposit + drep_register_deposit), - ) - expect only_output_datum: CrowdfundGovDatum = - output_inline_datum(only_output) - let output_datum_check = - only_output_datum == Proposed { - completion_script, - share_token, - funds_controlled, - deadline, - } - - let is_only_output_value_clean = - value_length(only_output.value) == 1 - - let reg_stake_cert_check = - register_stake_certificate(certificates, current_credential) - - let reg_drep_cert_check = - register_drep_certificate( - certificates, - current_credential, - drep_register_deposit, - ) - - let delegate_check = - delegate_vote_certificate( - certificates, - current_credential, - Registered(current_credential), - ) && delegate_stake_certificate( - certificates, - current_credential, - delegate_pool_id, - ) || delegate_stake_and_vote_certificate( - certificates, - current_credential, - delegate_pool_id, - Registered(current_credential), - ) - - let proposal_check = - list.has( - proposal_procedures, - ProposalProcedure { - deposit: lovelace_from_only_input - stake_register_deposit - drep_register_deposit, - return_address: current_address.payment_credential, - governance_action: gov_action, - }, - ) - lovelace_check? && output_datum_check? && is_only_output_value_clean? && reg_stake_cert_check? && reg_drep_cert_check? && delegate_check? && proposal_check? - } - _ -> False - } - - DeregisterCerts -> - when only_input_datum is { - Refundable { - share_token, - deadline, - funds_controlled, - completion_script, - } -> { - expect Some(current_stake_credential) = - current_address.stake_credential - - expect Inline(current_credential) = current_stake_credential - let validity_check = valid_after(validity_range, deadline) - expect [only_output] = outputs_at(outputs, current_address) - let lovelace_check = - check_lovelace_diff( - only_input, - only_output, - stake_register_deposit + drep_register_deposit, - ) - - expect only_output_datum: CrowdfundGovDatum = - output_inline_datum(only_output) - let output_datum_check = - only_output_datum == Refundable { - completion_script, - share_token, - funds_controlled, - deadline, - } - - let unreg_stake_cert_check = - unregister_stake_certificate(certificates, current_credential) - - let unreg_drep_cert_check = - unregister_drep_certificate( - certificates, - current_credential, - drep_register_deposit, - ) - validity_check? && lovelace_check? && output_datum_check? && unreg_stake_cert_check? && unreg_drep_cert_check? - } - - _ -> False - } - - ContributorWithdrawal -> - when only_input_datum is { - Refundable { - share_token, - deadline, - funds_controlled, - completion_script, - } -> { - let validity_check = valid_after(validity_range, deadline) - - expect [only_output] = outputs_at(outputs, current_address) - - let lovelace_from_only_input = - only_input.output.value |> lovelace_of() - let lovelace_from_only_output = only_output.value |> lovelace_of() - - let lovelace_withdrawn = - lovelace_from_only_output - lovelace_from_only_input - - let lovelace_withdrawn_check = lovelace_withdrawn < 0 - - expect only_output_datum: CrowdfundGovDatum = - output_inline_datum(only_output) - let output_datum_check = - only_output_datum == Refundable { - completion_script, - share_token, - funds_controlled: funds_controlled + lovelace_withdrawn, - deadline, - } - - let is_only_output_value_clean = - value_length(only_output.value) == 1 - - validity_check? && lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( - mint, - share_token, - completion_script, - lovelace_withdrawn, - )? - } - _ -> False - } - - RemoveEmptyInstance -> - when only_input_datum is { - Refundable { - share_token, - deadline, - funds_controlled, - completion_script, - } -> { - let validity_check = valid_after(validity_range, deadline) - - let token_burnt_check = - if funds_controlled > 0 { - only_minted_token( - mint, - share_token, - completion_script, - -funds_controlled, - ) - } else { - True - } - - let proposer_key_signed_check = - key_signed(extra_signatories, proposer_key_hash) - validity_check? && token_burnt_check? && proposer_key_signed_check? - } - _ -> False - } - } - } - - else(_) { - fail - } -} +// use aiken/collection/list +// use cardano/address.{Inline} +// use cardano/assets.{Lovelace, lovelace_of} +// use cardano/certificate.{Registered} +// use cardano/governance.{GovernanceAction, ProposalProcedure} +// use cardano/transaction.{OutputReference, Transaction, find_input} +// use cocktail.{ +// inputs_at, key_signed, only_minted_token, output_inline_datum, outputs_at, +// valid_after, value_length, +// } +// use types.{ +// ContributorWithdrawal, CrowdfundGovDatum, CrowdfundRedeemer, DeregisterCerts, +// Init, Proposed, Refundable, RegisterCerts, RemoveEmptyInstance, +// } +// use utils.{ +// check_lovelace_diff, delegate_stake_and_vote_certificate, +// delegate_stake_certificate, delegate_vote_certificate, +// register_drep_certificate, register_stake_certificate, +// unregister_drep_certificate, unregister_stake_certificate, +// } + +// validator spend( +// delegate_pool_id: ByteArray, +// gov_action: GovernanceAction, +// proposer_key_hash: ByteArray, +// stake_register_deposit: Lovelace, +// drep_register_deposit: Lovelace, +// ) { +// spend( +// datum_opt: Option, +// redeemer: CrowdfundRedeemer, +// input: OutputReference, +// self: Transaction, +// ) { +// let Transaction { +// inputs, +// validity_range, +// mint, +// outputs, +// extra_signatories, +// certificates, +// proposal_procedures, +// .. +// } = self + +// expect Some(own_input) = find_input(inputs, input) +// expect Some(only_input_datum) = datum_opt + +// let current_address = own_input.output.address + +// // check only 1 input from current address +// expect [only_input] = inputs_at(inputs, current_address) + +// when redeemer is { +// RegisterCerts -> +// when only_input_datum is { +// Init { share_token, deadline, funds_controlled, completion_script } -> { +// expect Some(current_stake_credential) = +// current_address.stake_credential + +// expect Inline(current_credential) = current_stake_credential + +// expect [only_output] = outputs_at(outputs, current_address) + +// let lovelace_from_only_input = +// only_input.output.value |> lovelace_of() + +// let lovelace_check = +// check_lovelace_diff( +// only_input, +// only_output, +// -(stake_register_deposit + drep_register_deposit), +// ) +// expect only_output_datum: CrowdfundGovDatum = +// output_inline_datum(only_output) +// let output_datum_check = +// only_output_datum == Proposed { +// completion_script, +// share_token, +// funds_controlled, +// deadline, +// } + +// let is_only_output_value_clean = +// value_length(only_output.value) == 1 + +// let reg_stake_cert_check = +// register_stake_certificate(certificates, current_credential) + +// let reg_drep_cert_check = +// register_drep_certificate( +// certificates, +// current_credential, +// drep_register_deposit, +// ) + +// let delegate_check = +// delegate_vote_certificate( +// certificates, +// current_credential, +// Registered(current_credential), +// ) && delegate_stake_certificate( +// certificates, +// current_credential, +// delegate_pool_id, +// ) || delegate_stake_and_vote_certificate( +// certificates, +// current_credential, +// delegate_pool_id, +// Registered(current_credential), +// ) + +// let proposal_check = +// list.has( +// proposal_procedures, +// ProposalProcedure { +// deposit: lovelace_from_only_input - stake_register_deposit - drep_register_deposit, +// return_address: current_address.payment_credential, +// governance_action: gov_action, +// }, +// ) +// lovelace_check? && output_datum_check? && is_only_output_value_clean? && reg_stake_cert_check? && reg_drep_cert_check? && delegate_check? && proposal_check? +// } +// _ -> False +// } + +// DeregisterCerts -> +// when only_input_datum is { +// Refundable { +// share_token, +// deadline, +// funds_controlled, +// completion_script, +// } -> { +// expect Some(current_stake_credential) = +// current_address.stake_credential + +// expect Inline(current_credential) = current_stake_credential +// let validity_check = valid_after(validity_range, deadline) +// expect [only_output] = outputs_at(outputs, current_address) +// let lovelace_check = +// check_lovelace_diff( +// only_input, +// only_output, +// stake_register_deposit + drep_register_deposit, +// ) + +// expect only_output_datum: CrowdfundGovDatum = +// output_inline_datum(only_output) +// let output_datum_check = +// only_output_datum == Refundable { +// completion_script, +// share_token, +// funds_controlled, +// deadline, +// } + +// let unreg_stake_cert_check = +// unregister_stake_certificate(certificates, current_credential) + +// let unreg_drep_cert_check = +// unregister_drep_certificate( +// certificates, +// current_credential, +// drep_register_deposit, +// ) +// validity_check? && lovelace_check? && output_datum_check? && unreg_stake_cert_check? && unreg_drep_cert_check? +// } + +// _ -> False +// } + +// ContributorWithdrawal -> +// when only_input_datum is { +// Refundable { +// share_token, +// deadline, +// funds_controlled, +// completion_script, +// } -> { +// let validity_check = valid_after(validity_range, deadline) + +// expect [only_output] = outputs_at(outputs, current_address) + +// let lovelace_from_only_input = +// only_input.output.value |> lovelace_of() +// let lovelace_from_only_output = only_output.value |> lovelace_of() + +// let lovelace_withdrawn = +// lovelace_from_only_output - lovelace_from_only_input + +// let lovelace_withdrawn_check = lovelace_withdrawn < 0 + +// expect only_output_datum: CrowdfundGovDatum = +// output_inline_datum(only_output) +// let output_datum_check = +// only_output_datum == Refundable { +// completion_script, +// share_token, +// funds_controlled: funds_controlled + lovelace_withdrawn, +// deadline, +// } + +// let is_only_output_value_clean = +// value_length(only_output.value) == 1 + +// validity_check? && lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( +// mint, +// share_token, +// completion_script, +// lovelace_withdrawn, +// )? +// } +// _ -> False +// } + +// RemoveEmptyInstance -> +// when only_input_datum is { +// Refundable { +// share_token, +// deadline, +// funds_controlled, +// completion_script, +// } -> { +// let validity_check = valid_after(validity_range, deadline) + +// let token_burnt_check = +// if funds_controlled > 0 { +// only_minted_token( +// mint, +// share_token, +// completion_script, +// -funds_controlled, +// ) +// } else { +// True +// } + +// let proposer_key_signed_check = +// key_signed(extra_signatories, proposer_key_hash) +// validity_check? && token_burnt_check? && proposer_key_signed_check? +// } +// _ -> False +// } +// } +// } + +// else(_) { +// fail +// } +// } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak deleted file mode 100644 index 969dd4024..000000000 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/stake.ak +++ /dev/null @@ -1,36 +0,0 @@ -use cardano/address.{from_script} -use cardano/script_context.{ScriptContext} -use cardano/transaction.{Transaction} -use cocktail.{inputs_at} -use types.{ - CrowdfundRedeemer, Deregister, DeregisterCerts, Register, RegisterCerts, - StakeRedeemer, -} -use utils.{redeemer_with_input} - -validator stake(spend_script_hash: ByteArray) { - else(ctx: ScriptContext) { - let ScriptContext { transaction, redeemer, .. } = ctx - expect stake_redeemer: StakeRedeemer = redeemer - let Transaction { inputs, redeemers, .. } = transaction - let spend_address = from_script(spend_script_hash) - expect [only_input] = inputs_at(inputs, spend_address) - expect Some(only_inpuy_redeemer_data) = - redeemer_with_input(redeemers, only_input) - - expect only_input_redeemer: CrowdfundRedeemer = only_inpuy_redeemer_data - - when stake_redeemer is { - Register -> { - let redeemer_check = only_input_redeemer == RegisterCerts - - redeemer_check? - } - Deregister -> { - let redeemer_check = only_input_redeemer == DeregisterCerts - - redeemer_check? - } - } - } -} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak index ce4fff784..12dea9345 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak @@ -1,20 +1,25 @@ -use cardano/address.{Address, Credential, Inline, Script} +use aiken/collection/pairs.{has_key} +use cardano/address.{Address, Credential, Inline, Script, from_script} use cardano/assets.{PolicyId, lovelace_of} use cardano/transaction.{Transaction} use cocktail.{ - input_inline_datum, inputs_with_policy, output_inline_datum, outputs_at, + input_inline_datum, inputs_at, inputs_with_policy, output_inline_datum, + outputs_at_with, policy_only_minted_token, } -use types.{CrowdfundDatum, CrowdfundGovDatum, Init} +use types.{ + CrowdfundDatum, CrowdfundGovDatum, CrowdfundRedeemer, Deregister, + DeregisterCerts, Init, MintPolarity, PublishRedeemer, RBurn, RMint, Register, + RegisterCerts, RemoveEmptyInstance, VoteOnGovAction, +} +use utils.{check_spend_script_input_redeemer, redeemer_with_input} validator start( auth_token: PolicyId, spend: ByteArray, - stake: ByteArray, gov_action_period: Int, ) { withdraw(_r, account: Credential, self: Transaction) { - let Transaction { inputs, outputs, .. } = self - + let Transaction { inputs, outputs, mint, .. } = self expect [auth_token_input] = inputs_with_policy(inputs, auth_token) expect auth_input_datum: CrowdfundDatum = input_inline_datum(auth_token_input) @@ -32,10 +37,11 @@ validator start( let gov_address = Address { payment_credential: Script(spend), - stake_credential: Some(Inline(Script(stake))), + stake_credential: Some(Inline(Script(completion_script))), } - expect [fundraise_target_output] = outputs_at(outputs, gov_address) + expect [fundraise_target_output] = + outputs_at_with(outputs, gov_address, completion_script, "") let fundraise_output_lovelace_check = lovelace_of(fundraise_target_output.value) == fundraise_target @@ -43,12 +49,71 @@ validator start( output_inline_datum(fundraise_target_output) let fundraise_output_datum_check = fundraise_output_datum == Init { - completion_script, + start_hash: completion_script, share_token, funds_controlled: current_fundraised_amount, deadline: deadline + gov_action_period, } - completion_script_check? && fundraise_output_lovelace_check? && fundraise_output_datum_check? + completion_script_check? && fundraise_output_lovelace_check? && fundraise_output_datum_check? && policy_only_minted_token( + mint, + completion_script, + "", + 1, + )? + } + + mint(redeemer: MintPolarity, policy_id: PolicyId, self: Transaction) { + let Transaction { withdrawals, inputs, redeemers, .. } = self + when redeemer is { + RMint -> { + let withdrawal_credential: Credential = Script(policy_id) + let withdrawal_script_check = + withdrawals + |> has_key(withdrawal_credential) + + withdrawal_script_check? + } + RBurn -> + check_spend_script_input_redeemer( + spend, + inputs, + redeemers, + RemoveEmptyInstance, + )? + } + } + + publish(redeemer: PublishRedeemer, _c, self: Transaction) { + let Transaction { inputs, redeemers, .. } = self + let spend_address = from_script(spend) + expect [only_input] = inputs_at(inputs, spend_address) + expect Some(only_inpuy_redeemer_data) = + redeemer_with_input(redeemers, only_input) + + expect only_input_redeemer: CrowdfundRedeemer = only_inpuy_redeemer_data + + when redeemer is { + Register -> { + let redeemer_check = only_input_redeemer == RegisterCerts + + redeemer_check? + } + Deregister -> { + let redeemer_check = only_input_redeemer == DeregisterCerts + + redeemer_check? + } + } + } + + propose(_r, _p, self: Transaction) { + let Transaction { inputs, redeemers, .. } = self + check_spend_script_input_redeemer(spend, inputs, redeemers, RegisterCerts)? + } + + vote(_r, _v, self: Transaction) { + let Transaction { inputs, redeemers, .. } = self + check_spend_script_input_redeemer(spend, inputs, redeemers, VoteOnGovAction)? } else(_) { diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak index 1e5e6e438..5f3e69afd 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak @@ -1,1369 +1,1369 @@ -use cardano/address.{Script} -use cardano/assets.{add, from_lovelace} -use cardano/certificate.{ - DelegateBlockProduction, DelegateCredential, DelegateVote, RegisterCredential, - RegisterDelegateRepresentative, Registered, UnregisterCredential, - UnregisterDelegateRepresentative, -} -use cardano/governance.{ProposalProcedure} -use cardano/transaction.{Transaction} -use mocktail.{ - add_certificate, add_extra_signatory, complete, invalid_before, mint, - mock_policy_id, mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, - tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, -} -use spend -use tests/utils.{ - add_proposal_procedure, mock_completion_script, - mock_contribute_min_fundraised_amount, mock_current_fundraised_amount, - mock_deadline, mock_delegate_pool_id, mock_drep_register_deposit, - mock_funds_controlled, mock_gov_action, mock_gov_action_period, - mock_gov_address, mock_proposer_key_hash, mock_share_token, - mock_spend_script_hash, mock_stake_register_deposit, mock_stake_script_hash, -} -use types.{ - ContributorWithdrawal, Init, Proposed, Refundable, RegisterCerts, - RemoveEmptyInstance, -} - -type RegisterCertsTestCase { - is_only_one_inputed: Bool, - is_only_one_outputed: Bool, - is_output_datum_correct: Bool, - is_output_value_clean: Bool, - is_output_value_correct: Bool, - is_stake_cert_register: Bool, - is_drep_cert_register: Bool, - is_drep_deposit_correct: Bool, - is_stake_delegated: Bool, - is_vote_delegated: Bool, - is_gov_proposed: Bool, -} - -fn mock_register_cert_tx(test_case: RegisterCertsTestCase) -> Transaction { - let RegisterCertsTestCase { - is_only_one_inputed, - is_only_one_outputed, - is_output_datum_correct, - is_output_value_clean, - is_output_value_correct, - is_stake_cert_register, - is_drep_cert_register, - is_drep_deposit_correct, - is_stake_delegated, - is_vote_delegated, - is_gov_proposed, - } = test_case - - let input_value = from_lovelace(mock_funds_controlled) - - let input_datum = - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - } - let output_value = - if is_output_value_correct { - from_lovelace( - mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, - ) - } else { - from_lovelace( - mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit + 10, - ) - } - - let output_datum = - if is_output_datum_correct { - Proposed { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - } - } else { - Proposed { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled + 10, - deadline: mock_deadline + mock_gov_action_period, - } - } - - let drep_deposit = - if is_drep_deposit_correct { - mock_drep_register_deposit - } else { - mock_drep_register_deposit - 1000000 - } - mocktail_tx() - |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) - |> tx_in_inline_datum(True, input_datum) - |> tx_in( - !is_only_one_inputed, - mock_tx_hash(0), - 1, - input_value, - mock_gov_address, - ) - |> tx_out(is_output_value_clean, mock_gov_address, output_value) - |> tx_out( - !is_output_value_clean, - mock_gov_address, - output_value |> add(mock_policy_id(999), mock_completion_script, 1), - ) - |> tx_out_inline_datum(True, output_datum) - |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) - |> complete() - |> add_certificate( - is_stake_cert_register, - RegisterCredential { - credential: Script(mock_stake_script_hash), - deposit: Never, - }, - ) - |> add_certificate( - is_drep_cert_register, - RegisterDelegateRepresentative { - delegate_representative: Script(mock_stake_script_hash), - deposit: drep_deposit, - }, - ) - |> add_certificate( - is_stake_delegated, - DelegateCredential { - credential: Script(mock_stake_script_hash), - delegate: DelegateBlockProduction { - stake_pool: mock_delegate_pool_id, - }, - }, - ) - |> add_certificate( - is_vote_delegated, - DelegateCredential { - credential: Script(mock_stake_script_hash), - delegate: DelegateVote { - delegate_representative: Registered(Script(mock_stake_script_hash)), - }, - }, - ) - |> add_proposal_procedure( - is_gov_proposed, - ProposalProcedure { - deposit: mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, - return_address: Script(mock_spend_script_hash), - governance_action: mock_gov_action, - }, - ) -} - -test s3_spend_success_reg_cert() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_not_init_state() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Proposed { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_more_than_one_input() fail { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: False, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_more_than_one_output() fail { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: False, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_incorrect_output_datum() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: False, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_output_value_not_clean() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: False, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_incorrect_output_value() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: False, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_stake_cert_not_reg() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: False, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_drep_cert_not_reg() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: False, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_drep_deposit_incorrect() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: False, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_stake_not_delegated() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: False, - is_vote_delegated: True, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_vote_not_delegated() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: False, - is_gov_proposed: True, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_reg_cert_with_gov_not_proposed() { - let tx = - mock_register_cert_tx( - RegisterCertsTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_output_value_correct: True, - is_stake_cert_register: True, - is_drep_cert_register: True, - is_drep_deposit_correct: True, - is_stake_delegated: True, - is_vote_delegated: True, - is_gov_proposed: False, - }, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_funds_controlled, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RegisterCerts, - mock_utxo_ref(0, 0), - tx, - ) -} - -type ContributorWithdrawalTestCase { - is_only_one_inputed: Bool, - is_only_one_outputed: Bool, - is_output_datum_correct: Bool, - is_output_value_clean: Bool, - is_unlock_value_correct: Bool, - is_deadline_passed: Bool, - is_shares_burnt: Bool, -} - -fn mock_contributor_withdrawal_tx( - test_case: ContributorWithdrawalTestCase, - current_fundraised_amount: Int, - withdraw_amount: Int, -) -> Transaction { - let ContributorWithdrawalTestCase { - is_only_one_inputed, - is_only_one_outputed, - is_output_datum_correct, - is_output_value_clean, - is_unlock_value_correct, - is_deadline_passed, - is_shares_burnt, - } = test_case - - let input_value = from_lovelace(current_fundraised_amount) - - let input_datum = - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - } - let output_value = - if is_unlock_value_correct { - from_lovelace(current_fundraised_amount - withdraw_amount) - } else { - from_lovelace(current_fundraised_amount - withdraw_amount + 10) - } - - let output_datum = - if is_output_datum_correct { - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: current_fundraised_amount - withdraw_amount, - deadline: mock_deadline + mock_gov_action_period, - } - } else { - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: current_fundraised_amount - withdraw_amount + 10, - deadline: mock_deadline + mock_gov_action_period, - } - } - - mocktail_tx() - |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) - |> tx_in_inline_datum(True, input_datum) - |> tx_in( - !is_only_one_inputed, - mock_tx_hash(0), - 1, - input_value, - mock_gov_address, - ) - |> tx_out(True, mock_pub_key_address(0, None), from_lovelace(withdraw_amount)) - |> tx_out(is_output_value_clean, mock_gov_address, output_value) - |> tx_out( - !is_output_value_clean, - mock_gov_address, - output_value |> add(mock_policy_id(999), mock_completion_script, 1), - ) - |> tx_out_inline_datum(True, output_datum) - |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) - |> invalid_before( - is_deadline_passed, - mock_deadline + mock_gov_action_period + 3600 * 24, - ) - |> invalid_before( - !is_deadline_passed, - mock_deadline + mock_gov_action_period - 3600 * 24, - ) - |> mint( - is_shares_burnt, - -withdraw_amount, - mock_share_token, - mock_completion_script, - ) - |> mint( - !is_shares_burnt, - -withdraw_amount + 9999999, - mock_share_token, - mock_completion_script, - ) - |> complete() -} - -test s3_spend_success_contributor_withdraw() { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_unlock_value_correct: True, - is_deadline_passed: True, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_state_not_refundable() { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_unlock_value_correct: True, - is_deadline_passed: True, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Proposed { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: False, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_unlock_value_correct: True, - is_deadline_passed: True, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: False, - is_output_datum_correct: True, - is_output_value_clean: True, - is_unlock_value_correct: True, - is_deadline_passed: True, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: False, - is_output_value_clean: True, - is_unlock_value_correct: True, - is_deadline_passed: True, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: False, - is_unlock_value_correct: True, - is_deadline_passed: True, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_unlock_value_correct: False, - is_deadline_passed: True, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_deadline_not_passed() { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_unlock_value_correct: True, - is_deadline_passed: False, - is_shares_burnt: True, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { - let tx = - mock_contributor_withdrawal_tx( - ContributorWithdrawalTestCase { - is_only_one_inputed: True, - is_only_one_outputed: True, - is_output_datum_correct: True, - is_output_value_clean: True, - is_unlock_value_correct: True, - is_deadline_passed: True, - is_shares_burnt: False, - }, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - ContributorWithdrawal, - mock_utxo_ref(0, 0), - tx, - ) -} - -type RemoveEmptyInstanceTestCase { - is_only_one_inputed: Bool, - is_deadline_passed: Bool, - is_shares_burnt: Bool, - is_proposer_signed: Bool, -} - -fn mock_remove_empty_instance_tx( - test_case: RemoveEmptyInstanceTestCase, - current_fundraised_amount: Int, -) -> Transaction { - let RemoveEmptyInstanceTestCase { - is_only_one_inputed, - is_deadline_passed, - is_shares_burnt, - is_proposer_signed, - } = test_case - - let input_value = from_lovelace(current_fundraised_amount) - - let input_datum = - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - } - - mocktail_tx() - |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) - |> tx_in_inline_datum(True, input_datum) - |> tx_in( - !is_only_one_inputed, - mock_tx_hash(0), - 1, - input_value, - mock_gov_address, - ) - |> tx_out( - True, - mock_pub_key_address(0, None), - from_lovelace(current_fundraised_amount), - ) - |> invalid_before( - is_deadline_passed, - mock_deadline + mock_gov_action_period + 3600 * 24, - ) - |> invalid_before( - !is_deadline_passed, - mock_deadline + mock_gov_action_period - 3600 * 24, - ) - |> mint( - is_shares_burnt, - -current_fundraised_amount, - mock_share_token, - mock_completion_script, - ) - |> mint( - !is_shares_burnt, - -current_fundraised_amount + 9999999, - mock_share_token, - mock_completion_script, - ) - |> complete() - |> add_extra_signatory(is_proposer_signed, mock_proposer_key_hash) -} - -test s3_spend_success_remove_empty_instance_wih_zero_fund() { - let tx = - mock_remove_empty_instance_tx( - RemoveEmptyInstanceTestCase { - is_only_one_inputed: True, - is_deadline_passed: True, - is_shares_burnt: True, - is_proposer_signed: True, - }, - 0, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: 0, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RemoveEmptyInstance, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_success_remove_empty_instance_wih_some_fund() { - let tx = - mock_remove_empty_instance_tx( - RemoveEmptyInstanceTestCase { - is_only_one_inputed: True, - is_deadline_passed: True, - is_shares_burnt: True, - is_proposer_signed: True, - }, - mock_current_fundraised_amount, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RemoveEmptyInstance, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_remove_empty_instance_wih_state_not_refundable() { - let tx = - mock_remove_empty_instance_tx( - RemoveEmptyInstanceTestCase { - is_only_one_inputed: True, - is_deadline_passed: True, - is_shares_burnt: True, - is_proposer_signed: True, - }, - mock_current_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RemoveEmptyInstance, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { - let tx = - mock_remove_empty_instance_tx( - RemoveEmptyInstanceTestCase { - is_only_one_inputed: False, - is_deadline_passed: True, - is_shares_burnt: True, - is_proposer_signed: True, - }, - mock_current_fundraised_amount, - ) - - spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RemoveEmptyInstance, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { - let tx = - mock_remove_empty_instance_tx( - RemoveEmptyInstanceTestCase { - is_only_one_inputed: True, - is_deadline_passed: False, - is_shares_burnt: True, - is_proposer_signed: True, - }, - mock_current_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RemoveEmptyInstance, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { - let tx = - mock_remove_empty_instance_tx( - RemoveEmptyInstanceTestCase { - is_only_one_inputed: True, - is_deadline_passed: True, - is_shares_burnt: False, - is_proposer_signed: True, - }, - mock_current_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RemoveEmptyInstance, - mock_utxo_ref(0, 0), - tx, - ) -} - -test s3_spend_fail_remove_empty_instance_wih_proposer_not_signed() { - let tx = - mock_remove_empty_instance_tx( - RemoveEmptyInstanceTestCase { - is_only_one_inputed: True, - is_deadline_passed: True, - is_shares_burnt: True, - is_proposer_signed: False, - }, - mock_current_fundraised_amount, - ) - - !spend.spend.spend( - mock_delegate_pool_id, - mock_gov_action, - mock_proposer_key_hash, - mock_stake_register_deposit, - mock_drep_register_deposit, - Some( - Refundable { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - }, - ), - RemoveEmptyInstance, - mock_utxo_ref(0, 0), - tx, - ) -} +// use cardano/address.{Script} +// use cardano/assets.{add, from_lovelace} +// use cardano/certificate.{ +// DelegateBlockProduction, DelegateCredential, DelegateVote, RegisterCredential, +// RegisterDelegateRepresentative, Registered, UnregisterCredential, +// UnregisterDelegateRepresentative, +// } +// use cardano/governance.{ProposalProcedure} +// use cardano/transaction.{Transaction} +// use mocktail.{ +// add_certificate, add_extra_signatory, complete, invalid_before, mint, +// mock_policy_id, mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, +// tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, +// } +// use spend +// use tests/utils.{ +// add_proposal_procedure, mock_completion_script, +// mock_contribute_min_fundraised_amount, mock_current_fundraised_amount, +// mock_deadline, mock_delegate_pool_id, mock_drep_register_deposit, +// mock_funds_controlled, mock_gov_action, mock_gov_action_period, +// mock_gov_address, mock_proposer_key_hash, mock_share_token, +// mock_spend_script_hash, mock_stake_register_deposit, mock_stake_script_hash, +// } +// use types.{ +// ContributorWithdrawal, Init, Proposed, Refundable, RegisterCerts, +// RemoveEmptyInstance, +// } + +// type RegisterCertsTestCase { +// is_only_one_inputed: Bool, +// is_only_one_outputed: Bool, +// is_output_datum_correct: Bool, +// is_output_value_clean: Bool, +// is_output_value_correct: Bool, +// is_stake_cert_register: Bool, +// is_drep_cert_register: Bool, +// is_drep_deposit_correct: Bool, +// is_stake_delegated: Bool, +// is_vote_delegated: Bool, +// is_gov_proposed: Bool, +// } + +// fn mock_register_cert_tx(test_case: RegisterCertsTestCase) -> Transaction { +// let RegisterCertsTestCase { +// is_only_one_inputed, +// is_only_one_outputed, +// is_output_datum_correct, +// is_output_value_clean, +// is_output_value_correct, +// is_stake_cert_register, +// is_drep_cert_register, +// is_drep_deposit_correct, +// is_stake_delegated, +// is_vote_delegated, +// is_gov_proposed, +// } = test_case + +// let input_value = from_lovelace(mock_funds_controlled) + +// let input_datum = +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// } +// let output_value = +// if is_output_value_correct { +// from_lovelace( +// mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, +// ) +// } else { +// from_lovelace( +// mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit + 10, +// ) +// } + +// let output_datum = +// if is_output_datum_correct { +// Proposed { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// } +// } else { +// Proposed { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled + 10, +// deadline: mock_deadline + mock_gov_action_period, +// } +// } + +// let drep_deposit = +// if is_drep_deposit_correct { +// mock_drep_register_deposit +// } else { +// mock_drep_register_deposit - 1000000 +// } +// mocktail_tx() +// |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) +// |> tx_in_inline_datum(True, input_datum) +// |> tx_in( +// !is_only_one_inputed, +// mock_tx_hash(0), +// 1, +// input_value, +// mock_gov_address, +// ) +// |> tx_out(is_output_value_clean, mock_gov_address, output_value) +// |> tx_out( +// !is_output_value_clean, +// mock_gov_address, +// output_value |> add(mock_policy_id(999), mock_completion_script, 1), +// ) +// |> tx_out_inline_datum(True, output_datum) +// |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) +// |> complete() +// |> add_certificate( +// is_stake_cert_register, +// RegisterCredential { +// credential: Script(mock_stake_script_hash), +// deposit: Never, +// }, +// ) +// |> add_certificate( +// is_drep_cert_register, +// RegisterDelegateRepresentative { +// delegate_representative: Script(mock_stake_script_hash), +// deposit: drep_deposit, +// }, +// ) +// |> add_certificate( +// is_stake_delegated, +// DelegateCredential { +// credential: Script(mock_stake_script_hash), +// delegate: DelegateBlockProduction { +// stake_pool: mock_delegate_pool_id, +// }, +// }, +// ) +// |> add_certificate( +// is_vote_delegated, +// DelegateCredential { +// credential: Script(mock_stake_script_hash), +// delegate: DelegateVote { +// delegate_representative: Registered(Script(mock_stake_script_hash)), +// }, +// }, +// ) +// |> add_proposal_procedure( +// is_gov_proposed, +// ProposalProcedure { +// deposit: mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, +// return_address: Script(mock_spend_script_hash), +// governance_action: mock_gov_action, +// }, +// ) +// } + +// test s3_spend_success_reg_cert() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_not_init_state() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Proposed { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_more_than_one_input() fail { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: False, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_more_than_one_output() fail { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: False, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_incorrect_output_datum() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: False, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_output_value_not_clean() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: False, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_incorrect_output_value() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: False, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_stake_cert_not_reg() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: False, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_drep_cert_not_reg() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: False, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_drep_deposit_incorrect() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: False, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_stake_not_delegated() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: False, +// is_vote_delegated: True, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_vote_not_delegated() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: False, +// is_gov_proposed: True, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_reg_cert_with_gov_not_proposed() { +// let tx = +// mock_register_cert_tx( +// RegisterCertsTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_output_value_correct: True, +// is_stake_cert_register: True, +// is_drep_cert_register: True, +// is_drep_deposit_correct: True, +// is_stake_delegated: True, +// is_vote_delegated: True, +// is_gov_proposed: False, +// }, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_funds_controlled, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RegisterCerts, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// type ContributorWithdrawalTestCase { +// is_only_one_inputed: Bool, +// is_only_one_outputed: Bool, +// is_output_datum_correct: Bool, +// is_output_value_clean: Bool, +// is_unlock_value_correct: Bool, +// is_deadline_passed: Bool, +// is_shares_burnt: Bool, +// } + +// fn mock_contributor_withdrawal_tx( +// test_case: ContributorWithdrawalTestCase, +// current_fundraised_amount: Int, +// withdraw_amount: Int, +// ) -> Transaction { +// let ContributorWithdrawalTestCase { +// is_only_one_inputed, +// is_only_one_outputed, +// is_output_datum_correct, +// is_output_value_clean, +// is_unlock_value_correct, +// is_deadline_passed, +// is_shares_burnt, +// } = test_case + +// let input_value = from_lovelace(current_fundraised_amount) + +// let input_datum = +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// } +// let output_value = +// if is_unlock_value_correct { +// from_lovelace(current_fundraised_amount - withdraw_amount) +// } else { +// from_lovelace(current_fundraised_amount - withdraw_amount + 10) +// } + +// let output_datum = +// if is_output_datum_correct { +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: current_fundraised_amount - withdraw_amount, +// deadline: mock_deadline + mock_gov_action_period, +// } +// } else { +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: current_fundraised_amount - withdraw_amount + 10, +// deadline: mock_deadline + mock_gov_action_period, +// } +// } + +// mocktail_tx() +// |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) +// |> tx_in_inline_datum(True, input_datum) +// |> tx_in( +// !is_only_one_inputed, +// mock_tx_hash(0), +// 1, +// input_value, +// mock_gov_address, +// ) +// |> tx_out(True, mock_pub_key_address(0, None), from_lovelace(withdraw_amount)) +// |> tx_out(is_output_value_clean, mock_gov_address, output_value) +// |> tx_out( +// !is_output_value_clean, +// mock_gov_address, +// output_value |> add(mock_policy_id(999), mock_completion_script, 1), +// ) +// |> tx_out_inline_datum(True, output_datum) +// |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) +// |> invalid_before( +// is_deadline_passed, +// mock_deadline + mock_gov_action_period + 3600 * 24, +// ) +// |> invalid_before( +// !is_deadline_passed, +// mock_deadline + mock_gov_action_period - 3600 * 24, +// ) +// |> mint( +// is_shares_burnt, +// -withdraw_amount, +// mock_share_token, +// mock_completion_script, +// ) +// |> mint( +// !is_shares_burnt, +// -withdraw_amount + 9999999, +// mock_share_token, +// mock_completion_script, +// ) +// |> complete() +// } + +// test s3_spend_success_contributor_withdraw() { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_unlock_value_correct: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_state_not_refundable() { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_unlock_value_correct: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Proposed { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: False, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_unlock_value_correct: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: False, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_unlock_value_correct: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: False, +// is_output_value_clean: True, +// is_unlock_value_correct: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: False, +// is_unlock_value_correct: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_unlock_value_correct: False, +// is_deadline_passed: True, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_deadline_not_passed() { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_unlock_value_correct: True, +// is_deadline_passed: False, +// is_shares_burnt: True, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { +// let tx = +// mock_contributor_withdrawal_tx( +// ContributorWithdrawalTestCase { +// is_only_one_inputed: True, +// is_only_one_outputed: True, +// is_output_datum_correct: True, +// is_output_value_clean: True, +// is_unlock_value_correct: True, +// is_deadline_passed: True, +// is_shares_burnt: False, +// }, +// mock_current_fundraised_amount, +// mock_contribute_min_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// type RemoveEmptyInstanceTestCase { +// is_only_one_inputed: Bool, +// is_deadline_passed: Bool, +// is_shares_burnt: Bool, +// is_proposer_signed: Bool, +// } + +// fn mock_remove_empty_instance_tx( +// test_case: RemoveEmptyInstanceTestCase, +// current_fundraised_amount: Int, +// ) -> Transaction { +// let RemoveEmptyInstanceTestCase { +// is_only_one_inputed, +// is_deadline_passed, +// is_shares_burnt, +// is_proposer_signed, +// } = test_case + +// let input_value = from_lovelace(current_fundraised_amount) + +// let input_datum = +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// } + +// mocktail_tx() +// |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) +// |> tx_in_inline_datum(True, input_datum) +// |> tx_in( +// !is_only_one_inputed, +// mock_tx_hash(0), +// 1, +// input_value, +// mock_gov_address, +// ) +// |> tx_out( +// True, +// mock_pub_key_address(0, None), +// from_lovelace(current_fundraised_amount), +// ) +// |> invalid_before( +// is_deadline_passed, +// mock_deadline + mock_gov_action_period + 3600 * 24, +// ) +// |> invalid_before( +// !is_deadline_passed, +// mock_deadline + mock_gov_action_period - 3600 * 24, +// ) +// |> mint( +// is_shares_burnt, +// -current_fundraised_amount, +// mock_share_token, +// mock_completion_script, +// ) +// |> mint( +// !is_shares_burnt, +// -current_fundraised_amount + 9999999, +// mock_share_token, +// mock_completion_script, +// ) +// |> complete() +// |> add_extra_signatory(is_proposer_signed, mock_proposer_key_hash) +// } + +// test s3_spend_success_remove_empty_instance_wih_zero_fund() { +// let tx = +// mock_remove_empty_instance_tx( +// RemoveEmptyInstanceTestCase { +// is_only_one_inputed: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// is_proposer_signed: True, +// }, +// 0, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: 0, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RemoveEmptyInstance, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_success_remove_empty_instance_wih_some_fund() { +// let tx = +// mock_remove_empty_instance_tx( +// RemoveEmptyInstanceTestCase { +// is_only_one_inputed: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// is_proposer_signed: True, +// }, +// mock_current_fundraised_amount, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RemoveEmptyInstance, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_remove_empty_instance_wih_state_not_refundable() { +// let tx = +// mock_remove_empty_instance_tx( +// RemoveEmptyInstanceTestCase { +// is_only_one_inputed: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// is_proposer_signed: True, +// }, +// mock_current_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RemoveEmptyInstance, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { +// let tx = +// mock_remove_empty_instance_tx( +// RemoveEmptyInstanceTestCase { +// is_only_one_inputed: False, +// is_deadline_passed: True, +// is_shares_burnt: True, +// is_proposer_signed: True, +// }, +// mock_current_fundraised_amount, +// ) + +// spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RemoveEmptyInstance, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { +// let tx = +// mock_remove_empty_instance_tx( +// RemoveEmptyInstanceTestCase { +// is_only_one_inputed: True, +// is_deadline_passed: False, +// is_shares_burnt: True, +// is_proposer_signed: True, +// }, +// mock_current_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RemoveEmptyInstance, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { +// let tx = +// mock_remove_empty_instance_tx( +// RemoveEmptyInstanceTestCase { +// is_only_one_inputed: True, +// is_deadline_passed: True, +// is_shares_burnt: False, +// is_proposer_signed: True, +// }, +// mock_current_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RemoveEmptyInstance, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +// test s3_spend_fail_remove_empty_instance_wih_proposer_not_signed() { +// let tx = +// mock_remove_empty_instance_tx( +// RemoveEmptyInstanceTestCase { +// is_only_one_inputed: True, +// is_deadline_passed: True, +// is_shares_burnt: True, +// is_proposer_signed: False, +// }, +// mock_current_fundraised_amount, +// ) + +// !spend.spend.spend( +// mock_delegate_pool_id, +// mock_gov_action, +// mock_proposer_key_hash, +// mock_stake_register_deposit, +// mock_drep_register_deposit, +// Some( +// Refundable { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// }, +// ), +// RemoveEmptyInstance, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak index e7188fa6a..327822a1e 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak @@ -1,149 +1,149 @@ -use cardano/assets.{from_lovelace} -use cardano/certificate.{RegisterCredential} -use cardano/script_context.{Publishing, ScriptContext} -use cardano/transaction.{OutputReference, Spend, Transaction} -use mocktail.{ - add_redeemer, complete, mock_script_credential, mock_tx_hash, mocktail_tx, - tx_in, -} -use stake -use tests/utils.{ - mock_crowdfund_gov_address, mock_fundraise_target, mock_spend_script_hash, -} -use types.{Deregister, DeregisterCerts, Register, RegisterCerts} +// use cardano/assets.{from_lovelace} +// use cardano/certificate.{RegisterCredential} +// use cardano/script_context.{Publishing, ScriptContext} +// use cardano/transaction.{OutputReference, Spend, Transaction} +// use mocktail.{ +// add_redeemer, complete, mock_script_credential, mock_tx_hash, mocktail_tx, +// tx_in, +// } +// use stake +// use tests/utils.{ +// mock_crowdfund_gov_address, mock_fundraise_target, mock_spend_script_hash, +// } +// use types.{Deregister, DeregisterCerts, Register, RegisterCerts} -type StakeTestCase { - is_only_one_auth_inputed: Bool, -} +// type StakeTestCase { +// is_only_one_auth_inputed: Bool, +// } -fn mock_stake_tx( - test_case: StakeTestCase, - only_input_redeemer: Data, -) -> Transaction { - let StakeTestCase { is_only_one_auth_inputed } = test_case - let only_input = from_lovelace(mock_fundraise_target) - mocktail_tx() - |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_gov_address) - |> tx_in( - !is_only_one_auth_inputed, - mock_tx_hash(0), - 1, - only_input, - mock_crowdfund_gov_address, - ) - |> complete() - |> add_redeemer( - True, - Pair( - Spend( - OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, - ), - only_input_redeemer, - ), - ) -} +// fn mock_stake_tx( +// test_case: StakeTestCase, +// only_input_redeemer: Data, +// ) -> Transaction { +// let StakeTestCase { is_only_one_auth_inputed } = test_case +// let only_input = from_lovelace(mock_fundraise_target) +// mocktail_tx() +// |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_gov_address) +// |> tx_in( +// !is_only_one_auth_inputed, +// mock_tx_hash(0), +// 1, +// only_input, +// mock_crowdfund_gov_address, +// ) +// |> complete() +// |> add_redeemer( +// True, +// Pair( +// Spend( +// OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, +// ), +// only_input_redeemer, +// ), +// ) +// } -test s2_success_stake_with_reg() { - let only_input_redeemer: Data = RegisterCerts +// test s2_success_stake_with_reg() { +// let only_input_redeemer: Data = RegisterCerts - let ctx = - ScriptContext { - transaction: mock_stake_tx( - StakeTestCase { is_only_one_auth_inputed: True }, - only_input_redeemer, - ), - redeemer: Register, - info: Publishing { - at: 0, - certificate: RegisterCredential { - credential: mock_script_credential(0), - deposit: Never, - }, - }, - } - stake.stake.else(mock_spend_script_hash, ctx) -} +// let ctx = +// ScriptContext { +// transaction: mock_stake_tx( +// StakeTestCase { is_only_one_auth_inputed: True }, +// only_input_redeemer, +// ), +// redeemer: Register, +// info: Publishing { +// at: 0, +// certificate: RegisterCredential { +// credential: mock_script_credential(0), +// deposit: Never, +// }, +// }, +// } +// stake.stake.else(mock_spend_script_hash, ctx) +// } -test s2_success_stake_with_dereg() { - let only_input_redeemer: Data = DeregisterCerts +// test s2_success_stake_with_dereg() { +// let only_input_redeemer: Data = DeregisterCerts - let ctx = - ScriptContext { - transaction: mock_stake_tx( - StakeTestCase { is_only_one_auth_inputed: True }, - only_input_redeemer, - ), - redeemer: Deregister, - info: Publishing { - at: 0, - certificate: RegisterCredential { - credential: mock_script_credential(0), - deposit: Never, - }, - }, - } - stake.stake.else(mock_spend_script_hash, ctx) -} +// let ctx = +// ScriptContext { +// transaction: mock_stake_tx( +// StakeTestCase { is_only_one_auth_inputed: True }, +// only_input_redeemer, +// ), +// redeemer: Deregister, +// info: Publishing { +// at: 0, +// certificate: RegisterCredential { +// credential: mock_script_credential(0), +// deposit: Never, +// }, +// }, +// } +// stake.stake.else(mock_spend_script_hash, ctx) +// } -test s2_fail_stake_with_reg_but_deregister_cert() { - let only_input_redeemer: Data = DeregisterCerts +// test s2_fail_stake_with_reg_but_deregister_cert() { +// let only_input_redeemer: Data = DeregisterCerts - let ctx = - ScriptContext { - transaction: mock_stake_tx( - StakeTestCase { is_only_one_auth_inputed: True }, - only_input_redeemer, - ), - redeemer: Register, - info: Publishing { - at: 0, - certificate: RegisterCredential { - credential: mock_script_credential(0), - deposit: Never, - }, - }, - } - !stake.stake.else(mock_spend_script_hash, ctx) -} +// let ctx = +// ScriptContext { +// transaction: mock_stake_tx( +// StakeTestCase { is_only_one_auth_inputed: True }, +// only_input_redeemer, +// ), +// redeemer: Register, +// info: Publishing { +// at: 0, +// certificate: RegisterCredential { +// credential: mock_script_credential(0), +// deposit: Never, +// }, +// }, +// } +// !stake.stake.else(mock_spend_script_hash, ctx) +// } -test s2_fail_stake_with_dereg_but_register_cert() { - let only_input_redeemer: Data = RegisterCerts +// test s2_fail_stake_with_dereg_but_register_cert() { +// let only_input_redeemer: Data = RegisterCerts - let ctx = - ScriptContext { - transaction: mock_stake_tx( - StakeTestCase { is_only_one_auth_inputed: True }, - only_input_redeemer, - ), - redeemer: Deregister, - info: Publishing { - at: 0, - certificate: RegisterCredential { - credential: mock_script_credential(0), - deposit: Never, - }, - }, - } - !stake.stake.else(mock_spend_script_hash, ctx) -} +// let ctx = +// ScriptContext { +// transaction: mock_stake_tx( +// StakeTestCase { is_only_one_auth_inputed: True }, +// only_input_redeemer, +// ), +// redeemer: Deregister, +// info: Publishing { +// at: 0, +// certificate: RegisterCredential { +// credential: mock_script_credential(0), +// deposit: Never, +// }, +// }, +// } +// !stake.stake.else(mock_spend_script_hash, ctx) +// } -test s2_fail_stake_with_more_than_one_input_from_hash() fail { - let only_input_redeemer: Data = RegisterCerts +// test s2_fail_stake_with_more_than_one_input_from_hash() fail { +// let only_input_redeemer: Data = RegisterCerts - let ctx = - ScriptContext { - transaction: mock_stake_tx( - StakeTestCase { is_only_one_auth_inputed: False }, - only_input_redeemer, - ), - redeemer: Register, - info: Publishing { - at: 0, - certificate: RegisterCredential { - credential: mock_script_credential(0), - deposit: Never, - }, - }, - } - stake.stake.else(mock_spend_script_hash, ctx) -} +// let ctx = +// ScriptContext { +// transaction: mock_stake_tx( +// StakeTestCase { is_only_one_auth_inputed: False }, +// only_input_redeemer, +// ), +// redeemer: Register, +// info: Publishing { +// at: 0, +// certificate: RegisterCredential { +// credential: mock_script_credential(0), +// deposit: Never, +// }, +// }, +// } +// stake.stake.else(mock_spend_script_hash, ctx) +// } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak index c1215bfab..89646ea10 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak @@ -1,206 +1,206 @@ -use cardano/address.{Script} -use cardano/assets.{add, from_lovelace} -use cardano/transaction.{Transaction} -use mocktail.{ - complete, mock_script_hash, mock_tx_hash, mocktail_tx, tx_in, - tx_in_inline_datum, tx_out, tx_out_inline_datum, -} -use start -use tests/utils.{ - mock_auth_token, mock_completion_script, mock_crowdfund_address, - mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, - mock_fundraise_target, mock_gov_action_period, mock_gov_address, - mock_share_token, mock_spend_script_hash, mock_stake_script_hash, -} -use types.{Init} - -type StartTestCase { - is_only_one_auth_inputed: Bool, - is_fundraise_target_sent: Bool, - is_fundraise_target_amount_correct: Bool, - is_fundraise_output_datum_correct: Bool, -} - -fn mock_stake_tx(test_case: StartTestCase) -> Transaction { - let StartTestCase { - is_only_one_auth_inputed, - is_fundraise_target_sent, - is_fundraise_target_amount_correct, - is_fundraise_output_datum_correct, - } = test_case - let auth_input = - from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) - - let fundraise_output = - if is_fundraise_target_amount_correct { - from_lovelace(mock_fundraise_target) - } else { - from_lovelace(mock_fundraise_target - 1000000) - } - - let fundraise_output_datum = - if is_fundraise_output_datum_correct { - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount, - deadline: mock_deadline + mock_gov_action_period, - } - } else { - Init { - completion_script: mock_completion_script, - share_token: mock_share_token, - funds_controlled: mock_current_fundraised_amount + 1000000, - deadline: mock_deadline + mock_gov_action_period, - } - } - - mocktail_tx() - |> tx_in(True, mock_tx_hash(0), 0, auth_input, mock_crowdfund_address) - |> tx_in_inline_datum( - True, - mock_crowdfund_datum(mock_current_fundraised_amount, True), - ) - |> tx_in( - !is_only_one_auth_inputed, - mock_tx_hash(0), - 1, - auth_input, - mock_crowdfund_address, - ) - |> tx_out(is_fundraise_target_sent, mock_gov_address, fundraise_output) - |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) - |> complete() -} - -test s3_withdraw_success() { - let tx = - mock_stake_tx( - StartTestCase { - is_only_one_auth_inputed: True, - is_fundraise_target_sent: True, - is_fundraise_target_amount_correct: True, - is_fundraise_output_datum_correct: True, - }, - ) - - start.start.withdraw( - mock_auth_token, - mock_spend_script_hash, - mock_stake_script_hash, - mock_gov_action_period, - None, - Script(mock_completion_script), - tx, - ) -} - -test s3_withdraw_fail_with_more_than_one_auth_inputed() fail { - let tx = - mock_stake_tx( - StartTestCase { - is_only_one_auth_inputed: False, - is_fundraise_target_sent: True, - is_fundraise_target_amount_correct: True, - is_fundraise_output_datum_correct: True, - }, - ) - - start.start.withdraw( - mock_auth_token, - mock_spend_script_hash, - mock_stake_script_hash, - mock_gov_action_period, - None, - Script(mock_completion_script), - tx, - ) -} - -test s3_withdraw_fail_with_fundraise_target_not_sent() fail { - let tx = - mock_stake_tx( - StartTestCase { - is_only_one_auth_inputed: True, - is_fundraise_target_sent: False, - is_fundraise_target_amount_correct: True, - is_fundraise_output_datum_correct: True, - }, - ) - - start.start.withdraw( - mock_auth_token, - mock_spend_script_hash, - mock_stake_script_hash, - mock_gov_action_period, - None, - Script(mock_completion_script), - tx, - ) -} - -test s3_withdraw_fail_with_incorrect_fundraise_target_output_amount() { - let tx = - mock_stake_tx( - StartTestCase { - is_only_one_auth_inputed: True, - is_fundraise_target_sent: True, - is_fundraise_target_amount_correct: False, - is_fundraise_output_datum_correct: True, - }, - ) - - !start.start.withdraw( - mock_auth_token, - mock_spend_script_hash, - mock_stake_script_hash, - mock_gov_action_period, - None, - Script(mock_completion_script), - tx, - ) -} - -test s3_withdraw_fail_with_incorrect_fundraise_target_output_datum() { - let tx = - mock_stake_tx( - StartTestCase { - is_only_one_auth_inputed: True, - is_fundraise_target_sent: True, - is_fundraise_target_amount_correct: True, - is_fundraise_output_datum_correct: False, - }, - ) - - !start.start.withdraw( - mock_auth_token, - mock_spend_script_hash, - mock_stake_script_hash, - mock_gov_action_period, - None, - Script(mock_completion_script), - tx, - ) -} - -test s3_withdraw_fail_with_different_completion_script() { - let tx = - mock_stake_tx( - StartTestCase { - is_only_one_auth_inputed: True, - is_fundraise_target_sent: True, - is_fundraise_target_amount_correct: True, - is_fundraise_output_datum_correct: False, - }, - ) - - !start.start.withdraw( - mock_auth_token, - mock_spend_script_hash, - mock_stake_script_hash, - mock_gov_action_period, - None, - Script(mock_script_hash(999)), - tx, - ) -} +// use cardano/address.{Script} +// use cardano/assets.{add, from_lovelace} +// use cardano/transaction.{Transaction} +// use mocktail.{ +// complete, mock_script_hash, mock_tx_hash, mocktail_tx, tx_in, +// tx_in_inline_datum, tx_out, tx_out_inline_datum, +// } +// use start +// use tests/utils.{ +// mock_auth_token, mock_completion_script, mock_crowdfund_address, +// mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, +// mock_fundraise_target, mock_gov_action_period, mock_gov_address, +// mock_share_token, mock_spend_script_hash, mock_stake_script_hash, +// } +// use types.{Init} + +// type StartTestCase { +// is_only_one_auth_inputed: Bool, +// is_fundraise_target_sent: Bool, +// is_fundraise_target_amount_correct: Bool, +// is_fundraise_output_datum_correct: Bool, +// } + +// fn mock_stake_tx(test_case: StartTestCase) -> Transaction { +// let StartTestCase { +// is_only_one_auth_inputed, +// is_fundraise_target_sent, +// is_fundraise_target_amount_correct, +// is_fundraise_output_datum_correct, +// } = test_case +// let auth_input = +// from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) + +// let fundraise_output = +// if is_fundraise_target_amount_correct { +// from_lovelace(mock_fundraise_target) +// } else { +// from_lovelace(mock_fundraise_target - 1000000) +// } + +// let fundraise_output_datum = +// if is_fundraise_output_datum_correct { +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// deadline: mock_deadline + mock_gov_action_period, +// } +// } else { +// Init { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount + 1000000, +// deadline: mock_deadline + mock_gov_action_period, +// } +// } + +// mocktail_tx() +// |> tx_in(True, mock_tx_hash(0), 0, auth_input, mock_crowdfund_address) +// |> tx_in_inline_datum( +// True, +// mock_crowdfund_datum(mock_current_fundraised_amount, True), +// ) +// |> tx_in( +// !is_only_one_auth_inputed, +// mock_tx_hash(0), +// 1, +// auth_input, +// mock_crowdfund_address, +// ) +// |> tx_out(is_fundraise_target_sent, mock_gov_address, fundraise_output) +// |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) +// |> complete() +// } + +// test s3_withdraw_success() { +// let tx = +// mock_stake_tx( +// StartTestCase { +// is_only_one_auth_inputed: True, +// is_fundraise_target_sent: True, +// is_fundraise_target_amount_correct: True, +// is_fundraise_output_datum_correct: True, +// }, +// ) + +// start.start.withdraw( +// mock_auth_token, +// mock_spend_script_hash, +// mock_stake_script_hash, +// mock_gov_action_period, +// None, +// Script(mock_completion_script), +// tx, +// ) +// } + +// test s3_withdraw_fail_with_more_than_one_auth_inputed() fail { +// let tx = +// mock_stake_tx( +// StartTestCase { +// is_only_one_auth_inputed: False, +// is_fundraise_target_sent: True, +// is_fundraise_target_amount_correct: True, +// is_fundraise_output_datum_correct: True, +// }, +// ) + +// start.start.withdraw( +// mock_auth_token, +// mock_spend_script_hash, +// mock_stake_script_hash, +// mock_gov_action_period, +// None, +// Script(mock_completion_script), +// tx, +// ) +// } + +// test s3_withdraw_fail_with_fundraise_target_not_sent() fail { +// let tx = +// mock_stake_tx( +// StartTestCase { +// is_only_one_auth_inputed: True, +// is_fundraise_target_sent: False, +// is_fundraise_target_amount_correct: True, +// is_fundraise_output_datum_correct: True, +// }, +// ) + +// start.start.withdraw( +// mock_auth_token, +// mock_spend_script_hash, +// mock_stake_script_hash, +// mock_gov_action_period, +// None, +// Script(mock_completion_script), +// tx, +// ) +// } + +// test s3_withdraw_fail_with_incorrect_fundraise_target_output_amount() { +// let tx = +// mock_stake_tx( +// StartTestCase { +// is_only_one_auth_inputed: True, +// is_fundraise_target_sent: True, +// is_fundraise_target_amount_correct: False, +// is_fundraise_output_datum_correct: True, +// }, +// ) + +// !start.start.withdraw( +// mock_auth_token, +// mock_spend_script_hash, +// mock_stake_script_hash, +// mock_gov_action_period, +// None, +// Script(mock_completion_script), +// tx, +// ) +// } + +// test s3_withdraw_fail_with_incorrect_fundraise_target_output_datum() { +// let tx = +// mock_stake_tx( +// StartTestCase { +// is_only_one_auth_inputed: True, +// is_fundraise_target_sent: True, +// is_fundraise_target_amount_correct: True, +// is_fundraise_output_datum_correct: False, +// }, +// ) + +// !start.start.withdraw( +// mock_auth_token, +// mock_spend_script_hash, +// mock_stake_script_hash, +// mock_gov_action_period, +// None, +// Script(mock_completion_script), +// tx, +// ) +// } + +// test s3_withdraw_fail_with_different_completion_script() { +// let tx = +// mock_stake_tx( +// StartTestCase { +// is_only_one_auth_inputed: True, +// is_fundraise_target_sent: True, +// is_fundraise_target_amount_correct: True, +// is_fundraise_output_datum_correct: False, +// }, +// ) + +// !start.start.withdraw( +// mock_auth_token, +// mock_spend_script_hash, +// mock_stake_script_hash, +// mock_gov_action_period, +// None, +// Script(mock_script_hash(999)), +// tx, +// ) +// } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak index 5278a3af4..b7a0b3cb7 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -1,96 +1,96 @@ -use aiken/collection/list -use cardano/address.{Address, Inline, Script, from_script} -use cardano/governance.{NoConfidence, ProposalProcedure} -use cardano/transaction.{Transaction} -use mocktail.{ - mock_policy_id, mock_pub_key_hash, mock_script_hash, - mock_script_stake_key_hash, -} -use types.{CrowdfundDatum} +// use aiken/collection/list +// use cardano/address.{Address, Inline, Script, from_script} +// use cardano/governance.{NoConfidence, ProposalProcedure} +// use cardano/transaction.{Transaction} +// use mocktail.{ +// mock_policy_id, mock_pub_key_hash, mock_script_hash, +// mock_script_stake_key_hash, +// } +// use types.{CrowdfundDatum} -pub const mock_auth_token = mock_policy_id(0) +// pub const mock_auth_token = mock_policy_id(0) -pub const mock_share_token = mock_policy_id(1) +// pub const mock_share_token = mock_policy_id(1) -pub const mock_completion_script = mock_script_hash(0) +// pub const mock_completion_script = mock_script_hash(0) -pub const mock_crowdfund_spend_script_hash = mock_script_hash(1) +// pub const mock_crowdfund_spend_script_hash = mock_script_hash(1) -pub const mock_crowdfund_stake_script_hash = mock_script_stake_key_hash(0) +// pub const mock_crowdfund_stake_script_hash = mock_script_stake_key_hash(0) -pub const mock_crowdfund_address = from_script(mock_crowdfund_spend_script_hash) +// pub const mock_crowdfund_address = from_script(mock_crowdfund_spend_script_hash) -pub const mock_fee_address = from_script("fee_address") +// pub const mock_fee_address = from_script("fee_address") -pub const mock_fundraise_target = 100000000000 +// pub const mock_fundraise_target = 100000000000 -pub const mock_current_fundraised_amount = mock_fundraise_target + 1000000 +// pub const mock_current_fundraised_amount = mock_fundraise_target + 1000000 -pub const mock_contribute_min_fundraised_amount = 2000000 +// pub const mock_contribute_min_fundraised_amount = 2000000 -pub const mock_deadline = 1750735607 +// pub const mock_deadline = 1750735607 -pub const mock_expiry_buffer = 3600 * 24 +// pub const mock_expiry_buffer = 3600 * 24 -pub const mock_min_charge = 0 +// pub const mock_min_charge = 0 -pub fn mock_crowdfund_datum( - current_fundraised_amount: Int, - allow_over_subscription: Bool, -) { - CrowdfundDatum { - completion_script: mock_completion_script, - share_token: mock_share_token, - crowdfund_address: mock_crowdfund_address, - fundraise_target: mock_fundraise_target, - current_fundraised_amount, - allow_over_subscription, - deadline: mock_deadline, - expiry_buffer: mock_expiry_buffer, - fee_address: mock_fee_address, - min_charge: mock_min_charge, - } -} +// pub fn mock_crowdfund_datum( +// current_fundraised_amount: Int, +// allow_over_subscription: Bool, +// ) { +// CrowdfundDatum { +// completion_script: mock_completion_script, +// share_token: mock_share_token, +// crowdfund_address: mock_crowdfund_address, +// fundraise_target: mock_fundraise_target, +// current_fundraised_amount, +// allow_over_subscription, +// deadline: mock_deadline, +// expiry_buffer: mock_expiry_buffer, +// fee_address: mock_fee_address, +// min_charge: mock_min_charge, +// } +// } -pub const mock_spend_script_hash = mock_script_hash(1) +// pub const mock_spend_script_hash = mock_script_hash(1) -pub const mock_stake_script_hash = mock_script_hash(2) +// pub const mock_stake_script_hash = mock_script_hash(2) -pub const mock_crowdfund_gov_address = from_script(mock_spend_script_hash) +// pub const mock_crowdfund_gov_address = from_script(mock_spend_script_hash) -pub const mock_gov_address = - Address { - payment_credential: Script(mock_spend_script_hash), - stake_credential: Some(Inline(Script(mock_stake_script_hash))), - } +// pub const mock_gov_address = +// Address { +// payment_credential: Script(mock_spend_script_hash), +// stake_credential: Some(Inline(Script(mock_stake_script_hash))), +// } -pub const mock_gov_action_period = 3600 +// pub const mock_gov_action_period = 3600 -pub const mock_delegate_pool_id = mock_script_hash(3) +// pub const mock_delegate_pool_id = mock_script_hash(3) -pub const mock_gov_action = NoConfidence { ancestor: None } +// pub const mock_gov_action = NoConfidence { ancestor: None } -pub const mock_proposer_key_hash = mock_pub_key_hash(0) +// pub const mock_proposer_key_hash = mock_pub_key_hash(0) -pub const mock_stake_register_deposit = 2000000 +// pub const mock_stake_register_deposit = 2000000 -pub const mock_drep_register_deposit = 500000000 +// pub const mock_drep_register_deposit = 500000000 -pub const mock_funds_controlled = - mock_fundraise_target + mock_stake_register_deposit + mock_drep_register_deposit +// pub const mock_funds_controlled = +// mock_fundraise_target + mock_stake_register_deposit + mock_drep_register_deposit -pub fn add_proposal_procedure( - tx: Transaction, - condition: Bool, - proposal_procedure: ProposalProcedure, -) -> Transaction { - if !condition { - tx - } else { - Transaction { - ..tx, - proposal_procedures: tx.proposal_procedures - |> list.concat([proposal_procedure]), - } - } -} +// pub fn add_proposal_procedure( +// tx: Transaction, +// condition: Bool, +// proposal_procedure: ProposalProcedure, +// ) -> Transaction { +// if !condition { +// tx +// } else { +// Transaction { +// ..tx, +// proposal_procedures: tx.proposal_procedures +// |> list.concat([proposal_procedure]), +// } +// } +// } From 529d1e353eb59712dab3b1d02ef33563f054aa37 Mon Sep 17 00:00:00 2001 From: kenlau666 Date: Fri, 27 Jun 2025 01:25:30 +0800 Subject: [PATCH 10/19] updated: spend todo: start and spend tests --- .../gov-crowdfund/validators/spend.ak | 520 +++++++++--------- 1 file changed, 269 insertions(+), 251 deletions(-) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak index 33648a5f7..3f96addb5 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak @@ -1,251 +1,269 @@ -// use aiken/collection/list -// use cardano/address.{Inline} -// use cardano/assets.{Lovelace, lovelace_of} -// use cardano/certificate.{Registered} -// use cardano/governance.{GovernanceAction, ProposalProcedure} -// use cardano/transaction.{OutputReference, Transaction, find_input} -// use cocktail.{ -// inputs_at, key_signed, only_minted_token, output_inline_datum, outputs_at, -// valid_after, value_length, -// } -// use types.{ -// ContributorWithdrawal, CrowdfundGovDatum, CrowdfundRedeemer, DeregisterCerts, -// Init, Proposed, Refundable, RegisterCerts, RemoveEmptyInstance, -// } -// use utils.{ -// check_lovelace_diff, delegate_stake_and_vote_certificate, -// delegate_stake_certificate, delegate_vote_certificate, -// register_drep_certificate, register_stake_certificate, -// unregister_drep_certificate, unregister_stake_certificate, -// } - -// validator spend( -// delegate_pool_id: ByteArray, -// gov_action: GovernanceAction, -// proposer_key_hash: ByteArray, -// stake_register_deposit: Lovelace, -// drep_register_deposit: Lovelace, -// ) { -// spend( -// datum_opt: Option, -// redeemer: CrowdfundRedeemer, -// input: OutputReference, -// self: Transaction, -// ) { -// let Transaction { -// inputs, -// validity_range, -// mint, -// outputs, -// extra_signatories, -// certificates, -// proposal_procedures, -// .. -// } = self - -// expect Some(own_input) = find_input(inputs, input) -// expect Some(only_input_datum) = datum_opt - -// let current_address = own_input.output.address - -// // check only 1 input from current address -// expect [only_input] = inputs_at(inputs, current_address) - -// when redeemer is { -// RegisterCerts -> -// when only_input_datum is { -// Init { share_token, deadline, funds_controlled, completion_script } -> { -// expect Some(current_stake_credential) = -// current_address.stake_credential - -// expect Inline(current_credential) = current_stake_credential - -// expect [only_output] = outputs_at(outputs, current_address) - -// let lovelace_from_only_input = -// only_input.output.value |> lovelace_of() - -// let lovelace_check = -// check_lovelace_diff( -// only_input, -// only_output, -// -(stake_register_deposit + drep_register_deposit), -// ) -// expect only_output_datum: CrowdfundGovDatum = -// output_inline_datum(only_output) -// let output_datum_check = -// only_output_datum == Proposed { -// completion_script, -// share_token, -// funds_controlled, -// deadline, -// } - -// let is_only_output_value_clean = -// value_length(only_output.value) == 1 - -// let reg_stake_cert_check = -// register_stake_certificate(certificates, current_credential) - -// let reg_drep_cert_check = -// register_drep_certificate( -// certificates, -// current_credential, -// drep_register_deposit, -// ) - -// let delegate_check = -// delegate_vote_certificate( -// certificates, -// current_credential, -// Registered(current_credential), -// ) && delegate_stake_certificate( -// certificates, -// current_credential, -// delegate_pool_id, -// ) || delegate_stake_and_vote_certificate( -// certificates, -// current_credential, -// delegate_pool_id, -// Registered(current_credential), -// ) - -// let proposal_check = -// list.has( -// proposal_procedures, -// ProposalProcedure { -// deposit: lovelace_from_only_input - stake_register_deposit - drep_register_deposit, -// return_address: current_address.payment_credential, -// governance_action: gov_action, -// }, -// ) -// lovelace_check? && output_datum_check? && is_only_output_value_clean? && reg_stake_cert_check? && reg_drep_cert_check? && delegate_check? && proposal_check? -// } -// _ -> False -// } - -// DeregisterCerts -> -// when only_input_datum is { -// Refundable { -// share_token, -// deadline, -// funds_controlled, -// completion_script, -// } -> { -// expect Some(current_stake_credential) = -// current_address.stake_credential - -// expect Inline(current_credential) = current_stake_credential -// let validity_check = valid_after(validity_range, deadline) -// expect [only_output] = outputs_at(outputs, current_address) -// let lovelace_check = -// check_lovelace_diff( -// only_input, -// only_output, -// stake_register_deposit + drep_register_deposit, -// ) - -// expect only_output_datum: CrowdfundGovDatum = -// output_inline_datum(only_output) -// let output_datum_check = -// only_output_datum == Refundable { -// completion_script, -// share_token, -// funds_controlled, -// deadline, -// } - -// let unreg_stake_cert_check = -// unregister_stake_certificate(certificates, current_credential) - -// let unreg_drep_cert_check = -// unregister_drep_certificate( -// certificates, -// current_credential, -// drep_register_deposit, -// ) -// validity_check? && lovelace_check? && output_datum_check? && unreg_stake_cert_check? && unreg_drep_cert_check? -// } - -// _ -> False -// } - -// ContributorWithdrawal -> -// when only_input_datum is { -// Refundable { -// share_token, -// deadline, -// funds_controlled, -// completion_script, -// } -> { -// let validity_check = valid_after(validity_range, deadline) - -// expect [only_output] = outputs_at(outputs, current_address) - -// let lovelace_from_only_input = -// only_input.output.value |> lovelace_of() -// let lovelace_from_only_output = only_output.value |> lovelace_of() - -// let lovelace_withdrawn = -// lovelace_from_only_output - lovelace_from_only_input - -// let lovelace_withdrawn_check = lovelace_withdrawn < 0 - -// expect only_output_datum: CrowdfundGovDatum = -// output_inline_datum(only_output) -// let output_datum_check = -// only_output_datum == Refundable { -// completion_script, -// share_token, -// funds_controlled: funds_controlled + lovelace_withdrawn, -// deadline, -// } - -// let is_only_output_value_clean = -// value_length(only_output.value) == 1 - -// validity_check? && lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( -// mint, -// share_token, -// completion_script, -// lovelace_withdrawn, -// )? -// } -// _ -> False -// } - -// RemoveEmptyInstance -> -// when only_input_datum is { -// Refundable { -// share_token, -// deadline, -// funds_controlled, -// completion_script, -// } -> { -// let validity_check = valid_after(validity_range, deadline) - -// let token_burnt_check = -// if funds_controlled > 0 { -// only_minted_token( -// mint, -// share_token, -// completion_script, -// -funds_controlled, -// ) -// } else { -// True -// } - -// let proposer_key_signed_check = -// key_signed(extra_signatories, proposer_key_hash) -// validity_check? && token_burnt_check? && proposer_key_signed_check? -// } -// _ -> False -// } -// } -// } - -// else(_) { -// fail -// } -// } +use aiken/collection/list +use cardano/address.{Inline} +use cardano/assets.{Lovelace, lovelace_of} +use cardano/certificate.{Registered} +use cardano/governance.{GovernanceAction, GovernanceActionId, ProposalProcedure} +use cardano/transaction.{OutputReference, Transaction, find_input} +use cocktail.{ + inputs_at, key_signed, only_minted_token, output_inline_datum, outputs_at, + policy_only_minted_token, valid_after, value_length, +} +use types.{ + ContributorWithdrawal, CrowdfundGovDatum, CrowdfundRedeemer, DeregisterCerts, + Init, Proposed, Refundable, RegisterCerts, RemoveEmptyInstance, + VoteOnGovAction, Voted, +} +use utils.{ + check_lovelace_diff, delegate_stake_and_vote_certificate, + delegate_stake_certificate, delegate_vote_certificate, + register_drep_certificate, register_stake_certificate, + unregister_drep_certificate, unregister_stake_certificate, +} + +validator spend( + delegate_pool_id: ByteArray, + gov_action: GovernanceAction, + proposer_key_hash: ByteArray, + stake_register_deposit: Lovelace, + drep_register_deposit: Lovelace, +) { + spend( + datum_opt: Option, + redeemer: CrowdfundRedeemer, + input: OutputReference, + self: Transaction, + ) { + let Transaction { + inputs, + validity_range, + mint, + outputs, + extra_signatories, + certificates, + proposal_procedures, + .. + } = self + + expect Some(own_input) = find_input(inputs, input) + expect Some(only_input_datum) = datum_opt + + let current_address = own_input.output.address + + // check only 1 input from current address + expect [only_input] = inputs_at(inputs, current_address) + + when redeemer is { + RegisterCerts -> + when only_input_datum is { + Init { start_hash, share_token, funds_controlled, deadline } -> { + expect Some(current_stake_credential) = + current_address.stake_credential + + expect Inline(current_credential) = current_stake_credential + + expect [only_output] = outputs_at(outputs, current_address) + + let lovelace_from_only_input = + only_input.output.value |> lovelace_of() + + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + -(stake_register_deposit + drep_register_deposit), + ) + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Proposed { + start_hash, + share_token, + funds_controlled, + deadline, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + + let reg_stake_cert_check = + register_stake_certificate(certificates, current_credential) + + let reg_drep_cert_check = + register_drep_certificate( + certificates, + current_credential, + drep_register_deposit, + ) + + let delegate_check = + delegate_vote_certificate( + certificates, + current_credential, + Registered(current_credential), + ) && delegate_stake_certificate( + certificates, + current_credential, + delegate_pool_id, + ) || delegate_stake_and_vote_certificate( + certificates, + current_credential, + delegate_pool_id, + Registered(current_credential), + ) + + let proposal_check = + list.has( + proposal_procedures, + ProposalProcedure { + deposit: lovelace_from_only_input - stake_register_deposit - drep_register_deposit, + return_address: current_address.payment_credential, + governance_action: gov_action, + }, + ) + lovelace_check? && output_datum_check? && is_only_output_value_clean? && reg_stake_cert_check? && reg_drep_cert_check? && delegate_check? && proposal_check? + } + _ -> False + } + VoteOnGovAction -> + when only_input_datum is { + Proposed { start_hash, share_token, funds_controlled, deadline } -> { + expect [only_output] = outputs_at(outputs, current_address) + + let lovelace_check = + check_lovelace_diff(only_input, only_output, -100000000000) + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Voted { + start_hash, + share_token, + funds_controlled, + gov_tx_id: GovernanceActionId { + transaction: own_input.output_reference.transaction_id, + proposal_procedure: 0, + }, + deadline, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + + lovelace_check? && output_datum_check? && is_only_output_value_clean? + } + _ -> False + } + DeregisterCerts -> + when only_input_datum is { + Voted { start_hash, share_token, funds_controlled, deadline, .. } -> { + expect Some(current_stake_credential) = + current_address.stake_credential + + expect Inline(current_credential) = current_stake_credential + let validity_check = valid_after(validity_range, deadline) + expect [only_output] = outputs_at(outputs, current_address) + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + stake_register_deposit + drep_register_deposit, + ) + + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Refundable { + start_hash, + share_token, + funds_controlled, + deadline, + } + + let unreg_stake_cert_check = + unregister_stake_certificate(certificates, current_credential) + + let unreg_drep_cert_check = + unregister_drep_certificate( + certificates, + current_credential, + drep_register_deposit, + ) + validity_check? && lovelace_check? && output_datum_check? && unreg_stake_cert_check? && unreg_drep_cert_check? + } + + _ -> False + } + + ContributorWithdrawal -> + when only_input_datum is { + Refundable { start_hash, share_token, funds_controlled, deadline } -> { + let validity_check = valid_after(validity_range, deadline) + + expect [only_output] = outputs_at(outputs, current_address) + + let lovelace_from_only_input = + only_input.output.value |> lovelace_of() + let lovelace_from_only_output = only_output.value |> lovelace_of() + + let lovelace_withdrawn = + lovelace_from_only_output - lovelace_from_only_input + + let lovelace_withdrawn_check = lovelace_withdrawn < 0 + + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Refundable { + start_hash, + share_token, + funds_controlled: funds_controlled + lovelace_withdrawn, + deadline, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + + validity_check? && lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( + mint, + share_token, + start_hash, + lovelace_withdrawn, + )? + } + _ -> False + } + + RemoveEmptyInstance -> + when only_input_datum is { + Refundable { start_hash, share_token, funds_controlled, deadline } -> { + let validity_check = valid_after(validity_range, deadline) + + let token_burnt_check = + if funds_controlled > 0 { + policy_only_minted_token( + mint, + share_token, + start_hash, + -funds_controlled, + ) + } else { + True + } + + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + validity_check? && token_burnt_check? && proposer_key_signed_check? && policy_only_minted_token( + mint, + start_hash, + "", + -1, + )? + } + _ -> False + } + } + } + + else(_) { + fail + } +} From 391dde1fd869630855786f6ae9dd18d0d400c301 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Fri, 27 Jun 2025 11:47:32 +0800 Subject: [PATCH 11/19] updated: start test --- .../gov-crowdfund/validators/tests/stake.ak | 149 ---- .../gov-crowdfund/validators/tests/start.ak | 773 +++++++++++++----- .../gov-crowdfund/validators/tests/utils.ak | 140 ++-- 3 files changed, 637 insertions(+), 425 deletions(-) delete mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak deleted file mode 100644 index 327822a1e..000000000 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/stake.ak +++ /dev/null @@ -1,149 +0,0 @@ -// use cardano/assets.{from_lovelace} -// use cardano/certificate.{RegisterCredential} -// use cardano/script_context.{Publishing, ScriptContext} -// use cardano/transaction.{OutputReference, Spend, Transaction} -// use mocktail.{ -// add_redeemer, complete, mock_script_credential, mock_tx_hash, mocktail_tx, -// tx_in, -// } -// use stake -// use tests/utils.{ -// mock_crowdfund_gov_address, mock_fundraise_target, mock_spend_script_hash, -// } -// use types.{Deregister, DeregisterCerts, Register, RegisterCerts} - -// type StakeTestCase { -// is_only_one_auth_inputed: Bool, -// } - -// fn mock_stake_tx( -// test_case: StakeTestCase, -// only_input_redeemer: Data, -// ) -> Transaction { -// let StakeTestCase { is_only_one_auth_inputed } = test_case -// let only_input = from_lovelace(mock_fundraise_target) -// mocktail_tx() -// |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_gov_address) -// |> tx_in( -// !is_only_one_auth_inputed, -// mock_tx_hash(0), -// 1, -// only_input, -// mock_crowdfund_gov_address, -// ) -// |> complete() -// |> add_redeemer( -// True, -// Pair( -// Spend( -// OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, -// ), -// only_input_redeemer, -// ), -// ) -// } - -// test s2_success_stake_with_reg() { -// let only_input_redeemer: Data = RegisterCerts - -// let ctx = -// ScriptContext { -// transaction: mock_stake_tx( -// StakeTestCase { is_only_one_auth_inputed: True }, -// only_input_redeemer, -// ), -// redeemer: Register, -// info: Publishing { -// at: 0, -// certificate: RegisterCredential { -// credential: mock_script_credential(0), -// deposit: Never, -// }, -// }, -// } -// stake.stake.else(mock_spend_script_hash, ctx) -// } - -// test s2_success_stake_with_dereg() { -// let only_input_redeemer: Data = DeregisterCerts - -// let ctx = -// ScriptContext { -// transaction: mock_stake_tx( -// StakeTestCase { is_only_one_auth_inputed: True }, -// only_input_redeemer, -// ), -// redeemer: Deregister, -// info: Publishing { -// at: 0, -// certificate: RegisterCredential { -// credential: mock_script_credential(0), -// deposit: Never, -// }, -// }, -// } -// stake.stake.else(mock_spend_script_hash, ctx) -// } - -// test s2_fail_stake_with_reg_but_deregister_cert() { -// let only_input_redeemer: Data = DeregisterCerts - -// let ctx = -// ScriptContext { -// transaction: mock_stake_tx( -// StakeTestCase { is_only_one_auth_inputed: True }, -// only_input_redeemer, -// ), -// redeemer: Register, -// info: Publishing { -// at: 0, -// certificate: RegisterCredential { -// credential: mock_script_credential(0), -// deposit: Never, -// }, -// }, -// } -// !stake.stake.else(mock_spend_script_hash, ctx) -// } - -// test s2_fail_stake_with_dereg_but_register_cert() { -// let only_input_redeemer: Data = RegisterCerts - -// let ctx = -// ScriptContext { -// transaction: mock_stake_tx( -// StakeTestCase { is_only_one_auth_inputed: True }, -// only_input_redeemer, -// ), -// redeemer: Deregister, -// info: Publishing { -// at: 0, -// certificate: RegisterCredential { -// credential: mock_script_credential(0), -// deposit: Never, -// }, -// }, -// } -// !stake.stake.else(mock_spend_script_hash, ctx) -// } - -// test s2_fail_stake_with_more_than_one_input_from_hash() fail { -// let only_input_redeemer: Data = RegisterCerts - -// let ctx = -// ScriptContext { -// transaction: mock_stake_tx( -// StakeTestCase { is_only_one_auth_inputed: False }, -// only_input_redeemer, -// ), -// redeemer: Register, -// info: Publishing { -// at: 0, -// certificate: RegisterCredential { -// credential: mock_script_credential(0), -// deposit: Never, -// }, -// }, -// } -// stake.stake.else(mock_spend_script_hash, ctx) -// } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak index 89646ea10..60a2d5521 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak @@ -1,206 +1,567 @@ -// use cardano/address.{Script} -// use cardano/assets.{add, from_lovelace} -// use cardano/transaction.{Transaction} -// use mocktail.{ -// complete, mock_script_hash, mock_tx_hash, mocktail_tx, tx_in, -// tx_in_inline_datum, tx_out, tx_out_inline_datum, -// } -// use start -// use tests/utils.{ -// mock_auth_token, mock_completion_script, mock_crowdfund_address, -// mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, -// mock_fundraise_target, mock_gov_action_period, mock_gov_address, -// mock_share_token, mock_spend_script_hash, mock_stake_script_hash, -// } -// use types.{Init} - -// type StartTestCase { -// is_only_one_auth_inputed: Bool, -// is_fundraise_target_sent: Bool, -// is_fundraise_target_amount_correct: Bool, -// is_fundraise_output_datum_correct: Bool, -// } - -// fn mock_stake_tx(test_case: StartTestCase) -> Transaction { -// let StartTestCase { -// is_only_one_auth_inputed, -// is_fundraise_target_sent, -// is_fundraise_target_amount_correct, -// is_fundraise_output_datum_correct, -// } = test_case -// let auth_input = -// from_lovelace(20000000) |> add(mock_auth_token, mock_completion_script, 1) - -// let fundraise_output = -// if is_fundraise_target_amount_correct { -// from_lovelace(mock_fundraise_target) -// } else { -// from_lovelace(mock_fundraise_target - 1000000) -// } - -// let fundraise_output_datum = -// if is_fundraise_output_datum_correct { -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// } -// } else { -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount + 1000000, -// deadline: mock_deadline + mock_gov_action_period, -// } -// } - -// mocktail_tx() -// |> tx_in(True, mock_tx_hash(0), 0, auth_input, mock_crowdfund_address) -// |> tx_in_inline_datum( -// True, -// mock_crowdfund_datum(mock_current_fundraised_amount, True), -// ) -// |> tx_in( -// !is_only_one_auth_inputed, -// mock_tx_hash(0), -// 1, -// auth_input, -// mock_crowdfund_address, -// ) -// |> tx_out(is_fundraise_target_sent, mock_gov_address, fundraise_output) -// |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) -// |> complete() -// } - -// test s3_withdraw_success() { -// let tx = -// mock_stake_tx( -// StartTestCase { -// is_only_one_auth_inputed: True, -// is_fundraise_target_sent: True, -// is_fundraise_target_amount_correct: True, -// is_fundraise_output_datum_correct: True, -// }, -// ) - -// start.start.withdraw( -// mock_auth_token, -// mock_spend_script_hash, -// mock_stake_script_hash, -// mock_gov_action_period, -// None, -// Script(mock_completion_script), -// tx, -// ) -// } - -// test s3_withdraw_fail_with_more_than_one_auth_inputed() fail { -// let tx = -// mock_stake_tx( -// StartTestCase { -// is_only_one_auth_inputed: False, -// is_fundraise_target_sent: True, -// is_fundraise_target_amount_correct: True, -// is_fundraise_output_datum_correct: True, -// }, -// ) - -// start.start.withdraw( -// mock_auth_token, -// mock_spend_script_hash, -// mock_stake_script_hash, -// mock_gov_action_period, -// None, -// Script(mock_completion_script), -// tx, -// ) -// } - -// test s3_withdraw_fail_with_fundraise_target_not_sent() fail { -// let tx = -// mock_stake_tx( -// StartTestCase { -// is_only_one_auth_inputed: True, -// is_fundraise_target_sent: False, -// is_fundraise_target_amount_correct: True, -// is_fundraise_output_datum_correct: True, -// }, -// ) - -// start.start.withdraw( -// mock_auth_token, -// mock_spend_script_hash, -// mock_stake_script_hash, -// mock_gov_action_period, -// None, -// Script(mock_completion_script), -// tx, -// ) -// } - -// test s3_withdraw_fail_with_incorrect_fundraise_target_output_amount() { -// let tx = -// mock_stake_tx( -// StartTestCase { -// is_only_one_auth_inputed: True, -// is_fundraise_target_sent: True, -// is_fundraise_target_amount_correct: False, -// is_fundraise_output_datum_correct: True, -// }, -// ) - -// !start.start.withdraw( -// mock_auth_token, -// mock_spend_script_hash, -// mock_stake_script_hash, -// mock_gov_action_period, -// None, -// Script(mock_completion_script), -// tx, -// ) -// } - -// test s3_withdraw_fail_with_incorrect_fundraise_target_output_datum() { -// let tx = -// mock_stake_tx( -// StartTestCase { -// is_only_one_auth_inputed: True, -// is_fundraise_target_sent: True, -// is_fundraise_target_amount_correct: True, -// is_fundraise_output_datum_correct: False, -// }, -// ) - -// !start.start.withdraw( -// mock_auth_token, -// mock_spend_script_hash, -// mock_stake_script_hash, -// mock_gov_action_period, -// None, -// Script(mock_completion_script), -// tx, -// ) -// } - -// test s3_withdraw_fail_with_different_completion_script() { -// let tx = -// mock_stake_tx( -// StartTestCase { -// is_only_one_auth_inputed: True, -// is_fundraise_target_sent: True, -// is_fundraise_target_amount_correct: True, -// is_fundraise_output_datum_correct: False, -// }, -// ) - -// !start.start.withdraw( -// mock_auth_token, -// mock_spend_script_hash, -// mock_stake_script_hash, -// mock_gov_action_period, -// None, -// Script(mock_script_hash(999)), -// tx, -// ) -// } +use cardano/address.{Script} +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction} +use mocktail.{ + add_redeemer, complete, mint, mock_script_hash, mock_tx_hash, mocktail_tx, + script_withdrawal, tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, +} +use start +use tests/utils.{ + mock_auth_token, mock_crowdfund_address, mock_crowdfund_datum, + mock_crowdfund_gov_address, mock_current_fundraised_amount, mock_deadline, + mock_fundraise_target, mock_gov_action_period, mock_gov_address, + mock_share_token, mock_spend_script_hash, mock_start_hash, +} +use types.{ + Deregister, DeregisterCerts, Init, RBurn, RMint, Register, RegisterCerts, + RemoveEmptyInstance, VoteOnGovAction, +} + +type WithdrawTestCase { + is_only_one_spend_inputed: Bool, + is_fundraise_target_sent: Bool, + is_fundraise_target_amount_correct: Bool, + is_fundraise_output_datum_correct: Bool, + is_token_minted: Bool, +} + +fn mock_withdraw_tx(test_case: WithdrawTestCase) -> Transaction { + let WithdrawTestCase { + is_only_one_spend_inputed, + is_fundraise_target_sent, + is_fundraise_target_amount_correct, + is_fundraise_output_datum_correct, + is_token_minted, + } = test_case + let auth_input = + from_lovelace(20000000) |> add(mock_auth_token, mock_start_hash, 1) + + let fundraise_output = + if is_fundraise_target_amount_correct { + from_lovelace(mock_fundraise_target) |> add(mock_start_hash, "", 1) + } else { + from_lovelace(mock_fundraise_target - 1000000) + |> add(mock_start_hash, "", 1) + } + + let fundraise_output_datum = + if is_fundraise_output_datum_correct { + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + } + } else { + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount + 1000000, + deadline: mock_deadline + mock_gov_action_period, + } + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, auth_input, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(mock_current_fundraised_amount, True), + ) + |> tx_in( + !is_only_one_spend_inputed, + mock_tx_hash(0), + 1, + auth_input, + mock_crowdfund_address, + ) + |> tx_out(is_fundraise_target_sent, mock_gov_address, fundraise_output) + |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) + |> mint(is_token_minted, 1, mock_start_hash, "") + |> complete() +} + +test s3_withdraw_success() { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + }, + ) + + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_start_hash), + tx, + ) +} + +test s3_withdraw_fail_with_more_than_one_auth_inputed() fail { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: False, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + }, + ) + + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_start_hash), + tx, + ) +} + +test s3_withdraw_fail_with_fundraise_target_not_sent() fail { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: True, + is_fundraise_target_sent: False, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + }, + ) + + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_start_hash), + tx, + ) +} + +test s3_withdraw_fail_with_incorrect_fundraise_target_output_amount() { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: False, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + }, + ) + + !start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_start_hash), + tx, + ) +} + +test s3_withdraw_fail_with_incorrect_fundraise_target_output_datum() { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: False, + is_token_minted: True, + }, + ) + + !start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_start_hash), + tx, + ) +} + +test s3_withdraw_fail_with_token_not_minted() { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: False, + }, + ) + + !start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_start_hash), + tx, + ) +} + +test s3_withdraw_fail_with_different_start_hash() { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + }, + ) + + !start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_script_hash(999)), + tx, + ) +} + +test s2_success_mint() { + let tx = + mocktail_tx() + |> script_withdrawal(True, mock_start_hash, 2_000_000) + |> complete() + + start.start.mint( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + RMint, + mock_start_hash, + tx, + ) +} + +test s2_fail_mint_with_no_withdraw() { + let tx = + mocktail_tx() + |> script_withdrawal(False, mock_start_hash, 2_000_000) + |> complete() + + !start.start.mint( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + RMint, + mock_start_hash, + tx, + ) +} + +test s2_fail_mint_with_other_withdraw() { + let tx = + mocktail_tx() + |> script_withdrawal(True, mock_script_hash(999), 2_000_000) + |> complete() + + !start.start.mint( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + RMint, + mock_start_hash, + tx, + ) +} + +type StartTestCase { + is_only_one_spend_inputed: Bool, +} + +fn mock_start_tx( + test_case: StartTestCase, + only_input_redeemer: Data, +) -> Transaction { + let StartTestCase { is_only_one_spend_inputed } = test_case + let only_input = + from_lovelace(mock_fundraise_target) |> add(mock_start_hash, "", 1) + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, only_input, mock_crowdfund_gov_address) + |> tx_in( + !is_only_one_spend_inputed, + mock_tx_hash(0), + 1, + only_input, + mock_crowdfund_gov_address, + ) + |> complete() + |> add_redeemer( + True, + Pair( + Spend( + OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, + ), + only_input_redeemer, + ), + ) +} + +test s2_success_burn() { + let only_input_redeemer: Data = RemoveEmptyInstance + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + start.start.mint( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + RBurn, + mock_start_hash, + tx, + ) +} + +test s2_fail_burn_with_wrong_redeemer() { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + !start.start.mint( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + RBurn, + mock_start_hash, + tx, + ) +} + +test s2_fail_burn_with_more_than_one_inputed() fail { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: False }, + only_input_redeemer, + ) + start.start.mint( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + RBurn, + mock_start_hash, + tx, + ) +} + +test s2_success_publish_with_reg() { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + start.start.publish( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + Register, + None, + tx, + ) +} + +test s2_success_publish_with_dereg() { + let only_input_redeemer: Data = DeregisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + start.start.publish( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + Deregister, + None, + tx, + ) +} + +test s2_fail_publish_with_reg_but_deregister_cert() { + let only_input_redeemer: Data = DeregisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + !start.start.publish( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + Register, + None, + tx, + ) +} + +test s2_fail_publish_with_dereg_but_register_cert() { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + !start.start.publish( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + Deregister, + None, + tx, + ) +} + +test s2_fail_publish_with_more_than_one_input_from_hash() fail { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: False }, + only_input_redeemer, + ) + start.start.publish( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + Register, + None, + tx, + ) +} + +test s2_success_propose() { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + start.start.propose( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + None, + tx, + ) +} + +test s2_fail_propose_with_wrong_redeemer() { + let only_input_redeemer: Data = VoteOnGovAction + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + !start.start.propose( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + None, + tx, + ) +} + +test s2_fail_propose_with_more_than_one_inputed() fail { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: False }, + only_input_redeemer, + ) + start.start.propose( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + None, + tx, + ) +} + +test s2_success_vote() { + let only_input_redeemer: Data = VoteOnGovAction + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + start.start.vote( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + None, + tx, + ) +} + +test s2_fail_vote_with_wrong_redeemer() { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + !start.start.vote( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + None, + tx, + ) +} + +test s2_fail_vote_with_more_than_one_inputed() fail { + let only_input_redeemer: Data = VoteOnGovAction + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: False }, + only_input_redeemer, + ) + start.start.vote( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + None, + tx, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak index b7a0b3cb7..516b3055c 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -1,96 +1,96 @@ -// use aiken/collection/list -// use cardano/address.{Address, Inline, Script, from_script} -// use cardano/governance.{NoConfidence, ProposalProcedure} -// use cardano/transaction.{Transaction} -// use mocktail.{ -// mock_policy_id, mock_pub_key_hash, mock_script_hash, -// mock_script_stake_key_hash, -// } -// use types.{CrowdfundDatum} +use aiken/collection/list +use cardano/address.{Address, Inline, Script, from_script} +use cardano/governance.{NoConfidence, ProposalProcedure} +use cardano/transaction.{Transaction} +use mocktail.{ + mock_policy_id, mock_pub_key_hash, mock_script_hash, + mock_script_stake_key_hash, +} +use types.{CrowdfundDatum} -// pub const mock_auth_token = mock_policy_id(0) +pub const mock_auth_token = mock_policy_id(0) -// pub const mock_share_token = mock_policy_id(1) +pub const mock_share_token = mock_policy_id(1) -// pub const mock_completion_script = mock_script_hash(0) +pub const mock_completion_script = mock_script_hash(0) -// pub const mock_crowdfund_spend_script_hash = mock_script_hash(1) +pub const mock_crowdfund_spend_script_hash = mock_script_hash(1) -// pub const mock_crowdfund_stake_script_hash = mock_script_stake_key_hash(0) +pub const mock_crowdfund_stake_script_hash = mock_script_stake_key_hash(0) -// pub const mock_crowdfund_address = from_script(mock_crowdfund_spend_script_hash) +pub const mock_crowdfund_address = from_script(mock_crowdfund_spend_script_hash) -// pub const mock_fee_address = from_script("fee_address") +pub const mock_fee_address = from_script("fee_address") -// pub const mock_fundraise_target = 100000000000 +pub const mock_fundraise_target = 100000000000 -// pub const mock_current_fundraised_amount = mock_fundraise_target + 1000000 +pub const mock_current_fundraised_amount = mock_fundraise_target + 1000000 -// pub const mock_contribute_min_fundraised_amount = 2000000 +pub const mock_contribute_min_fundraised_amount = 2000000 -// pub const mock_deadline = 1750735607 +pub const mock_deadline = 1750735607 -// pub const mock_expiry_buffer = 3600 * 24 +pub const mock_expiry_buffer = 3600 * 24 -// pub const mock_min_charge = 0 +pub const mock_min_charge = 0 -// pub fn mock_crowdfund_datum( -// current_fundraised_amount: Int, -// allow_over_subscription: Bool, -// ) { -// CrowdfundDatum { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// crowdfund_address: mock_crowdfund_address, -// fundraise_target: mock_fundraise_target, -// current_fundraised_amount, -// allow_over_subscription, -// deadline: mock_deadline, -// expiry_buffer: mock_expiry_buffer, -// fee_address: mock_fee_address, -// min_charge: mock_min_charge, -// } -// } +pub fn mock_crowdfund_datum( + current_fundraised_amount: Int, + allow_over_subscription: Bool, +) { + CrowdfundDatum { + completion_script: mock_completion_script, + share_token: mock_share_token, + crowdfund_address: mock_crowdfund_address, + fundraise_target: mock_fundraise_target, + current_fundraised_amount, + allow_over_subscription, + deadline: mock_deadline, + expiry_buffer: mock_expiry_buffer, + fee_address: mock_fee_address, + min_charge: mock_min_charge, + } +} -// pub const mock_spend_script_hash = mock_script_hash(1) +pub const mock_start_hash = mock_script_hash(0) -// pub const mock_stake_script_hash = mock_script_hash(2) +pub const mock_spend_script_hash = mock_script_hash(1) -// pub const mock_crowdfund_gov_address = from_script(mock_spend_script_hash) +pub const mock_crowdfund_gov_address = from_script(mock_spend_script_hash) -// pub const mock_gov_address = -// Address { -// payment_credential: Script(mock_spend_script_hash), -// stake_credential: Some(Inline(Script(mock_stake_script_hash))), -// } +pub const mock_gov_address = + Address { + payment_credential: Script(mock_spend_script_hash), + stake_credential: Some(Inline(Script(mock_start_hash))), + } -// pub const mock_gov_action_period = 3600 +pub const mock_gov_action_period = 3600 -// pub const mock_delegate_pool_id = mock_script_hash(3) +pub const mock_delegate_pool_id = mock_script_hash(3) -// pub const mock_gov_action = NoConfidence { ancestor: None } +pub const mock_gov_action = NoConfidence { ancestor: None } -// pub const mock_proposer_key_hash = mock_pub_key_hash(0) +pub const mock_proposer_key_hash = mock_pub_key_hash(0) -// pub const mock_stake_register_deposit = 2000000 +pub const mock_stake_register_deposit = 2000000 -// pub const mock_drep_register_deposit = 500000000 +pub const mock_drep_register_deposit = 500000000 -// pub const mock_funds_controlled = -// mock_fundraise_target + mock_stake_register_deposit + mock_drep_register_deposit +pub const mock_funds_controlled = + mock_fundraise_target + mock_stake_register_deposit + mock_drep_register_deposit -// pub fn add_proposal_procedure( -// tx: Transaction, -// condition: Bool, -// proposal_procedure: ProposalProcedure, -// ) -> Transaction { -// if !condition { -// tx -// } else { -// Transaction { -// ..tx, -// proposal_procedures: tx.proposal_procedures -// |> list.concat([proposal_procedure]), -// } -// } -// } +pub fn add_proposal_procedure( + tx: Transaction, + condition: Bool, + proposal_procedure: ProposalProcedure, +) -> Transaction { + if !condition { + tx + } else { + Transaction { + ..tx, + proposal_procedures: tx.proposal_procedures + |> list.concat([proposal_procedure]), + } + } +} From f3f6ae66845da51d092cf40961fb9d7753ef5094 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Fri, 27 Jun 2025 17:44:28 +0800 Subject: [PATCH 12/19] added: spend test --- .../gov-crowdfund/lib/gov.ak | 166 +- .../gov-crowdfund/lib/types.ak | 3 +- .../gov-crowdfund/lib/utils.ak | 41 +- .../gov-crowdfund/validators/spend.ak | 103 +- .../gov-crowdfund/validators/tests/spend.ak | 3386 ++++++++++------- .../gov-crowdfund/validators/tests/start.ak | 14 +- .../gov-crowdfund/validators/tests/utils.ak | 26 +- 7 files changed, 2287 insertions(+), 1452 deletions(-) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak index 215e09f88..b50730be8 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak @@ -1,95 +1,77 @@ -// use aiken/cbor -// use aiken/crypto.{ScriptHash} -// use aiken/math/rational.{Rational} -// use cardano/address.{Credential} -// use cardano/assets.{Lovelace} -// use cardano/governance.{ -// Constitution, GovernanceAction, GovernanceActionId, Mandate, -// ProtocolParameters, ProtocolVersion, -// } -// use cardano/governance/protocol_parameters.{ProtocolParametersUpdate} +use aiken/crypto.{ScriptHash} +use aiken/math/rational.{Rational} +use cardano/address.{Credential} +use cardano/assets.{Lovelace} +use cardano/governance.{ + Constitution, GovernanceActionId, Mandate, ProtocolVersion, +} -// pub fn to_aiken_gov_action(gov_action: VGovernanceAction) -> GovernanceAction { -// // let raw = cbor.serialise(gov_action) -// // expect Some(output): Option = cbor.deserialise(raw) -// // expect gov: GovernanceAction = output -// when gov_action is { -// VProtocolParameters { ancestor, new_parameters, guardrails } -> -// ProtocolParameters { -// ancestor, -// new_parameters: ProtocolParametersUpdate { inner: new_parameters.inner }, -// guardrails, -// } -// _ -> gov_action -// } -// } +type ProtocolParametersIndex = + Int -// type ProtocolParametersIndex = -// Int +pub type VProtocolParametersUpdate { + inner: Pairs, +} -// pub type VProtocolParametersUpdate { -// inner: Pairs, -// } - -// pub type VGovernanceAction { -// VProtocolParameters { -// /// The last governance action of type 'ProtocolParameters'. They must all -// /// form a chain. -// ancestor: Option, -// /// The new proposed protocol parameters. Only values set to `Some` are relevant. -// new_parameters: VProtocolParametersUpdate, -// /// The optional guardrails script defined in the constitution. The script -// /// is executed by the ledger in addition to the hard-coded ledger rules. -// /// -// /// It must pass for the new protocol parameters to be deemed valid. -// guardrails: Option, -// } -// HardFork { -// /// The last governance action of type `HardFork`. They must all -// /// form a chain. -// ancestor: Option, -// /// The new proposed version. Few rules apply to proposing new versions: -// /// -// /// - The `major` component, if incremented, must be exactly one more than the current. -// /// - The `minor` component, if incremented, must be exactly one more than the current. -// /// - If the `major` component is incremented, `minor` must be set to `0`. -// /// - Neither `minor` nor `major` can be decremented. -// new_version: ProtocolVersion, -// } -// TreasuryWithdrawal { -// /// A collection of beneficiaries, which can be plain verification key -// /// hashes or script hashes (e.g. DAO). -// beneficiaries: Pairs, -// /// The optional guardrails script defined in the constitution. The script -// /// is executed by the ledger in addition to the hard-coded ledger rules. -// /// -// /// It must pass for the withdrawals to be authorized. -// guardrails: Option, -// } -// NoConfidence { -// /// The last governance action of type `NoConfidence` or -// /// `ConstitutionalCommittee`. They must all / form a chain. -// ancestor: Option, -// } -// ConstitutionalCommittee { -// /// The last governance action of type `NoConfidence` or -// /// `ConstitutionalCommittee`. They must all / form a chain. -// ancestor: Option, -// /// Constitutional members to be removed. -// evicted_members: List, -// /// Constitutional members to be added. -// added_members: Pairs, -// /// The new quorum value, as a ratio of a numerator and a denominator. The -// /// quorum specifies the threshold of 'Yes' votes necessary for the -// /// constitutional committee to accept a proposal procedure. -// quorum: Rational, -// } -// NewConstitution { -// /// The last governance action of type `Constitution` or -// /// `ConstitutionalCommittee`. They must all / form a chain. -// ancestor: Option, -// /// The new proposed constitution. -// constitution: Constitution, -// } -// NicePoll -// } +pub type VGovernanceAction { + VProtocolParameters { + /// The last governance action of type 'ProtocolParameters'. They must all + /// form a chain. + ancestor: Option, + /// The new proposed protocol parameters. Only values set to `Some` are relevant. + new_parameters: VProtocolParametersUpdate, + /// The optional guardrails script defined in the constitution. The script + /// is executed by the ledger in addition to the hard-coded ledger rules. + /// + /// It must pass for the new protocol parameters to be deemed valid. + guardrails: Option, + } + HardFork { + /// The last governance action of type `HardFork`. They must all + /// form a chain. + ancestor: Option, + /// The new proposed version. Few rules apply to proposing new versions: + /// + /// - The `major` component, if incremented, must be exactly one more than the current. + /// - The `minor` component, if incremented, must be exactly one more than the current. + /// - If the `major` component is incremented, `minor` must be set to `0`. + /// - Neither `minor` nor `major` can be decremented. + new_version: ProtocolVersion, + } + TreasuryWithdrawal { + /// A collection of beneficiaries, which can be plain verification key + /// hashes or script hashes (e.g. DAO). + beneficiaries: Pairs, + /// The optional guardrails script defined in the constitution. The script + /// is executed by the ledger in addition to the hard-coded ledger rules. + /// + /// It must pass for the withdrawals to be authorized. + guardrails: Option, + } + NoConfidence { + /// The last governance action of type `NoConfidence` or + /// `ConstitutionalCommittee`. They must all / form a chain. + ancestor: Option, + } + ConstitutionalCommittee { + /// The last governance action of type `NoConfidence` or + /// `ConstitutionalCommittee`. They must all / form a chain. + ancestor: Option, + /// Constitutional members to be removed. + evicted_members: List, + /// Constitutional members to be added. + added_members: Pairs, + /// The new quorum value, as a ratio of a numerator and a denominator. The + /// quorum specifies the threshold of 'Yes' votes necessary for the + /// constitutional committee to accept a proposal procedure. + quorum: Rational, + } + NewConstitution { + /// The last governance action of type `Constitution` or + /// `ConstitutionalCommittee`. They must all / form a chain. + ancestor: Option, + /// The new proposed constitution. + constitution: Constitution, + } + NicePoll +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak index 4d53cd0de..90eb956d5 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak @@ -3,8 +3,8 @@ use cardano/governance.{GovernanceActionId} pub type CrowdfundRedeemer { RegisterCerts - DeregisterCerts VoteOnGovAction + DeregisterCerts ContributorWithdrawal RemoveEmptyInstance } @@ -46,7 +46,6 @@ pub type CrowdfundGovDatum { start_hash: ByteArray, share_token: ByteArray, funds_controlled: Int, - deadline: Int, } } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak index e9d0491e3..0d66337fe 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak @@ -1,5 +1,6 @@ +use aiken/cbor use aiken/collection/list -use aiken/collection/pairs +use aiken/collection/pairs.{get_first} use cardano/address.{Credential, from_script} use cardano/assets.{Lovelace, lovelace_of} use cardano/certificate.{ @@ -8,8 +9,12 @@ use cardano/certificate.{ RegisterDelegateRepresentative, StakePoolId, UnregisterCredential, UnregisterDelegateRepresentative, } +use cardano/governance.{ + GovernanceAction, GovernanceActionId, ProposalProcedure, Vote, Voter, Yes, +} use cardano/transaction.{Input, Output, Redeemer, ScriptPurpose, Spend} use cocktail.{inputs_at} +use gov.{VGovernanceAction} use types.{CrowdfundRedeemer} pub fn redeemer_with_input( @@ -127,3 +132,37 @@ pub fn check_spend_script_input_redeemer( only_input_redeemer == redeemer } + +pub fn compare_gov_action(agov: GovernanceAction, vgov: VGovernanceAction) { + let se_agov = cbor.serialise(agov) + let se_vgov = cbor.serialise(vgov) + se_agov == se_vgov +} + +pub fn check_proposal_procedure( + proposal_procedures: List, + deposit: Lovelace, + return_address: Credential, + vgovernance_action: VGovernanceAction, +) { + list.count( + proposal_procedures, + fn(proposal_procedure) { + proposal_procedure.deposit == deposit && proposal_procedure.return_address == return_address && compare_gov_action( + proposal_procedure.governance_action, + vgovernance_action, + ) + }, + ) == 1 +} + +pub fn check_vote( + votes: Pairs>, + drep: Voter, + gov_tx_id: GovernanceActionId, +) { + let value_list = get_first(votes, drep) + + expect Some(gov_pair) = value_list + list.has(gov_pair, Pair(gov_tx_id, Yes)) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak index 3f96addb5..59343009a 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak @@ -1,28 +1,29 @@ -use aiken/collection/list -use cardano/address.{Inline} +use cardano/address.{Inline, Script} use cardano/assets.{Lovelace, lovelace_of} use cardano/certificate.{Registered} -use cardano/governance.{GovernanceAction, GovernanceActionId, ProposalProcedure} +use cardano/governance.{DelegateRepresentative, GovernanceActionId} use cardano/transaction.{OutputReference, Transaction, find_input} use cocktail.{ - inputs_at, key_signed, only_minted_token, output_inline_datum, outputs_at, - policy_only_minted_token, valid_after, value_length, + inputs_at_with, key_signed, only_minted_token, output_inline_datum, + outputs_at_with, policy_only_minted_token, valid_after, value_length, } +use gov.{VGovernanceAction} use types.{ ContributorWithdrawal, CrowdfundGovDatum, CrowdfundRedeemer, DeregisterCerts, Init, Proposed, Refundable, RegisterCerts, RemoveEmptyInstance, VoteOnGovAction, Voted, } use utils.{ - check_lovelace_diff, delegate_stake_and_vote_certificate, - delegate_stake_certificate, delegate_vote_certificate, - register_drep_certificate, register_stake_certificate, - unregister_drep_certificate, unregister_stake_certificate, + check_lovelace_diff, check_proposal_procedure, check_vote, + delegate_stake_and_vote_certificate, delegate_stake_certificate, + delegate_vote_certificate, register_drep_certificate, + register_stake_certificate, unregister_drep_certificate, + unregister_stake_certificate, } validator spend( delegate_pool_id: ByteArray, - gov_action: GovernanceAction, + gov_action: VGovernanceAction, proposer_key_hash: ByteArray, stake_register_deposit: Lovelace, drep_register_deposit: Lovelace, @@ -41,6 +42,7 @@ validator spend( extra_signatories, certificates, proposal_procedures, + votes, .. } = self @@ -49,28 +51,26 @@ validator spend( let current_address = own_input.output.address - // check only 1 input from current address - expect [only_input] = inputs_at(inputs, current_address) - when redeemer is { RegisterCerts -> when only_input_datum is { Init { start_hash, share_token, funds_controlled, deadline } -> { + // check only 1 input with token from current address + expect [only_input] = + inputs_at_with(inputs, current_address, start_hash, "") expect Some(current_stake_credential) = current_address.stake_credential expect Inline(current_credential) = current_stake_credential - expect [only_output] = outputs_at(outputs, current_address) - - let lovelace_from_only_input = - only_input.output.value |> lovelace_of() + expect [only_output] = + outputs_at_with(outputs, current_address, start_hash, "") let lovelace_check = check_lovelace_diff( only_input, only_output, - -(stake_register_deposit + drep_register_deposit), + -(stake_register_deposit + drep_register_deposit + 100000000000), ) expect only_output_datum: CrowdfundGovDatum = output_inline_datum(only_output) @@ -112,13 +112,11 @@ validator spend( ) let proposal_check = - list.has( + check_proposal_procedure( proposal_procedures, - ProposalProcedure { - deposit: lovelace_from_only_input - stake_register_deposit - drep_register_deposit, - return_address: current_address.payment_credential, - governance_action: gov_action, - }, + 100000000000, + current_address.payment_credential, + gov_action, ) lovelace_check? && output_datum_check? && is_only_output_value_clean? && reg_stake_cert_check? && reg_drep_cert_check? && delegate_check? && proposal_check? } @@ -127,40 +125,53 @@ validator spend( VoteOnGovAction -> when only_input_datum is { Proposed { start_hash, share_token, funds_controlled, deadline } -> { - expect [only_output] = outputs_at(outputs, current_address) + // check only 1 input with token from current address + expect [only_input] = + inputs_at_with(inputs, current_address, start_hash, "") + expect [only_output] = + outputs_at_with(outputs, current_address, start_hash, "") - let lovelace_check = - check_lovelace_diff(only_input, only_output, -100000000000) + let value_check = only_input.output.value == only_output.value expect only_output_datum: CrowdfundGovDatum = output_inline_datum(only_output) + let gov_tx_id = + GovernanceActionId { + transaction: own_input.output_reference.transaction_id, + proposal_procedure: 0, + } let output_datum_check = only_output_datum == Voted { start_hash, share_token, funds_controlled, - gov_tx_id: GovernanceActionId { - transaction: own_input.output_reference.transaction_id, - proposal_procedure: 0, - }, + gov_tx_id, deadline, } let is_only_output_value_clean = value_length(only_output.value) == 2 - lovelace_check? && output_datum_check? && is_only_output_value_clean? + value_check? && output_datum_check? && is_only_output_value_clean? && check_vote( + votes, + DelegateRepresentative(Script(start_hash)), + gov_tx_id, + ) } _ -> False } DeregisterCerts -> when only_input_datum is { Voted { start_hash, share_token, funds_controlled, deadline, .. } -> { + // check only 1 input with token from current address + expect [only_input] = + inputs_at_with(inputs, current_address, start_hash, "") expect Some(current_stake_credential) = current_address.stake_credential expect Inline(current_credential) = current_stake_credential let validity_check = valid_after(validity_range, deadline) - expect [only_output] = outputs_at(outputs, current_address) + expect [only_output] = + outputs_at_with(outputs, current_address, start_hash, "") let lovelace_check = check_lovelace_diff( only_input, @@ -175,7 +186,6 @@ validator spend( start_hash, share_token, funds_controlled, - deadline, } let unreg_stake_cert_check = @@ -187,7 +197,10 @@ validator spend( current_credential, drep_register_deposit, ) - validity_check? && lovelace_check? && output_datum_check? && unreg_stake_cert_check? && unreg_drep_cert_check? + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + validity_check? && lovelace_check? && output_datum_check? && unreg_stake_cert_check? && unreg_drep_cert_check? && is_only_output_value_clean? } _ -> False @@ -195,10 +208,13 @@ validator spend( ContributorWithdrawal -> when only_input_datum is { - Refundable { start_hash, share_token, funds_controlled, deadline } -> { - let validity_check = valid_after(validity_range, deadline) + Refundable { start_hash, share_token, funds_controlled } -> { + // check only 1 input with token from current address + expect [only_input] = + inputs_at_with(inputs, current_address, start_hash, "") - expect [only_output] = outputs_at(outputs, current_address) + expect [only_output] = + outputs_at_with(outputs, current_address, start_hash, "") let lovelace_from_only_input = only_input.output.value |> lovelace_of() @@ -216,13 +232,12 @@ validator spend( start_hash, share_token, funds_controlled: funds_controlled + lovelace_withdrawn, - deadline, } let is_only_output_value_clean = value_length(only_output.value) == 2 - validity_check? && lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( + lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( mint, share_token, start_hash, @@ -234,9 +249,9 @@ validator spend( RemoveEmptyInstance -> when only_input_datum is { - Refundable { start_hash, share_token, funds_controlled, deadline } -> { - let validity_check = valid_after(validity_range, deadline) - + Refundable { start_hash, share_token, funds_controlled } -> { + // check only 1 input with token from current address + expect [_] = inputs_at_with(inputs, current_address, start_hash, "") let token_burnt_check = if funds_controlled > 0 { policy_only_minted_token( @@ -251,7 +266,7 @@ validator spend( let proposer_key_signed_check = key_signed(extra_signatories, proposer_key_hash) - validity_check? && token_burnt_check? && proposer_key_signed_check? && policy_only_minted_token( + token_burnt_check? && proposer_key_signed_check? && policy_only_minted_token( mint, start_hash, "", diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak index 5f3e69afd..32e69ea13 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak @@ -1,1009 +1,1756 @@ -// use cardano/address.{Script} -// use cardano/assets.{add, from_lovelace} -// use cardano/certificate.{ -// DelegateBlockProduction, DelegateCredential, DelegateVote, RegisterCredential, -// RegisterDelegateRepresentative, Registered, UnregisterCredential, -// UnregisterDelegateRepresentative, -// } -// use cardano/governance.{ProposalProcedure} -// use cardano/transaction.{Transaction} -// use mocktail.{ -// add_certificate, add_extra_signatory, complete, invalid_before, mint, -// mock_policy_id, mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, -// tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, -// } -// use spend -// use tests/utils.{ -// add_proposal_procedure, mock_completion_script, -// mock_contribute_min_fundraised_amount, mock_current_fundraised_amount, -// mock_deadline, mock_delegate_pool_id, mock_drep_register_deposit, -// mock_funds_controlled, mock_gov_action, mock_gov_action_period, -// mock_gov_address, mock_proposer_key_hash, mock_share_token, -// mock_spend_script_hash, mock_stake_register_deposit, mock_stake_script_hash, -// } -// use types.{ -// ContributorWithdrawal, Init, Proposed, Refundable, RegisterCerts, -// RemoveEmptyInstance, -// } - -// type RegisterCertsTestCase { -// is_only_one_inputed: Bool, -// is_only_one_outputed: Bool, -// is_output_datum_correct: Bool, -// is_output_value_clean: Bool, -// is_output_value_correct: Bool, -// is_stake_cert_register: Bool, -// is_drep_cert_register: Bool, -// is_drep_deposit_correct: Bool, -// is_stake_delegated: Bool, -// is_vote_delegated: Bool, -// is_gov_proposed: Bool, -// } - -// fn mock_register_cert_tx(test_case: RegisterCertsTestCase) -> Transaction { -// let RegisterCertsTestCase { -// is_only_one_inputed, -// is_only_one_outputed, -// is_output_datum_correct, -// is_output_value_clean, -// is_output_value_correct, -// is_stake_cert_register, -// is_drep_cert_register, -// is_drep_deposit_correct, -// is_stake_delegated, -// is_vote_delegated, -// is_gov_proposed, -// } = test_case - -// let input_value = from_lovelace(mock_funds_controlled) - -// let input_datum = -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// } -// let output_value = -// if is_output_value_correct { -// from_lovelace( -// mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, -// ) -// } else { -// from_lovelace( -// mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit + 10, -// ) -// } - -// let output_datum = -// if is_output_datum_correct { -// Proposed { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// } -// } else { -// Proposed { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled + 10, -// deadline: mock_deadline + mock_gov_action_period, -// } -// } - -// let drep_deposit = -// if is_drep_deposit_correct { -// mock_drep_register_deposit -// } else { -// mock_drep_register_deposit - 1000000 -// } -// mocktail_tx() -// |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) -// |> tx_in_inline_datum(True, input_datum) -// |> tx_in( -// !is_only_one_inputed, -// mock_tx_hash(0), -// 1, -// input_value, -// mock_gov_address, -// ) -// |> tx_out(is_output_value_clean, mock_gov_address, output_value) -// |> tx_out( -// !is_output_value_clean, -// mock_gov_address, -// output_value |> add(mock_policy_id(999), mock_completion_script, 1), -// ) -// |> tx_out_inline_datum(True, output_datum) -// |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) -// |> complete() -// |> add_certificate( -// is_stake_cert_register, -// RegisterCredential { -// credential: Script(mock_stake_script_hash), -// deposit: Never, -// }, -// ) -// |> add_certificate( -// is_drep_cert_register, -// RegisterDelegateRepresentative { -// delegate_representative: Script(mock_stake_script_hash), -// deposit: drep_deposit, -// }, -// ) -// |> add_certificate( -// is_stake_delegated, -// DelegateCredential { -// credential: Script(mock_stake_script_hash), -// delegate: DelegateBlockProduction { -// stake_pool: mock_delegate_pool_id, -// }, -// }, -// ) -// |> add_certificate( -// is_vote_delegated, -// DelegateCredential { -// credential: Script(mock_stake_script_hash), -// delegate: DelegateVote { -// delegate_representative: Registered(Script(mock_stake_script_hash)), -// }, -// }, -// ) -// |> add_proposal_procedure( -// is_gov_proposed, -// ProposalProcedure { -// deposit: mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit, -// return_address: Script(mock_spend_script_hash), -// governance_action: mock_gov_action, -// }, -// ) -// } - -// test s3_spend_success_reg_cert() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_not_init_state() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Proposed { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_more_than_one_input() fail { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: False, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_more_than_one_output() fail { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: False, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_incorrect_output_datum() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: False, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_output_value_not_clean() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: False, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_incorrect_output_value() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: False, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_stake_cert_not_reg() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: False, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_drep_cert_not_reg() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: False, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_drep_deposit_incorrect() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: False, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_stake_not_delegated() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: False, -// is_vote_delegated: True, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_vote_not_delegated() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: False, -// is_gov_proposed: True, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_reg_cert_with_gov_not_proposed() { -// let tx = -// mock_register_cert_tx( -// RegisterCertsTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_output_value_correct: True, -// is_stake_cert_register: True, -// is_drep_cert_register: True, -// is_drep_deposit_correct: True, -// is_stake_delegated: True, -// is_vote_delegated: True, -// is_gov_proposed: False, -// }, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_funds_controlled, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RegisterCerts, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// type ContributorWithdrawalTestCase { -// is_only_one_inputed: Bool, -// is_only_one_outputed: Bool, -// is_output_datum_correct: Bool, -// is_output_value_clean: Bool, -// is_unlock_value_correct: Bool, -// is_deadline_passed: Bool, -// is_shares_burnt: Bool, -// } - -// fn mock_contributor_withdrawal_tx( -// test_case: ContributorWithdrawalTestCase, -// current_fundraised_amount: Int, -// withdraw_amount: Int, -// ) -> Transaction { -// let ContributorWithdrawalTestCase { -// is_only_one_inputed, -// is_only_one_outputed, -// is_output_datum_correct, -// is_output_value_clean, -// is_unlock_value_correct, -// is_deadline_passed, -// is_shares_burnt, -// } = test_case - -// let input_value = from_lovelace(current_fundraised_amount) - -// let input_datum = -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// } -// let output_value = -// if is_unlock_value_correct { -// from_lovelace(current_fundraised_amount - withdraw_amount) -// } else { -// from_lovelace(current_fundraised_amount - withdraw_amount + 10) -// } - -// let output_datum = -// if is_output_datum_correct { -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: current_fundraised_amount - withdraw_amount, -// deadline: mock_deadline + mock_gov_action_period, -// } -// } else { -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: current_fundraised_amount - withdraw_amount + 10, -// deadline: mock_deadline + mock_gov_action_period, -// } -// } - -// mocktail_tx() -// |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) -// |> tx_in_inline_datum(True, input_datum) -// |> tx_in( -// !is_only_one_inputed, -// mock_tx_hash(0), -// 1, -// input_value, -// mock_gov_address, -// ) -// |> tx_out(True, mock_pub_key_address(0, None), from_lovelace(withdraw_amount)) -// |> tx_out(is_output_value_clean, mock_gov_address, output_value) -// |> tx_out( -// !is_output_value_clean, -// mock_gov_address, -// output_value |> add(mock_policy_id(999), mock_completion_script, 1), -// ) -// |> tx_out_inline_datum(True, output_datum) -// |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) -// |> invalid_before( -// is_deadline_passed, -// mock_deadline + mock_gov_action_period + 3600 * 24, -// ) -// |> invalid_before( -// !is_deadline_passed, -// mock_deadline + mock_gov_action_period - 3600 * 24, -// ) -// |> mint( -// is_shares_burnt, -// -withdraw_amount, -// mock_share_token, -// mock_completion_script, -// ) -// |> mint( -// !is_shares_burnt, -// -withdraw_amount + 9999999, -// mock_share_token, -// mock_completion_script, -// ) -// |> complete() -// } - -// test s3_spend_success_contributor_withdraw() { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_unlock_value_correct: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_contributor_withdraw_with_state_not_refundable() { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_unlock_value_correct: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Proposed { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: False, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_unlock_value_correct: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: False, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_unlock_value_correct: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: False, -// is_output_value_clean: True, -// is_unlock_value_correct: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: False, -// is_unlock_value_correct: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_unlock_value_correct: False, -// is_deadline_passed: True, -// is_shares_burnt: True, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } +use cardano/address.{Script} +use cardano/assets.{add, from_lovelace} +use cardano/certificate.{ + DelegateBlockProduction, DelegateCredential, DelegateVote, RegisterCredential, + RegisterDelegateRepresentative, Registered, UnregisterCredential, + UnregisterDelegateRepresentative, +} +use cardano/governance.{ + DelegateRepresentative, GovernanceActionId, NoConfidence, ProposalProcedure, + Yes, +} +use cardano/transaction.{Transaction} +use mocktail.{ + add_certificate, add_extra_signatory, complete, invalid_before, mint, + mock_policy_id, mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, + tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, +} +use spend +use tests/utils.{ + add_proposal_procedure, add_vote, mock_contribute_min_fundraised_amount, + mock_current_fundraised_amount, mock_deadline, mock_delegate_pool_id, + mock_drep_register_deposit, mock_fundraise_target, mock_funds_controlled, + mock_gov_action, mock_gov_action_id, mock_gov_action_period, mock_gov_address, + mock_proposer_key_hash, mock_share_token, mock_spend_script_hash, + mock_stake_register_deposit, mock_start_hash, +} +use types.{ + ContributorWithdrawal, DeregisterCerts, Init, Proposed, Refundable, + RegisterCerts, RemoveEmptyInstance, VoteOnGovAction, Voted, +} + +type RegisterCertsTestCase { + is_only_one_inputed: Bool, + is_only_one_outputed: Bool, + is_output_datum_correct: Bool, + is_output_value_clean: Bool, + is_output_value_correct: Bool, + is_stake_cert_register: Bool, + is_drep_cert_register: Bool, + is_drep_deposit_correct: Bool, + is_stake_delegated: Bool, + is_vote_delegated: Bool, + is_gov_proposed: Bool, +} + +fn mock_register_cert_tx(test_case: RegisterCertsTestCase) -> Transaction { + let RegisterCertsTestCase { + is_only_one_inputed, + is_only_one_outputed, + is_output_datum_correct, + is_output_value_clean, + is_output_value_correct, + is_stake_cert_register, + is_drep_cert_register, + is_drep_deposit_correct, + is_stake_delegated, + is_vote_delegated, + is_gov_proposed, + } = test_case + + let input_value = + from_lovelace(mock_funds_controlled) |> add(mock_start_hash, "", 1) + + let input_datum = + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + } + let output_value = + if is_output_value_correct { + from_lovelace( + mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit - mock_fundraise_target, + ) + |> add(mock_start_hash, "", 1) + } else { + from_lovelace( + mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit + 10 - mock_fundraise_target, + ) + |> add(mock_start_hash, "", 1) + } + + let output_datum = + if is_output_datum_correct { + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + } + } else { + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled + 10, + deadline: mock_deadline + mock_gov_action_period, + } + } + + let drep_deposit = + if is_drep_deposit_correct { + mock_drep_register_deposit + } else { + mock_drep_register_deposit - 1000000 + } + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out(is_output_value_clean, mock_gov_address, output_value) + |> tx_out( + !is_output_value_clean, + mock_gov_address, + output_value |> add(mock_policy_id(999), mock_start_hash, 1), + ) + |> tx_out_inline_datum(True, output_datum) + |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) + |> complete() + |> add_certificate( + is_stake_cert_register, + RegisterCredential { + credential: Script(mock_start_hash), + deposit: Never, + }, + ) + |> add_certificate( + is_drep_cert_register, + RegisterDelegateRepresentative { + delegate_representative: Script(mock_start_hash), + deposit: drep_deposit, + }, + ) + |> add_certificate( + is_stake_delegated, + DelegateCredential { + credential: Script(mock_start_hash), + delegate: DelegateBlockProduction { + stake_pool: mock_delegate_pool_id, + }, + }, + ) + |> add_certificate( + is_vote_delegated, + DelegateCredential { + credential: Script(mock_start_hash), + delegate: DelegateVote { + delegate_representative: Registered(Script(mock_start_hash)), + }, + }, + ) + |> add_proposal_procedure( + is_gov_proposed, + ProposalProcedure { + deposit: mock_fundraise_target, + return_address: Script(mock_spend_script_hash), + governance_action: NoConfidence { ancestor: None }, + }, + ) +} + +test s3_spend_success_reg_cert() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_not_init_state() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_more_than_one_input() fail { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: False, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_more_than_one_output() fail { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: False, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_incorrect_output_datum() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: False, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_output_value_not_clean() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: False, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_incorrect_output_value() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: False, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_stake_cert_not_reg() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: False, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_drep_cert_not_reg() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: False, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_drep_deposit_incorrect() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: False, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_stake_not_delegated() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: False, + is_vote_delegated: True, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_vote_not_delegated() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: False, + is_gov_proposed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_reg_cert_with_gov_not_proposed() { + let tx = + mock_register_cert_tx( + RegisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_register: True, + is_drep_cert_register: True, + is_drep_deposit_correct: True, + is_stake_delegated: True, + is_vote_delegated: True, + is_gov_proposed: False, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +type VoteOnGovActionTestCase { + is_only_one_inputed: Bool, + is_only_one_outputed: Bool, + is_output_datum_correct: Bool, + is_output_value_clean: Bool, + is_output_value_same: Bool, + is_voted_by_drep: Bool, +} + +fn mock_vote_on_gov_action_tx(test_case: VoteOnGovActionTestCase) -> Transaction { + let VoteOnGovActionTestCase { + is_only_one_inputed, + is_only_one_outputed, + is_output_datum_correct, + is_output_value_clean, + is_output_value_same, + is_voted_by_drep, + } = test_case + + let input_value = + from_lovelace(mock_current_fundraised_amount) |> add(mock_start_hash, "", 1) + + let input_datum = + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + } + let output_value = + if is_output_value_same { + from_lovelace(mock_current_fundraised_amount) + |> add(mock_start_hash, "", 1) + } else { + from_lovelace(mock_current_fundraised_amount + 10) + |> add(mock_start_hash, "", 1) + } + + let output_datum = + if is_output_datum_correct { + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + gov_tx_id: mock_gov_action_id, + } + } else { + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + gov_tx_id: GovernanceActionId { + transaction: mock_tx_hash(0), + proposal_procedure: 1, + }, + } + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out( + True, + mock_pub_key_address(0, None), + from_lovelace(mock_fundraise_target), + ) + |> tx_out(is_output_value_clean, mock_gov_address, output_value) + |> tx_out( + !is_output_value_clean, + mock_gov_address, + output_value |> add(mock_policy_id(999), mock_start_hash, 1), + ) + |> tx_out_inline_datum(True, output_datum) + |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) + |> complete() + |> add_vote( + is_voted_by_drep, + Pair( + DelegateRepresentative(Script(mock_start_hash)), + [Pair(mock_gov_action_id, Yes)], + ), + ) +} + +test s3_spend_success_vote_on_gov_action() { + let tx = + mock_vote_on_gov_action_tx( + VoteOnGovActionTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_same: True, + is_voted_by_drep: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + VoteOnGovAction, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_vote_on_gov_action_with_more_than_one_inputed() fail { + let tx = + mock_vote_on_gov_action_tx( + VoteOnGovActionTestCase { + is_only_one_inputed: False, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_same: True, + is_voted_by_drep: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + VoteOnGovAction, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_vote_on_gov_action_with_more_than_one_outputed() fail { + let tx = + mock_vote_on_gov_action_tx( + VoteOnGovActionTestCase { + is_only_one_inputed: True, + is_only_one_outputed: False, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_same: True, + is_voted_by_drep: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + VoteOnGovAction, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_vote_on_gov_action_with_output_datum_wrong() { + let tx = + mock_vote_on_gov_action_tx( + VoteOnGovActionTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: False, + is_output_value_clean: True, + is_output_value_same: True, + is_voted_by_drep: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + VoteOnGovAction, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_vote_on_gov_action_with_output_value_not_clean() { + let tx = + mock_vote_on_gov_action_tx( + VoteOnGovActionTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: False, + is_output_value_same: True, + is_voted_by_drep: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + VoteOnGovAction, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_vote_on_gov_action_with_incorrect_output_value() { + let tx = + mock_vote_on_gov_action_tx( + VoteOnGovActionTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_same: False, + is_voted_by_drep: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + VoteOnGovAction, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_vote_on_gov_action_with_no_vote() fail { + let tx = + mock_vote_on_gov_action_tx( + VoteOnGovActionTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_same: True, + is_voted_by_drep: False, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + VoteOnGovAction, + mock_utxo_ref(0, 0), + tx, + ) +} + +type DeregisterCertsTestCase { + is_only_one_inputed: Bool, + is_only_one_outputed: Bool, + is_output_datum_correct: Bool, + is_output_value_clean: Bool, + is_output_value_correct: Bool, + is_stake_cert_deregister: Bool, + is_drep_cert_deregister: Bool, + is_deadline_passed: Bool, +} + +fn mock_deregister_cert_tx(test_case: DeregisterCertsTestCase) -> Transaction { + let DeregisterCertsTestCase { + is_only_one_inputed, + is_only_one_outputed, + is_output_datum_correct, + is_output_value_clean, + is_output_value_correct, + is_stake_cert_deregister, + is_drep_cert_deregister, + is_deadline_passed, + } = test_case + + let input_value = + from_lovelace(mock_funds_controlled) |> add(mock_start_hash, "", 1) + + let input_datum = + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + } + let output_value = + if is_output_value_correct { + from_lovelace( + mock_funds_controlled + mock_stake_register_deposit + mock_drep_register_deposit, + ) + |> add(mock_start_hash, "", 1) + } else { + from_lovelace( + mock_funds_controlled + mock_stake_register_deposit + mock_drep_register_deposit - 10, + ) + |> add(mock_start_hash, "", 1) + } + + let output_datum = + if is_output_datum_correct { + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + } + } else { + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled + 10, + } + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out(is_output_value_clean, mock_gov_address, output_value) + |> tx_out( + !is_output_value_clean, + mock_gov_address, + output_value |> add(mock_policy_id(999), mock_start_hash, 1), + ) + |> tx_out_inline_datum(True, output_datum) + |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) + |> invalid_before( + is_deadline_passed, + mock_deadline + mock_gov_action_period + 3600 * 24, + ) + |> invalid_before( + !is_deadline_passed, + mock_deadline + mock_gov_action_period - 3600 * 24, + ) + |> complete() + |> add_certificate( + is_stake_cert_deregister, + UnregisterCredential { + credential: Script(mock_start_hash), + refund: Never, + }, + ) + |> add_certificate( + is_drep_cert_deregister, + UnregisterDelegateRepresentative { + delegate_representative: Script(mock_start_hash), + refund: mock_drep_register_deposit, + }, + ) +} + +test s3_spend_success_unregister_certs() { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_deregister: True, + is_drep_cert_deregister: True, + is_deadline_passed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_more_than_one_inputed() fail { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: False, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_deregister: True, + is_drep_cert_deregister: True, + is_deadline_passed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_more_than_one_outputed() fail { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: False, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_deregister: True, + is_drep_cert_deregister: True, + is_deadline_passed: True, + }, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_output_datum_incorrect() { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: False, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_deregister: True, + is_drep_cert_deregister: True, + is_deadline_passed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_output_value_not_clean() { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: False, + is_output_value_correct: True, + is_stake_cert_deregister: True, + is_drep_cert_deregister: True, + is_deadline_passed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_output_value_incorrect() { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: False, + is_stake_cert_deregister: True, + is_drep_cert_deregister: True, + is_deadline_passed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_stake_not_unregister() { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_deregister: False, + is_drep_cert_deregister: True, + is_deadline_passed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_drep_not_unregister() { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_deregister: True, + is_drep_cert_deregister: False, + is_deadline_passed: True, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_unregister_certs_with_deadline_not_passed() { + let tx = + mock_deregister_cert_tx( + DeregisterCertsTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_output_value_correct: True, + is_stake_cert_deregister: True, + is_drep_cert_deregister: True, + is_deadline_passed: False, + }, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Voted { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + gov_tx_id: mock_gov_action_id, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + DeregisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +type ContributorWithdrawalTestCase { + is_only_one_inputed: Bool, + is_only_one_outputed: Bool, + is_output_datum_correct: Bool, + is_output_value_clean: Bool, + is_unlock_value_correct: Bool, + // is_deadline_passed: Bool, + is_shares_burnt: Bool, +} + +fn mock_contributor_withdrawal_tx( + test_case: ContributorWithdrawalTestCase, + current_fundraised_amount: Int, + withdraw_amount: Int, +) -> Transaction { + let ContributorWithdrawalTestCase { + is_only_one_inputed, + is_only_one_outputed, + is_output_datum_correct, + is_output_value_clean, + is_unlock_value_correct, + is_shares_burnt, + } = test_case + + let input_value = + from_lovelace(current_fundraised_amount) |> add(mock_start_hash, "", 1) + + let input_datum = + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount, + } + let output_value = + if is_unlock_value_correct { + from_lovelace(current_fundraised_amount - withdraw_amount) + |> add(mock_start_hash, "", 1) + } else { + from_lovelace(current_fundraised_amount - withdraw_amount + 10) + |> add(mock_start_hash, "", 1) + } + + let output_datum = + if is_output_datum_correct { + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount - withdraw_amount, + } + } else { + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount - withdraw_amount + 10, + } + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out(True, mock_pub_key_address(0, None), from_lovelace(withdraw_amount)) + |> tx_out(is_output_value_clean, mock_gov_address, output_value) + |> tx_out( + !is_output_value_clean, + mock_gov_address, + output_value |> add(mock_policy_id(999), mock_start_hash, 1), + ) + |> tx_out_inline_datum(True, output_datum) + |> tx_out(!is_only_one_outputed, mock_gov_address, output_value) // |> invalid_before( + // is_deadline_passed, + // mock_deadline + mock_gov_action_period + 3600 * 24, + // ) + // |> invalid_before( + // !is_deadline_passed, + // mock_deadline + mock_gov_action_period - 3600 * 24, + // ) + + |> mint(is_shares_burnt, -withdraw_amount, mock_share_token, mock_start_hash) + |> mint( + !is_shares_burnt, + -withdraw_amount + 9999999, + mock_share_token, + mock_start_hash, + ) + |> complete() +} + +test s3_spend_success_contributor_withdraw() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + // is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_state_not_refundable() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + // is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Proposed { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: False, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + // is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: False, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + // is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: False, + is_output_value_clean: True, + is_unlock_value_correct: True, + // is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: False, + is_unlock_value_correct: True, + // is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: False, + // is_deadline_passed: True, + is_shares_burnt: True, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} // test s3_spend_fail_contributor_withdraw_with_deadline_not_passed() { // let tx = @@ -1029,10 +1776,9 @@ // mock_drep_register_deposit, // Some( // Refundable { -// completion_script: mock_completion_script, +// start_hash: mock_start_hash, // share_token: mock_share_token, // funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, // }, // ), // ContributorWithdrawal, @@ -1041,236 +1787,238 @@ // ) // } -// test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { -// let tx = -// mock_contributor_withdrawal_tx( -// ContributorWithdrawalTestCase { -// is_only_one_inputed: True, -// is_only_one_outputed: True, -// is_output_datum_correct: True, -// is_output_value_clean: True, -// is_unlock_value_correct: True, -// is_deadline_passed: True, -// is_shares_burnt: False, -// }, -// mock_current_fundraised_amount, -// mock_contribute_min_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// ContributorWithdrawal, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// type RemoveEmptyInstanceTestCase { -// is_only_one_inputed: Bool, -// is_deadline_passed: Bool, -// is_shares_burnt: Bool, -// is_proposer_signed: Bool, -// } - -// fn mock_remove_empty_instance_tx( -// test_case: RemoveEmptyInstanceTestCase, -// current_fundraised_amount: Int, -// ) -> Transaction { -// let RemoveEmptyInstanceTestCase { -// is_only_one_inputed, -// is_deadline_passed, -// is_shares_burnt, -// is_proposer_signed, -// } = test_case - -// let input_value = from_lovelace(current_fundraised_amount) - -// let input_datum = -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// } - -// mocktail_tx() -// |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) -// |> tx_in_inline_datum(True, input_datum) -// |> tx_in( -// !is_only_one_inputed, -// mock_tx_hash(0), -// 1, -// input_value, -// mock_gov_address, -// ) -// |> tx_out( -// True, -// mock_pub_key_address(0, None), -// from_lovelace(current_fundraised_amount), -// ) -// |> invalid_before( -// is_deadline_passed, -// mock_deadline + mock_gov_action_period + 3600 * 24, -// ) -// |> invalid_before( -// !is_deadline_passed, -// mock_deadline + mock_gov_action_period - 3600 * 24, -// ) -// |> mint( -// is_shares_burnt, -// -current_fundraised_amount, -// mock_share_token, -// mock_completion_script, -// ) -// |> mint( -// !is_shares_burnt, -// -current_fundraised_amount + 9999999, -// mock_share_token, -// mock_completion_script, -// ) -// |> complete() -// |> add_extra_signatory(is_proposer_signed, mock_proposer_key_hash) -// } - -// test s3_spend_success_remove_empty_instance_wih_zero_fund() { -// let tx = -// mock_remove_empty_instance_tx( -// RemoveEmptyInstanceTestCase { -// is_only_one_inputed: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// is_proposer_signed: True, -// }, -// 0, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: 0, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RemoveEmptyInstance, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_success_remove_empty_instance_wih_some_fund() { -// let tx = -// mock_remove_empty_instance_tx( -// RemoveEmptyInstanceTestCase { -// is_only_one_inputed: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// is_proposer_signed: True, -// }, -// mock_current_fundraised_amount, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RemoveEmptyInstance, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_remove_empty_instance_wih_state_not_refundable() { -// let tx = -// mock_remove_empty_instance_tx( -// RemoveEmptyInstanceTestCase { -// is_only_one_inputed: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// is_proposer_signed: True, -// }, -// mock_current_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Init { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RemoveEmptyInstance, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { -// let tx = -// mock_remove_empty_instance_tx( -// RemoveEmptyInstanceTestCase { -// is_only_one_inputed: False, -// is_deadline_passed: True, -// is_shares_burnt: True, -// is_proposer_signed: True, -// }, -// mock_current_fundraised_amount, -// ) - -// spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RemoveEmptyInstance, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } +test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { + let tx = + mock_contributor_withdrawal_tx( + ContributorWithdrawalTestCase { + is_only_one_inputed: True, + is_only_one_outputed: True, + is_output_datum_correct: True, + is_output_value_clean: True, + is_unlock_value_correct: True, + // is_deadline_passed: True, + is_shares_burnt: False, + }, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +type RemoveEmptyInstanceTestCase { + is_only_one_inputed: Bool, + // is_deadline_passed: Bool, + is_shares_burnt: Bool, + is_token_burnt: Bool, + is_proposer_signed: Bool, +} + +fn mock_remove_empty_instance_tx( + test_case: RemoveEmptyInstanceTestCase, + current_fundraised_amount: Int, +) -> Transaction { + let RemoveEmptyInstanceTestCase { + is_only_one_inputed, + is_shares_burnt, + is_token_burnt, + is_proposer_signed, + } = test_case + + let input_value = + from_lovelace(current_fundraised_amount) |> add(mock_start_hash, "", 1) + + let input_datum = + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount, + } + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_gov_address) + |> tx_in_inline_datum(True, input_datum) + |> tx_in( + !is_only_one_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_gov_address, + ) + |> tx_out( + True, + mock_pub_key_address(0, None), + from_lovelace(current_fundraised_amount), + ) // |> invalid_before( + // is_deadline_passed, + // mock_deadline + mock_gov_action_period + 3600 * 24, + // ) + // |> invalid_before( + // !is_deadline_passed, + // mock_deadline + mock_gov_action_period - 3600 * 24, + // ) + + |> mint( + is_shares_burnt, + -current_fundraised_amount, + mock_share_token, + mock_start_hash, + ) + |> mint( + !is_shares_burnt, + -current_fundraised_amount + 9999999, + mock_share_token, + mock_start_hash, + ) + |> mint(is_token_burnt, -1, mock_start_hash, "") + |> complete() + |> add_extra_signatory(is_proposer_signed, mock_proposer_key_hash) +} + +test s3_spend_success_remove_empty_instance_wih_zero_fund() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + // is_deadline_passed: True, + is_shares_burnt: True, + is_token_burnt: True, + is_proposer_signed: True, + }, + 0, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: 0, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_success_remove_empty_instance_wih_some_fund() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + // is_deadline_passed: True, + is_shares_burnt: True, + is_token_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_state_not_refundable() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + // is_deadline_passed: True, + is_shares_burnt: True, + is_token_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: False, + // is_deadline_passed: True, + is_shares_burnt: True, + is_token_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} // test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { // let tx = @@ -1279,6 +2027,7 @@ // is_only_one_inputed: True, // is_deadline_passed: False, // is_shares_burnt: True, +// is_token_burnt: True, // is_proposer_signed: True, // }, // mock_current_fundraised_amount, @@ -1292,42 +2041,9 @@ // mock_drep_register_deposit, // Some( // Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RemoveEmptyInstance, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } - -// test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { -// let tx = -// mock_remove_empty_instance_tx( -// RemoveEmptyInstanceTestCase { -// is_only_one_inputed: True, -// is_deadline_passed: True, -// is_shares_burnt: False, -// is_proposer_signed: True, -// }, -// mock_current_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, +// start_hash: mock_start_hash, // share_token: mock_share_token, // funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, // }, // ), // RemoveEmptyInstance, @@ -1336,34 +2052,98 @@ // ) // } -// test s3_spend_fail_remove_empty_instance_wih_proposer_not_signed() { -// let tx = -// mock_remove_empty_instance_tx( -// RemoveEmptyInstanceTestCase { -// is_only_one_inputed: True, -// is_deadline_passed: True, -// is_shares_burnt: True, -// is_proposer_signed: False, -// }, -// mock_current_fundraised_amount, -// ) - -// !spend.spend.spend( -// mock_delegate_pool_id, -// mock_gov_action, -// mock_proposer_key_hash, -// mock_stake_register_deposit, -// mock_drep_register_deposit, -// Some( -// Refundable { -// completion_script: mock_completion_script, -// share_token: mock_share_token, -// funds_controlled: mock_current_fundraised_amount, -// deadline: mock_deadline + mock_gov_action_period, -// }, -// ), -// RemoveEmptyInstance, -// mock_utxo_ref(0, 0), -// tx, -// ) -// } +test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + // is_deadline_passed: True, + is_shares_burnt: False, + is_token_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_token_not_burnt() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + // is_deadline_passed: True, + is_shares_burnt: True, + is_token_burnt: False, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_spend_fail_remove_empty_instance_wih_proposer_not_signed() { + let tx = + mock_remove_empty_instance_tx( + RemoveEmptyInstanceTestCase { + is_only_one_inputed: True, + // is_deadline_passed: True, + is_shares_burnt: True, + is_token_burnt: True, + is_proposer_signed: False, + }, + mock_current_fundraised_amount, + ) + + !spend.spend.spend( + mock_delegate_pool_id, + mock_gov_action, + mock_proposer_key_hash, + mock_stake_register_deposit, + mock_drep_register_deposit, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: mock_current_fundraised_amount, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak index 60a2d5521..2313b8147 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak @@ -80,7 +80,7 @@ fn mock_withdraw_tx(test_case: WithdrawTestCase) -> Transaction { |> complete() } -test s3_withdraw_success() { +test s2_withdraw_success() { let tx = mock_withdraw_tx( WithdrawTestCase { @@ -102,7 +102,7 @@ test s3_withdraw_success() { ) } -test s3_withdraw_fail_with_more_than_one_auth_inputed() fail { +test s2_withdraw_fail_with_more_than_one_auth_inputed() fail { let tx = mock_withdraw_tx( WithdrawTestCase { @@ -124,7 +124,7 @@ test s3_withdraw_fail_with_more_than_one_auth_inputed() fail { ) } -test s3_withdraw_fail_with_fundraise_target_not_sent() fail { +test s2_withdraw_fail_with_fundraise_target_not_sent() fail { let tx = mock_withdraw_tx( WithdrawTestCase { @@ -146,7 +146,7 @@ test s3_withdraw_fail_with_fundraise_target_not_sent() fail { ) } -test s3_withdraw_fail_with_incorrect_fundraise_target_output_amount() { +test s2_withdraw_fail_with_incorrect_fundraise_target_output_amount() { let tx = mock_withdraw_tx( WithdrawTestCase { @@ -168,7 +168,7 @@ test s3_withdraw_fail_with_incorrect_fundraise_target_output_amount() { ) } -test s3_withdraw_fail_with_incorrect_fundraise_target_output_datum() { +test s2_withdraw_fail_with_incorrect_fundraise_target_output_datum() { let tx = mock_withdraw_tx( WithdrawTestCase { @@ -190,7 +190,7 @@ test s3_withdraw_fail_with_incorrect_fundraise_target_output_datum() { ) } -test s3_withdraw_fail_with_token_not_minted() { +test s2_withdraw_fail_with_token_not_minted() { let tx = mock_withdraw_tx( WithdrawTestCase { @@ -212,7 +212,7 @@ test s3_withdraw_fail_with_token_not_minted() { ) } -test s3_withdraw_fail_with_different_start_hash() { +test s2_withdraw_fail_with_different_start_hash() { let tx = mock_withdraw_tx( WithdrawTestCase { diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak index 516b3055c..caac96b94 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -1,10 +1,11 @@ use aiken/collection/list use cardano/address.{Address, Inline, Script, from_script} -use cardano/governance.{NoConfidence, ProposalProcedure} +use cardano/governance.{GovernanceActionId, ProposalProcedure, Vote, Voter} use cardano/transaction.{Transaction} +use gov.{NoConfidence} use mocktail.{ mock_policy_id, mock_pub_key_hash, mock_script_hash, - mock_script_stake_key_hash, + mock_script_stake_key_hash, mock_tx_hash, } use types.{CrowdfundDatum} @@ -77,7 +78,10 @@ pub const mock_stake_register_deposit = 2000000 pub const mock_drep_register_deposit = 500000000 pub const mock_funds_controlled = - mock_fundraise_target + mock_stake_register_deposit + mock_drep_register_deposit + mock_fundraise_target + mock_stake_register_deposit + mock_drep_register_deposit + 1000000 + +pub const mock_gov_action_id = + GovernanceActionId { transaction: mock_tx_hash(0), proposal_procedure: 0 } pub fn add_proposal_procedure( tx: Transaction, @@ -94,3 +98,19 @@ pub fn add_proposal_procedure( } } } + +pub fn add_vote( + tx: Transaction, + condition: Bool, + vote: Pair>, +) -> Transaction { + if !condition { + tx + } else { + Transaction { + ..tx, + votes: tx.votes + |> list.concat([vote]), + } + } +} From 2a0ad0cc3332df01fb08af46cf1401db3ff6e559 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Fri, 27 Jun 2025 17:51:28 +0800 Subject: [PATCH 13/19] fixed: opaque type --- .../gov-crowdfund/lib/gov.ak | 8 +- .../gov-crowdfund/plutus.json | 596 +++++++++++++++++- 2 files changed, 590 insertions(+), 14 deletions(-) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak index b50730be8..d29db7b58 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak @@ -1,5 +1,4 @@ use aiken/crypto.{ScriptHash} -use aiken/math/rational.{Rational} use cardano/address.{Credential} use cardano/assets.{Lovelace} use cardano/governance.{ @@ -13,6 +12,11 @@ pub type VProtocolParametersUpdate { inner: Pairs, } +pub type VRational { + numerator: Int, + denominator: Int, +} + pub type VGovernanceAction { VProtocolParameters { /// The last governance action of type 'ProtocolParameters'. They must all @@ -64,7 +68,7 @@ pub type VGovernanceAction { /// The new quorum value, as a ratio of a numerator and a denominator. The /// quorum specifies the threshold of 'Yes' votes necessary for the /// constitutional committee to accept a proposal procedure. - quorum: Rational, + quorum: VRational, } NewConstitution { /// The last governance action of type `Constitution` or diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json index 4f4bf0764..0b930888d 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json @@ -11,6 +11,95 @@ "license": "Apache-2.0" }, "validators": [ + { + "title": "spend.spend.spend", + "datum": { + "title": "datum_opt", + "schema": { + "$ref": "#/definitions/types~1CrowdfundGovDatum" + } + }, + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1CrowdfundRedeemer" + } + }, + "parameters": [ + { + "title": "delegate_pool_id", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action", + "schema": { + "$ref": "#/definitions/gov~1VGovernanceAction" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "stake_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + } + ], + "compiledCode": "591a430101003232323232323223222322322322533300b323232323253323301130013012375400426466446464646464a66603260080022a66603860366ea802c0085854ccc064c02400454ccc070c06cdd50058010b0a99980c98028008a99980e180d9baa00b002161533301930030011533301c301b37540160042c2a66603266e1d20080011533301c301b37540160042c2c60326ea80284c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0a4c050c0a8dd50008992999815180a98159baa0171323232323232323232325323232333037302200a1533303730223038375401a2646464666644446464a666086608c004264a666082605860846ea80044c94ccc108c0b4c10cdd5000899191929998241825801099191980c800899191919191929998268040a9998268030a9998268028a9998268020a9998268018a99982680108008a5014a029405280a5014a064607a646600200205244a6660a400229000099912999828a99982899b87375a605660a66ea80092080a0b787e905153330513375e604c60a66ea80080144cdc79bb3305630573057305337540046ecc1385280a501301b001100130540013300200230550013026304e3754040a666096a66609666030054602e6609e0126609e602c6609e60486609e01297ae04bd7025eb804cc0600a8c05ccc13c024cc13cc090cc13cdd4824a5eb812f5c0294052889980c015180b9982780499827980b998279ba90493304f30243304f0094bd7025eb812f5c06602e05266e9520083304e0083304e375008297ae03301602830223304d0073304d4c103d87a80004bd70181a1929998260008a4000264602864a66609c004290000980a9980080098288011129998278008a40002602c6600400460a4002609e00264660020026eacc078c12cdd50029129998268008a5eb804c8c8c8c8cc004004dd5982800211299982900088018991982a1ba733054375200a660a860a2002660a860a400297ae03300300330560023054001330040043052003375c6098002609e00266ebc004c048cc12cdd4806998259ba900c3304b3750016660966ea00292f5c064a66608e606660906ea80044c130c124dd50008b18259826182618241baa00233301300600133702900019b803370007c0789040505bc3f4828b182480099198008008129129998240008a5eb804cc894ccc11d4ccc11ccdd7982618249baa00201b130373253330483038304937540022900009bad304d304a375400264a666090607060926ea80045300103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e301f0031533304e301e0031302733052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c098cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c1380045280998258011980200200089980200200098250009825800982398221baa001163046304337540022c602a60846ea805058c110004c8cc004004084894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd51823982418221baa002016130323253330433033304437540022900009bad30483045375400264a666086606660886ea80045300103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e604e0142a66606e604e60706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c8c94ccc114c1200084c8c8cc0580044c8c8c94ccc11c01454ccc11c00854ccc11c0044c8c94ccc124c0d0c128dd50008999119198008008019129998280008a5013322533304f3375e6e98cc14c0092f5bded8c06e98cc14c0152f5bded8c029444cc010010004c148004c14c004dd5982718259baa0013376000a980103d87a800016323300100102522533304d00114c0103d87a8000132333222533304e3375e00e0062604e660a46e980092f5c026600c00c00260980026eacc134004c144008c13c004c048cc12cc048cc12cdd4806a5eb812f5c029405280a50303232533304a0011480004c8c048c94ccc130008520001301333001001304f00222533304d0011480004c050cc008008c140004c134004c8cc004004dd5980e18249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd78011808998249ba900b330493752014660926ea0024cc124004cc124dd400425eb80c074cc120c078c118dd5180f18231baa01b330484c010100004bd70192999822181818229baa00113049304637540022c609060926092608a6ea8008cdd7980b98221baa301730443754006602e60886ea800458c118004c8cc004004088894ccc11400452f5c026644a666088a66608866ebcc124c118dd500100c0981a192999822981a98231baa0011480004dd6982518239baa0013253330453035304637540022980103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b301c0031533304b301b003130243304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00322533304900114c103d87a8000132333222533304a337220200062a66609466e3c04000c4c08ccc138dd300125eb80530103d87a8000133006006001375c60900026eacc124004c134008c12c00452809982400119802002000899802002000982380098240008b182200099198008008109129998218008a5eb804cc894ccc1094ccc108cdd7982398221baa304730483044375400402c2606464a666086606660886ea8004520001375a6090608a6ea8004c94ccc10cc0ccc110dd50008a6103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e60460142a66606e604660706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c94ccc104c0b0c108dd50008992999821181698219baa0011323232325333049304c002132323301a001132323232533304c0091533304c0061533304c0041533304c0031533304c002100114a029405280a5014a0606e64a66609e00229000099180b9929998288010a4000260306600200260a800444a6660a4002290000980c99801001182a800982900099198008009bab3021304e375400e44a6660a0002297ae013232323233001001375660a600844a6660aa0022006264660ae6e9ccc15cdd48029982b982a0009982b982a800a5eb80cc00c00cc164008c15c004cc010010c15400cdd7182780098290009980b81499ba548030cc138020cc138dd4020a5eb80cc0580a0c050cc13401ccc13530103d87a80004bd7019baf0013374a9003198261ba900e3304c375201a660986ea00312f5c064a666090606860926ea80044c134c128dd50008b18261826982698249baa0023330140070013370007e07a2c6094002646600200204c44a666092002297ae013322533304853330483375e609a60946ea80080704c0e0c94ccc124c0e4c128dd50008a400026eb4c138c12cdd5000992999824981c98251baa00114c0103d87a8000132330010013756609e60986ea8008894ccc138004530103d87a8000132333222533304f30200031533304f301f0031302833053375000497ae014c103d87a8000133006006001375c609a0026eb4c138004c148008c140004c8cc004004dd59827182798259baa00322533304d00114c103d87a8000132333222533304e337220280062a66609c66e3c05000c4c09ccc148dd300125eb80530103d87a8000133006006001375c60980026eacc134004c144008c13c00452809982600119802002000899802002000982580098260009919192999823181b18239baa0011533304630363047375460966098004266e20024dd6982598241baa0011337120126eb4c12cc120dd50008a50304a001330483049001330483330443034304537546092609400298103d87a80004c0103d87980004bd7018229baa304830453754042608e60886ea800458c118c10cdd50008b180a98211baa014163044001323300100102122533304300114bd70099912999821299982119baf304730443754608e609060886ea80080584c0c8c94ccc10cc0ccc110dd50008a400026eb4c120c114dd5000992999821981998221baa00114c0103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f98201820000981f800981f000981c9baa00d14a02a66606e60420142a66606e604260706ea80344c8c8ccc888c8c94ccc104c1100084c8c94ccc10cc1180084c8c8c8cc0540044c8c94ccc11401054ccc11400854ccc1140044c8c94ccc12800400854ccc128c1340044c8c8ccc8894ccc130cdc78018090a99982619b8f00201313370e00201829405281bae304e002375c609c0026eb4c138c13c004c138004dd6182600080119198008008139129998258008a5eb804c8c8c8c8cc004004dd598270021129998280008801899198291ba733052375200a660a4609e002660a460a000297ae03300300330540023052001330040043050003375c6094002609a00229405280a5014a0606064a6660900022900009918081929998250010a40002602266002002609a00444a6660960022900009809198010011827000982580099198008009bab301a3047375400c44a666092002297ae0132323232330010013756609800844a66609c0022006264660a06e9ccc140dd4802998281826800998281827000a5eb80cc00c00cc148008c140004cc010010c13800cdd71824000982580099baf0013374a9003198239ba900a3304737520126608e6ea0cdc0004001a5eb80c94ccc10cc0bcc110dd50008982418229baa001163047304830483044375400666e20005200033702601e6eacc054c108dd500098079bab301530423754602a60846ea800c58c110004c8cc004004080894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd500100b09819192999821981998221baa0011480004dd6982418229baa001325333043303330443754002298103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa00322533304700114c103d87a800013233322253330483372201e0062a66609066e3c03c00c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230008b1821000991980080080f9129998208008a5eb804cc894ccc1014ccc100cdd7982298211baa30453046304237540040282606064a666082606260846ea8004520001375a608c60866ea8004c94ccc104c0c4c108dd50008a6103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c00452809982200119802002000899802002000982180098220009bae303e002375c607c0026eb4c0f8c0fc004c0f8004c0e4dd50068a501533303730213038375401a26464666444a66607e6084646600200203e44a666082002297ae013322533304053330403375e608a60846ea8c114c118c108dd500100a09818192999820981898211baa0011480004dd6982318219baa001325333041303130423754002298103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c0045280998220011980200200089980200200098218009822000899299981ea99981e99b88480000084c8c8c94ccc10c00400854ccc10cc1180044c8cc894ccc10ccdc7801005099b8700100614a06eb8c118004dd69823182380098231bac30450010023233001001323300100102122533304500114bd70099191919198008009bab304800422533304a00110031323304c374e660986ea4014cc130c124004cc130c1280052f5c066006006609c00460980026600800860940066eb8c110004c11c004894ccc11000452f5c026644a66608666e3cdd718240010048998239ba7002330040040011330040040013758608c002608e0022940cdc0a4000004294454ccc0f40044c8c94ccc10800400854ccc108c1140044c8cc894ccc108c0480084cdc3800a40022940dd718228009bad304530460013045375860880020046466002002646600200204044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230009129998218008a5eb804cc894ccc108cdc79bae3047002009133046374e004660080080022660080080026eb0c114004c1180045280a5014a0646600200203444a66608200229404cc894ccc100cdc780101d8a51133004004001375c608600260880022c6eb8c0f8008dd7181f0009bad303e303f001303e0013039375401a2940dc0240046e952002374a900211191980080080191299981d0008a501332253330393375e00400a29444cc010010004c0f0004c0f4004888cdc399b81300437566014606e6ea8008c010dd59805181b9baa300a30373754006002464a666066604660686ea8004520001375a6070606a6ea8004c94ccc0ccc08cc0d0dd50008a60103d87a80001323300100137566072606c6ea8008894ccc0e0004530103d87a80001323332225333039300a003153330393009003130123303d375000497ae014c103d87a8000133006006001375c606e0026eb4c0e0004c0f0008c0e8004c8cc004004008894ccc0dc0045300103d87a800013233322253330383009003153330383008003130113303c374c00497ae014c103d87a8000133006006001375c606c0026eacc0dc004c0ec008c0e4004dc7a4500372291010022325333031301c00113232323232323232533303c303f00200a16375a607a002607a0046eb4c0ec004c0ec008dd7181c800981c8011bae3037001303337540062a666062604200226464646464646464a666078607e0040142c6eb4c0f4004c0f4008dd6981d800981d8011bae30390013039002375c606e00260666ea800c54ccc0c4c0740044c8c8c8c8c8c8c8c8c8c94ccc0f8c10400854ccc0ecc098c0f0dd5001899191919299982118228010080b1bad30430013043002375c6082002607a6ea800c5858dd6981f800981f801181e800981e8011bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018a999818980d8008991919191919299981d181e8010040b1bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018b18189baa002302e375403e600c605c6ea8c004c0b8dd5001918189819000981798161baa01716302e302b37540022c646600200201644a66605a002298103d87a800013322533302c3375e600c605c6ea80080684c014cc0c00092f5c0266008008002605e00260600026e9520002302c0013758605460560106eacc0a401cdd6181400398138039bac30260073756604a00e6eb0c09001cdd6181180398119811981198118009811000981098108009810000980f980f800980f180f000980c9baa00a370e90031b8748000dc3a4008602e002602e603000260266ea8008dc3a40042c6028602a006602600460240046024002601a6ea800452613656375a0026eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d11", + "hash": "b77e4f80ee4d5887de1f3954470f392f455198ff4372c4c7d0d6480c" + }, + { + "title": "spend.spend.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "delegate_pool_id", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action", + "schema": { + "$ref": "#/definitions/gov~1VGovernanceAction" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "stake_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + } + ], + "compiledCode": "591a430101003232323232323223222322322322533300b323232323253323301130013012375400426466446464646464a66603260080022a66603860366ea802c0085854ccc064c02400454ccc070c06cdd50058010b0a99980c98028008a99980e180d9baa00b002161533301930030011533301c301b37540160042c2a66603266e1d20080011533301c301b37540160042c2c60326ea80284c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0a4c050c0a8dd50008992999815180a98159baa0171323232323232323232325323232333037302200a1533303730223038375401a2646464666644446464a666086608c004264a666082605860846ea80044c94ccc108c0b4c10cdd5000899191929998241825801099191980c800899191919191929998268040a9998268030a9998268028a9998268020a9998268018a99982680108008a5014a029405280a5014a064607a646600200205244a6660a400229000099912999828a99982899b87375a605660a66ea80092080a0b787e905153330513375e604c60a66ea80080144cdc79bb3305630573057305337540046ecc1385280a501301b001100130540013300200230550013026304e3754040a666096a66609666030054602e6609e0126609e602c6609e60486609e01297ae04bd7025eb804cc0600a8c05ccc13c024cc13cc090cc13cdd4824a5eb812f5c0294052889980c015180b9982780499827980b998279ba90493304f30243304f0094bd7025eb812f5c06602e05266e9520083304e0083304e375008297ae03301602830223304d0073304d4c103d87a80004bd70181a1929998260008a4000264602864a66609c004290000980a9980080098288011129998278008a40002602c6600400460a4002609e00264660020026eacc078c12cdd50029129998268008a5eb804c8c8c8c8cc004004dd5982800211299982900088018991982a1ba733054375200a660a860a2002660a860a400297ae03300300330560023054001330040043052003375c6098002609e00266ebc004c048cc12cdd4806998259ba900c3304b3750016660966ea00292f5c064a66608e606660906ea80044c130c124dd50008b18259826182618241baa00233301300600133702900019b803370007c0789040505bc3f4828b182480099198008008129129998240008a5eb804cc894ccc11d4ccc11ccdd7982618249baa00201b130373253330483038304937540022900009bad304d304a375400264a666090607060926ea80045300103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e301f0031533304e301e0031302733052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c098cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c1380045280998258011980200200089980200200098250009825800982398221baa001163046304337540022c602a60846ea805058c110004c8cc004004084894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd51823982418221baa002016130323253330433033304437540022900009bad30483045375400264a666086606660886ea80045300103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e604e0142a66606e604e60706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c8c94ccc114c1200084c8c8cc0580044c8c8c94ccc11c01454ccc11c00854ccc11c0044c8c94ccc124c0d0c128dd50008999119198008008019129998280008a5013322533304f3375e6e98cc14c0092f5bded8c06e98cc14c0152f5bded8c029444cc010010004c148004c14c004dd5982718259baa0013376000a980103d87a800016323300100102522533304d00114c0103d87a8000132333222533304e3375e00e0062604e660a46e980092f5c026600c00c00260980026eacc134004c144008c13c004c048cc12cc048cc12cdd4806a5eb812f5c029405280a50303232533304a0011480004c8c048c94ccc130008520001301333001001304f00222533304d0011480004c050cc008008c140004c134004c8cc004004dd5980e18249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd78011808998249ba900b330493752014660926ea0024cc124004cc124dd400425eb80c074cc120c078c118dd5180f18231baa01b330484c010100004bd70192999822181818229baa00113049304637540022c609060926092608a6ea8008cdd7980b98221baa301730443754006602e60886ea800458c118004c8cc004004088894ccc11400452f5c026644a666088a66608866ebcc124c118dd500100c0981a192999822981a98231baa0011480004dd6982518239baa0013253330453035304637540022980103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b301c0031533304b301b003130243304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00322533304900114c103d87a8000132333222533304a337220200062a66609466e3c04000c4c08ccc138dd300125eb80530103d87a8000133006006001375c60900026eacc124004c134008c12c00452809982400119802002000899802002000982380098240008b182200099198008008109129998218008a5eb804cc894ccc1094ccc108cdd7982398221baa304730483044375400402c2606464a666086606660886ea8004520001375a6090608a6ea8004c94ccc10cc0ccc110dd50008a6103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e60460142a66606e604660706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c94ccc104c0b0c108dd50008992999821181698219baa0011323232325333049304c002132323301a001132323232533304c0091533304c0061533304c0041533304c0031533304c002100114a029405280a5014a0606e64a66609e00229000099180b9929998288010a4000260306600200260a800444a6660a4002290000980c99801001182a800982900099198008009bab3021304e375400e44a6660a0002297ae013232323233001001375660a600844a6660aa0022006264660ae6e9ccc15cdd48029982b982a0009982b982a800a5eb80cc00c00cc164008c15c004cc010010c15400cdd7182780098290009980b81499ba548030cc138020cc138dd4020a5eb80cc0580a0c050cc13401ccc13530103d87a80004bd7019baf0013374a9003198261ba900e3304c375201a660986ea00312f5c064a666090606860926ea80044c134c128dd50008b18261826982698249baa0023330140070013370007e07a2c6094002646600200204c44a666092002297ae013322533304853330483375e609a60946ea80080704c0e0c94ccc124c0e4c128dd50008a400026eb4c138c12cdd5000992999824981c98251baa00114c0103d87a8000132330010013756609e60986ea8008894ccc138004530103d87a8000132333222533304f30200031533304f301f0031302833053375000497ae014c103d87a8000133006006001375c609a0026eb4c138004c148008c140004c8cc004004dd59827182798259baa00322533304d00114c103d87a8000132333222533304e337220280062a66609c66e3c05000c4c09ccc148dd300125eb80530103d87a8000133006006001375c60980026eacc134004c144008c13c00452809982600119802002000899802002000982580098260009919192999823181b18239baa0011533304630363047375460966098004266e20024dd6982598241baa0011337120126eb4c12cc120dd50008a50304a001330483049001330483330443034304537546092609400298103d87a80004c0103d87980004bd7018229baa304830453754042608e60886ea800458c118c10cdd50008b180a98211baa014163044001323300100102122533304300114bd70099912999821299982119baf304730443754608e609060886ea80080584c0c8c94ccc10cc0ccc110dd50008a400026eb4c120c114dd5000992999821981998221baa00114c0103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f98201820000981f800981f000981c9baa00d14a02a66606e60420142a66606e604260706ea80344c8c8ccc888c8c94ccc104c1100084c8c94ccc10cc1180084c8c8c8cc0540044c8c94ccc11401054ccc11400854ccc1140044c8c94ccc12800400854ccc128c1340044c8c8ccc8894ccc130cdc78018090a99982619b8f00201313370e00201829405281bae304e002375c609c0026eb4c138c13c004c138004dd6182600080119198008008139129998258008a5eb804c8c8c8c8cc004004dd598270021129998280008801899198291ba733052375200a660a4609e002660a460a000297ae03300300330540023052001330040043050003375c6094002609a00229405280a5014a0606064a6660900022900009918081929998250010a40002602266002002609a00444a6660960022900009809198010011827000982580099198008009bab301a3047375400c44a666092002297ae0132323232330010013756609800844a66609c0022006264660a06e9ccc140dd4802998281826800998281827000a5eb80cc00c00cc148008c140004cc010010c13800cdd71824000982580099baf0013374a9003198239ba900a3304737520126608e6ea0cdc0004001a5eb80c94ccc10cc0bcc110dd50008982418229baa001163047304830483044375400666e20005200033702601e6eacc054c108dd500098079bab301530423754602a60846ea800c58c110004c8cc004004080894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd500100b09819192999821981998221baa0011480004dd6982418229baa001325333043303330443754002298103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa00322533304700114c103d87a800013233322253330483372201e0062a66609066e3c03c00c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230008b1821000991980080080f9129998208008a5eb804cc894ccc1014ccc100cdd7982298211baa30453046304237540040282606064a666082606260846ea8004520001375a608c60866ea8004c94ccc104c0c4c108dd50008a6103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c00452809982200119802002000899802002000982180098220009bae303e002375c607c0026eb4c0f8c0fc004c0f8004c0e4dd50068a501533303730213038375401a26464666444a66607e6084646600200203e44a666082002297ae013322533304053330403375e608a60846ea8c114c118c108dd500100a09818192999820981898211baa0011480004dd6982318219baa001325333041303130423754002298103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c0045280998220011980200200089980200200098218009822000899299981ea99981e99b88480000084c8c8c94ccc10c00400854ccc10cc1180044c8cc894ccc10ccdc7801005099b8700100614a06eb8c118004dd69823182380098231bac30450010023233001001323300100102122533304500114bd70099191919198008009bab304800422533304a00110031323304c374e660986ea4014cc130c124004cc130c1280052f5c066006006609c00460980026600800860940066eb8c110004c11c004894ccc11000452f5c026644a66608666e3cdd718240010048998239ba7002330040040011330040040013758608c002608e0022940cdc0a4000004294454ccc0f40044c8c94ccc10800400854ccc108c1140044c8cc894ccc108c0480084cdc3800a40022940dd718228009bad304530460013045375860880020046466002002646600200204044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230009129998218008a5eb804cc894ccc108cdc79bae3047002009133046374e004660080080022660080080026eb0c114004c1180045280a5014a0646600200203444a66608200229404cc894ccc100cdc780101d8a51133004004001375c608600260880022c6eb8c0f8008dd7181f0009bad303e303f001303e0013039375401a2940dc0240046e952002374a900211191980080080191299981d0008a501332253330393375e00400a29444cc010010004c0f0004c0f4004888cdc399b81300437566014606e6ea8008c010dd59805181b9baa300a30373754006002464a666066604660686ea8004520001375a6070606a6ea8004c94ccc0ccc08cc0d0dd50008a60103d87a80001323300100137566072606c6ea8008894ccc0e0004530103d87a80001323332225333039300a003153330393009003130123303d375000497ae014c103d87a8000133006006001375c606e0026eb4c0e0004c0f0008c0e8004c8cc004004008894ccc0dc0045300103d87a800013233322253330383009003153330383008003130113303c374c00497ae014c103d87a8000133006006001375c606c0026eacc0dc004c0ec008c0e4004dc7a4500372291010022325333031301c00113232323232323232533303c303f00200a16375a607a002607a0046eb4c0ec004c0ec008dd7181c800981c8011bae3037001303337540062a666062604200226464646464646464a666078607e0040142c6eb4c0f4004c0f4008dd6981d800981d8011bae30390013039002375c606e00260666ea800c54ccc0c4c0740044c8c8c8c8c8c8c8c8c8c94ccc0f8c10400854ccc0ecc098c0f0dd5001899191919299982118228010080b1bad30430013043002375c6082002607a6ea800c5858dd6981f800981f801181e800981e8011bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018a999818980d8008991919191919299981d181e8010040b1bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018b18189baa002302e375403e600c605c6ea8c004c0b8dd5001918189819000981798161baa01716302e302b37540022c646600200201644a66605a002298103d87a800013322533302c3375e600c605c6ea80080684c014cc0c00092f5c0266008008002605e00260600026e9520002302c0013758605460560106eacc0a401cdd6181400398138039bac30260073756604a00e6eb0c09001cdd6181180398119811981198118009811000981098108009810000980f980f800980f180f000980c9baa00a370e90031b8748000dc3a4008602e002602e603000260266ea8008dc3a40042c6028602a006602600460240046024002601a6ea800452613656375a0026eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d11", + "hash": "b77e4f80ee4d5887de1f3954470f392f455198ff4372c4c7d0d6480c" + }, { "title": "start.start.withdraw", "redeemer": { @@ -39,8 +128,8 @@ } } ], - "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" }, { "title": "start.start.mint", @@ -70,8 +159,8 @@ } } ], - "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" }, { "title": "start.start.publish", @@ -101,8 +190,8 @@ } } ], - "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" }, { "title": "start.start.propose", @@ -132,8 +221,8 @@ } } ], - "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" }, { "title": "start.start.vote", @@ -163,8 +252,8 @@ } } ], - "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" }, { "title": "start.start.else", @@ -191,8 +280,8 @@ } } ], - "compiledCode": "590be6010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa00315333044303300113232323232323232533304f305200200a16375a60a000260a00046eb4c138004c138008dd7182600098260011bae304a001304637540062c60886ea80084c94ccc10c02054ccc10c00c54ccc10c0044c8c94ccc12000400854ccc120c12c0044c8cc894ccc120c02c0084c0e40045281bae304b001375a6096609800260966eb0c128004008c8cc004004c8cc0040040b8894ccc12800452f5c0264646464660020026eacc134010894ccc13c004400c4c8cc144dd3998289ba900533051304e00133051304f0014bd7019801801982980118288009980200218278019bae3049001304c00122533304900114bd7009991299982419b8f375c609a0040242660986e9c008cc0100100044cc010010004dd6182580098260008a5014a0294052819baf00130303304637520186608c6ea402ccc118dd4004998231ba83370001007897ae03253330423032304337540022608e60886ea800458c118c11cc11cc10cdd500119b873253330413032304237540022900009bad30463043375400264a666082606460846ea80045300103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87a80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87b8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "21fdcd57e8d9b595b36d777501ba22ae06d2a7dcdf379b53f5552dd6" + "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", + "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" } ], "definitions": { @@ -203,13 +292,496 @@ "title": "Data", "description": "Any Plutus data." }, + "Index": { + "title": "Index", + "dataType": "integer" + }, "Int": { "dataType": "integer" }, + "List$cardano/address/Credential": { + "dataType": "list", + "items": { + "$ref": "#/definitions/cardano~1address~1Credential" + } + }, + "Lovelace": { + "title": "Lovelace", + "dataType": "integer" + }, + "Mandate": { + "title": "Mandate", + "dataType": "integer" + }, + "Option$ScriptHash": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/ScriptHash" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Option$cardano/governance/GovernanceActionId": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1governance~1GovernanceActionId" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Pairs$ProtocolParametersIndex_Data": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/ProtocolParametersIndex" + }, + "values": { + "$ref": "#/definitions/Data" + } + }, + "Pairs$cardano/address/Credential_Lovelace": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/Lovelace" + } + }, + "Pairs$cardano/address/Credential_Mandate": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/Mandate" + } + }, "PolicyId": { "title": "PolicyId", "dataType": "bytes" }, + "ProtocolParametersIndex": { + "title": "ProtocolParametersIndex", + "dataType": "integer" + }, + "ScriptHash": { + "title": "ScriptHash", + "dataType": "bytes" + }, + "TransactionId": { + "title": "TransactionId", + "dataType": "bytes" + }, + "VerificationKeyHash": { + "title": "VerificationKeyHash", + "dataType": "bytes" + }, + "cardano/address/Credential": { + "title": "Credential", + "description": "A general structure for representing an on-chain `Credential`.\n\n Credentials are always one of two kinds: a direct public/private key\n pair, or a script (native or Plutus).", + "anyOf": [ + { + "title": "VerificationKey", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/ScriptHash" + } + ] + } + ] + }, + "cardano/governance/Constitution": { + "title": "Constitution", + "anyOf": [ + { + "title": "Constitution", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "guardrails", + "$ref": "#/definitions/Option$ScriptHash" + } + ] + } + ] + }, + "cardano/governance/GovernanceActionId": { + "title": "GovernanceActionId", + "anyOf": [ + { + "title": "GovernanceActionId", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "transaction", + "$ref": "#/definitions/TransactionId" + }, + { + "title": "proposal_procedure", + "$ref": "#/definitions/Index" + } + ] + } + ] + }, + "cardano/governance/ProtocolVersion": { + "title": "ProtocolVersion", + "anyOf": [ + { + "title": "ProtocolVersion", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "major", + "$ref": "#/definitions/Int" + }, + { + "title": "minor", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "gov/VGovernanceAction": { + "title": "VGovernanceAction", + "anyOf": [ + { + "title": "VProtocolParameters", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type 'ProtocolParameters'. They must all\n form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "new_parameters", + "description": "The new proposed protocol parameters. Only values set to `Some` are relevant.", + "$ref": "#/definitions/gov~1VProtocolParametersUpdate" + }, + { + "title": "guardrails", + "description": "The optional guardrails script defined in the constitution. The script\n is executed by the ledger in addition to the hard-coded ledger rules.\n\n It must pass for the new protocol parameters to be deemed valid.", + "$ref": "#/definitions/Option$ScriptHash" + } + ] + }, + { + "title": "HardFork", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `HardFork`. They must all\n form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "new_version", + "description": "The new proposed version. Few rules apply to proposing new versions:\n\n - The `major` component, if incremented, must be exactly one more than the current.\n - The `minor` component, if incremented, must be exactly one more than the current.\n - If the `major` component is incremented, `minor` must be set to `0`.\n - Neither `minor` nor `major` can be decremented.", + "$ref": "#/definitions/cardano~1governance~1ProtocolVersion" + } + ] + }, + { + "title": "TreasuryWithdrawal", + "dataType": "constructor", + "index": 2, + "fields": [ + { + "title": "beneficiaries", + "description": "A collection of beneficiaries, which can be plain verification key\n hashes or script hashes (e.g. DAO).", + "$ref": "#/definitions/Pairs$cardano~1address~1Credential_Lovelace" + }, + { + "title": "guardrails", + "description": "The optional guardrails script defined in the constitution. The script\n is executed by the ledger in addition to the hard-coded ledger rules.\n\n It must pass for the withdrawals to be authorized.", + "$ref": "#/definitions/Option$ScriptHash" + } + ] + }, + { + "title": "NoConfidence", + "dataType": "constructor", + "index": 3, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `NoConfidence` or\n `ConstitutionalCommittee`. They must all / form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + } + ] + }, + { + "title": "ConstitutionalCommittee", + "dataType": "constructor", + "index": 4, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `NoConfidence` or\n `ConstitutionalCommittee`. They must all / form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "evicted_members", + "description": "Constitutional members to be removed.", + "$ref": "#/definitions/List$cardano~1address~1Credential" + }, + { + "title": "added_members", + "description": "Constitutional members to be added.", + "$ref": "#/definitions/Pairs$cardano~1address~1Credential_Mandate" + }, + { + "title": "quorum", + "description": "The new quorum value, as a ratio of a numerator and a denominator. The\n quorum specifies the threshold of 'Yes' votes necessary for the\n constitutional committee to accept a proposal procedure.", + "$ref": "#/definitions/gov~1VRational" + } + ] + }, + { + "title": "NewConstitution", + "dataType": "constructor", + "index": 5, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `Constitution` or\n `ConstitutionalCommittee`. They must all / form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "constitution", + "description": "The new proposed constitution.", + "$ref": "#/definitions/cardano~1governance~1Constitution" + } + ] + }, + { + "title": "NicePoll", + "dataType": "constructor", + "index": 6, + "fields": [] + } + ] + }, + "gov/VProtocolParametersUpdate": { + "title": "VProtocolParametersUpdate", + "anyOf": [ + { + "title": "VProtocolParametersUpdate", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "inner", + "$ref": "#/definitions/Pairs$ProtocolParametersIndex_Data" + } + ] + } + ] + }, + "gov/VRational": { + "title": "VRational", + "anyOf": [ + { + "title": "VRational", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "numerator", + "$ref": "#/definitions/Int" + }, + { + "title": "denominator", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "types/CrowdfundGovDatum": { + "title": "CrowdfundGovDatum", + "anyOf": [ + { + "title": "Init", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "start_hash", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "share_token", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "funds_controlled", + "$ref": "#/definitions/Int" + }, + { + "title": "deadline", + "$ref": "#/definitions/Int" + } + ] + }, + { + "title": "Proposed", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "title": "start_hash", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "share_token", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "funds_controlled", + "$ref": "#/definitions/Int" + }, + { + "title": "deadline", + "$ref": "#/definitions/Int" + } + ] + }, + { + "title": "Voted", + "dataType": "constructor", + "index": 2, + "fields": [ + { + "title": "start_hash", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "share_token", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "funds_controlled", + "$ref": "#/definitions/Int" + }, + { + "title": "gov_tx_id", + "$ref": "#/definitions/cardano~1governance~1GovernanceActionId" + }, + { + "title": "deadline", + "$ref": "#/definitions/Int" + } + ] + }, + { + "title": "Refundable", + "dataType": "constructor", + "index": 3, + "fields": [ + { + "title": "start_hash", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "share_token", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "funds_controlled", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "types/CrowdfundRedeemer": { + "title": "CrowdfundRedeemer", + "anyOf": [ + { + "title": "RegisterCerts", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "VoteOnGovAction", + "dataType": "constructor", + "index": 1, + "fields": [] + }, + { + "title": "DeregisterCerts", + "dataType": "constructor", + "index": 2, + "fields": [] + }, + { + "title": "ContributorWithdrawal", + "dataType": "constructor", + "index": 3, + "fields": [] + }, + { + "title": "RemoveEmptyInstance", + "dataType": "constructor", + "index": 4, + "fields": [] + } + ] + }, "types/MintPolarity": { "title": "MintPolarity", "anyOf": [ From ca6458dc72943740ad194e47ca1d0e75bff78ec1 Mon Sep 17 00:00:00 2001 From: kenlau666 Date: Sat, 28 Jun 2025 18:50:55 +0800 Subject: [PATCH 14/19] added: contribute fund integration test --- .../tests/integration_test/contribute_fund.ak | 385 ++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak new file mode 100644 index 000000000..4284bd939 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak @@ -0,0 +1,385 @@ +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction} +use crowdfund/spend as crowdfund_spend +use mocktail.{ + add_redeemer, complete, invalid_hereafter, mint, mock_policy_id, + mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, tx_in, + tx_in_inline_datum, tx_out, tx_out_inline_datum, +} +use share_token/mint as share_token_mint +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_contribute_min_fundraised_amount, + mock_contribute_over_fundraised_amount, mock_crowdfund_address, + mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, + mock_share_token, +} +use types.{CompleteCrowdfund, ContributeFund, CrowdfundRedeemer, RMint} + +type ContributeFundTestCase { + is_only_one_auth_inputed: Bool, + is_only_one_auth_outputed: Bool, + is_auth_output_datum_correct: Bool, + is_auth_output_value_clean: Bool, + is_deadline_not_passed: Bool, + is_shares_minted: Bool, +} + +fn mock_contribute_fund_tx( + test_case: ContributeFundTestCase, + current_fundraised_amount: Int, + contribute_amount: Int, + allow_over_subscription: Bool, + auth_token_redeemer: CrowdfundRedeemer, +) -> Transaction { + let ContributeFundTestCase { + is_only_one_auth_inputed, + is_only_one_auth_outputed, + is_auth_output_datum_correct, + is_auth_output_value_clean, + is_deadline_not_passed, + is_shares_minted, + } = test_case + let auth_token_redeemer_data: Data = auth_token_redeemer + + let input_value = + from_lovelace(current_fundraised_amount) + |> add(mock_auth_token, mock_completion_script, 1) + + let output_value = + from_lovelace(current_fundraised_amount + contribute_amount) + |> add(mock_auth_token, mock_completion_script, 1) + + let auth_correct_output_datum = + mock_crowdfund_datum( + current_fundraised_amount + contribute_amount, + allow_over_subscription, + ) + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(current_fundraised_amount, allow_over_subscription), + ) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_crowdfund_address, + ) + |> tx_in( + True, + mock_tx_hash(1), + 0, + from_lovelace(contribute_amount), + mock_pub_key_address(0, None), + ) + |> tx_out(is_auth_output_value_clean, mock_crowdfund_address, output_value) + |> tx_out( + !is_auth_output_value_clean, + mock_crowdfund_address, + output_value |> add(mock_policy_id(999), mock_completion_script, 1), + ) + |> tx_out_inline_datum(is_auth_output_datum_correct, auth_correct_output_datum) + |> tx_out_inline_datum( + !is_auth_output_datum_correct, + mock_crowdfund_datum( + current_fundraised_amount + contribute_amount + 9999999, + allow_over_subscription, + ), + ) + |> tx_out(!is_only_one_auth_outputed, mock_crowdfund_address, output_value) + |> invalid_hereafter(is_deadline_not_passed, mock_deadline - 3600 * 24) + |> invalid_hereafter(!is_deadline_not_passed, mock_deadline + 3600 * 24) + |> mint( + is_shares_minted, + contribute_amount, + mock_share_token, + mock_completion_script, + ) + |> mint( + !is_shares_minted, + contribute_amount + 9999999, + mock_share_token, + mock_completion_script, + ) + |> complete() + |> add_redeemer( + True, + Pair( + Spend( + OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, + ), + auth_token_redeemer_data, + ), + ) +} + +fn check_all_scripts( + test_case: ContributeFundTestCase, + current_fundraised_amount: Int, + contribute_amount: Int, + allow_over_subscription: Bool, + auth_token_redeemer: CrowdfundRedeemer, +) { + let tx = + mock_contribute_fund_tx( + test_case, + current_fundraised_amount, + contribute_amount, + allow_over_subscription, + auth_token_redeemer, + ) + + let check_auth_spend = + crowdfund_spend.crowdfund.spend( + mock_auth_token, + Some( + mock_crowdfund_datum( + mock_current_fundraised_amount, + allow_over_subscription, + ), + ), + auth_token_redeemer, + mock_utxo_ref(0, 0), + tx, + ) + let check_share_mint = + share_token_mint.share_token.mint( + mock_auth_token, + RMint, + mock_share_token, + tx, + ) + + check_auth_spend? && check_share_mint? +} + +test contribute_fund_success_with_not_allow_over_subscription() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_success_with_allow_over_subscription() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + True, + ContributeFund, + ) +} + +test contribute_fund_success_with_allow_over_subscription_and_over_fundraised() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_over_fundraised_amount, + True, + ContributeFund, + ) +} + +test contribute_fund_fail_with_not_allow_over_subscription_but_over_fundraised() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_over_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_fail_with_over_current_fundraised() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + !check_all_scripts( + test_case, + mock_contribute_over_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_fail_with_wrong_redeemer() fail { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + CompleteCrowdfund, + ) +} + +test contribute_fund_fail_with_more_than_one_auth_inputed() fail { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: False, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_fail_with_more_than_one_auth_outputed() fail { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: False, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_fail_with_incorrect_auth_output_datum() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: False, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: True, + } + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_fail_with_auth_output_not_clean() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: False, + is_deadline_not_passed: True, + is_shares_minted: True, + } + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_fail_with_deadline_passed() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: False, + is_shares_minted: True, + } + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} + +test contribute_fund_fail_with_wrong_shares_minted() { + let test_case = + ContributeFundTestCase { + is_only_one_auth_inputed: True, + is_only_one_auth_outputed: True, + is_auth_output_datum_correct: True, + is_auth_output_value_clean: True, + is_deadline_not_passed: True, + is_shares_minted: False, + } + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + mock_contribute_min_fundraised_amount, + False, + ContributeFund, + ) +} From 7342a61874b5be8cb0b614a9a6e01e62067b18cb Mon Sep 17 00:00:00 2001 From: kenlau666 Date: Sun, 29 Jun 2025 02:23:49 +0800 Subject: [PATCH 15/19] added: complete fund integration test --- .../tests/integration_test/contribute_fund.ak | 57 --- .../gov-crowdfund/validators/crowdfund.ak | 211 +++++++++ .../intergration_test/complete_crowdfund.ak | 439 ++++++++++++++++++ .../gov-crowdfund/validators/tests/utils.ak | 12 +- 4 files changed, 659 insertions(+), 60 deletions(-) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak index 4284bd939..ba13be51e 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak @@ -156,63 +156,6 @@ fn check_all_scripts( check_auth_spend? && check_share_mint? } -test contribute_fund_success_with_not_allow_over_subscription() { - let test_case = - ContributeFundTestCase { - is_only_one_auth_inputed: True, - is_only_one_auth_outputed: True, - is_auth_output_datum_correct: True, - is_auth_output_value_clean: True, - is_deadline_not_passed: True, - is_shares_minted: True, - } - check_all_scripts( - test_case, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - False, - ContributeFund, - ) -} - -test contribute_fund_success_with_allow_over_subscription() { - let test_case = - ContributeFundTestCase { - is_only_one_auth_inputed: True, - is_only_one_auth_outputed: True, - is_auth_output_datum_correct: True, - is_auth_output_value_clean: True, - is_deadline_not_passed: True, - is_shares_minted: True, - } - check_all_scripts( - test_case, - mock_current_fundraised_amount, - mock_contribute_min_fundraised_amount, - True, - ContributeFund, - ) -} - -test contribute_fund_success_with_allow_over_subscription_and_over_fundraised() { - let test_case = - ContributeFundTestCase { - is_only_one_auth_inputed: True, - is_only_one_auth_outputed: True, - is_auth_output_datum_correct: True, - is_auth_output_value_clean: True, - is_deadline_not_passed: True, - is_shares_minted: True, - } - check_all_scripts( - test_case, - mock_current_fundraised_amount, - mock_contribute_over_fundraised_amount, - True, - ContributeFund, - ) -} - test contribute_fund_fail_with_not_allow_over_subscription_but_over_fundraised() { let test_case = ContributeFundTestCase { diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak new file mode 100644 index 000000000..fb60cf331 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak @@ -0,0 +1,211 @@ +use aiken/collection/list.{delete} +use aiken/collection/pairs.{has_key} +use cardano/address.{Address, Credential, Script} +use cardano/assets.{ + PolicyId, Value, from_lovelace, lovelace_of, merge, policies, restricted_to, +} +use cardano/transaction.{Output, OutputReference, Transaction, find_input} +use cocktail.{ + inputs_at_with_policy, only_minted_token, output_inline_datum, + outputs_at_with_policy, policy_only_minted_token, valid_after, valid_before, + value_length, +} +use types.{CrowdfundDatum} + +pub type CrowdfundRedeemer { + ContributeFund + CompleteCrowdfund + ContributorWithdrawal + RemoveEmptyInstance +} + +fn check_fundraise_target( + allow_over_subscription: Bool, + fundraise_target: Int, + current_fundraised_amount: Int, +) -> Bool { + if allow_over_subscription { + True + } else { + current_fundraised_amount <= fundraise_target + } +} + +fn output_at_with_value( + outputs: List, + address: Address, + value: Value, +) -> List { + list.filter( + outputs, + fn(output) { + let are_values_equal = output.value == value + are_values_equal && output.address == address + }, + ) +} + +validator crowdfund(auth_token: PolicyId) { + spend( + datum_opt: Option, + redeemer: CrowdfundRedeemer, + input: OutputReference, + self: Transaction, + ) { + let Transaction { inputs, validity_range, mint, outputs, withdrawals, .. } = + self + + expect Some(own_input) = find_input(inputs, input) + expect Some(auth_input_datum) = datum_opt + + let current_address = own_input.output.address + + // check only 1 auth toke input from current address + expect [auth_input] = + inputs_at_with_policy(inputs, current_address, auth_token) + + let CrowdfundDatum { + current_fundraised_amount, + fundraise_target, + allow_over_subscription, + deadline, + completion_script, + share_token, + min_charge, + fee_address, + expiry_buffer, + .. + } = auth_input_datum + when redeemer is { + ContributeFund -> { + expect [auth_output] = + outputs_at_with_policy(outputs, current_address, auth_token) + + let lovelace_from_auth_input = auth_input.output.value |> lovelace_of() + let lovelace_from_auth_output = auth_output.value |> lovelace_of() + expect auth_output_datum: CrowdfundDatum = + output_inline_datum(auth_output) + + let fundraise_added = + lovelace_from_auth_output - lovelace_from_auth_input + let fundraise_check = + (fundraise_added == auth_output_datum.current_fundraised_amount - current_fundraised_amount)? && (fundraise_added >= 2000000)? + + let fundraise_target_check = + check_fundraise_target( + allow_over_subscription, + fundraise_target, + auth_output_datum.current_fundraised_amount, + ) + + let validity_check = valid_before(validity_range, deadline) + + let output_datum_check = + auth_output_datum == CrowdfundDatum { + ..auth_input_datum, + current_fundraised_amount: current_fundraised_amount + fundraise_added, + } + + let is_auth_output_value_clean = value_length(auth_output.value) == 2 + fundraise_check? && fundraise_target_check? && validity_check? && output_datum_check? && is_auth_output_value_clean? && only_minted_token( + mint, + share_token, + completion_script, + fundraise_added, + )? + } + + CompleteCrowdfund -> { + let fee_value = + from_lovelace( + lovelace_of(auth_input.output.value) - current_fundraised_amount - min_charge, + ) + + let other_policy = + policies(auth_input.output.value) + |> delete(auth_token) + |> delete("") + let other_value = restricted_to(auth_input.output.value, other_policy) + + expect [_] = + output_at_with_value( + outputs, + fee_address, + merge(other_value, fee_value), + ) + + let fundraise_check = current_fundraised_amount >= fundraise_target + let completion_script_withdrawal_credential: Credential = + Script(completion_script) + let withdrawal_script_check = + withdrawals + |> has_key(completion_script_withdrawal_credential) + fundraise_check? && withdrawal_script_check? && policy_only_minted_token( + mint, + auth_token, + completion_script, + -1, + )? + } + + ContributorWithdrawal -> { + let validity_check = + valid_after(validity_range, deadline + expiry_buffer) + let fund_check = current_fundraised_amount <= fundraise_target + + expect [auth_output] = + outputs_at_with_policy(outputs, current_address, auth_token) + + let lovelace_from_auth_input = auth_input.output.value |> lovelace_of() + let lovelace_from_auth_output = auth_output.value |> lovelace_of() + + let lovelace_withdrawn = + lovelace_from_auth_output - lovelace_from_auth_input + + let lovelace_withdrawn_check = lovelace_withdrawn < 0 + + expect auth_output_datum: CrowdfundDatum = + output_inline_datum(auth_output) + let output_datum_check = + auth_output_datum == CrowdfundDatum { + ..auth_input_datum, + current_fundraised_amount: current_fundraised_amount + lovelace_withdrawn, + } + + let is_auth_output_value_clean = value_length(auth_output.value) == 2 + (validity_check || fund_check)? && lovelace_withdrawn_check? && output_datum_check? && is_auth_output_value_clean? && only_minted_token( + mint, + share_token, + completion_script, + lovelace_withdrawn, + )? + } + + RemoveEmptyInstance -> { + let validity_check = valid_after(validity_range, deadline) + + let token_burnt_check = + if current_fundraised_amount > 0 { + policy_only_minted_token( + mint, + share_token, + completion_script, + -current_fundraised_amount, + )? && policy_only_minted_token( + mint, + auth_token, + completion_script, + -1, + )? + } else { + only_minted_token(mint, auth_token, completion_script, -1)? + } + validity_check? && token_burnt_check? + } + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak new file mode 100644 index 000000000..d6ca58f7f --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak @@ -0,0 +1,439 @@ +use cardano/address.{Script} +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction} +use crowdfund.{ + CompleteCrowdfund, ContributeFund, CrowdfundRedeemer as ACrowdfundRedeemer, +} +use mocktail.{ + add_redeemer, complete, mint, mock_policy_id, mock_script_hash, mock_tx_hash, + mock_utxo_ref, mocktail_tx, script_withdrawal, tx_in, tx_in_inline_datum, + tx_out, tx_out_inline_datum, +} +use start +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, + mock_extra_fundraised_amount, mock_fee_address, mock_fundraise_target, + mock_gov_action_period, mock_gov_address, mock_min_charge, mock_share_token, + mock_spend_script_hash, mock_start_hash, +} +use types.{Init, RMint} + +type CompleteCrowdfundTestCase { + is_only_one_auth_inputed: Bool, + is_output_to_fee_address_correct: Bool, + is_auth_burnt: Bool, + is_completion_script_executed: Bool, + is_fundraise_target_sent: Bool, + is_fundraise_target_amount_correct: Bool, + is_fundraise_output_datum_correct: Bool, + is_token_minted: Bool, +} + +fn mock_complete_crowdfund_tx( + test_case: CompleteCrowdfundTestCase, + current_fundraised_amount: Int, + auth_token_redeemer: ACrowdfundRedeemer, +) -> Transaction { + let CompleteCrowdfundTestCase { + is_only_one_auth_inputed, + is_output_to_fee_address_correct, + is_auth_burnt, + is_completion_script_executed, + is_fundraise_target_sent, + is_fundraise_target_amount_correct, + is_fundraise_output_datum_correct, + is_token_minted, + } = test_case + let auth_token_redeemer_data: Data = auth_token_redeemer + let fundraise_output = + if is_fundraise_target_amount_correct { + from_lovelace(mock_fundraise_target) + |> add(mock_start_hash, "", 1) + } else { + from_lovelace(mock_fundraise_target - 1000000) + |> add(mock_start_hash, "", 1) + } + let fundraise_output_datum = + if is_fundraise_output_datum_correct { + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount, + deadline: mock_deadline + mock_gov_action_period, + } + } else { + Init { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: current_fundraised_amount + 1000000, + deadline: mock_deadline + mock_gov_action_period, + } + } + let input_value = + from_lovelace( + current_fundraised_amount + mock_min_charge + mock_extra_fundraised_amount, + ) + |> add(mock_auth_token, mock_completion_script, 1) + |> add(mock_policy_id(999), mock_completion_script, 10) + + let output_value = + from_lovelace(mock_extra_fundraised_amount) + |> add(mock_policy_id(999), mock_completion_script, 10) + + mocktail_tx() + |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) + |> tx_in_inline_datum( + True, + mock_crowdfund_datum(current_fundraised_amount, False), + ) + |> tx_in( + !is_only_one_auth_inputed, + mock_tx_hash(0), + 1, + input_value, + mock_crowdfund_address, + ) + |> tx_out(is_output_to_fee_address_correct, mock_fee_address, output_value) + |> tx_out( + !is_output_to_fee_address_correct, + mock_fee_address, + from_lovelace(mock_extra_fundraised_amount - 10) + |> add(mock_policy_id(999), mock_completion_script, 10), + ) + |> tx_out(is_fundraise_target_sent, mock_gov_address, fundraise_output) + |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) + |> script_withdrawal( + is_completion_script_executed, + mock_completion_script, + 2_000_000, + ) + |> mint(is_auth_burnt, -1, mock_auth_token, mock_completion_script) + |> mint(is_token_minted, 1, mock_start_hash, "") + |> complete() + |> add_redeemer( + True, + Pair( + Spend( + OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, + ), + auth_token_redeemer_data, + ), + ) +} + +fn check_all_scripts( + test_case: CompleteCrowdfundTestCase, + current_fundraised_amount: Int, + auth_token_redeemer: ACrowdfundRedeemer, + start_hash: ByteArray, +) { + let tx = + mock_complete_crowdfund_tx( + test_case, + current_fundraised_amount, + auth_token_redeemer, + ) + + let check_auth_spend = + crowdfund.crowdfund.spend( + mock_auth_token, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + auth_token_redeemer, + mock_utxo_ref(0, 0), + tx, + ) + let check_token_mint = + start.start.mint( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + RMint, + start_hash, + tx, + ) + + let check_start_withdraw = + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(start_hash), + tx, + ) + check_auth_spend? && check_token_mint? && check_start_withdraw? +} + +test complete_crowdfund_success_with_amount_equal_to_target() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_success_with_amount_larger_than_target() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_amount_less_than_target() fail { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + check_all_scripts( + test_case, + mock_current_fundraised_amount - 1000000, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_more_than_one_auth_inputed() fail { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: False, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_incorrect_fee_output() fail { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: False, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_no_auth_burnt() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: False, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_no_completion_script_executed() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: False, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_fundraise_target_not_sent() fail { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: False, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_incorrect_fundraise_target_output_amount() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: False, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_incorrect_fundraise_target_output_datum() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: False, + is_token_minted: True, + } + + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_token_not_minted() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: False, + } + + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_start_hash, + ) +} + +test complete_crowdfund_fail_with_different_start_hash() { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_script_hash(999), + ) +} + +test complete_crowdfund_fail_with_input_wrong_redeemer() fail { + let test_case = + CompleteCrowdfundTestCase { + is_only_one_auth_inputed: True, + is_output_to_fee_address_correct: True, + is_auth_burnt: True, + is_completion_script_executed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + } + + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + ContributeFund, + mock_script_hash(999), + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak index caac96b94..80f8da539 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -25,16 +25,22 @@ pub const mock_fee_address = from_script("fee_address") pub const mock_fundraise_target = 100000000000 -pub const mock_current_fundraised_amount = mock_fundraise_target + 1000000 +pub const mock_extra_fundraised_amount = 4000000 + +pub const mock_min_charge = 0 + +pub const mock_current_fundraised_amount = + mock_fundraise_target + mock_extra_fundraised_amount + mock_min_charge pub const mock_contribute_min_fundraised_amount = 2000000 +pub const mock_contribute_over_fundraised_amount = + mock_fundraise_target + mock_contribute_min_fundraised_amount + pub const mock_deadline = 1750735607 pub const mock_expiry_buffer = 3600 * 24 -pub const mock_min_charge = 0 - pub fn mock_crowdfund_datum( current_fundraised_amount: Int, allow_over_subscription: Bool, From a708b2cd519ea82a09f6618795393bb40ed4eed3 Mon Sep 17 00:00:00 2001 From: kenlau666 Date: Sun, 29 Jun 2025 03:01:35 +0800 Subject: [PATCH 16/19] added: user doc --- .../specs/application_setup_doc.md | 14 ++++++++ .../aiken-crowdfund/specs/user_action_doc.md | 29 ++++++++++++++++ .../gov-crowdfund/specs/user_action_doc.md | 33 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/application_setup_doc.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md create mode 100644 packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/user_action_doc.md diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/application_setup_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/application_setup_doc.md new file mode 100644 index 000000000..4cdb0de40 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/application_setup_doc.md @@ -0,0 +1,14 @@ +# Application Setup Documentation + +## Setup + +The are 2 steps of setting up the applications: + +1. Minting `auth_token`, one time minting policy with empty token name with quantity of 1. + + - Validation: 1.1 + +2. Sending the the `auth_token` to `crowdfund` + + - With inline datum `CrowdfundDatum` of proposal details, `completion_script` set to be `2_start` script hash from `gov_crowdfund`, `share_token` set to be `2_share` script hash, `crowdfund` set to be `3_crowdfund` script hash and `current_fundraised_amount` set to be the lovelace value of output + - Validation: N/A \ No newline at end of file diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md new file mode 100644 index 000000000..ac70649b9 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md @@ -0,0 +1,29 @@ +# User Actions Documentation + +## Normal Users + +1. Contribute fund. Minting `share_token` + + - Validation: 2.1, 3.1 + +2. Withdraw fund. Burning ``share_token`` + + - Validation: 2.2, 3.3 + +## Proposer + +1. Contribute fund. Minting `share_token` + + - Validation: 2.1, 3.1 + +2. Withdraw fund. Burning `share_token` + + - Validation: 2.2, 3.3 + +3. Complete Crowdfund. Sending `auth_token` and `fundraised_amount` to `1_spend` from `gov-aiken` + + - Validation: 3.2, 2.1 `Withdraw`, 2.1 `Mint` from `gov_crowdfund` + +4. Remove Crowdfund. Burning the `auth_token` + + - Validation: 1.2, 2.2, 3.4 \ No newline at end of file diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/user_action_doc.md new file mode 100644 index 000000000..1dec29f5d --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/user_action_doc.md @@ -0,0 +1,33 @@ +# User Actions Documentation + +## Normal Users + +1. Withdraw fund. Burning ``share_token`` + + - Validation: 1.4, 2.2 from `aiken_crowdfund` + +## Proposer + +1. Complete Crowdfund. Sending `auth_token` and `fundraised_amount` to start the proposal + + - Validation: 2.1 `Withdraw`, 2.1 `Mint`, 3.2 from `aiken_crowdfund` + +2. Register Certificates. Proposing `gov_action`, registering stake cert, registering drep cert, delegating vote to drep and delegating stake to `delegate_pool_id` + + - Validation: 1.1, 2.1 `Publish`, 2.1 `Propose` + +3. Vote Own Proposal. Voting `yes` to own proposal by drep + + - Validation: 1.2, 2.1 `Vote` + +4. Unregister Certificates. unregistering stake cert and unregistering drep cert + + - Validation: 1.3, 2.2 `Publish` + +5. Withdraw fund. Burning `share_token` + + - Validation: 1.4, 2.2 from `aiken_crowdfund` + +6. Remove Crowdfund. Burning the `only_token` + + - Validation: 1.4, 2.2 `Mint`, 2.2 from `aiken_crowdfund` \ No newline at end of file From 0ce167e6c3d8c719aa5468738317c5882681bf21 Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Mon, 30 Jun 2025 10:35:55 +0800 Subject: [PATCH 17/19] chore: rename test case --- .../gov-crowdfund/validators/tests/spend.ak | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak index 32e69ea13..2aec6f790 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak @@ -165,7 +165,7 @@ fn mock_register_cert_tx(test_case: RegisterCertsTestCase) -> Transaction { ) } -test s3_spend_success_reg_cert() { +test s1_spend_success_reg_cert() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -203,7 +203,7 @@ test s3_spend_success_reg_cert() { ) } -test s3_spend_fail_reg_cert_with_not_init_state() { +test s1_spend_fail_reg_cert_with_not_init_state() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -241,7 +241,7 @@ test s3_spend_fail_reg_cert_with_not_init_state() { ) } -test s3_spend_fail_reg_cert_with_more_than_one_input() fail { +test s1_spend_fail_reg_cert_with_more_than_one_input() fail { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -279,7 +279,7 @@ test s3_spend_fail_reg_cert_with_more_than_one_input() fail { ) } -test s3_spend_fail_reg_cert_with_more_than_one_output() fail { +test s1_spend_fail_reg_cert_with_more_than_one_output() fail { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -317,7 +317,7 @@ test s3_spend_fail_reg_cert_with_more_than_one_output() fail { ) } -test s3_spend_fail_reg_cert_with_incorrect_output_datum() { +test s1_spend_fail_reg_cert_with_incorrect_output_datum() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -355,7 +355,7 @@ test s3_spend_fail_reg_cert_with_incorrect_output_datum() { ) } -test s3_spend_fail_reg_cert_with_output_value_not_clean() { +test s1_spend_fail_reg_cert_with_output_value_not_clean() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -393,7 +393,7 @@ test s3_spend_fail_reg_cert_with_output_value_not_clean() { ) } -test s3_spend_fail_reg_cert_with_incorrect_output_value() { +test s1_spend_fail_reg_cert_with_incorrect_output_value() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -431,7 +431,7 @@ test s3_spend_fail_reg_cert_with_incorrect_output_value() { ) } -test s3_spend_fail_reg_cert_with_stake_cert_not_reg() { +test s1_spend_fail_reg_cert_with_stake_cert_not_reg() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -469,7 +469,7 @@ test s3_spend_fail_reg_cert_with_stake_cert_not_reg() { ) } -test s3_spend_fail_reg_cert_with_drep_cert_not_reg() { +test s1_spend_fail_reg_cert_with_drep_cert_not_reg() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -507,7 +507,7 @@ test s3_spend_fail_reg_cert_with_drep_cert_not_reg() { ) } -test s3_spend_fail_reg_cert_with_drep_deposit_incorrect() { +test s1_spend_fail_reg_cert_with_drep_deposit_incorrect() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -545,7 +545,7 @@ test s3_spend_fail_reg_cert_with_drep_deposit_incorrect() { ) } -test s3_spend_fail_reg_cert_with_stake_not_delegated() { +test s1_spend_fail_reg_cert_with_stake_not_delegated() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -583,7 +583,7 @@ test s3_spend_fail_reg_cert_with_stake_not_delegated() { ) } -test s3_spend_fail_reg_cert_with_vote_not_delegated() { +test s1_spend_fail_reg_cert_with_vote_not_delegated() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -621,7 +621,7 @@ test s3_spend_fail_reg_cert_with_vote_not_delegated() { ) } -test s3_spend_fail_reg_cert_with_gov_not_proposed() { +test s1_spend_fail_reg_cert_with_gov_not_proposed() { let tx = mock_register_cert_tx( RegisterCertsTestCase { @@ -752,7 +752,7 @@ fn mock_vote_on_gov_action_tx(test_case: VoteOnGovActionTestCase) -> Transaction ) } -test s3_spend_success_vote_on_gov_action() { +test s1_spend_success_vote_on_gov_action() { let tx = mock_vote_on_gov_action_tx( VoteOnGovActionTestCase { @@ -785,7 +785,7 @@ test s3_spend_success_vote_on_gov_action() { ) } -test s3_spend_fail_vote_on_gov_action_with_more_than_one_inputed() fail { +test s1_spend_fail_vote_on_gov_action_with_more_than_one_inputed() fail { let tx = mock_vote_on_gov_action_tx( VoteOnGovActionTestCase { @@ -818,7 +818,7 @@ test s3_spend_fail_vote_on_gov_action_with_more_than_one_inputed() fail { ) } -test s3_spend_fail_vote_on_gov_action_with_more_than_one_outputed() fail { +test s1_spend_fail_vote_on_gov_action_with_more_than_one_outputed() fail { let tx = mock_vote_on_gov_action_tx( VoteOnGovActionTestCase { @@ -851,7 +851,7 @@ test s3_spend_fail_vote_on_gov_action_with_more_than_one_outputed() fail { ) } -test s3_spend_fail_vote_on_gov_action_with_output_datum_wrong() { +test s1_spend_fail_vote_on_gov_action_with_output_datum_wrong() { let tx = mock_vote_on_gov_action_tx( VoteOnGovActionTestCase { @@ -884,7 +884,7 @@ test s3_spend_fail_vote_on_gov_action_with_output_datum_wrong() { ) } -test s3_spend_fail_vote_on_gov_action_with_output_value_not_clean() { +test s1_spend_fail_vote_on_gov_action_with_output_value_not_clean() { let tx = mock_vote_on_gov_action_tx( VoteOnGovActionTestCase { @@ -917,7 +917,7 @@ test s3_spend_fail_vote_on_gov_action_with_output_value_not_clean() { ) } -test s3_spend_fail_vote_on_gov_action_with_incorrect_output_value() { +test s1_spend_fail_vote_on_gov_action_with_incorrect_output_value() { let tx = mock_vote_on_gov_action_tx( VoteOnGovActionTestCase { @@ -950,7 +950,7 @@ test s3_spend_fail_vote_on_gov_action_with_incorrect_output_value() { ) } -test s3_spend_fail_vote_on_gov_action_with_no_vote() fail { +test s1_spend_fail_vote_on_gov_action_with_no_vote() fail { let tx = mock_vote_on_gov_action_tx( VoteOnGovActionTestCase { @@ -1088,7 +1088,7 @@ fn mock_deregister_cert_tx(test_case: DeregisterCertsTestCase) -> Transaction { ) } -test s3_spend_success_unregister_certs() { +test s1_spend_success_unregister_certs() { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1124,7 +1124,7 @@ test s3_spend_success_unregister_certs() { ) } -test s3_spend_fail_unregister_certs_with_more_than_one_inputed() fail { +test s1_spend_fail_unregister_certs_with_more_than_one_inputed() fail { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1160,7 +1160,7 @@ test s3_spend_fail_unregister_certs_with_more_than_one_inputed() fail { ) } -test s3_spend_fail_unregister_certs_with_more_than_one_outputed() fail { +test s1_spend_fail_unregister_certs_with_more_than_one_outputed() fail { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1196,7 +1196,7 @@ test s3_spend_fail_unregister_certs_with_more_than_one_outputed() fail { ) } -test s3_spend_fail_unregister_certs_with_output_datum_incorrect() { +test s1_spend_fail_unregister_certs_with_output_datum_incorrect() { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1232,7 +1232,7 @@ test s3_spend_fail_unregister_certs_with_output_datum_incorrect() { ) } -test s3_spend_fail_unregister_certs_with_output_value_not_clean() { +test s1_spend_fail_unregister_certs_with_output_value_not_clean() { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1268,7 +1268,7 @@ test s3_spend_fail_unregister_certs_with_output_value_not_clean() { ) } -test s3_spend_fail_unregister_certs_with_output_value_incorrect() { +test s1_spend_fail_unregister_certs_with_output_value_incorrect() { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1304,7 +1304,7 @@ test s3_spend_fail_unregister_certs_with_output_value_incorrect() { ) } -test s3_spend_fail_unregister_certs_with_stake_not_unregister() { +test s1_spend_fail_unregister_certs_with_stake_not_unregister() { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1340,7 +1340,7 @@ test s3_spend_fail_unregister_certs_with_stake_not_unregister() { ) } -test s3_spend_fail_unregister_certs_with_drep_not_unregister() { +test s1_spend_fail_unregister_certs_with_drep_not_unregister() { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1376,7 +1376,7 @@ test s3_spend_fail_unregister_certs_with_drep_not_unregister() { ) } -test s3_spend_fail_unregister_certs_with_deadline_not_passed() { +test s1_spend_fail_unregister_certs_with_deadline_not_passed() { let tx = mock_deregister_cert_tx( DeregisterCertsTestCase { @@ -1506,7 +1506,7 @@ fn mock_contributor_withdrawal_tx( |> complete() } -test s3_spend_success_contributor_withdraw() { +test s1_spend_success_contributor_withdraw() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1541,7 +1541,7 @@ test s3_spend_success_contributor_withdraw() { ) } -test s3_spend_fail_contributor_withdraw_with_state_not_refundable() { +test s1_spend_fail_contributor_withdraw_with_state_not_refundable() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1577,7 +1577,7 @@ test s3_spend_fail_contributor_withdraw_with_state_not_refundable() { ) } -test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { +test s1_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1612,7 +1612,7 @@ test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_inputed() fail { ) } -test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail { +test s1_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1647,7 +1647,7 @@ test s3_spend_fail_contributor_withdraw_with_more_than_one_auth_outputed() fail ) } -test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { +test s1_spend_fail_contributor_withdraw_with_incorrect_output_datum() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1682,7 +1682,7 @@ test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { ) } -test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { +test s1_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1717,7 +1717,7 @@ test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { ) } -test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { +test s1_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1752,7 +1752,7 @@ test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { ) } -// test s3_spend_fail_contributor_withdraw_with_deadline_not_passed() { +// test s1_spend_fail_contributor_withdraw_with_deadline_not_passed() { // let tx = // mock_contributor_withdrawal_tx( // ContributorWithdrawalTestCase { @@ -1787,7 +1787,7 @@ test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { // ) // } -test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { +test s1_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { let tx = mock_contributor_withdrawal_tx( ContributorWithdrawalTestCase { @@ -1891,7 +1891,7 @@ fn mock_remove_empty_instance_tx( |> add_extra_signatory(is_proposer_signed, mock_proposer_key_hash) } -test s3_spend_success_remove_empty_instance_wih_zero_fund() { +test s1_spend_success_remove_empty_instance_wih_zero_fund() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1923,7 +1923,7 @@ test s3_spend_success_remove_empty_instance_wih_zero_fund() { ) } -test s3_spend_success_remove_empty_instance_wih_some_fund() { +test s1_spend_success_remove_empty_instance_wih_some_fund() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1955,7 +1955,7 @@ test s3_spend_success_remove_empty_instance_wih_some_fund() { ) } -test s3_spend_fail_remove_empty_instance_wih_state_not_refundable() { +test s1_spend_fail_remove_empty_instance_wih_state_not_refundable() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -1988,7 +1988,7 @@ test s3_spend_fail_remove_empty_instance_wih_state_not_refundable() { ) } -test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { +test s1_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -2020,7 +2020,7 @@ test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { ) } -// test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { +// test s1_spend_fail_remove_empty_instance_wih_deadline_not_passed() { // let tx = // mock_remove_empty_instance_tx( // RemoveEmptyInstanceTestCase { @@ -2052,7 +2052,7 @@ test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { // ) // } -test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { +test s1_spend_fail_remove_empty_instance_wih_share_not_burnt() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -2084,7 +2084,7 @@ test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { ) } -test s3_spend_fail_remove_empty_instance_wih_token_not_burnt() { +test s1_spend_fail_remove_empty_instance_wih_token_not_burnt() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { @@ -2116,7 +2116,7 @@ test s3_spend_fail_remove_empty_instance_wih_token_not_burnt() { ) } -test s3_spend_fail_remove_empty_instance_wih_proposer_not_signed() { +test s1_spend_fail_remove_empty_instance_wih_proposer_not_signed() { let tx = mock_remove_empty_instance_tx( RemoveEmptyInstanceTestCase { From 43da75b6066794ae1d87ea24670ee2f9fefc193c Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Mon, 30 Jun 2025 14:56:41 +0800 Subject: [PATCH 18/19] updated: min_charge --- .../aiken-crowdfund/lib/utils.ak | 10 +-- .../aiken-crowdfund/specs/3_crowdfund.md | 5 +- .../aiken-crowdfund/specs/user_action_doc.md | 6 +- .../validators/crowdfund/spend.ak | 47 ++++++-------- .../validators/tests/crowdfund/spend.ak | 62 +++++++++++++++---- .../tests/integration_test/contribute_fund.ak | 3 +- .../aiken-crowdfund/validators/tests/utils.ak | 9 ++- .../gov-crowdfund/specs/2_start.md | 1 + .../gov-crowdfund/validators/crowdfund.ak | 54 +++++++--------- .../gov-crowdfund/validators/start.ak | 13 +++- .../intergration_test/complete_crowdfund.ak | 15 ++--- .../gov-crowdfund/validators/tests/start.ak | 44 +++++++++++++ .../gov-crowdfund/validators/tests/utils.ak | 2 +- 13 files changed, 178 insertions(+), 93 deletions(-) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak index 9216d4927..75d90a275 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak @@ -1,7 +1,7 @@ use aiken/collection/list use aiken/collection/pairs use cardano/address.{Address} -use cardano/assets.{Value} +use cardano/assets.{Lovelace, from_lovelace} use cardano/transaction.{Input, Output, Redeemer, ScriptPurpose, Spend} pub fn redeemer_with_input( @@ -24,16 +24,16 @@ pub fn check_fundraise_target( } } -pub fn output_at_with_value( +pub fn outputs_at_with_lovelace( outputs: List, address: Address, - value: Value, + lovelace: Lovelace, ) -> List { list.filter( outputs, fn(output) { - let are_values_equal = output.value == value - are_values_equal && output.address == address + let is_lovelace_match = output.value == from_lovelace(lovelace) + is_lovelace_match && output.address == address }, ) } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md index d63202f8e..a99dbcc26 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md @@ -3,6 +3,7 @@ ## Parameter - `auth_token`: The policy id of `AuthToken` +- `proposer_key_hash`: ByteArray ## Datum @@ -30,7 +31,8 @@ 2. CompleteCrowdfund - - Any value in the current utxos - (`current_fundraised_amount` + `min_charge`) goes to `fee_address` + - `min_charge` goes to `fee_address` + - utxo value >= `min_charge` + `current_fundraised_amount` - `current_fundraised_amount` >= `fundraise_target` - `completion_script` withdrawal script is executed - `auth_token` from current input is burnt @@ -48,3 +50,4 @@ - `deadline` is passed - share token with token name `completion_script` burning in current tx == `current_fundraised_amount` - `auth_token` from current input is burnt + - signed by `proposer_key_hash` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md index ac70649b9..c2912625c 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md @@ -6,7 +6,7 @@ - Validation: 2.1, 3.1 -2. Withdraw fund. Burning ``share_token`` +2. Withdraw fund. Burning `share_token` - Validation: 2.2, 3.3 @@ -20,10 +20,10 @@ - Validation: 2.2, 3.3 -3. Complete Crowdfund. Sending `auth_token` and `fundraised_amount` to `1_spend` from `gov-aiken` +3. Complete Crowdfund. Sending `auth_token` and `fundraised_amount` to `1_spend` from `gov-aiken`. Proposer is required to add `min_charge` to `auth_token` utxo - Validation: 3.2, 2.1 `Withdraw`, 2.1 `Mint` from `gov_crowdfund` 4. Remove Crowdfund. Burning the `auth_token` - - Validation: 1.2, 2.2, 3.4 \ No newline at end of file + - Validation: 1.2, 2.2, 3.4 diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak index 017f07a62..544ee930b 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak @@ -1,12 +1,9 @@ -use aiken/collection/list.{delete} use aiken/collection/pairs.{has_key} use cardano/address.{Credential, Script} -use cardano/assets.{ - PolicyId, from_lovelace, lovelace_of, merge, policies, restricted_to, -} +use cardano/assets.{PolicyId, lovelace_of} use cardano/transaction.{OutputReference, Transaction, find_input} use cocktail.{ - inputs_at_with_policy, only_minted_token, output_inline_datum, + inputs_at_with_policy, key_signed, only_minted_token, output_inline_datum, outputs_at_with_policy, policy_only_minted_token, valid_after, valid_before, value_length, } @@ -14,17 +11,24 @@ use types.{ CompleteCrowdfund, ContributeFund, ContributorWithdrawal, CrowdfundDatum, CrowdfundRedeemer, RemoveEmptyInstance, } -use utils.{check_fundraise_target, output_at_with_value} +use utils.{check_fundraise_target, outputs_at_with_lovelace} -validator crowdfund(auth_token: PolicyId) { +validator crowdfund(auth_token: PolicyId, proposer_key_hash: ByteArray) { spend( datum_opt: Option, redeemer: CrowdfundRedeemer, input: OutputReference, self: Transaction, ) { - let Transaction { inputs, validity_range, mint, outputs, withdrawals, .. } = - self + let Transaction { + inputs, + validity_range, + mint, + outputs, + withdrawals, + extra_signatories, + .. + } = self expect Some(own_input) = find_input(inputs, input) expect Some(auth_input_datum) = datum_opt @@ -87,23 +91,10 @@ validator crowdfund(auth_token: PolicyId) { } CompleteCrowdfund -> { - let fee_value = - from_lovelace( - lovelace_of(auth_input.output.value) - current_fundraised_amount - min_charge, - ) + let input_lovelace_check = + lovelace_of(auth_input.output.value) >= min_charge + current_fundraised_amount - let other_policy = - policies(auth_input.output.value) - |> delete(auth_token) - |> delete("") - let other_value = restricted_to(auth_input.output.value, other_policy) - - expect [_] = - output_at_with_value( - outputs, - fee_address, - merge(other_value, fee_value), - ) + expect [_] = outputs_at_with_lovelace(outputs, fee_address, min_charge) let fundraise_check = current_fundraised_amount >= fundraise_target let completion_script_withdrawal_credential: Credential = @@ -111,7 +102,7 @@ validator crowdfund(auth_token: PolicyId) { let withdrawal_script_check = withdrawals |> has_key(completion_script_withdrawal_credential) - fundraise_check? && withdrawal_script_check? && policy_only_minted_token( + fundraise_check? && withdrawal_script_check? && input_lovelace_check? && policy_only_minted_token( mint, auth_token, completion_script, @@ -171,7 +162,9 @@ validator crowdfund(auth_token: PolicyId) { } else { only_minted_token(mint, auth_token, completion_script, -1)? } - validity_check? && token_burnt_check? + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + validity_check? && token_burnt_check? && proposer_key_signed_check? } } } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak index 30acf36bc..2b68446f5 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak @@ -2,8 +2,8 @@ use cardano/assets.{add, from_lovelace} use cardano/transaction.{Transaction} use crowdfund/spend as crowdfund_spend use mocktail.{ - complete, invalid_before, invalid_hereafter, mint, mock_policy_id, - mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, + add_extra_signatory, complete, invalid_before, invalid_hereafter, mint, + mock_policy_id, mock_pub_key_address, mock_tx_hash, mock_utxo_ref, mocktail_tx, script_withdrawal, tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, } use tests/utils.{ @@ -11,7 +11,8 @@ use tests/utils.{ mock_contribute_over_fundraised_amount, mock_crowdfund_address, mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, mock_expiry_buffer, mock_extra_fundraised_amount, mock_fee_address, - mock_fundraise_target, mock_min_charge, mock_share_token, + mock_fundraise_target, mock_min_charge, mock_proposer_key_hash, + mock_share_token, } use types.{ CompleteCrowdfund, ContributeFund, ContributorWithdrawal, RemoveEmptyInstance, @@ -125,6 +126,7 @@ test s3_spend_success_contribute_fund_with_not_allow_over_subscription() { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -150,6 +152,7 @@ test s3_spend_success_contribute_fund_with_allow_over_subscription() { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, True)), ContributeFund, mock_utxo_ref(0, 0), @@ -175,6 +178,7 @@ test s3_spend_success_contribute_fund_with_allow_over_subscription_and_over_fund crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, True)), ContributeFund, mock_utxo_ref(0, 0), @@ -200,6 +204,7 @@ test s3_spend_fail_contribute_fund_with_not_allow_over_subscription_but_over_fun !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -225,6 +230,7 @@ test s3_spend_fail_contribute_fund_with_over_current_fundraised() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -250,6 +256,7 @@ test s3_spend_fail_contribute_fund_with_more_than_one_auth_inputed() fail { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -275,6 +282,7 @@ test s3_spend_fail_contribute_fund_with_more_than_one_auth_outputed() fail { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -300,6 +308,7 @@ test s3_spend_fail_contribute_fund_with_incorrect_auth_output_datum() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -325,6 +334,7 @@ test s3_spend_fail_contribute_fund_with_auth_output_not_clean() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -350,6 +360,7 @@ test s3_spend_fail_contribute_fund_with_deadline_passed() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -375,6 +386,7 @@ test s3_spend_fail_contribute_fund_with_wrong_shares_minted() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), ContributeFund, mock_utxo_ref(0, 0), @@ -402,15 +414,10 @@ fn mock_complete_crowdfund_tx( } = test_case let input_value = - from_lovelace( - current_fundraised_amount + mock_min_charge + mock_extra_fundraised_amount, - ) + from_lovelace(current_fundraised_amount + mock_min_charge) |> add(mock_auth_token, mock_completion_script, 1) - |> add(mock_policy_id(999), mock_completion_script, 10) - let output_value = - from_lovelace(mock_extra_fundraised_amount) - |> add(mock_policy_id(999), mock_completion_script, 10) + let output_value = from_lovelace(mock_min_charge) mocktail_tx() |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) @@ -429,8 +436,7 @@ fn mock_complete_crowdfund_tx( |> tx_out( !is_output_to_fee_address_correct, mock_fee_address, - from_lovelace(mock_extra_fundraised_amount - 10) - |> add(mock_policy_id(999), mock_completion_script, 10), + from_lovelace(mock_extra_fundraised_amount - 10), ) |> script_withdrawal( is_completion_script_executed, @@ -456,6 +462,7 @@ test s3_spend_success_complete_crowdfund_with_amount_equal_to_target() { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_fundraise_target, False)), CompleteCrowdfund, mock_utxo_ref(0, 0), @@ -478,6 +485,7 @@ test s3_spend_success_complete_crowdfund_with_amount_larger_than_target() { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), CompleteCrowdfund, mock_utxo_ref(0, 0), @@ -500,6 +508,7 @@ test s3_spend_fail_complete_crowdfund_with_amount_less_than_target() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_fundraise_target - 1, False)), CompleteCrowdfund, mock_utxo_ref(0, 0), @@ -522,6 +531,7 @@ test s3_spend_fail_complete_crowdfund_with_more_than_one_auth_inputed() fail { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_fundraise_target, False)), CompleteCrowdfund, mock_utxo_ref(0, 0), @@ -544,6 +554,7 @@ test s3_spend_fail_complete_crowdfund_with_incorrect_fee_output() fail { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_fundraise_target, False)), CompleteCrowdfund, mock_utxo_ref(0, 0), @@ -566,6 +577,7 @@ test s3_spend_fail_complete_crowdfund_with_no_auth_burnt() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_fundraise_target, False)), CompleteCrowdfund, mock_utxo_ref(0, 0), @@ -588,6 +600,7 @@ test s3_spend_fail_complete_crowdfund_with_no_completion_script_executed() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_fundraise_target, False)), CompleteCrowdfund, mock_utxo_ref(0, 0), @@ -711,6 +724,7 @@ test s3_spend_success_contributor_withdraw_with_deadline_passed_but_fundraised_r crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -737,6 +751,7 @@ test s3_spend_success_contributor_withdraw_with_deadline_passed_and_fundraised_l crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount * 2, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -763,6 +778,7 @@ test s3_spend_success_contributor_withdraw_with_deadline_not_passed_but_fundrais crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount * 2, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -789,6 +805,7 @@ test s3_spend_fail_contributor_withdraw_with_deadline_not_passed_and_fundraised_ !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -815,6 +832,7 @@ test s3_spend_fail_contributor_withdraw_with_more_thanone_auth_inputed() fail { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -841,6 +859,7 @@ test s3_spend_fail_contributor_withdraw_with_more_thanone_auth_outputed() fail { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -867,6 +886,7 @@ test s3_spend_fail_contributor_withdraw_with_incorrect_output_datum() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -893,6 +913,7 @@ test s3_spend_fail_contributor_withdraw_with_auth_output_value_not_clean() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -919,6 +940,7 @@ test s3_spend_fail_contributor_withdraw_with_incorrect_auth_unlock_value() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -945,6 +967,7 @@ test s3_spend_fail_contributor_withdraw_with_incorrect_shares_burnt() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), ContributorWithdrawal, mock_utxo_ref(0, 0), @@ -957,6 +980,7 @@ type RemoveEmptyInstanceTestCase { is_deadline_passed: Bool, is_shares_burnt: Bool, is_auth_burnt: Bool, + is_proposer_signed: Bool, } fn mock_remove_empty_instance_tx( @@ -969,6 +993,7 @@ fn mock_remove_empty_instance_tx( is_deadline_passed, is_shares_burnt, is_auth_burnt, + is_proposer_signed, } = test_case let input_value = @@ -1004,6 +1029,7 @@ fn mock_remove_empty_instance_tx( ) |> mint(is_auth_burnt, -1, mock_auth_token, mock_completion_script) |> complete() + |> add_extra_signatory(is_proposer_signed, mock_proposer_key_hash) } test s3_spend_success_remove_empty_instance_wih_zero_fund() { @@ -1014,6 +1040,7 @@ test s3_spend_success_remove_empty_instance_wih_zero_fund() { is_deadline_passed: True, is_shares_burnt: True, is_auth_burnt: True, + is_proposer_signed: True, }, 0, False, @@ -1021,6 +1048,7 @@ test s3_spend_success_remove_empty_instance_wih_zero_fund() { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(0, False)), RemoveEmptyInstance, mock_utxo_ref(0, 0), @@ -1036,6 +1064,7 @@ test s3_spend_success_remove_empty_instance_wih_some_fund() { is_deadline_passed: True, is_shares_burnt: True, is_auth_burnt: True, + is_proposer_signed: True, }, mock_current_fundraised_amount, False, @@ -1043,6 +1072,7 @@ test s3_spend_success_remove_empty_instance_wih_some_fund() { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), RemoveEmptyInstance, mock_utxo_ref(0, 0), @@ -1058,6 +1088,7 @@ test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { is_deadline_passed: True, is_shares_burnt: True, is_auth_burnt: True, + is_proposer_signed: True, }, mock_current_fundraised_amount, False, @@ -1065,6 +1096,7 @@ test s3_spend_fail_remove_empty_instance_wih_more_than_one_auth_inputed() fail { crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), RemoveEmptyInstance, mock_utxo_ref(0, 0), @@ -1080,6 +1112,7 @@ test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { is_deadline_passed: False, is_shares_burnt: True, is_auth_burnt: True, + is_proposer_signed: True, }, mock_current_fundraised_amount, False, @@ -1087,6 +1120,7 @@ test s3_spend_fail_remove_empty_instance_wih_deadline_not_passed() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), RemoveEmptyInstance, mock_utxo_ref(0, 0), @@ -1102,6 +1136,7 @@ test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { is_deadline_passed: True, is_shares_burnt: False, is_auth_burnt: True, + is_proposer_signed: True, }, mock_current_fundraised_amount, False, @@ -1109,6 +1144,7 @@ test s3_spend_fail_remove_empty_instance_wih_share_not_burnt() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), RemoveEmptyInstance, mock_utxo_ref(0, 0), @@ -1124,6 +1160,7 @@ test s3_spend_fail_remove_empty_instance_wih_authe_not_burnt() { is_deadline_passed: True, is_shares_burnt: True, is_auth_burnt: False, + is_proposer_signed: True, }, mock_current_fundraised_amount, False, @@ -1131,6 +1168,7 @@ test s3_spend_fail_remove_empty_instance_wih_authe_not_burnt() { !crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), RemoveEmptyInstance, mock_utxo_ref(0, 0), diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak index ba13be51e..1bbcc7e28 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak @@ -11,7 +11,7 @@ use tests/utils.{ mock_auth_token, mock_completion_script, mock_contribute_min_fundraised_amount, mock_contribute_over_fundraised_amount, mock_crowdfund_address, mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, - mock_share_token, + mock_proposer_key_hash, mock_share_token, } use types.{CompleteCrowdfund, ContributeFund, CrowdfundRedeemer, RMint} @@ -135,6 +135,7 @@ fn check_all_scripts( let check_auth_spend = crowdfund_spend.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some( mock_crowdfund_datum( mock_current_fundraised_amount, diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak index a752a80c8..c2ee6a99b 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak @@ -1,5 +1,8 @@ use cardano/address.{from_script} -use mocktail.{mock_policy_id, mock_script_hash, mock_script_stake_key_hash} +use mocktail.{ + mock_policy_id, mock_pub_key_hash, mock_script_hash, + mock_script_stake_key_hash, +} use types.{CrowdfundDatum} pub const mock_auth_token = mock_policy_id(0) @@ -22,7 +25,7 @@ pub const mock_deadline = 1750735607 pub const mock_expiry_buffer = 3600 * 24 -pub const mock_min_charge = 0 +pub const mock_min_charge = 10 pub fn mock_crowdfund_datum( current_fundraised_amount: Int, @@ -57,3 +60,5 @@ pub const auth_allow_over_subscription = pub const auth_not_allow_over_subscription = mock_crowdfund_datum(mock_current_fundraised_amount, False) + +pub const mock_proposer_key_hash = mock_pub_key_hash(0) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md index 3471a3568..6e2f79a27 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md @@ -11,6 +11,7 @@ 1. Validate completion of crowdfunding - Only one input with `auth_token`, with inline datum + `completion_script` same as current crendential hash + - Exactly 1 token with `auth_token` policy + `completion_script` asset name is burnt - Exactly 1 token with `current_script_hash` policy is minted - All `fundraise_target` amount of ADA + currently minted token is sent to address composed of `spend` and `current_script_hash` (both script hash) - With datum: diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak index fb60cf331..107f76017 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak @@ -1,12 +1,10 @@ -use aiken/collection/list.{delete} +use aiken/collection/list use aiken/collection/pairs.{has_key} use cardano/address.{Address, Credential, Script} -use cardano/assets.{ - PolicyId, Value, from_lovelace, lovelace_of, merge, policies, restricted_to, -} +use cardano/assets.{Lovelace, PolicyId, from_lovelace, lovelace_of} use cardano/transaction.{Output, OutputReference, Transaction, find_input} use cocktail.{ - inputs_at_with_policy, only_minted_token, output_inline_datum, + inputs_at_with_policy, key_signed, only_minted_token, output_inline_datum, outputs_at_with_policy, policy_only_minted_token, valid_after, valid_before, value_length, } @@ -31,29 +29,36 @@ fn check_fundraise_target( } } -fn output_at_with_value( +pub fn outputs_at_with_lovelace( outputs: List, address: Address, - value: Value, + lovelace: Lovelace, ) -> List { list.filter( outputs, fn(output) { - let are_values_equal = output.value == value - are_values_equal && output.address == address + let is_lovelace_match = output.value == from_lovelace(lovelace) + is_lovelace_match && output.address == address }, ) } -validator crowdfund(auth_token: PolicyId) { +validator crowdfund(auth_token: PolicyId, proposer_key_hash: ByteArray) { spend( datum_opt: Option, redeemer: CrowdfundRedeemer, input: OutputReference, self: Transaction, ) { - let Transaction { inputs, validity_range, mint, outputs, withdrawals, .. } = - self + let Transaction { + inputs, + validity_range, + mint, + outputs, + withdrawals, + extra_signatories, + .. + } = self expect Some(own_input) = find_input(inputs, input) expect Some(auth_input_datum) = datum_opt @@ -116,23 +121,10 @@ validator crowdfund(auth_token: PolicyId) { } CompleteCrowdfund -> { - let fee_value = - from_lovelace( - lovelace_of(auth_input.output.value) - current_fundraised_amount - min_charge, - ) + let input_lovelace_check = + lovelace_of(auth_input.output.value) >= min_charge + current_fundraised_amount - let other_policy = - policies(auth_input.output.value) - |> delete(auth_token) - |> delete("") - let other_value = restricted_to(auth_input.output.value, other_policy) - - expect [_] = - output_at_with_value( - outputs, - fee_address, - merge(other_value, fee_value), - ) + expect [_] = outputs_at_with_lovelace(outputs, fee_address, min_charge) let fundraise_check = current_fundraised_amount >= fundraise_target let completion_script_withdrawal_credential: Credential = @@ -140,7 +132,7 @@ validator crowdfund(auth_token: PolicyId) { let withdrawal_script_check = withdrawals |> has_key(completion_script_withdrawal_credential) - fundraise_check? && withdrawal_script_check? && policy_only_minted_token( + fundraise_check? && withdrawal_script_check? && input_lovelace_check? && policy_only_minted_token( mint, auth_token, completion_script, @@ -200,7 +192,9 @@ validator crowdfund(auth_token: PolicyId) { } else { only_minted_token(mint, auth_token, completion_script, -1)? } - validity_check? && token_burnt_check? + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + validity_check? && token_burnt_check? && proposer_key_signed_check? } } } diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak index 12dea9345..fc6cc226e 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak @@ -6,6 +6,7 @@ use cocktail.{ input_inline_datum, inputs_at, inputs_with_policy, output_inline_datum, outputs_at_with, policy_only_minted_token, } +use crowdfund.{CompleteCrowdfund, CrowdfundRedeemer as ACrowdfundRedeemer} use types.{ CrowdfundDatum, CrowdfundGovDatum, CrowdfundRedeemer, Deregister, DeregisterCerts, Init, MintPolarity, PublishRedeemer, RBurn, RMint, Register, @@ -19,7 +20,7 @@ validator start( gov_action_period: Int, ) { withdraw(_r, account: Credential, self: Transaction) { - let Transaction { inputs, outputs, mint, .. } = self + let Transaction { inputs, outputs, mint, redeemers, .. } = self expect [auth_token_input] = inputs_with_policy(inputs, auth_token) expect auth_input_datum: CrowdfundDatum = input_inline_datum(auth_token_input) @@ -54,12 +55,20 @@ validator start( funds_controlled: current_fundraised_amount, deadline: deadline + gov_action_period, } + + expect Some(auth_token_input_redeemer_data) = + redeemer_with_input(redeemers, auth_token_input) + + expect auth_token_input_redeemer: ACrowdfundRedeemer = + auth_token_input_redeemer_data + + let auth_redeemer_check = auth_token_input_redeemer == CompleteCrowdfund completion_script_check? && fundraise_output_lovelace_check? && fundraise_output_datum_check? && policy_only_minted_token( mint, completion_script, "", 1, - )? + )? && auth_redeemer_check? } mint(redeemer: MintPolarity, policy_id: PolicyId, self: Transaction) { diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak index d6ca58f7f..aae163a0c 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak @@ -14,8 +14,9 @@ use tests/utils.{ mock_auth_token, mock_completion_script, mock_crowdfund_address, mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, mock_extra_fundraised_amount, mock_fee_address, mock_fundraise_target, - mock_gov_action_period, mock_gov_address, mock_min_charge, mock_share_token, - mock_spend_script_hash, mock_start_hash, + mock_gov_action_period, mock_gov_address, mock_min_charge, + mock_proposer_key_hash, mock_share_token, mock_spend_script_hash, + mock_start_hash, } use types.{Init, RMint} @@ -71,15 +72,10 @@ fn mock_complete_crowdfund_tx( } } let input_value = - from_lovelace( - current_fundraised_amount + mock_min_charge + mock_extra_fundraised_amount, - ) + from_lovelace(current_fundraised_amount + mock_min_charge) |> add(mock_auth_token, mock_completion_script, 1) - |> add(mock_policy_id(999), mock_completion_script, 10) - let output_value = - from_lovelace(mock_extra_fundraised_amount) - |> add(mock_policy_id(999), mock_completion_script, 10) + let output_value = from_lovelace(mock_min_charge) mocktail_tx() |> tx_in(True, mock_tx_hash(0), 0, input_value, mock_crowdfund_address) @@ -138,6 +134,7 @@ fn check_all_scripts( let check_auth_spend = crowdfund.crowdfund.spend( mock_auth_token, + mock_proposer_key_hash, Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), auth_token_redeemer, mock_utxo_ref(0, 0), diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak index 2313b8147..79410b8f2 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak @@ -1,6 +1,7 @@ use cardano/address.{Script} use cardano/assets.{add, from_lovelace} use cardano/transaction.{OutputReference, Spend, Transaction} +use crowdfund.{CompleteCrowdfund} use mocktail.{ add_redeemer, complete, mint, mock_script_hash, mock_tx_hash, mocktail_tx, script_withdrawal, tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, @@ -23,6 +24,7 @@ type WithdrawTestCase { is_fundraise_target_amount_correct: Bool, is_fundraise_output_datum_correct: Bool, is_token_minted: Bool, + is_redeemer_correct: Bool, } fn mock_withdraw_tx(test_case: WithdrawTestCase) -> Transaction { @@ -32,7 +34,10 @@ fn mock_withdraw_tx(test_case: WithdrawTestCase) -> Transaction { is_fundraise_target_amount_correct, is_fundraise_output_datum_correct, is_token_minted, + is_redeemer_correct, } = test_case + + let auth_input_redeemer: Data = CompleteCrowdfund let auth_input = from_lovelace(20000000) |> add(mock_auth_token, mock_start_hash, 1) @@ -78,6 +83,15 @@ fn mock_withdraw_tx(test_case: WithdrawTestCase) -> Transaction { |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) |> mint(is_token_minted, 1, mock_start_hash, "") |> complete() + |> add_redeemer( + is_redeemer_correct, + Pair( + Spend( + OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, + ), + auth_input_redeemer, + ), + ) } test s2_withdraw_success() { @@ -89,6 +103,7 @@ test s2_withdraw_success() { is_fundraise_target_amount_correct: True, is_fundraise_output_datum_correct: True, is_token_minted: True, + is_redeemer_correct: True, }, ) @@ -111,6 +126,7 @@ test s2_withdraw_fail_with_more_than_one_auth_inputed() fail { is_fundraise_target_amount_correct: True, is_fundraise_output_datum_correct: True, is_token_minted: True, + is_redeemer_correct: True, }, ) @@ -133,6 +149,7 @@ test s2_withdraw_fail_with_fundraise_target_not_sent() fail { is_fundraise_target_amount_correct: True, is_fundraise_output_datum_correct: True, is_token_minted: True, + is_redeemer_correct: True, }, ) @@ -155,6 +172,7 @@ test s2_withdraw_fail_with_incorrect_fundraise_target_output_amount() { is_fundraise_target_amount_correct: False, is_fundraise_output_datum_correct: True, is_token_minted: True, + is_redeemer_correct: True, }, ) @@ -177,6 +195,7 @@ test s2_withdraw_fail_with_incorrect_fundraise_target_output_datum() { is_fundraise_target_amount_correct: True, is_fundraise_output_datum_correct: False, is_token_minted: True, + is_redeemer_correct: True, }, ) @@ -199,6 +218,7 @@ test s2_withdraw_fail_with_token_not_minted() { is_fundraise_target_amount_correct: True, is_fundraise_output_datum_correct: True, is_token_minted: False, + is_redeemer_correct: True, }, ) @@ -212,6 +232,29 @@ test s2_withdraw_fail_with_token_not_minted() { ) } +test s2_withdraw_fail_with_redeemer_wrong() fail { + let tx = + mock_withdraw_tx( + WithdrawTestCase { + is_only_one_spend_inputed: True, + is_fundraise_target_sent: True, + is_fundraise_target_amount_correct: True, + is_fundraise_output_datum_correct: True, + is_token_minted: True, + is_redeemer_correct: False, + }, + ) + + start.start.withdraw( + mock_auth_token, + mock_spend_script_hash, + mock_gov_action_period, + None, + Script(mock_start_hash), + tx, + ) +} + test s2_withdraw_fail_with_different_start_hash() { let tx = mock_withdraw_tx( @@ -221,6 +264,7 @@ test s2_withdraw_fail_with_different_start_hash() { is_fundraise_target_amount_correct: True, is_fundraise_output_datum_correct: True, is_token_minted: True, + is_redeemer_correct: True, }, ) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak index 80f8da539..7d9e01d43 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak @@ -27,7 +27,7 @@ pub const mock_fundraise_target = 100000000000 pub const mock_extra_fundraised_amount = 4000000 -pub const mock_min_charge = 0 +pub const mock_min_charge = 10 pub const mock_current_fundraised_amount = mock_fundraise_target + mock_extra_fundraised_amount + mock_min_charge From 7595bf2366d96501b5d568acd37cb28fb268d6ed Mon Sep 17 00:00:00 2001 From: Ken Lau Date: Mon, 30 Jun 2025 15:05:09 +0800 Subject: [PATCH 19/19] chore: update plutus.json --- .../aiken-crowdfund/plutus.json | 424 +++++++++++++++--- .../gov-crowdfund/plutus.json | 280 +++++++++++- 2 files changed, 642 insertions(+), 62 deletions(-) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json index 67ed61785..4e0876c10 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json @@ -6,96 +6,420 @@ "plutusVersion": "v3", "compiler": { "name": "Aiken", - "version": "v1.1.16+23061c0" + "version": "v1.1.7+e2fb28b" }, "license": "Apache-2.0" }, "validators": [ { - "title": "placeholder.placeholder.mint", + "title": "auth_token/mint.auth_token.mint", "redeemer": { - "title": "_redeemer", + "title": "redeemer", "schema": { - "$ref": "#/definitions/Data" + "$ref": "#/definitions/types~1MintPolarity" } }, - "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", - "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + } + ], + "compiledCode": "5901770101003232323232323222533300332323232325332330093001300a3754004264646464a66601a600a0022a666020601e6ea801c0085854ccc034c00c00454ccc040c03cdd50038010b0b18069baa006132325333010301300213232533300f3007301037540122a66601e646600200200444a66602800229404cc894ccc04ccdd7980c180a9baa00201214a2266008008002602c002602e0022600a00429404cdc3801240026eb0c04cc040dd50049bad300f00116301100132533300c3002300d3754002297adef6c60137566022601c6ea8004c8cc004004dd59808980918091809180918071baa00722533301000114c103d87a80001323332225333011337220100062a66602266e3c02000c4cdd2a40006602a6e980092f5c02980103d87a8000133006006001375c601e0026eacc040004c050008c048004dc3a40046eb8c038c02cdd50011b874800058c030c03400cc02c008c028008c028004c014dd50008a4c26cacae6955ceaab9e5573eae815d0aba21", + "hash": "a5415b8df863848b7c9c9c9826a86f83852d90608c3bd1a00ad1b6ad" }, { - "title": "placeholder.placeholder.spend", - "datum": { - "title": "_datum", - "schema": { - "$ref": "#/definitions/Data" - } - }, + "title": "auth_token/mint.auth_token.else", "redeemer": { - "title": "_redeemer", - "schema": { - "$ref": "#/definitions/Data" - } + "schema": {} }, - "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", - "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + } + ], + "compiledCode": "5901770101003232323232323222533300332323232325332330093001300a3754004264646464a66601a600a0022a666020601e6ea801c0085854ccc034c00c00454ccc040c03cdd50038010b0b18069baa006132325333010301300213232533300f3007301037540122a66601e646600200200444a66602800229404cc894ccc04ccdd7980c180a9baa00201214a2266008008002602c002602e0022600a00429404cdc3801240026eb0c04cc040dd50049bad300f00116301100132533300c3002300d3754002297adef6c60137566022601c6ea8004c8cc004004dd59808980918091809180918071baa00722533301000114c103d87a80001323332225333011337220100062a66602266e3c02000c4cdd2a40006602a6e980092f5c02980103d87a8000133006006001375c601e0026eacc040004c050008c048004dc3a40046eb8c038c02cdd50011b874800058c030c03400cc02c008c028008c028004c014dd50008a4c26cacae6955ceaab9e5573eae815d0aba21", + "hash": "a5415b8df863848b7c9c9c9826a86f83852d90608c3bd1a00ad1b6ad" }, { - "title": "placeholder.placeholder.withdraw", - "redeemer": { - "title": "_redeemer", + "title": "crowdfund/spend.crowdfund.spend", + "datum": { + "title": "datum_opt", "schema": { - "$ref": "#/definitions/Data" + "$ref": "#/definitions/types~1CrowdfundDatum" } }, - "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", - "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" - }, - { - "title": "placeholder.placeholder.publish", "redeemer": { - "title": "_redeemer", + "title": "redeemer", "schema": { - "$ref": "#/definitions/Data" + "$ref": "#/definitions/types~1CrowdfundRedeemer" } }, - "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", - "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "59121c0101003232323232323223223225333006323232323253323300c3001300d3754004264664464646464a66602660060022a66602c602a6ea80280085854ccc04cc02000454ccc058c054dd50050010b0a99980998020008a99980b180a9baa00a00216153330133370e90030008a99980b180a9baa00a00216163013375401226464646464646464646464646464a66603e601e60406ea80044c94ccc080c040c084dd500909919191919299981418158010991919191919191919191919191919191919191919191929919981e9816803899192999821182280109919191980480089919191919192999824299982419b87006337026eb4c014c128dd500380c099b89482024bd0040185280a9998240020a9998240018a9998240010a9998240008991929998268008010a999826982800089919199911299982799b8f0030211533304f3371e004044266e1c0040345280a50375c60a20046eb8c144004dd69828982900098288009bac304f001002323300100103222533304e00114bd70099191919198008009bab3051004225333053001100313233055374e660aa6ea4014cc154c148004cc154c14c0052f5c06600600660ae00460aa0026600800860a60066eb8c134004c1400045280a5014a029405280a50303832533304b0011480004c8c034c94ccc134008520001300e33001001305000222533304e0011480004c03ccc008008c144004c138004c8cc004004dd5981398251baa00a22533304c00114bd70099191919198008009bab304f004225333051001100313233053374e660a66ea4014cc14cc140004cc14cc1440052f5c06600600660aa00460a60026600800860a20066eb8c12c004c138004cdd7802991919191816998271827802198271827801998271827801198271827800998271ba83370003401060a060a0002609e002609c002609a00260906ea8098c8c8c94ccc120c0f4c124dd50008a999824181e98249baa304d304e0021337106eb4c134c128dd500080b099b89375a609a60946ea8004058528182600099825182580099825199823181d98239baa304b304c0014c0103d87a80004c0103d87980004bd7018239baa304a304b3047375405664a66608a02829444cdc480080b1bad30013046375400646092609460946094609400266e0400800cc94ccc108c0ccc10cdd50008982398221baa0011630463047304730433754006600a6eacc07cc108dd500118021bab301e30413754603c60826ea806c58c10c004c8cc00400409c894ccc10800452f5c026644a666082a66608266ebcc118c10cdd500100f8991980080099198008009bab304830493045375400844a66608e002297ae0132323232330010013756609400844a66609800220062646609c6e9ccc138dd4802998271825800998271826000a5eb80cc00c00cc140008c138004cc010010c13000cdd7182300098248009129998230008a501332253330453371e6eb8c12800810c5288998020020009bac3048001304900114a026608a004660080080022660080080026088002608a0022a6466607c6066010264a666084608a646600200205244a666088002297ae013322533304353330433375e6044608a6ea8008dd3299982198198070a5eb7bdb1804c8c8cc0040052f5bded8c044a66609200226609466ec13001014000374c00697adef6c60132333222533304a3372091010000313304e337609801014000374c00e00a2a666094602000626609c66ec13001014000374c00e00226609c66ec0dd48019ba600233006006001375c60900026eacc124004c134008c12c004c8cc0040052f5bded8c044a66609000226609266ec13001014000375002097adef6c6013233322253330493372091010000313304d337609801014000375002800a2a666092601e00626609a66ec13001014000375002800226609a66ec0dd48019ba800233006006001375c608e0026eb4c120004c130008c1280044cdd7981398229baa00200f14a026608e00466008008002266008008002608c002608e002264a66608066e2404404054ccc10000454ccc1000084c8c94ccc11400400854ccc114c1200044c8cc894ccc114cdc780100c098040008a50375c60900026eb4c120c124004c120dd61823800801191980080099198008008159129998238008a5eb804c8c8c8c8cc004004dd598250021129998260008801899198271ba73304e375200a6609c60960026609c609800297ae0330030033050002304e00133004004304c003375c608c002609200244a66608c002297ae01332253330453371e6eb8c12800810c4cc124dd3801198020020008998020020009bac3048001304900114a029405280a5032323300100102822533304500114a026644a66608866ebc01400852889980200200098219823800982400099ba548008cc10cdd480925eb8058cdc499b8000900e30033756603a60806ea8c074c100dd500d0a99981f181780409919191929998229824001099191919806000899192999823a9998238048a51100815333047004153330470021533304700113232533304c0010021533304c304f00113232333222533304e3371e0060402a66609c66e3c0080844cdc38008060a5014a06eb8c140008dd718280009bad3050305100130500013758609c002004646600200206244a66609a002297ae013232323233001001375660a000844a6660a40022006264660a86e9ccc150dd48029982a18288009982a1829000a5eb80cc00c00cc158008c150004cc010010c14800cdd7182600098278008a5014a029405280a50303732533304a0011480004c8c030c94ccc130008520001300d33001001304f00222533304d0011480004c038cc008008c140004c134004c8cc004004dd5981318249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd7800991919191816198269827002198269827001998269827001198269827000998269ba83370003200e609e609e002609c002609a0026098002608e6ea8094c94ccc114c0d8c118dd50008982518239baa001163049304a304a3046375400666e20005200033702600e6eacc084c110dd500098039bab302130443754604260886ea807858c118004c8cc0040040a8894ccc11400452f5c026644a666088a66608866ebcc124c118dd50010110991980080099198008009bab304b304c3048375400844a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a501332253330483371e6eb8c1340081185288998020020009bac304b001304c00114a026609000466008008002266008008002608e002609000266e2403c040c8c8c8c94ccc108c0dcc10cdd50008a999821181b98219baa304730480021337100086eb4c11cc110dd5000899b89004375a608e60886ea8004528182300099822182280099822199820181a98209baa304530460014c103d87a80004c0103d87980004bd7018209baa30443041375404a66e0003002c4c8c94ccc100c8c8c94ccc10cc0e0c110dd50008a999821981c18221baa304830490021337100226eb4c120c114dd5000899b89011375a6090608a6ea8004528182380099822982300099822999820981b18211baa304630470014c0103d87a80004c0103d87980004bd7018211baa30453042375404c2a6660800042002294052819198008008129129998220008a501332253330433371e00407e29444cc010010004dd718230009823800a99981f19b884800003854ccc0f8c8c8c94ccc11000400854ccc110c11c0044c8cc894ccc110cdc780100b899b8700100614a06eb8c11c004dd69823982400098239bac30460010023233001001323300100102a22533304600114bd70099191919198008009bab304900422533304b00110031323304d374e6609a6ea4014cc134c128004cc134c12c0052f5c066006006609e004609a0026600800860960066eb8c114004c120004894ccc11400452f5c026644a66608866e3cdd7182480100b0998241ba7002330040040011330040040013758608e00260900022940cdc0a400001c26464a6660860020042a666086608c0022646644a66608666e3c0080584c0180045281bae3046001375a608c608e002608c6eb0c114004008c8cc004004c8cc0040040a4894ccc11400452f5c0264646464660020026eacc120010894ccc128004400c4c8cc130dd3998261ba90053304c30490013304c304a0014bd7019801801982700118260009980200218250019bae3044001304700122533304400114bd7009991299982199b8f375c609000408226608e6e9c008cc0100100044cc010010004dd6182300098238008a5014a026464a6660860020042a666086608c00226464666444a66608a66e3c00c10c54ccc114cdc780100c098040008a5014a06eb8c11c008dd718238009bad3047304800130470013758608a002004646600200205044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230008a50370e90009b80480088c94ccc0f4c0c8c0f8dd50008a400026eb4c108c0fcdd500099299981e9819181f1baa00114c0103d87a8000132330010013756608660806ea8008894ccc108004530103d87a8000132333222533304333722911000031533304330090031302633047375000497ae014c103d87a8000133006006001375c60820026eb4c108004c118008c110004c8cc004004008894ccc1040045300103d87a8000132333222533304233722911000031533304230080031302533046374c00497ae014c103d87a8000133006006001375c60800026eacc104004c114008c10c004dc7a450022533303b302b303c375400426464646464646464646464646464646464646464a6660a460aa00426602e01e26602e00602a2c6eb4c14c004c14c008c144004c144008dd6982780098278011bad304d001304d00232533304a30490011533304733712900218240008b0981e18240008b1baa304b001304b002375a609200260920046eb4c11c004c11c008c114004c114008dd7182180098218011bae3041001303d37540042c44a666074605460766ea80084c8c8c8c94ccc104c1100084cc01c00c4c94ccc0fcc0bc0044c8c94ccc110c11c0084c94ccc108c0c80044c8c94ccc11cc1280084cc03400402c58c120004c110dd50010a999821181b8008991919191919299982598270010078b1bad304c001304c002375a609400260940046eb4c120004c110dd50010b18211baa001163045001304137540042a66607e60680022a66608460826ea80080185858c0fcdd50008b182100098210011820000981e1baa002162232533303a302a00113232533303f304200200416375c608000260786ea800c54ccc0e8c0bc0044c8c94ccc0fcc10800801058dd71820000981e1baa00316303a3754004606e6ea80b4dd6981d181d804981c8041bad3038008375a606e010604c60646ea8c0d8020dd6981a8041bad3034008375c60660106eb8c0c8020c0c8004c0c4004c0c0004c0bc004c0b8004c0b4c0b4004c0b0004c09cdd50028b181480099198008008071129998140008a5eb804cc894ccc09d4ccc09ccdd7981618149baa302c302d3029375400400a2646600200264660020026eacc0b8c0bcc0acdd51817181798159baa00422533302d00114bd70099191919198008009bab3030004225333032001100313233034374e660686ea4014cc0d0c0c4004cc0d0c0c80052f5c066006006606c00460680026600800860640066eb8c0b0004c0bc004894ccc0b000452809991299981599b8f375c606000405229444cc010010004dd6181700098178008a5013302b00233004004001133004004001302a001302b001300630243754600260486ea800c8c09cc0a0004c094c088dd50090b181218109baa00116323300100100922533302300114c103d87a80001332253330223375e600c60486ea80080544c014cc0980092f5c0266008008002604a002604c0026e9520002302200137586040604200c603e00a6eacc078014dd5980e8029bac301c0053758603600a603600260346034002603260320026030603000260266ea8024dc3a40006e1d2004301200130123013001300e37540046e1d200216300f3010003300e002300d002300d0013008375400229309b2b1bae001375c002ae6955ceaab9e5573eae815d0aba201", + "hash": "c0f352bf5856e696038a0449a91382f35ba4a5741946736ca1480382" }, { - "title": "placeholder.placeholder.vote", + "title": "crowdfund/spend.crowdfund.else", "redeemer": { - "title": "_redeemer", - "schema": { - "$ref": "#/definitions/Data" - } + "schema": {} }, - "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", - "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "59121c0101003232323232323223223225333006323232323253323300c3001300d3754004264664464646464a66602660060022a66602c602a6ea80280085854ccc04cc02000454ccc058c054dd50050010b0a99980998020008a99980b180a9baa00a00216153330133370e90030008a99980b180a9baa00a00216163013375401226464646464646464646464646464a66603e601e60406ea80044c94ccc080c040c084dd500909919191919299981418158010991919191919191919191919191919191919191919191929919981e9816803899192999821182280109919191980480089919191919192999824299982419b87006337026eb4c014c128dd500380c099b89482024bd0040185280a9998240020a9998240018a9998240010a9998240008991929998268008010a999826982800089919199911299982799b8f0030211533304f3371e004044266e1c0040345280a50375c60a20046eb8c144004dd69828982900098288009bac304f001002323300100103222533304e00114bd70099191919198008009bab3051004225333053001100313233055374e660aa6ea4014cc154c148004cc154c14c0052f5c06600600660ae00460aa0026600800860a60066eb8c134004c1400045280a5014a029405280a50303832533304b0011480004c8c034c94ccc134008520001300e33001001305000222533304e0011480004c03ccc008008c144004c138004c8cc004004dd5981398251baa00a22533304c00114bd70099191919198008009bab304f004225333051001100313233053374e660a66ea4014cc14cc140004cc14cc1440052f5c06600600660aa00460a60026600800860a20066eb8c12c004c138004cdd7802991919191816998271827802198271827801998271827801198271827800998271ba83370003401060a060a0002609e002609c002609a00260906ea8098c8c8c94ccc120c0f4c124dd50008a999824181e98249baa304d304e0021337106eb4c134c128dd500080b099b89375a609a60946ea8004058528182600099825182580099825199823181d98239baa304b304c0014c0103d87a80004c0103d87980004bd7018239baa304a304b3047375405664a66608a02829444cdc480080b1bad30013046375400646092609460946094609400266e0400800cc94ccc108c0ccc10cdd50008982398221baa0011630463047304730433754006600a6eacc07cc108dd500118021bab301e30413754603c60826ea806c58c10c004c8cc00400409c894ccc10800452f5c026644a666082a66608266ebcc118c10cdd500100f8991980080099198008009bab304830493045375400844a66608e002297ae0132323232330010013756609400844a66609800220062646609c6e9ccc138dd4802998271825800998271826000a5eb80cc00c00cc140008c138004cc010010c13000cdd7182300098248009129998230008a501332253330453371e6eb8c12800810c5288998020020009bac3048001304900114a026608a004660080080022660080080026088002608a0022a6466607c6066010264a666084608a646600200205244a666088002297ae013322533304353330433375e6044608a6ea8008dd3299982198198070a5eb7bdb1804c8c8cc0040052f5bded8c044a66609200226609466ec13001014000374c00697adef6c60132333222533304a3372091010000313304e337609801014000374c00e00a2a666094602000626609c66ec13001014000374c00e00226609c66ec0dd48019ba600233006006001375c60900026eacc124004c134008c12c004c8cc0040052f5bded8c044a66609000226609266ec13001014000375002097adef6c6013233322253330493372091010000313304d337609801014000375002800a2a666092601e00626609a66ec13001014000375002800226609a66ec0dd48019ba800233006006001375c608e0026eb4c120004c130008c1280044cdd7981398229baa00200f14a026608e00466008008002266008008002608c002608e002264a66608066e2404404054ccc10000454ccc1000084c8c94ccc11400400854ccc114c1200044c8cc894ccc114cdc780100c098040008a50375c60900026eb4c120c124004c120dd61823800801191980080099198008008159129998238008a5eb804c8c8c8c8cc004004dd598250021129998260008801899198271ba73304e375200a6609c60960026609c609800297ae0330030033050002304e00133004004304c003375c608c002609200244a66608c002297ae01332253330453371e6eb8c12800810c4cc124dd3801198020020008998020020009bac3048001304900114a029405280a5032323300100102822533304500114a026644a66608866ebc01400852889980200200098219823800982400099ba548008cc10cdd480925eb8058cdc499b8000900e30033756603a60806ea8c074c100dd500d0a99981f181780409919191929998229824001099191919806000899192999823a9998238048a51100815333047004153330470021533304700113232533304c0010021533304c304f00113232333222533304e3371e0060402a66609c66e3c0080844cdc38008060a5014a06eb8c140008dd718280009bad3050305100130500013758609c002004646600200206244a66609a002297ae013232323233001001375660a000844a6660a40022006264660a86e9ccc150dd48029982a18288009982a1829000a5eb80cc00c00cc158008c150004cc010010c14800cdd7182600098278008a5014a029405280a50303732533304a0011480004c8c030c94ccc130008520001300d33001001304f00222533304d0011480004c038cc008008c140004c134004c8cc004004dd5981318249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd7800991919191816198269827002198269827001998269827001198269827000998269ba83370003200e609e609e002609c002609a0026098002608e6ea8094c94ccc114c0d8c118dd50008982518239baa001163049304a304a3046375400666e20005200033702600e6eacc084c110dd500098039bab302130443754604260886ea807858c118004c8cc0040040a8894ccc11400452f5c026644a666088a66608866ebcc124c118dd50010110991980080099198008009bab304b304c3048375400844a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a501332253330483371e6eb8c1340081185288998020020009bac304b001304c00114a026609000466008008002266008008002608e002609000266e2403c040c8c8c8c94ccc108c0dcc10cdd50008a999821181b98219baa304730480021337100086eb4c11cc110dd5000899b89004375a608e60886ea8004528182300099822182280099822199820181a98209baa304530460014c103d87a80004c0103d87980004bd7018209baa30443041375404a66e0003002c4c8c94ccc100c8c8c94ccc10cc0e0c110dd50008a999821981c18221baa304830490021337100226eb4c120c114dd5000899b89011375a6090608a6ea8004528182380099822982300099822999820981b18211baa304630470014c0103d87a80004c0103d87980004bd7018211baa30453042375404c2a6660800042002294052819198008008129129998220008a501332253330433371e00407e29444cc010010004dd718230009823800a99981f19b884800003854ccc0f8c8c8c94ccc11000400854ccc110c11c0044c8cc894ccc110cdc780100b899b8700100614a06eb8c11c004dd69823982400098239bac30460010023233001001323300100102a22533304600114bd70099191919198008009bab304900422533304b00110031323304d374e6609a6ea4014cc134c128004cc134c12c0052f5c066006006609e004609a0026600800860960066eb8c114004c120004894ccc11400452f5c026644a66608866e3cdd7182480100b0998241ba7002330040040011330040040013758608e00260900022940cdc0a400001c26464a6660860020042a666086608c0022646644a66608666e3c0080584c0180045281bae3046001375a608c608e002608c6eb0c114004008c8cc004004c8cc0040040a4894ccc11400452f5c0264646464660020026eacc120010894ccc128004400c4c8cc130dd3998261ba90053304c30490013304c304a0014bd7019801801982700118260009980200218250019bae3044001304700122533304400114bd7009991299982199b8f375c609000408226608e6e9c008cc0100100044cc010010004dd6182300098238008a5014a026464a6660860020042a666086608c00226464666444a66608a66e3c00c10c54ccc114cdc780100c098040008a5014a06eb8c11c008dd718238009bad3047304800130470013758608a002004646600200205044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230008a50370e90009b80480088c94ccc0f4c0c8c0f8dd50008a400026eb4c108c0fcdd500099299981e9819181f1baa00114c0103d87a8000132330010013756608660806ea8008894ccc108004530103d87a8000132333222533304333722911000031533304330090031302633047375000497ae014c103d87a8000133006006001375c60820026eb4c108004c118008c110004c8cc004004008894ccc1040045300103d87a8000132333222533304233722911000031533304230080031302533046374c00497ae014c103d87a8000133006006001375c60800026eacc104004c114008c10c004dc7a450022533303b302b303c375400426464646464646464646464646464646464646464a6660a460aa00426602e01e26602e00602a2c6eb4c14c004c14c008c144004c144008dd6982780098278011bad304d001304d00232533304a30490011533304733712900218240008b0981e18240008b1baa304b001304b002375a609200260920046eb4c11c004c11c008c114004c114008dd7182180098218011bae3041001303d37540042c44a666074605460766ea80084c8c8c8c94ccc104c1100084cc01c00c4c94ccc0fcc0bc0044c8c94ccc110c11c0084c94ccc108c0c80044c8c94ccc11cc1280084cc03400402c58c120004c110dd50010a999821181b8008991919191919299982598270010078b1bad304c001304c002375a609400260940046eb4c120004c110dd50010b18211baa001163045001304137540042a66607e60680022a66608460826ea80080185858c0fcdd50008b182100098210011820000981e1baa002162232533303a302a00113232533303f304200200416375c608000260786ea800c54ccc0e8c0bc0044c8c94ccc0fcc10800801058dd71820000981e1baa00316303a3754004606e6ea80b4dd6981d181d804981c8041bad3038008375a606e010604c60646ea8c0d8020dd6981a8041bad3034008375c60660106eb8c0c8020c0c8004c0c4004c0c0004c0bc004c0b8004c0b4c0b4004c0b0004c09cdd50028b181480099198008008071129998140008a5eb804cc894ccc09d4ccc09ccdd7981618149baa302c302d3029375400400a2646600200264660020026eacc0b8c0bcc0acdd51817181798159baa00422533302d00114bd70099191919198008009bab3030004225333032001100313233034374e660686ea4014cc0d0c0c4004cc0d0c0c80052f5c066006006606c00460680026600800860640066eb8c0b0004c0bc004894ccc0b000452809991299981599b8f375c606000405229444cc010010004dd6181700098178008a5013302b00233004004001133004004001302a001302b001300630243754600260486ea800c8c09cc0a0004c094c088dd50090b181218109baa00116323300100100922533302300114c103d87a80001332253330223375e600c60486ea80080544c014cc0980092f5c0266008008002604a002604c0026e9520002302200137586040604200c603e00a6eacc078014dd5980e8029bac301c0053758603600a603600260346034002603260320026030603000260266ea8024dc3a40006e1d2004301200130123013001300e37540046e1d200216300f3010003300e002300d002300d0013008375400229309b2b1bae001375c002ae6955ceaab9e5573eae815d0aba201", + "hash": "c0f352bf5856e696038a0449a91382f35ba4a5741946736ca1480382" }, { - "title": "placeholder.placeholder.propose", + "title": "share_token/mint.share_token.mint", "redeemer": { - "title": "_redeemer", + "title": "redeemer", "schema": { - "$ref": "#/definitions/Data" + "$ref": "#/definitions/types~1MintPolarity" } }, - "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", - "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + } + ], + "compiledCode": "5903020101003232323232323223225333004323232323253323300a3001300b3754004264646464a66601c600a0022a66602260206ea801c0085854ccc038c00c00454ccc044c040dd50038010b0b18071baa0061323253330113014002132323232533301230093013375401626464a66602e6034004264a66602a6018602c6ea80044c8c8c94ccc060c03c00454ccc06cc068dd50018010b0a99980c18068008a99980d980d1baa00300216153330183370e90020008a99980d980d1baa00300216153330183370e90030008a99980d980d1baa003002161630183754004266ebc005300103d8798000301a301737540022c64646600200200a44a666034002298103d87a8000132333222533301b3375e00e006266e9520003301f0024bd70099803003000980c800980d000980f001180e00099ba548008cc060c064c058dd5000a5eb8058c060004c8cc00400400c894ccc05c00452f5c026644a66602c646600200264660020026eacc074c078c068dd5180e980f180d1baa00422533301c00114bd70099191919198008009bab301f004225333021001100313233023374e660466ea4014cc08cc080004cc08cc0840052f5c066006006604a00460460026600800860420066eb8c06c004c078004894ccc06c00452809991299980d19b8f375c603e00403029444cc010010004dd6180e800980f00089980d00119802002000899802002000980c800980d000899b8700448004dd5980b180b980b980b980b980b980b980b980b980b8011bac3015001301137540126eb4c04000458c048004c94ccc034c008c038dd50008a5eb7bdb1804dd5980918079baa0013233001001375660246026602660266026601e6ea801c894ccc0440045300103d87a80001323332225333012337220100062a66602466e3c02000c4cdd2a40006602c6e980092f5c02980103d87a8000133006006001375c60200026eacc044004c054008c04c004dc3a40046eb8c03cc030dd50011b874800058c034c03800cc030008c02c008c02c004c018dd50008a4c26cac6eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "203a21ede4281a3cd5b9ea4e88b1ca32b5296dca9a715601632fbd4b" }, { - "title": "placeholder.placeholder.else", + "title": "share_token/mint.share_token.else", "redeemer": { "schema": {} }, - "compiledCode": "58d001010029800aba2aba1aab9eaab9dab9a48888966002646465300130053754003300700398038012444b30013370e9000001c4c98dd7180518049baa0048acc004cdc3a400400713233226300b001300b300c0013009375400915980099b874801000e264c601460126ea80122b30013370e9003001c4c8cc898dd698058009805980600098049baa0048acc004cdc3a40100071326300a3009375400913233226375a60160026016601800260126ea8011007200e401c80390070c018c01c004c018004c00cdd5003452689b2b20021", - "hash": "f2388d136606a27c4a531d0040c3e12e07eb95cd5011793c160707dc" + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + } + ], + "compiledCode": "5903020101003232323232323223225333004323232323253323300a3001300b3754004264646464a66601c600a0022a66602260206ea801c0085854ccc038c00c00454ccc044c040dd50038010b0b18071baa0061323253330113014002132323232533301230093013375401626464a66602e6034004264a66602a6018602c6ea80044c8c8c94ccc060c03c00454ccc06cc068dd50018010b0a99980c18068008a99980d980d1baa00300216153330183370e90020008a99980d980d1baa00300216153330183370e90030008a99980d980d1baa003002161630183754004266ebc005300103d8798000301a301737540022c64646600200200a44a666034002298103d87a8000132333222533301b3375e00e006266e9520003301f0024bd70099803003000980c800980d000980f001180e00099ba548008cc060c064c058dd5000a5eb8058c060004c8cc00400400c894ccc05c00452f5c026644a66602c646600200264660020026eacc074c078c068dd5180e980f180d1baa00422533301c00114bd70099191919198008009bab301f004225333021001100313233023374e660466ea4014cc08cc080004cc08cc0840052f5c066006006604a00460460026600800860420066eb8c06c004c078004894ccc06c00452809991299980d19b8f375c603e00403029444cc010010004dd6180e800980f00089980d00119802002000899802002000980c800980d000899b8700448004dd5980b180b980b980b980b980b980b980b980b980b8011bac3015001301137540126eb4c04000458c048004c94ccc034c008c038dd50008a5eb7bdb1804dd5980918079baa0013233001001375660246026602660266026601e6ea801c894ccc0440045300103d87a80001323332225333012337220100062a66602466e3c02000c4cdd2a40006602c6e980092f5c02980103d87a8000133006006001375c60200026eacc044004c054008c04c004dc3a40046eb8c03cc030dd50011b874800058c034c03800cc030008c02c008c02c004c018dd50008a4c26cac6eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "203a21ede4281a3cd5b9ea4e88b1ca32b5296dca9a715601632fbd4b" } ], "definitions": { - "Data": { - "title": "Data", - "description": "Any Plutus data." + "Bool": { + "title": "Bool", + "anyOf": [ + { + "title": "False", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "True", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "ByteArray": { + "dataType": "bytes" + }, + "Int": { + "dataType": "integer" + }, + "Option$StakeCredential": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/StakeCredential" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "PaymentCredential": { + "title": "PaymentCredential", + "description": "A general structure for representing an on-chain `Credential`.\n\n Credentials are always one of two kinds: a direct public/private key\n pair, or a script (native or Plutus).", + "anyOf": [ + { + "title": "VerificationKey", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/ScriptHash" + } + ] + } + ] + }, + "PolicyId": { + "title": "PolicyId", + "dataType": "bytes" + }, + "ScriptHash": { + "title": "ScriptHash", + "dataType": "bytes" + }, + "StakeCredential": { + "title": "StakeCredential", + "description": "Represent a type of object that can be represented either inline (by hash)\n or via a reference (i.e. a pointer to an on-chain location).\n\n This is mainly use for capturing pointers to a stake credential\n registration certificate in the case of so-called pointer addresses.", + "anyOf": [ + { + "title": "Inline", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1address~1Credential" + } + ] + }, + { + "title": "Pointer", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "title": "slot_number", + "$ref": "#/definitions/Int" + }, + { + "title": "transaction_index", + "$ref": "#/definitions/Int" + }, + { + "title": "certificate_index", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "VerificationKeyHash": { + "title": "VerificationKeyHash", + "dataType": "bytes" + }, + "cardano/address/Address": { + "title": "Address", + "description": "A Cardano `Address` typically holding one or two credential references.\n\n Note that legacy bootstrap addresses (a.k.a. 'Byron addresses') are\n completely excluded from Plutus contexts. Thus, from an on-chain\n perspective only exists addresses of type 00, 01, ..., 07 as detailed\n in [CIP-0019 :: Shelley Addresses](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0019/#shelley-addresses).", + "anyOf": [ + { + "title": "Address", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "payment_credential", + "$ref": "#/definitions/PaymentCredential" + }, + { + "title": "stake_credential", + "$ref": "#/definitions/Option$StakeCredential" + } + ] + } + ] + }, + "cardano/address/Credential": { + "title": "Credential", + "description": "A general structure for representing an on-chain `Credential`.\n\n Credentials are always one of two kinds: a direct public/private key\n pair, or a script (native or Plutus).", + "anyOf": [ + { + "title": "VerificationKey", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/ScriptHash" + } + ] + } + ] + }, + "cardano/transaction/OutputReference": { + "title": "OutputReference", + "description": "An `OutputReference` is a unique reference to an output on-chain. The `output_index`\n corresponds to the position in the output list of the transaction (identified by its id)\n that produced that output", + "anyOf": [ + { + "title": "OutputReference", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "transaction_id", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "output_index", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "types/CrowdfundDatum": { + "title": "CrowdfundDatum", + "anyOf": [ + { + "title": "CrowdfundDatum", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "completion_script", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "share_token", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "crowdfund_address", + "$ref": "#/definitions/cardano~1address~1Address" + }, + { + "title": "fundraise_target", + "$ref": "#/definitions/Int" + }, + { + "title": "current_fundraised_amount", + "$ref": "#/definitions/Int" + }, + { + "title": "allow_over_subscription", + "$ref": "#/definitions/Bool" + }, + { + "title": "deadline", + "$ref": "#/definitions/Int" + }, + { + "title": "expiry_buffer", + "$ref": "#/definitions/Int" + }, + { + "title": "fee_address", + "$ref": "#/definitions/cardano~1address~1Address" + }, + { + "title": "min_charge", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "types/CrowdfundRedeemer": { + "title": "CrowdfundRedeemer", + "anyOf": [ + { + "title": "ContributeFund", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "CompleteCrowdfund", + "dataType": "constructor", + "index": 1, + "fields": [] + }, + { + "title": "ContributorWithdrawal", + "dataType": "constructor", + "index": 2, + "fields": [] + }, + { + "title": "RemoveEmptyInstance", + "dataType": "constructor", + "index": 3, + "fields": [] + } + ] + }, + "types/MintPolarity": { + "title": "MintPolarity", + "anyOf": [ + { + "title": "RMint", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "RBurn", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] } } } \ No newline at end of file diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json index 0b930888d..3c9d7328d 100644 --- a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json @@ -11,6 +11,59 @@ "license": "Apache-2.0" }, "validators": [ + { + "title": "crowdfund.crowdfund.spend", + "datum": { + "title": "datum_opt", + "schema": { + "$ref": "#/definitions/types~1CrowdfundDatum" + } + }, + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/crowdfund~1CrowdfundRedeemer" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "59121c0101003232323232323223223225333006323232323253323300c3001300d3754004264664464646464a66602660060022a66602c602a6ea80280085854ccc04cc02000454ccc058c054dd50050010b0a99980998020008a99980b180a9baa00a00216153330133370e90030008a99980b180a9baa00a00216163013375401226464646464646464646464646464a66603e601e60406ea80044c94ccc080c040c084dd500909919191919299981418158010991919191919191919191919191919191919191919191929919981e9816803899192999821182280109919191980480089919191919192999824299982419b87006337026eb4c014c128dd500380c099b89482024bd0040185280a9998240020a9998240018a9998240010a9998240008991929998268008010a999826982800089919199911299982799b8f0030211533304f3371e004044266e1c0040345280a50375c60a20046eb8c144004dd69828982900098288009bac304f001002323300100103222533304e00114bd70099191919198008009bab3051004225333053001100313233055374e660aa6ea4014cc154c148004cc154c14c0052f5c06600600660ae00460aa0026600800860a60066eb8c134004c1400045280a5014a029405280a50303832533304b0011480004c8c034c94ccc134008520001300e33001001305000222533304e0011480004c03ccc008008c144004c138004c8cc004004dd5981398251baa00a22533304c00114bd70099191919198008009bab304f004225333051001100313233053374e660a66ea4014cc14cc140004cc14cc1440052f5c06600600660aa00460a60026600800860a20066eb8c12c004c138004cdd7802991919191816998271827802198271827801998271827801198271827800998271ba83370003401060a060a0002609e002609c002609a00260906ea8098c8c8c94ccc120c0f4c124dd50008a999824181e98249baa304d304e0021337106eb4c134c128dd500080b099b89375a609a60946ea8004058528182600099825182580099825199823181d98239baa304b304c0014c0103d87a80004c0103d87980004bd7018239baa304a304b3047375405664a66608a02829444cdc480080b1bad30013046375400646092609460946094609400266e0400800cc94ccc108c0ccc10cdd50008982398221baa0011630463047304730433754006600a6eacc07cc108dd500118021bab301e30413754603c60826ea806c58c10c004c8cc00400409c894ccc10800452f5c026644a666082a66608266ebcc118c10cdd500100f8991980080099198008009bab304830493045375400844a66608e002297ae0132323232330010013756609400844a66609800220062646609c6e9ccc138dd4802998271825800998271826000a5eb80cc00c00cc140008c138004cc010010c13000cdd7182300098248009129998230008a501332253330453371e6eb8c12800810c5288998020020009bac3048001304900114a026608a004660080080022660080080026088002608a0022a6466607c6066010264a666084608a646600200205244a666088002297ae013322533304353330433375e6044608a6ea8008dd3299982198198070a5eb7bdb1804c8c8cc0040052f5bded8c044a66609200226609466ec13001014000374c00697adef6c60132333222533304a3372091010000313304e337609801014000374c00e00a2a666094602000626609c66ec13001014000374c00e00226609c66ec0dd48019ba600233006006001375c60900026eacc124004c134008c12c004c8cc0040052f5bded8c044a66609000226609266ec13001014000375002097adef6c6013233322253330493372091010000313304d337609801014000375002800a2a666092601e00626609a66ec13001014000375002800226609a66ec0dd48019ba800233006006001375c608e0026eb4c120004c130008c1280044cdd7981398229baa00200f14a026608e00466008008002266008008002608c002608e002264a66608066e2404404054ccc10000454ccc1000084c8c94ccc11400400854ccc114c1200044c8cc894ccc114cdc780100c098040008a50375c60900026eb4c120c124004c120dd61823800801191980080099198008008159129998238008a5eb804c8c8c8c8cc004004dd598250021129998260008801899198271ba73304e375200a6609c60960026609c609800297ae0330030033050002304e00133004004304c003375c608c002609200244a66608c002297ae01332253330453371e6eb8c12800810c4cc124dd3801198020020008998020020009bac3048001304900114a029405280a5032323300100102822533304500114a026644a66608866ebc01400852889980200200098219823800982400099ba548008cc10cdd480925eb8058cdc499b8000900e30033756603a60806ea8c074c100dd500d0a99981f181780409919191929998229824001099191919806000899192999823a9998238048a51100815333047004153330470021533304700113232533304c0010021533304c304f00113232333222533304e3371e0060402a66609c66e3c0080844cdc38008060a5014a06eb8c140008dd718280009bad3050305100130500013758609c002004646600200206244a66609a002297ae013232323233001001375660a000844a6660a40022006264660a86e9ccc150dd48029982a18288009982a1829000a5eb80cc00c00cc158008c150004cc010010c14800cdd7182600098278008a5014a029405280a50303732533304a0011480004c8c030c94ccc130008520001300d33001001304f00222533304d0011480004c038cc008008c140004c134004c8cc004004dd5981318249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd7800991919191816198269827002198269827001998269827001198269827000998269ba83370003200e609e609e002609c002609a0026098002608e6ea8094c94ccc114c0d8c118dd50008982518239baa001163049304a304a3046375400666e20005200033702600e6eacc084c110dd500098039bab302130443754604260886ea807858c118004c8cc0040040a8894ccc11400452f5c026644a666088a66608866ebcc124c118dd50010110991980080099198008009bab304b304c3048375400844a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a501332253330483371e6eb8c1340081185288998020020009bac304b001304c00114a026609000466008008002266008008002608e002609000266e2403c040c8c8c8c94ccc108c0dcc10cdd50008a999821181b98219baa304730480021337100086eb4c11cc110dd5000899b89004375a608e60886ea8004528182300099822182280099822199820181a98209baa304530460014c103d87a80004c0103d87980004bd7018209baa30443041375404a66e0003002c4c8c94ccc100c8c8c94ccc10cc0e0c110dd50008a999821981c18221baa304830490021337100226eb4c120c114dd5000899b89011375a6090608a6ea8004528182380099822982300099822999820981b18211baa304630470014c0103d87a80004c0103d87980004bd7018211baa30453042375404c2a6660800042002294052819198008008129129998220008a501332253330433371e00407e29444cc010010004dd718230009823800a99981f19b884800003854ccc0f8c8c8c94ccc11000400854ccc110c11c0044c8cc894ccc110cdc780100b899b8700100614a06eb8c11c004dd69823982400098239bac30460010023233001001323300100102a22533304600114bd70099191919198008009bab304900422533304b00110031323304d374e6609a6ea4014cc134c128004cc134c12c0052f5c066006006609e004609a0026600800860960066eb8c114004c120004894ccc11400452f5c026644a66608866e3cdd7182480100b0998241ba7002330040040011330040040013758608e00260900022940cdc0a400001c26464a6660860020042a666086608c0022646644a66608666e3c0080584c0180045281bae3046001375a608c608e002608c6eb0c114004008c8cc004004c8cc0040040a4894ccc11400452f5c0264646464660020026eacc120010894ccc128004400c4c8cc130dd3998261ba90053304c30490013304c304a0014bd7019801801982700118260009980200218250019bae3044001304700122533304400114bd7009991299982199b8f375c609000408226608e6e9c008cc0100100044cc010010004dd6182300098238008a5014a026464a6660860020042a666086608c00226464666444a66608a66e3c00c10c54ccc114cdc780100c098040008a5014a06eb8c11c008dd718238009bad3047304800130470013758608a002004646600200205044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230008a50370e90009b80480088c94ccc0f4c0c8c0f8dd50008a400026eb4c108c0fcdd500099299981e9819181f1baa00114c0103d87a8000132330010013756608660806ea8008894ccc108004530103d87a8000132333222533304333722911000031533304330090031302633047375000497ae014c103d87a8000133006006001375c60820026eb4c108004c118008c110004c8cc004004008894ccc1040045300103d87a8000132333222533304233722911000031533304230080031302533046374c00497ae014c103d87a8000133006006001375c60800026eacc104004c114008c10c004dc7a450022533303b302b303c375400426464646464646464646464646464646464646464a6660a460aa00426602e01e26602e00602a2c6eb4c14c004c14c008c144004c144008dd6982780098278011bad304d001304d00232533304a30490011533304733712900218240008b0981e18240008b1baa304b001304b002375a609200260920046eb4c11c004c11c008c114004c114008dd7182180098218011bae3041001303d37540042c44a666074605460766ea80084c8c8c8c94ccc104c1100084cc01c00c4c94ccc0fcc0bc0044c8c94ccc110c11c0084c94ccc108c0c80044c8c94ccc11cc1280084cc03400402c58c120004c110dd50010a999821181b8008991919191919299982598270010078b1bad304c001304c002375a609400260940046eb4c120004c110dd50010b18211baa001163045001304137540042a66607e60680022a66608460826ea80080185858c0fcdd50008b182100098210011820000981e1baa002162232533303a302a00113232533303f304200200416375c608000260786ea800c54ccc0e8c0bc0044c8c94ccc0fcc10800801058dd71820000981e1baa00316303a3754004606e6ea80b4dd6981d181d804981c8041bad3038008375a606e010604c60646ea8c0d8020dd6981a8041bad3034008375c60660106eb8c0c8020c0c8004c0c4004c0c0004c0bc004c0b8004c0b4c0b4004c0b0004c09cdd50028b181480099198008008071129998140008a5eb804cc894ccc09d4ccc09ccdd7981618149baa302c302d3029375400400a2646600200264660020026eacc0b8c0bcc0acdd51817181798159baa00422533302d00114bd70099191919198008009bab3030004225333032001100313233034374e660686ea4014cc0d0c0c4004cc0d0c0c80052f5c066006006606c00460680026600800860640066eb8c0b0004c0bc004894ccc0b000452809991299981599b8f375c606000405229444cc010010004dd6181700098178008a5013302b00233004004001133004004001302a001302b001300630243754600260486ea800c8c09cc0a0004c094c088dd50090b181218109baa00116323300100100922533302300114c103d87a80001332253330223375e600c60486ea80080544c014cc0980092f5c0266008008002604a002604c0026e9520002302200137586040604200c603e00a6eacc078014dd5980e8029bac301c0053758603600a603600260346034002603260320026030603000260266ea8024dc3a40006e1d2004301200130123013001300e37540046e1d200216300f3010003300e002300d002300d0013008375400229309b2b1bae001375c002ae6955ceaab9e5573eae815d0aba201", + "hash": "c0f352bf5856e696038a0449a91382f35ba4a5741946736ca1480382" + }, + { + "title": "crowdfund.crowdfund.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "59121c0101003232323232323223223225333006323232323253323300c3001300d3754004264664464646464a66602660060022a66602c602a6ea80280085854ccc04cc02000454ccc058c054dd50050010b0a99980998020008a99980b180a9baa00a00216153330133370e90030008a99980b180a9baa00a00216163013375401226464646464646464646464646464a66603e601e60406ea80044c94ccc080c040c084dd500909919191919299981418158010991919191919191919191919191919191919191919191929919981e9816803899192999821182280109919191980480089919191919192999824299982419b87006337026eb4c014c128dd500380c099b89482024bd0040185280a9998240020a9998240018a9998240010a9998240008991929998268008010a999826982800089919199911299982799b8f0030211533304f3371e004044266e1c0040345280a50375c60a20046eb8c144004dd69828982900098288009bac304f001002323300100103222533304e00114bd70099191919198008009bab3051004225333053001100313233055374e660aa6ea4014cc154c148004cc154c14c0052f5c06600600660ae00460aa0026600800860a60066eb8c134004c1400045280a5014a029405280a50303832533304b0011480004c8c034c94ccc134008520001300e33001001305000222533304e0011480004c03ccc008008c144004c138004c8cc004004dd5981398251baa00a22533304c00114bd70099191919198008009bab304f004225333051001100313233053374e660a66ea4014cc14cc140004cc14cc1440052f5c06600600660aa00460a60026600800860a20066eb8c12c004c138004cdd7802991919191816998271827802198271827801998271827801198271827800998271ba83370003401060a060a0002609e002609c002609a00260906ea8098c8c8c94ccc120c0f4c124dd50008a999824181e98249baa304d304e0021337106eb4c134c128dd500080b099b89375a609a60946ea8004058528182600099825182580099825199823181d98239baa304b304c0014c0103d87a80004c0103d87980004bd7018239baa304a304b3047375405664a66608a02829444cdc480080b1bad30013046375400646092609460946094609400266e0400800cc94ccc108c0ccc10cdd50008982398221baa0011630463047304730433754006600a6eacc07cc108dd500118021bab301e30413754603c60826ea806c58c10c004c8cc00400409c894ccc10800452f5c026644a666082a66608266ebcc118c10cdd500100f8991980080099198008009bab304830493045375400844a66608e002297ae0132323232330010013756609400844a66609800220062646609c6e9ccc138dd4802998271825800998271826000a5eb80cc00c00cc140008c138004cc010010c13000cdd7182300098248009129998230008a501332253330453371e6eb8c12800810c5288998020020009bac3048001304900114a026608a004660080080022660080080026088002608a0022a6466607c6066010264a666084608a646600200205244a666088002297ae013322533304353330433375e6044608a6ea8008dd3299982198198070a5eb7bdb1804c8c8cc0040052f5bded8c044a66609200226609466ec13001014000374c00697adef6c60132333222533304a3372091010000313304e337609801014000374c00e00a2a666094602000626609c66ec13001014000374c00e00226609c66ec0dd48019ba600233006006001375c60900026eacc124004c134008c12c004c8cc0040052f5bded8c044a66609000226609266ec13001014000375002097adef6c6013233322253330493372091010000313304d337609801014000375002800a2a666092601e00626609a66ec13001014000375002800226609a66ec0dd48019ba800233006006001375c608e0026eb4c120004c130008c1280044cdd7981398229baa00200f14a026608e00466008008002266008008002608c002608e002264a66608066e2404404054ccc10000454ccc1000084c8c94ccc11400400854ccc114c1200044c8cc894ccc114cdc780100c098040008a50375c60900026eb4c120c124004c120dd61823800801191980080099198008008159129998238008a5eb804c8c8c8c8cc004004dd598250021129998260008801899198271ba73304e375200a6609c60960026609c609800297ae0330030033050002304e00133004004304c003375c608c002609200244a66608c002297ae01332253330453371e6eb8c12800810c4cc124dd3801198020020008998020020009bac3048001304900114a029405280a5032323300100102822533304500114a026644a66608866ebc01400852889980200200098219823800982400099ba548008cc10cdd480925eb8058cdc499b8000900e30033756603a60806ea8c074c100dd500d0a99981f181780409919191929998229824001099191919806000899192999823a9998238048a51100815333047004153330470021533304700113232533304c0010021533304c304f00113232333222533304e3371e0060402a66609c66e3c0080844cdc38008060a5014a06eb8c140008dd718280009bad3050305100130500013758609c002004646600200206244a66609a002297ae013232323233001001375660a000844a6660a40022006264660a86e9ccc150dd48029982a18288009982a1829000a5eb80cc00c00cc158008c150004cc010010c14800cdd7182600098278008a5014a029405280a50303732533304a0011480004c8c030c94ccc130008520001300d33001001304f00222533304d0011480004c038cc008008c140004c134004c8cc004004dd5981318249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd7800991919191816198269827002198269827001998269827001198269827000998269ba83370003200e609e609e002609c002609a0026098002608e6ea8094c94ccc114c0d8c118dd50008982518239baa001163049304a304a3046375400666e20005200033702600e6eacc084c110dd500098039bab302130443754604260886ea807858c118004c8cc0040040a8894ccc11400452f5c026644a666088a66608866ebcc124c118dd50010110991980080099198008009bab304b304c3048375400844a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a501332253330483371e6eb8c1340081185288998020020009bac304b001304c00114a026609000466008008002266008008002608e002609000266e2403c040c8c8c8c94ccc108c0dcc10cdd50008a999821181b98219baa304730480021337100086eb4c11cc110dd5000899b89004375a608e60886ea8004528182300099822182280099822199820181a98209baa304530460014c103d87a80004c0103d87980004bd7018209baa30443041375404a66e0003002c4c8c94ccc100c8c8c94ccc10cc0e0c110dd50008a999821981c18221baa304830490021337100226eb4c120c114dd5000899b89011375a6090608a6ea8004528182380099822982300099822999820981b18211baa304630470014c0103d87a80004c0103d87980004bd7018211baa30453042375404c2a6660800042002294052819198008008129129998220008a501332253330433371e00407e29444cc010010004dd718230009823800a99981f19b884800003854ccc0f8c8c8c94ccc11000400854ccc110c11c0044c8cc894ccc110cdc780100b899b8700100614a06eb8c11c004dd69823982400098239bac30460010023233001001323300100102a22533304600114bd70099191919198008009bab304900422533304b00110031323304d374e6609a6ea4014cc134c128004cc134c12c0052f5c066006006609e004609a0026600800860960066eb8c114004c120004894ccc11400452f5c026644a66608866e3cdd7182480100b0998241ba7002330040040011330040040013758608e00260900022940cdc0a400001c26464a6660860020042a666086608c0022646644a66608666e3c0080584c0180045281bae3046001375a608c608e002608c6eb0c114004008c8cc004004c8cc0040040a4894ccc11400452f5c0264646464660020026eacc120010894ccc128004400c4c8cc130dd3998261ba90053304c30490013304c304a0014bd7019801801982700118260009980200218250019bae3044001304700122533304400114bd7009991299982199b8f375c609000408226608e6e9c008cc0100100044cc010010004dd6182300098238008a5014a026464a6660860020042a666086608c00226464666444a66608a66e3c00c10c54ccc114cdc780100c098040008a5014a06eb8c11c008dd718238009bad3047304800130470013758608a002004646600200205044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230008a50370e90009b80480088c94ccc0f4c0c8c0f8dd50008a400026eb4c108c0fcdd500099299981e9819181f1baa00114c0103d87a8000132330010013756608660806ea8008894ccc108004530103d87a8000132333222533304333722911000031533304330090031302633047375000497ae014c103d87a8000133006006001375c60820026eb4c108004c118008c110004c8cc004004008894ccc1040045300103d87a8000132333222533304233722911000031533304230080031302533046374c00497ae014c103d87a8000133006006001375c60800026eacc104004c114008c10c004dc7a450022533303b302b303c375400426464646464646464646464646464646464646464a6660a460aa00426602e01e26602e00602a2c6eb4c14c004c14c008c144004c144008dd6982780098278011bad304d001304d00232533304a30490011533304733712900218240008b0981e18240008b1baa304b001304b002375a609200260920046eb4c11c004c11c008c114004c114008dd7182180098218011bae3041001303d37540042c44a666074605460766ea80084c8c8c8c94ccc104c1100084cc01c00c4c94ccc0fcc0bc0044c8c94ccc110c11c0084c94ccc108c0c80044c8c94ccc11cc1280084cc03400402c58c120004c110dd50010a999821181b8008991919191919299982598270010078b1bad304c001304c002375a609400260940046eb4c120004c110dd50010b18211baa001163045001304137540042a66607e60680022a66608460826ea80080185858c0fcdd50008b182100098210011820000981e1baa002162232533303a302a00113232533303f304200200416375c608000260786ea800c54ccc0e8c0bc0044c8c94ccc0fcc10800801058dd71820000981e1baa00316303a3754004606e6ea80b4dd6981d181d804981c8041bad3038008375a606e010604c60646ea8c0d8020dd6981a8041bad3034008375c60660106eb8c0c8020c0c8004c0c4004c0c0004c0bc004c0b8004c0b4c0b4004c0b0004c09cdd50028b181480099198008008071129998140008a5eb804cc894ccc09d4ccc09ccdd7981618149baa302c302d3029375400400a2646600200264660020026eacc0b8c0bcc0acdd51817181798159baa00422533302d00114bd70099191919198008009bab3030004225333032001100313233034374e660686ea4014cc0d0c0c4004cc0d0c0c80052f5c066006006606c00460680026600800860640066eb8c0b0004c0bc004894ccc0b000452809991299981599b8f375c606000405229444cc010010004dd6181700098178008a5013302b00233004004001133004004001302a001302b001300630243754600260486ea800c8c09cc0a0004c094c088dd50090b181218109baa00116323300100100922533302300114c103d87a80001332253330223375e600c60486ea80080544c014cc0980092f5c0266008008002604a002604c0026e9520002302200137586040604200c603e00a6eacc078014dd5980e8029bac301c0053758603600a603600260346034002603260320026030603000260266ea8024dc3a40006e1d2004301200130123013001300e37540046e1d200216300f3010003300e002300d002300d0013008375400229309b2b1bae001375c002ae6955ceaab9e5573eae815d0aba201", + "hash": "c0f352bf5856e696038a0449a91382f35ba4a5741946736ca1480382" + }, { "title": "spend.spend.spend", "datum": { @@ -128,8 +181,8 @@ } } ], - "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" }, { "title": "start.start.mint", @@ -159,8 +212,8 @@ } } ], - "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" }, { "title": "start.start.publish", @@ -190,8 +243,8 @@ } } ], - "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" }, { "title": "start.start.propose", @@ -221,8 +274,8 @@ } } ], - "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" }, { "title": "start.start.vote", @@ -252,8 +305,8 @@ } } ], - "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" }, { "title": "start.start.else", @@ -280,11 +333,28 @@ } } ], - "compiledCode": "590bdb010100323232323232322322322322533300832323232323253232323232323330143004007132323232323232533301e30210021323232533301e3010301f375400626464646464646464646464646464646464646464a66606a607000426602a01e26602a00626464646464646464646464646464a666086608c004264646464a666088606c00226464646464646464a66609e60a40040142c6eb4c140004c140008dd6982700098270011bae304c001304c002375c6094002608c6ea800c54ccc110c0d40044c8c8c8c8c8c8c8c94ccc13cc14800802858dd6982800098280011bad304e001304e002375c609800260980046eb8c128004c118dd50018a999822181a0008991919191919191919192999828982a0010a999827182018279baa0031323232325333055305800201016375a60ac00260ac0046eb8c150004c140dd50018b0b1bad3052001305200230500013050002375a609c002609c0046eb8c130004c130008dd7182500098231baa0031533304430330011323232323232533304d305000200816375a609c002609c0046eb8c130004c130008dd7182500098231baa0031630443754004264a6660860102a6660860062a66608600226464a6660900020042a66609060960022646644a6660906016004260720022940dd718258009bad304b304c001304b375860940020046466002002646600200205c44a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a5eb804cc894ccc120cdc79bae304d00201213304c374e004660080080022660080080026eb0c12c004c1300045280a5014a02940cdd78009818198231ba900c3304637520166608c6ea0024cc118dd419b8000803c4bd70192999821181918219baa00113047304437540022c608c608e608e60866ea8008cdc3992999820981918211baa0011480004dd6982318219baa0013253330413032304237540022980103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a80001323332225333047300b00315333047300a003130353304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa00222533304500114c103d87a80001323332225333046300a003153330463009003130343304a374c00497ae014c103d87a8000133006006001375c60880026eacc114004c124008c11c00402058c110004c8c8cc0040040a4894ccc11000452f5c026644a666086a66608666ebcc120c114dd50010028981a192999822181a98229baa0011480004dd6982498231baa001325333044303530453754002298103d87a80001323300100137566094608e6ea8008894ccc124004530103d87a8000132333222533304a300e0031533304a300d003130383304e375000497ae014c103d87a8000133006006001375c60900026eb4c124004c134008c12c004c8cc004004dd59824982518231baa00322533304800114c103d87a80001323332225333049337220260062a66609266e3c04c00c4c0dccc134dd300125eb80530103d87a8000133006006001375c608e0026eacc120004c130008c12800452809982380119802002000899802002000982300098238009816198211815998211ba903a4bd70198211816198211816198211815998211ba90084bd7025eb812f5c097ae0371e9110037229101003375e60506607e6ea40152f5c004e6eb4c0fcc100c100014dd6981f0021bad303d004375c60780086eb8c0ec010c0ec004c0e8c0e8004c0e4004c0d0dd500b8b1bad3036001303600230340013034002375a606400260640046eb4c0c0004c0c0008c94ccc0b4c0b000454ccc0a8cdc4a400860560022c2603660560022c6ea8c0b8004c0b8008dd6981600098160011bad302a001302a00230280013028002375c604c002604c0046eb8c090004c080dd50018b11299980f980898101baa0021323232325333026302900213300700313253330243016001132325333029302c0021325333027301900113232533302c302f00213300d00100b16302d001302937540042a66604e60300022646464646464a666060606600401e2c6eb4c0c4004c0c4008dd6981780098178011bad302d001302937540042c604e6ea800458c0a8004c098dd50010a999812180a8008a99981398131baa0020061616302437540022c604e002604e004604a00260426ea80085888c94ccc07cc0440044c8c94ccc090c09c00801058dd7181280098109baa0031533301f3010001132325333024302700200416375c604a00260426ea800c58c07cdd500119299980e1806180e9baa00113021301e37540022c604060426042603a6ea8c080c084c074dd50008b180f80099198008009bac301f00522533301e00114bd7009991299980e991980080099198008009bab30243025302137546048604a60426ea8010894ccc08c00452f5c0264646464660020026eacc098010894ccc0a0004400c4c8cc0a8dd3998151ba90053302a30270013302a30280014bd7019801801981600118150009980200218140019bae3022001302500122533302200114a026644a66604266e3cdd7181300100f8a5113300400400137586048002604a00226604200466008008002266008008002604000260420026eacc074c078c078008dd6180e000980e180e000980b9baa00b301930163754010264646464a66603060140162646464a666036601a0022a66603c603a6ea80400085854ccc06cc03000454ccc078c074dd50080010b0b180d9baa00f13232323232533301e3010301f3754026264646600200200844a66604800229404cc894ccc08ccdd78028010a51133004004001302230260013027001300b33022375200c97ae01333300701a0030014c0103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc02c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300901937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919804800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd5001002899812001198020020008998020020009811800981200098038021119299980c98058008a99980e180d9baa0030021615333019300a0011533301c301b37540060042c2a66603260120022a66603860366ea800c0085854ccc064c02000454ccc070c06cdd50018010b0a99980c99b874802000454ccc070c06cdd50018010b0b180c9baa0022232323300100100422533301d00114c103d87a8000132333222533301e3375e00e006260186604400497ae0133006006001301c001301d0013021002301f00130043301b301c3019375400297ae02300333019300233019375200297ae0330194c0103d87a80004bd701ba548008dd2a40006e1d2006370e90021b8748008dc3a4000601c6ea8004c044c04800cc040008c03c008c03c004c028dd50008a4c26cac6eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d101", - "hash": "eaf3b4c500aa3f149b863085350a2b0f2a8dba7e8bcd69e2e4eada34" + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" } ], "definitions": { + "Bool": { + "title": "Bool", + "anyOf": [ + { + "title": "False", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "True", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, "ByteArray": { "dataType": "bytes" }, @@ -336,6 +406,29 @@ } ] }, + "Option$StakeCredential": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/StakeCredential" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, "Option$cardano/governance/GovernanceActionId": { "title": "Option", "anyOf": [ @@ -389,6 +482,32 @@ "$ref": "#/definitions/Mandate" } }, + "PaymentCredential": { + "title": "PaymentCredential", + "description": "A general structure for representing an on-chain `Credential`.\n\n Credentials are always one of two kinds: a direct public/private key\n pair, or a script (native or Plutus).", + "anyOf": [ + { + "title": "VerificationKey", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/ScriptHash" + } + ] + } + ] + }, "PolicyId": { "title": "PolicyId", "dataType": "bytes" @@ -401,6 +520,41 @@ "title": "ScriptHash", "dataType": "bytes" }, + "StakeCredential": { + "title": "StakeCredential", + "description": "Represent a type of object that can be represented either inline (by hash)\n or via a reference (i.e. a pointer to an on-chain location).\n\n This is mainly use for capturing pointers to a stake credential\n registration certificate in the case of so-called pointer addresses.", + "anyOf": [ + { + "title": "Inline", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1address~1Credential" + } + ] + }, + { + "title": "Pointer", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "title": "slot_number", + "$ref": "#/definitions/Int" + }, + { + "title": "transaction_index", + "$ref": "#/definitions/Int" + }, + { + "title": "certificate_index", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, "TransactionId": { "title": "TransactionId", "dataType": "bytes" @@ -409,6 +563,27 @@ "title": "VerificationKeyHash", "dataType": "bytes" }, + "cardano/address/Address": { + "title": "Address", + "description": "A Cardano `Address` typically holding one or two credential references.\n\n Note that legacy bootstrap addresses (a.k.a. 'Byron addresses') are\n completely excluded from Plutus contexts. Thus, from an on-chain\n perspective only exists addresses of type 00, 01, ..., 07 as detailed\n in [CIP-0019 :: Shelley Addresses](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0019/#shelley-addresses).", + "anyOf": [ + { + "title": "Address", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "payment_credential", + "$ref": "#/definitions/PaymentCredential" + }, + { + "title": "stake_credential", + "$ref": "#/definitions/Option$StakeCredential" + } + ] + } + ] + }, "cardano/address/Credential": { "title": "Credential", "description": "A general structure for representing an on-chain `Credential`.\n\n Credentials are always one of two kinds: a direct public/private key\n pair, or a script (native or Plutus).", @@ -491,6 +666,35 @@ } ] }, + "crowdfund/CrowdfundRedeemer": { + "title": "CrowdfundRedeemer", + "anyOf": [ + { + "title": "ContributeFund", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "CompleteCrowdfund", + "dataType": "constructor", + "index": 1, + "fields": [] + }, + { + "title": "ContributorWithdrawal", + "dataType": "constructor", + "index": 2, + "fields": [] + }, + { + "title": "RemoveEmptyInstance", + "dataType": "constructor", + "index": 3, + "fields": [] + } + ] + }, "gov/VGovernanceAction": { "title": "VGovernanceAction", "anyOf": [ @@ -650,6 +854,58 @@ } ] }, + "types/CrowdfundDatum": { + "title": "CrowdfundDatum", + "anyOf": [ + { + "title": "CrowdfundDatum", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "completion_script", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "share_token", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "crowdfund_address", + "$ref": "#/definitions/cardano~1address~1Address" + }, + { + "title": "fundraise_target", + "$ref": "#/definitions/Int" + }, + { + "title": "current_fundraised_amount", + "$ref": "#/definitions/Int" + }, + { + "title": "allow_over_subscription", + "$ref": "#/definitions/Bool" + }, + { + "title": "deadline", + "$ref": "#/definitions/Int" + }, + { + "title": "expiry_buffer", + "$ref": "#/definitions/Int" + }, + { + "title": "fee_address", + "$ref": "#/definitions/cardano~1address~1Address" + }, + { + "title": "min_charge", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, "types/CrowdfundGovDatum": { "title": "CrowdfundGovDatum", "anyOf": [