diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/README.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/README.md new file mode 100644 index 000000000..e76d22490 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/README.md @@ -0,0 +1 @@ +Implement in core mesh repo `mesh-contract` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/aiken.lock b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/aiken.lock new file mode 100644 index 000000000..2e65bd164 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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/base-crowdfund/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/aiken.toml new file mode 100644 index 000000000..62cb1af77 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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/base-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/lib/types.ak new file mode 100644 index 000000000..0232fc7aa --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/lib/types.ak @@ -0,0 +1,26 @@ +use cardano/address.{Address} + +pub type MintPolarity { + RMint + RBurn +} + +pub type CrowdfundRedeemer { + ContributeFund + CompleteCrowdfund + 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/base-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/lib/utils.ak new file mode 100644 index 000000000..75d90a275 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/lib/utils.ak @@ -0,0 +1,39 @@ +use aiken/collection/list +use aiken/collection/pairs +use cardano/address.{Address} +use cardano/assets.{Lovelace, from_lovelace} +use cardano/transaction.{Input, Output, 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)) +} + +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 outputs_at_with_lovelace( + outputs: List, + address: Address, + lovelace: Lovelace, +) -> List { + list.filter( + outputs, + fn(output) { + 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/base-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/plutus.json new file mode 100644 index 000000000..4e0876c10 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/plutus.json @@ -0,0 +1,425 @@ +{ + "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.7+e2fb28b" + }, + "license": "Apache-2.0" + }, + "validators": [ + { + "title": "auth_token/mint.auth_token.mint", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1MintPolarity" + } + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + } + ], + "compiledCode": "5901770101003232323232323222533300332323232325332330093001300a3754004264646464a66601a600a0022a666020601e6ea801c0085854ccc034c00c00454ccc040c03cdd50038010b0b18069baa006132325333010301300213232533300f3007301037540122a66601e646600200200444a66602800229404cc894ccc04ccdd7980c180a9baa00201214a2266008008002602c002602e0022600a00429404cdc3801240026eb0c04cc040dd50049bad300f00116301100132533300c3002300d3754002297adef6c60137566022601c6ea8004c8cc004004dd59808980918091809180918071baa00722533301000114c103d87a80001323332225333011337220100062a66602266e3c02000c4cdd2a40006602a6e980092f5c02980103d87a8000133006006001375c601e0026eacc040004c050008c048004dc3a40046eb8c038c02cdd50011b874800058c030c03400cc02c008c028008c028004c014dd50008a4c26cacae6955ceaab9e5573eae815d0aba21", + "hash": "a5415b8df863848b7c9c9c9826a86f83852d90608c3bd1a00ad1b6ad" + }, + { + "title": "auth_token/mint.auth_token.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + } + ], + "compiledCode": "5901770101003232323232323222533300332323232325332330093001300a3754004264646464a66601a600a0022a666020601e6ea801c0085854ccc034c00c00454ccc040c03cdd50038010b0b18069baa006132325333010301300213232533300f3007301037540122a66601e646600200200444a66602800229404cc894ccc04ccdd7980c180a9baa00201214a2266008008002602c002602e0022600a00429404cdc3801240026eb0c04cc040dd50049bad300f00116301100132533300c3002300d3754002297adef6c60137566022601c6ea8004c8cc004004dd59808980918091809180918071baa00722533301000114c103d87a80001323332225333011337220100062a66602266e3c02000c4cdd2a40006602a6e980092f5c02980103d87a8000133006006001375c601e0026eacc040004c050008c048004dc3a40046eb8c038c02cdd50011b874800058c030c03400cc02c008c028008c028004c014dd50008a4c26cacae6955ceaab9e5573eae815d0aba21", + "hash": "a5415b8df863848b7c9c9c9826a86f83852d90608c3bd1a00ad1b6ad" + }, + { + "title": "crowdfund/spend.crowdfund.spend", + "datum": { + "title": "datum_opt", + "schema": { + "$ref": "#/definitions/types~1CrowdfundDatum" + } + }, + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1CrowdfundRedeemer" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "59121c0101003232323232323223223225333006323232323253323300c3001300d3754004264664464646464a66602660060022a66602c602a6ea80280085854ccc04cc02000454ccc058c054dd50050010b0a99980998020008a99980b180a9baa00a00216153330133370e90030008a99980b180a9baa00a00216163013375401226464646464646464646464646464a66603e601e60406ea80044c94ccc080c040c084dd500909919191919299981418158010991919191919191919191919191919191919191919191929919981e9816803899192999821182280109919191980480089919191919192999824299982419b87006337026eb4c014c128dd500380c099b89482024bd0040185280a9998240020a9998240018a9998240010a9998240008991929998268008010a999826982800089919199911299982799b8f0030211533304f3371e004044266e1c0040345280a50375c60a20046eb8c144004dd69828982900098288009bac304f001002323300100103222533304e00114bd70099191919198008009bab3051004225333053001100313233055374e660aa6ea4014cc154c148004cc154c14c0052f5c06600600660ae00460aa0026600800860a60066eb8c134004c1400045280a5014a029405280a50303832533304b0011480004c8c034c94ccc134008520001300e33001001305000222533304e0011480004c03ccc008008c144004c138004c8cc004004dd5981398251baa00a22533304c00114bd70099191919198008009bab304f004225333051001100313233053374e660a66ea4014cc14cc140004cc14cc1440052f5c06600600660aa00460a60026600800860a20066eb8c12c004c138004cdd7802991919191816998271827802198271827801998271827801198271827800998271ba83370003401060a060a0002609e002609c002609a00260906ea8098c8c8c94ccc120c0f4c124dd50008a999824181e98249baa304d304e0021337106eb4c134c128dd500080b099b89375a609a60946ea8004058528182600099825182580099825199823181d98239baa304b304c0014c0103d87a80004c0103d87980004bd7018239baa304a304b3047375405664a66608a02829444cdc480080b1bad30013046375400646092609460946094609400266e0400800cc94ccc108c0ccc10cdd50008982398221baa0011630463047304730433754006600a6eacc07cc108dd500118021bab301e30413754603c60826ea806c58c10c004c8cc00400409c894ccc10800452f5c026644a666082a66608266ebcc118c10cdd500100f8991980080099198008009bab304830493045375400844a66608e002297ae0132323232330010013756609400844a66609800220062646609c6e9ccc138dd4802998271825800998271826000a5eb80cc00c00cc140008c138004cc010010c13000cdd7182300098248009129998230008a501332253330453371e6eb8c12800810c5288998020020009bac3048001304900114a026608a004660080080022660080080026088002608a0022a6466607c6066010264a666084608a646600200205244a666088002297ae013322533304353330433375e6044608a6ea8008dd3299982198198070a5eb7bdb1804c8c8cc0040052f5bded8c044a66609200226609466ec13001014000374c00697adef6c60132333222533304a3372091010000313304e337609801014000374c00e00a2a666094602000626609c66ec13001014000374c00e00226609c66ec0dd48019ba600233006006001375c60900026eacc124004c134008c12c004c8cc0040052f5bded8c044a66609000226609266ec13001014000375002097adef6c6013233322253330493372091010000313304d337609801014000375002800a2a666092601e00626609a66ec13001014000375002800226609a66ec0dd48019ba800233006006001375c608e0026eb4c120004c130008c1280044cdd7981398229baa00200f14a026608e00466008008002266008008002608c002608e002264a66608066e2404404054ccc10000454ccc1000084c8c94ccc11400400854ccc114c1200044c8cc894ccc114cdc780100c098040008a50375c60900026eb4c120c124004c120dd61823800801191980080099198008008159129998238008a5eb804c8c8c8c8cc004004dd598250021129998260008801899198271ba73304e375200a6609c60960026609c609800297ae0330030033050002304e00133004004304c003375c608c002609200244a66608c002297ae01332253330453371e6eb8c12800810c4cc124dd3801198020020008998020020009bac3048001304900114a029405280a5032323300100102822533304500114a026644a66608866ebc01400852889980200200098219823800982400099ba548008cc10cdd480925eb8058cdc499b8000900e30033756603a60806ea8c074c100dd500d0a99981f181780409919191929998229824001099191919806000899192999823a9998238048a51100815333047004153330470021533304700113232533304c0010021533304c304f00113232333222533304e3371e0060402a66609c66e3c0080844cdc38008060a5014a06eb8c140008dd718280009bad3050305100130500013758609c002004646600200206244a66609a002297ae013232323233001001375660a000844a6660a40022006264660a86e9ccc150dd48029982a18288009982a1829000a5eb80cc00c00cc158008c150004cc010010c14800cdd7182600098278008a5014a029405280a50303732533304a0011480004c8c030c94ccc130008520001300d33001001304f00222533304d0011480004c038cc008008c140004c134004c8cc004004dd5981318249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd7800991919191816198269827002198269827001998269827001198269827000998269ba83370003200e609e609e002609c002609a0026098002608e6ea8094c94ccc114c0d8c118dd50008982518239baa001163049304a304a3046375400666e20005200033702600e6eacc084c110dd500098039bab302130443754604260886ea807858c118004c8cc0040040a8894ccc11400452f5c026644a666088a66608866ebcc124c118dd50010110991980080099198008009bab304b304c3048375400844a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a501332253330483371e6eb8c1340081185288998020020009bac304b001304c00114a026609000466008008002266008008002608e002609000266e2403c040c8c8c8c94ccc108c0dcc10cdd50008a999821181b98219baa304730480021337100086eb4c11cc110dd5000899b89004375a608e60886ea8004528182300099822182280099822199820181a98209baa304530460014c103d87a80004c0103d87980004bd7018209baa30443041375404a66e0003002c4c8c94ccc100c8c8c94ccc10cc0e0c110dd50008a999821981c18221baa304830490021337100226eb4c120c114dd5000899b89011375a6090608a6ea8004528182380099822982300099822999820981b18211baa304630470014c0103d87a80004c0103d87980004bd7018211baa30453042375404c2a6660800042002294052819198008008129129998220008a501332253330433371e00407e29444cc010010004dd718230009823800a99981f19b884800003854ccc0f8c8c8c94ccc11000400854ccc110c11c0044c8cc894ccc110cdc780100b899b8700100614a06eb8c11c004dd69823982400098239bac30460010023233001001323300100102a22533304600114bd70099191919198008009bab304900422533304b00110031323304d374e6609a6ea4014cc134c128004cc134c12c0052f5c066006006609e004609a0026600800860960066eb8c114004c120004894ccc11400452f5c026644a66608866e3cdd7182480100b0998241ba7002330040040011330040040013758608e00260900022940cdc0a400001c26464a6660860020042a666086608c0022646644a66608666e3c0080584c0180045281bae3046001375a608c608e002608c6eb0c114004008c8cc004004c8cc0040040a4894ccc11400452f5c0264646464660020026eacc120010894ccc128004400c4c8cc130dd3998261ba90053304c30490013304c304a0014bd7019801801982700118260009980200218250019bae3044001304700122533304400114bd7009991299982199b8f375c609000408226608e6e9c008cc0100100044cc010010004dd6182300098238008a5014a026464a6660860020042a666086608c00226464666444a66608a66e3c00c10c54ccc114cdc780100c098040008a5014a06eb8c11c008dd718238009bad3047304800130470013758608a002004646600200205044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230008a50370e90009b80480088c94ccc0f4c0c8c0f8dd50008a400026eb4c108c0fcdd500099299981e9819181f1baa00114c0103d87a8000132330010013756608660806ea8008894ccc108004530103d87a8000132333222533304333722911000031533304330090031302633047375000497ae014c103d87a8000133006006001375c60820026eb4c108004c118008c110004c8cc004004008894ccc1040045300103d87a8000132333222533304233722911000031533304230080031302533046374c00497ae014c103d87a8000133006006001375c60800026eacc104004c114008c10c004dc7a450022533303b302b303c375400426464646464646464646464646464646464646464a6660a460aa00426602e01e26602e00602a2c6eb4c14c004c14c008c144004c144008dd6982780098278011bad304d001304d00232533304a30490011533304733712900218240008b0981e18240008b1baa304b001304b002375a609200260920046eb4c11c004c11c008c114004c114008dd7182180098218011bae3041001303d37540042c44a666074605460766ea80084c8c8c8c94ccc104c1100084cc01c00c4c94ccc0fcc0bc0044c8c94ccc110c11c0084c94ccc108c0c80044c8c94ccc11cc1280084cc03400402c58c120004c110dd50010a999821181b8008991919191919299982598270010078b1bad304c001304c002375a609400260940046eb4c120004c110dd50010b18211baa001163045001304137540042a66607e60680022a66608460826ea80080185858c0fcdd50008b182100098210011820000981e1baa002162232533303a302a00113232533303f304200200416375c608000260786ea800c54ccc0e8c0bc0044c8c94ccc0fcc10800801058dd71820000981e1baa00316303a3754004606e6ea80b4dd6981d181d804981c8041bad3038008375a606e010604c60646ea8c0d8020dd6981a8041bad3034008375c60660106eb8c0c8020c0c8004c0c4004c0c0004c0bc004c0b8004c0b4c0b4004c0b0004c09cdd50028b181480099198008008071129998140008a5eb804cc894ccc09d4ccc09ccdd7981618149baa302c302d3029375400400a2646600200264660020026eacc0b8c0bcc0acdd51817181798159baa00422533302d00114bd70099191919198008009bab3030004225333032001100313233034374e660686ea4014cc0d0c0c4004cc0d0c0c80052f5c066006006606c00460680026600800860640066eb8c0b0004c0bc004894ccc0b000452809991299981599b8f375c606000405229444cc010010004dd6181700098178008a5013302b00233004004001133004004001302a001302b001300630243754600260486ea800c8c09cc0a0004c094c088dd50090b181218109baa00116323300100100922533302300114c103d87a80001332253330223375e600c60486ea80080544c014cc0980092f5c0266008008002604a002604c0026e9520002302200137586040604200c603e00a6eacc078014dd5980e8029bac301c0053758603600a603600260346034002603260320026030603000260266ea8024dc3a40006e1d2004301200130123013001300e37540046e1d200216300f3010003300e002300d002300d0013008375400229309b2b1bae001375c002ae6955ceaab9e5573eae815d0aba201", + "hash": "c0f352bf5856e696038a0449a91382f35ba4a5741946736ca1480382" + }, + { + "title": "crowdfund/spend.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": "share_token/mint.share_token.mint", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1MintPolarity" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + } + ], + "compiledCode": "5903020101003232323232323223225333004323232323253323300a3001300b3754004264646464a66601c600a0022a66602260206ea801c0085854ccc038c00c00454ccc044c040dd50038010b0b18071baa0061323253330113014002132323232533301230093013375401626464a66602e6034004264a66602a6018602c6ea80044c8c8c94ccc060c03c00454ccc06cc068dd50018010b0a99980c18068008a99980d980d1baa00300216153330183370e90020008a99980d980d1baa00300216153330183370e90030008a99980d980d1baa003002161630183754004266ebc005300103d8798000301a301737540022c64646600200200a44a666034002298103d87a8000132333222533301b3375e00e006266e9520003301f0024bd70099803003000980c800980d000980f001180e00099ba548008cc060c064c058dd5000a5eb8058c060004c8cc00400400c894ccc05c00452f5c026644a66602c646600200264660020026eacc074c078c068dd5180e980f180d1baa00422533301c00114bd70099191919198008009bab301f004225333021001100313233023374e660466ea4014cc08cc080004cc08cc0840052f5c066006006604a00460460026600800860420066eb8c06c004c078004894ccc06c00452809991299980d19b8f375c603e00403029444cc010010004dd6180e800980f00089980d00119802002000899802002000980c800980d000899b8700448004dd5980b180b980b980b980b980b980b980b980b980b8011bac3015001301137540126eb4c04000458c048004c94ccc034c008c038dd50008a5eb7bdb1804dd5980918079baa0013233001001375660246026602660266026601e6ea801c894ccc0440045300103d87a80001323332225333012337220100062a66602466e3c02000c4cdd2a40006602c6e980092f5c02980103d87a8000133006006001375c60200026eacc044004c054008c04c004dc3a40046eb8c03cc030dd50011b874800058c034c03800cc030008c02c008c02c004c018dd50008a4c26cac6eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "203a21ede4281a3cd5b9ea4e88b1ca32b5296dca9a715601632fbd4b" + }, + { + "title": "share_token/mint.share_token.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + } + ], + "compiledCode": "5903020101003232323232323223225333004323232323253323300a3001300b3754004264646464a66601c600a0022a66602260206ea801c0085854ccc038c00c00454ccc044c040dd50038010b0b18071baa0061323253330113014002132323232533301230093013375401626464a66602e6034004264a66602a6018602c6ea80044c8c8c94ccc060c03c00454ccc06cc068dd50018010b0a99980c18068008a99980d980d1baa00300216153330183370e90020008a99980d980d1baa00300216153330183370e90030008a99980d980d1baa003002161630183754004266ebc005300103d8798000301a301737540022c64646600200200a44a666034002298103d87a8000132333222533301b3375e00e006266e9520003301f0024bd70099803003000980c800980d000980f001180e00099ba548008cc060c064c058dd5000a5eb8058c060004c8cc00400400c894ccc05c00452f5c026644a66602c646600200264660020026eacc074c078c068dd5180e980f180d1baa00422533301c00114bd70099191919198008009bab301f004225333021001100313233023374e660466ea4014cc08cc080004cc08cc0840052f5c066006006604a00460460026600800860420066eb8c06c004c078004894ccc06c00452809991299980d19b8f375c603e00403029444cc010010004dd6180e800980f00089980d00119802002000899802002000980c800980d000899b8700448004dd5980b180b980b980b980b980b980b980b980b980b8011bac3015001301137540126eb4c04000458c048004c94ccc034c008c038dd50008a5eb7bdb1804dd5980918079baa0013233001001375660246026602660266026601e6ea801c894ccc0440045300103d87a80001323332225333012337220100062a66602466e3c02000c4cdd2a40006602c6e980092f5c02980103d87a8000133006006001375c60200026eacc044004c054008c04c004dc3a40046eb8c03cc030dd50011b874800058c034c03800cc030008c02c008c02c004c018dd50008a4c26cac6eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "203a21ede4281a3cd5b9ea4e88b1ca32b5296dca9a715601632fbd4b" + } + ], + "definitions": { + "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/base-crowdfund/specs/1_auth_token.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/1_auth_token.md new file mode 100644 index 000000000..86a689cd0 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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/base-crowdfund/specs/2_shares.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/2_shares.md new file mode 100644 index 000000000..4492912d7 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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/base-crowdfund/specs/3_crowdfund.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/3_crowdfund.md new file mode 100644 index 000000000..37c54e806 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/3_crowdfund.md @@ -0,0 +1,53 @@ +# Specification - Crowdfund + +## Parameter + +- `auth_token`: The policy id of `AuthToken` +- `proposer_key_hash`: ByteArray + +## 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 lovelace contributed, with token name of `completion_script` + +2. CompleteCrowdfund + + - `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 + +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 + - signed by `proposer_key_hash` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/_scripts.md new file mode 100644 index 000000000..72da5bb9a --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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` - `utxo_ref` + +2. Second layer + + - `shares` - param `auth_token` + - `crowdfund` - param `auth_token` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/application_setup_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/application_setup_doc.md new file mode 100644 index 000000000..4cdb0de40 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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/base-crowdfund/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/specs/user_action_doc.md new file mode 100644 index 000000000..c2912625c --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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`. 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 diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/auth_token/mint.ak new file mode 100644 index 000000000..57706664d --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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/base-crowdfund/validators/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/crowdfund/spend.ak new file mode 100644 index 000000000..544ee930b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/crowdfund/spend.ak @@ -0,0 +1,175 @@ +use aiken/collection/pairs.{has_key} +use cardano/address.{Credential, Script} +use cardano/assets.{PolicyId, lovelace_of} +use cardano/transaction.{OutputReference, Transaction, find_input} +use cocktail.{ + 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, +} +use types.{ + CompleteCrowdfund, ContributeFund, ContributorWithdrawal, CrowdfundDatum, + CrowdfundRedeemer, RemoveEmptyInstance, +} +use utils.{check_fundraise_target, outputs_at_with_lovelace} + +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, + extra_signatories, + .. + } = 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 input_lovelace_check = + lovelace_of(auth_input.output.value) >= min_charge + current_fundraised_amount + + expect [_] = outputs_at_with_lovelace(outputs, fee_address, min_charge) + + 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? && input_lovelace_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)? + } + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + validity_check? && token_burnt_check? && proposer_key_signed_check? + } + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/share_token/mint.ak new file mode 100644 index 000000000..2ff086575 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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 < 0 + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/auth_token/mint.ak new file mode 100644 index 000000000..b113dd1c5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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 s1_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 s1_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 s1_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 s1_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 s1_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/base-crowdfund/validators/tests/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/crowdfund/spend.ak new file mode 100644 index 000000000..2b68446f5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/crowdfund/spend.ak @@ -0,0 +1,1177 @@ +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{Transaction} +use crowdfund/spend as crowdfund_spend +use mocktail.{ + 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.{ + 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_proposer_key_hash, + 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 s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, True)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, True)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + ContributeFund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + 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) + |> add(mock_auth_token, mock_completion_script, 1) + + let output_value = from_lovelace(mock_min_charge) + + 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), + ) + |> 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 s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_fundraise_target - 1, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_fundraise_target, False)), + CompleteCrowdfund, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + 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 s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount * 2, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_current_fundraised_amount * 2, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + ContributorWithdrawal, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s3_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + 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_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + 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_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + 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_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, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(mock_contribute_over_fundraised_amount, False)), + 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_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, + mock_proposer_key_hash, + 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, + is_proposer_signed: 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, + is_proposer_signed, + } = 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() + |> 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_auth_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_auth_burnt: True, + is_proposer_signed: True, + }, + 0, + False, + ) + + crowdfund_spend.crowdfund.spend( + mock_auth_token, + mock_proposer_key_hash, + Some(mock_crowdfund_datum(0, False)), + 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_auth_inputed: True, + is_deadline_passed: True, + is_shares_burnt: True, + is_auth_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + False, + ) + + 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), + 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_auth_inputed: False, + is_deadline_passed: True, + is_shares_burnt: True, + is_auth_burnt: True, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + False, + ) + + 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), + tx, + ) +} + +test s3_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, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + False, + ) + + !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), + tx, + ) +} + +test s3_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, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + False, + ) + + !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), + tx, + ) +} + +test s3_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, + is_proposer_signed: True, + }, + mock_current_fundraised_amount, + False, + ) + + !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), + tx, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/integration_test/contribute_fund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/integration_test/contribute_fund.ak new file mode 100644 index 000000000..1bbcc7e28 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/integration_test/contribute_fund.ak @@ -0,0 +1,329 @@ +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_proposer_key_hash, 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, + mock_proposer_key_hash, + 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_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, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/share_token/mint.ak new file mode 100644 index 000000000..6ad5a815e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-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 s2_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 s2_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 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) + 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 s2_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 s2_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 s2_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/base-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/utils.ak new file mode 100644 index 000000000..c2ee6a99b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/base-crowdfund/validators/tests/utils.ak @@ -0,0 +1,64 @@ +use cardano/address.{from_script} +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_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_deadline = 1750735607 + +pub const mock_expiry_buffer = 3600 * 24 + +pub const mock_min_charge = 10 + +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) + +pub const mock_proposer_key_hash = mock_pub_key_hash(0) diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/.github/workflows/continuous-integration.yml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/.github/workflows/continuous-integration.yml new file mode 100644 index 000000000..ba419b4a2 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/.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-crowdfundV2/.gitignore b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/.gitignore new file mode 100644 index 000000000..ff7811b15 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/.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-crowdfundV2/README.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/README.md new file mode 100644 index 000000000..de5ef005b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/README.md @@ -0,0 +1 @@ +Implement separately & publish SDK diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/aiken.lock b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/aiken.lock new file mode 100644 index 000000000..2e65bd164 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/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-crowdfundV2/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/aiken.toml new file mode 100644 index 000000000..018228ce9 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/aiken.toml @@ -0,0 +1,23 @@ +name = "sidan-lab-&-MeshJS/gov-crowdfundV2" +version = "0.0.0" +compiler = "v1.1.16" +plutus = "v3" +license = "Apache-2.0" +description = "Aiken contracts for project 'gov-crowdfundV2'" + +[repository] +user = "sidan-lab-&-MeshJS" +project = "gov-crowdfundV2" +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/gov-crowdfundV2/lib/gov.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/lib/gov.ak new file mode 100644 index 000000000..d29db7b58 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/lib/gov.ak @@ -0,0 +1,81 @@ +use aiken/crypto.{ScriptHash} +use cardano/address.{Credential} +use cardano/assets.{Lovelace} +use cardano/governance.{ + Constitution, GovernanceActionId, Mandate, ProtocolVersion, +} + +type ProtocolParametersIndex = + Int + +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 + /// 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: VRational, + } + 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-crowdfundV2/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/lib/types.ak new file mode 100644 index 000000000..db909cf85 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/lib/types.ak @@ -0,0 +1,56 @@ +use cardano/address.{Address} +use cardano/governance.{GovernanceActionId} + +pub type CrowdfundGovRedeemer { + ContributeFund + CompleteCrowdfund + PreMatureContributorWithdrawal + PreMatureRemoveEmptyInstance + RegisterCerts + VoteOnGovAction + DeregisterCerts + AfterCompleteContributorWithdrawal + AfterCompleteRemoveEmptyInstance +} + +pub type CrowdfundGovDatum { + Crowdfund { + stake_hash: ByteArray, + share_token: ByteArray, + crowdfund_address: Address, + fundraise_target: Int, + current_fundraised_amount: Int, + allow_over_subscription: Bool, + deadline: Int, + expiry_buffer: Int, + min_charge: Int + } + Proposed { + stake_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + Voted { + stake_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + gov_tx_id: GovernanceActionId, + deadline: Int, + } + Refundable { + stake_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + } +} + +pub type MintPolarity { + RMint + RBurn +} + +pub type PublishRedeemer { + Register + Deregister +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/lib/utils.ak new file mode 100644 index 000000000..3c4b45970 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/lib/utils.ak @@ -0,0 +1,195 @@ +use aiken/cbor +use aiken/collection/list +use aiken/collection/pairs.{get_first} +use cardano/address.{Address, Credential, from_script} +use cardano/assets.{Lovelace, lovelace_of, from_lovelace} +use cardano/certificate.{ + Certificate, DelegateBlockProduction, DelegateBoth, DelegateCredential, + DelegateRepresentative, DelegateVote, RegisterCredential, + 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.{CrowdfundGovRedeemer} + + +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 outputs_at_with_lovelace( + outputs: List, + address: Address, + lovelace: Lovelace, +) -> List { + list.filter( + outputs, + fn(output) { + let is_lovelace_match = output.value == from_lovelace(lovelace) + is_lovelace_match && output.address == address + }, + ) +} + +pub fn redeemer_with_input( + redeemers: Pairs, + input: Input, +) -> Option { + 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 +} + +pub fn check_spend_script_input_redeemer( + spend: ByteArray, + inputs: List, + redeemers: Pairs, + redeemer: CrowdfundGovRedeemer, +) { + let spend_address = from_script(spend) + expect [only_input] = inputs_at(inputs, spend_address) + expect Some(only_input_redeemer_data) = + redeemer_with_input(redeemers, only_input) + + expect only_input_redeemer: CrowdfundGovRedeemer = only_input_redeemer_data + + 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-crowdfundV2/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/plutus.json new file mode 100644 index 000000000..7d9844021 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/plutus.json @@ -0,0 +1,1039 @@ +{ + "preamble": { + "title": "sidan-lab-&-MeshJS/gov-crowdfundV2", + "description": "Aiken contracts for project 'gov-crowdfundV2'", + "version": "0.0.0", + "plutusVersion": "v3", + "compiler": { + "name": "Aiken", + "version": "v1.1.17+c3a7fba" + }, + "license": "Apache-2.0" + }, + "validators": [ + { + "title": "auth_token/mint.gcf_auth_mint.mint", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1MintPolarity" + } + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + } + ], + "compiledCode": "590178010100229800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400130080024888966002600460106ea800e266446644b300130060018acc004c034dd5004400a2c80722b300130030018acc004c034dd5004400a2c80722c805900b0992cc004c040006264b30013006300c375401115980099198008009bac3011300e375400c44b30010018a508acc004cdd7980918079baa30120010158a518998010011809800a01a4041130030018a50402d13370e0029000a016375a6018601e00316403464b30013002300b375400314bd6f7b63044dd5980798061baa001402864660020026eacc03cc040c040c040c040c030dd5002112cc0040062980103d87a8000899192cc004cdc8803000c56600266e3c018006266e95200033011300f0024bd7045300103d87a80004035133004004301300340346eb8c034004c04000500e18051baa006375c601860126ea800cdc3a400516401c300800130033754011149a26cac8009", + "hash": "476e529a91415c9d54d4a5293c81b21918d23f7695473cba3621b896" + }, + { + "title": "auth_token/mint.gcf_auth_mint.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + } + ], + "compiledCode": "590178010100229800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400130080024888966002600460106ea800e266446644b300130060018acc004c034dd5004400a2c80722b300130030018acc004c034dd5004400a2c80722c805900b0992cc004c040006264b30013006300c375401115980099198008009bac3011300e375400c44b30010018a508acc004cdd7980918079baa30120010158a518998010011809800a01a4041130030018a50402d13370e0029000a016375a6018601e00316403464b30013002300b375400314bd6f7b63044dd5980798061baa001402864660020026eacc03cc040c040c040c040c030dd5002112cc0040062980103d87a8000899192cc004cdc8803000c56600266e3c018006266e95200033011300f0024bd7045300103d87a80004035133004004301300340346eb8c034004c04000500e18051baa006375c601860126ea800cdc3a400516401c300800130033754011149a26cac8009", + "hash": "476e529a91415c9d54d4a5293c81b21918d23f7695473cba3621b896" + }, + { + "title": "gcf_spend.gCf_spend.spend", + "datum": { + "title": "datum_opt", + "schema": { + "$ref": "#/definitions/types~1CrowdfundGovDatum" + } + }, + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1CrowdfundGovRedeemer" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action", + "schema": { + "$ref": "#/definitions/gov~1VGovernanceAction" + } + }, + { + "title": "delegate_pool_id", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "stake_register_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + { + "title": "gov_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + } + ], + "compiledCode": "592890010100222222229800aba2aba1aba0aab9faab9eaab9dab9a9bae0089bae0079bae0059bad0049bad0039bad002488888888888896600264653001300e00198071807800cdc3a4005300e00248889660026004601c6ea800e33001300f3754007370e90024dc3a400d370e90004c038dd5002244444664464b300130050048acc004c05cdd500640062c80c22b3001300a0048acc004c05cdd500640062c80c22b300130070048acc004c05cdd500640062c80c22b300130060048acc004c05cdd500640062c80c22b30013370e90040024566002602e6ea803200316406115980099b87480280122b3001301737540190018b20308acc004cdc3a4018009159800980b9baa00c800c59018456600266e1d200e0048acc004c05cdd500640062c80c22b30013370e90080024566002602e6ea803200316406116405480a9015202a405480a9015202a40542653001301b301b0019bac301a0019ba548001222323232323298009bab30220019bac302230230019919800800804112cc0040062980103d87a80008992cc004cdd7981298111baa00100e8980499812000a5eb82266006006604c0048100c0900050224dd618110044dd59811002cdd618110024c08800e6eb0c0880092222222259800980a98131baa0068992cc004c058c09cdd5009c4c8c8cc896600260600051980098178014c0acdd5010c88c966002603a0031323259800981a80140122c8190dd7181980098179baa0038acc004c08800626464b300130350028024590321bae3033001302f37540071640b48168c0b4dd50014dc8a45009b8f4881009b80480092222223322598009811003c566002604460666ea8026264646464646464653001375a607e003375a607e6080003323300100101b2259800800c52f5c11332259800acc004cdd7982198201baa0020178991980080099198008009bab304530463042375400844b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc00400629422b30013371e6eb8c114dd6182280081fc528c4cc008008c11800504020868a5040f913304200233004004001899802002000a07c3041001304200140fd375c607e011375c607e00f303f0069bad303f0059bad303f0049817981d9baa303f0039bad303f002488888888896600260940111329800980a1bab301f304737540033259800981c18239baa0018982598241baa0018b208c304a304b304b3047375400330143756603e608e6ea8c07cc11cdd500da444660300042b30013038304937540051332259800acc004cdc380099b81002009899b89482024bd004006294104a4566002b30010088a51899b8900200a41291598009919192cc004c108c138dd5000c5660026084609c6ea8c148c14c00a266e20dd6982918279baa00100a899b89375a60a4609e6ea800402904d4528209a30510013304f30500013304f9800982018261baa30503051001a60103d87a8000a60103d8798000412c97ae0304c3754609e60a060986ea809e2b30013375e00860666609c6ea4034cc138dd480619827005998271ba800a3304e375066e00024004cc13a60020114c103d87a8000a60103d879800041286609c6ea001ccc138dd4008198271ba800f4bd704566002607864b30010018a4001132301d32598008014520008980f19800800982980120a02259800800c520008980f99801001182a000a0a23051001413864660020026eacc094c134dd5003912cc004006297ae0899199119198008009bab30520042259800800c400e264660ac6e9ccc158dd48029982b18298009982b182a000a5eb80cc00c00cc160008c1580050541bae304e0013300300330530023051001413d1332259800800c00a2b30013052001899192cc004cdc79bae30530020108acc004c080dd71829800c4cdc39bad305330540010058a50413914a08270c14c004dd61828800c00904f209e14a0646600200205444b30010018a5eb82264664464660020026eacc148010896600200310038991982b1ba733056375200a660ac60a6002660ac60a800297ae0330030033058002305600141506eb8c138004cc00c00cc14c008c14400504f452820948a50412914a08252294104a45282094375a609a609c609c609c609c60946ea8008cdc0801800c528209018248044590470c0fc004c0f8004c0f4004c0f0004c0ec004c0e8004c0e4004c0d0dd5004c52820648acc004c09001e2b3001302230333754013132323232329800981e800cdd6981e000cdd6981e00124446464664530013232332259800981b98219baa0028acc004c0dcc10cdd518239824001c4cdc40009bad3047304437540051337120026eb4c11cc110dd500120848a504108608a00266e0000c010cc10cc110004cc10e6002606860806ea8c110c11400698103d87a8000a60103d879800040fc97ae030403754608660806ea806e646600200203e44b30010018a5eb8226644b30015980099baf304730443754004037132330010013233001001375660926094608c6ea8010896600200314bd7044c8cc88c8cc004004dd59825802112cc00400620071323304f374e6609e6ea4014cc13cc130004cc13cc1340052f5c06600600660a2004609e0028268dd718238009980180198260011825000a0902259800800c528456600266e3cdd718249bac30490010438a518998010011825000a088411d14a0821226608c004660080080031330040040014108608a002608c002821a6eb8c10c0326eb8c10c02e60860153371200c00b3033303f3754608600f375a60866088006911111112cc004c13001e264646644660340022b3001303a304b3754003159800acc0040322946200e82522b30010028acc004cdd78009819998271ba900a3304e37520126609c0106609c6ea0044cc138dd419b800120033304e98008035300103d87a8000a60103d879800041286609c6ea0034cc138dd4007198271ba80054bd704566002607864b30010018a4001132301d32598008014520008980f19800800982980120a02259800800c520008980f99801001182a000a0a23051001413864660020026eacc094c134dd5002912cc004006297ae0899199119198008009bab30520042259800800c400e264660ac6e9ccc158dd48029982b18298009982b182a000a5eb80cc00c00cc160008c1580050541bae304e0013300300330530023051001413d1332259800800c00a2b30013052001899192cc004cdc79bae305300200d8acc004c080dd71829800c4cdc39bad305330540010078a50413914a08270c14c004dd61828800c00904f209e14a0646600200205444b30010018a5eb82264664464660020026eacc148010896600200310038991982b1ba733056375200a660ac60a6002660ac60a800297ae0330030033058002305600141506eb8c138004cc00c00cc14c008c14400504f452820948a50412914a08252294104a45282094337100029000192cc004c0ecc128dd5000c4c138c12cdd5000c5904918269827182718251baa00233702602c6eacc084c124dd5000980b1bab302130493754604260926ea8074c12c01e2c82486eb4c104004dd69820801182080098200018c0f0004c0ec004c0e8004c0e4004c0d0dd5004c5282064899912cc004c0940262b30013024303537540171323298009bad303b0019bad303b303c303c0019bae303b002488966002646464b30013031303d37540031598009818981e9baa30413042002899b88005375a6082607c6ea8006266e24014dd69820981f1baa00140f114a081e0c100004cc0f8c0fc004cc0fa6002605e60766ea8c0fcc10000698103d87a8000a60103d879800040e897ae0303b3754607c60766ea805a2b30015980099b884800000e2b300198009803801c5284c8cc004004c8cc004004068896600200314bd7044c8cc88c8cc004004dd59821002112cc004006200713233046374e6608c6ea4014cc118c10c004cc118c1100052f5c0660060066090004608c0028220dd7181f0009980180198218011820800a07e2259800800c52f5c1133225980099b8f375c608400400b133041374e0046600800800313300400400140f46eb0c100004c10400503e2444b3001001801456600260840031325980098079bae3042001899b87375a6084608600200914a081e8c108dd61820800c00903f207e44cc89660020030028acc004c104006264b3001300e375c608200313009375a6082608400314a081e0c104dd61820000c00903e207c14a06466002002646600200203444b30010018a5eb82264664464660020026eacc10801089660020031003899198231ba733046375200a6608c60860026608c608800297ae0330030033048002304600141106eb8c0f8004cc00c00cc10c008c10400503f112cc004006297ae0899912cc004cdc79bae304200203c8998209ba700233004004001899802002000a07a37586080002608200281f2294103944cc89660020030028acc004c10400626464b30013371e6eb8c1080080f22b3001300f375c60840031300a375a6084608600314a081ea294103d18210009bac3040001801207c40f82940c8cc004004064896600200314bd7044c8cc88c8cc004004dd59820802112cc004006200713233045374e6608a6ea4014cc114c108004cc114c10c0052f5c066006006608e004608a0028218dd7181e8009980180198210011820000a07c40e5132330010010162259800800c528456600266e3cdd7182000081cc528c4cc008008c10400503b207c8a5040e514a081c86076607660760026074606c6ea802e294103446600244466e1ccdc098031bab301130393754004600c6eacc044c0e4dd51808981c9baa003001911919800800801912cc00400629422b30013375e607a00200714a3133002002303e00140e081da6e9520049ba54800a6e440ce6e3c0cd2222225980099b874802003e2b3001302a303b3754023132323298009bad30420019bad3042304330430019919800800814112cc004006297ae0899912cc0056600266ebcc118c10cdd51823182398219baa00201a8981b192cc004c0dcc10cdd5000c5200089bad3047304437540028210c966002606e60866ea80062980103d87a8000899198008009bab30483045375400444b30010018a6103d87a8000899192cc004c0640062b300130180018981799825182400125eb82298103d87a80004119133004004304c00341186eb8c118004c124005047208432330010013756608e609060886ea8c11cc120c110dd5001912cc004006298103d87a8000899192cc004c0340062b3001300c0018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c1200050464528208289982280119802002000c4cc01001000504118220009822800a0849bae30420039bae304200248888966002609000713259800981998221baa0018992cc004c0d0c114dd5000c4cc89660026098003132332233019001159800801456600266ebc004c048cc134dd4804998269ba90083304d37500186609a6ea002d2f5c1159800981d992cc0040062900044c8c070c9660020051480022603a6600200260a4004827889660020031480022603c6600400460a60028280c14000504d19198008009bab3024304c375400844b30010018a5eb82264664464660020026eacc144010896600200310038991982a9ba733055375200a660aa60a4002660aa60a600297ae03300300330570023055001414c6eb8c134004cc00c00cc148008c14000504e45660026602804e60646609a00a6609a98103d87a80004bd7045660026602804e66e9520083304d0053304d375008897ae08acc00566002b30013301402730133304d0053304d30123304d30323304d0054bd7025eb812f5c113301402730133304d0053304d30323304d375208c97ae04bd70452820928a5189980a013980999826802998269809998269ba90463304d30323304d0054bd7025eb812f5c0824a264607e646600200205a44b30010018a40011332259800acc004cdc39bad30533050375400409115980099baf30283050375400400b13371e6eccc14cc150c150c140dd50011bb305a8a50413914a082722603e0031001413860a20026600400460a40028278c048cc134dd4804a5eb822941049452820928a50412514a0824a294104945282092980098260044006602a66e00cdc0021821020a0263259800981d18249baa0018982698251baa0018b2090304c304d304d3049375400260960031641246092608c6ea8004c8cc004004094896600200314bd7044cc8966002b30013375e609a60946ea80080862607a64b3001303e304a375400314800226eb4c138c12cdd5000a0923259800981f18251baa0018a60103d87a8000899198008009bab304f304c375400444b30010018a6103d87a8000899192cc004c0800062b3001301f0018981b19828982780125eb82298103d87a80004135133004004305300341346eb8c134004c14000504e209232330010013756609c609e60966ea800c896600200314c103d87a8000899192cc004c0500062b300130130018981a99828182700125eb82298103d87a80004131133004004305200341306eb8c130004c13c00504d4528209089982600119802002000c4cc01001000504818258009826000a0928b208830483045375400316410c603860886ea806e2c8228608460846084002608200260786ea8046294103a456600266e1d200a00f8acc004c0bcc0ecdd5008c4c8c8ca60026eb4c1080066eb4c108c10c006646600200205044b30010018a5eb8226644b30015980099baf304630433754608c608e60866ea800806a2606c64b300130373043375400314800226eb4c11cc110dd5000a0843259800981b98219baa0018a60103d87a8000899198008009bab30483045375400444b30010018a6103d87a8000899192cc004c0640062b300130180018981799825182400125eb82298103d87a80004119133004004304c00341186eb8c118004c124005047208432330010013756608e609060886ea8c11cc120c110dd5001912cc004006298103d87a8000899192cc004c0340062b3001300c0018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c1200050464528208289982280119802002000c4cc01001000504118220009822800a0849bae30420039bae3042002488889660026090007132598009824800c4c8cc88cc0580044c96600200715980099baf00230113304b375200e660966ea4018cc12cdd400519825800998259ba80094bd704566002607264b30010018a4001132301a32598008014520008980d998008009828001209a2259800800c520008980e198010011828800a09c304e001412c64660020026eacc088c128dd5002912cc004006297ae0899199119198008009bab304f0042259800800c400e264660a66e9ccc14cdd4802998299828000998299828800a5eb80cc00c00cc154008c14c0050511bae304b001330030033050002304e00141311323259800981c98251baa001899199119801001000912cc00400629422b30013375e6e98cc140c1440052f5bded8c06e98cc14000d2f5bded8c114a3133002002305200141308278dd5982798261baa00233760006980103d87a80008b2092323300100102c2259800800c530103d87a80008992cc004cdd78021826000c4c0d0cc13cc1340052f5c11330030033051002412c609e0028268c040cc12cc040cc12cdd4803a5eb812f5c114a0823a29410474528208e302f3304a304b30483754609660906ea8084cc12930010100004bd7019baf301e30463754603c608c6ea8c124014c078c118dd5000992cc004c0dcc118dd5000c4c128c11cdd5000c5904518249825182518231baa00130480018b208c32330010010232259800800c52f5c11332259800acc004cdd7982598241baa00201f8981d992cc004c0f0c120dd5000c5200089bad304c304937540028238c966002607860906ea8006298103d87a8000899198008009bab304d304a375400444b30010018a6103d87a8000899192cc004c0780062b3001301d0018981a19827982680125eb82298103d87a8000412d1330040043051003412c6eb8c12c004c13800504c208e323300100137566098609a60926ea800c896600200314c103d87a8000899192cc004c0480062b300130110018981999827182600125eb82298103d87a80004129133004004305000341286eb8c128004c13400504b4528208c89982500119802002000c4cc01001000504618248009825000a08e8b208a18210009820800981e1baa0118a5040e915980099b874803003e2b3001302c303b3754023132323298009bad30420019bad3042304330430019919800800814112cc004006297ae0899912cc0056600266ebcc118c10cdd51823182398219baa00201a8981b192cc004c0dcc10cdd5000c5200089bad3047304437540028210c966002606e60866ea8006298103d87a8000899198008009bab30483045375400444b30010018a6103d87a8000899192cc004c0640062b300130180018981799825182400125eb82298103d87a80004119133004004304c00341186eb8c118004c124005047208432330010013756608e609060886ea8c11cc120c110dd5001912cc004006298103d87a8000899192cc004c0340062b3001300c0018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c1200050464528208289982280119802002000c4cc01001000504118220009822800a0849bae30420039bae304200248888966002609000713259800981998221baa0018992cc004c0d0c114dd5000c660026092608c6ea8006646464b3001303c30483754003159800981e18241baa304c304d002899b88009375a609860926ea8006266e24024dd6982618249baa001411d14a08238c12c004cc124c128004cc12660026074608c6ea8c128c12c00698103d87a8000a60103d8798000411497ae0304637546092608c6ea8086646600200204a44b30010018a5eb8226644b30015980099baf304d304a37540040431303d3259800981f18251baa0018a40011375a609c60966ea8005049192cc004c0f8c128dd5000c5300103d87a8000899198008009bab304f304c375400444b30010018a6103d87a8000899192cc004c0800062b3001301f0018981b19828982780125eb82298103d87a80004135133004004305300341346eb8c134004c14000504e209232330010013756609c609e60966ea800c896600200314c103d87a8000899192cc004c0500062b300130130018981a99828182700125eb82298103d87a80004131133004004305200341306eb8c130004c13c00504d4528209089982600119802002000c4cc01001000504818258009826000a092488966002609a00313233223301a001159800802c56600200515980099baf0013374a9003198271ba900a3304e37520126609c6ea00352f5c11598009980a81418099982700319827260103d87a80004bd7045660026602a05066e95200c3304e0063304e375008a97ae08981e192cc0040062900044c8c074c9660020051480022603c6600200260a6004828089660020031480022603e6600400460a80028288c14400504e19198008009bab3025304d375400844b30010018a5eb82264664464660020026eacc148010896600200310038991982b1ba733056375200a660ac60a6002660ac60a800297ae0330030033058002305600141506eb8c138004cc00c00cc14c008c14400504f452820948a50412914a08252294104a4528209498009826804c00666e00cdc002202182120283259800981d98251baa0018982718259baa0018b2092304d304e304e304a375400260980031641288b208830483045375400316410c603860886ea806e2c82286084002608200260786ea8046294103a456600266e1d200e00f8acc004c0acc0ecdd5008c4c8ca60026eb8c1040066eb4c104c108006646600200204e44b30010018a5eb8226644b30015980099baf304530423754608a608c60846ea80080662606a64b300130363042375400314800226eb4c118c10cdd5000a0823259800981b18211baa0018a6103d87a8000899198008009bab30473044375400444b30010018a6103d87a8000899192cc004c0600062b300130170018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c120005046208232330010013756608c608e60866ea8c118c11cc10cdd5001912cc004006298103d87a8000899192cc004c0300062b3001300b0018981699824182300125eb82298103d87a80004111133004004304a00341106eb8c110004c11c0050454528208089982200119802002000c4cc01001000504018218009822000a0829bae30410024888966002608c005132598009823800c4c8c8cc88cc05400456600200515980099baf0013374a9003198249ba9006330493752012660926ea0cdc0004001a5eb822b300130373259800800c52000899180c192cc00400a2900044c064cc004004c13800904b112cc0040062900044c068cc008008c13c00504c1826000a09232330010013756604060906ea8014896600200314bd7044c8cc88c8cc004004dd59826802112cc004006200713233051374e660a26ea4014cc144c138004cc144c13c0052f5c06600600660a600460a20028278dd718248009980180198270011826000a094899912cc0040060051598009826800c4c8c96600266e3cdd71827001006c56600260366eb8c138006266e1cdd698271827800803c52820928a504124609c0026eb0c130006004825104a0a5032330010010252259800800c52f5c1132332232330010013756609a00844b30010018801c4c8cc144dd3998289ba900533051304e00133051304f0014bd701980180198298011828800a09e375c609200266006006609c0046098002825229410454528208a8a50411466e2000520003259800981b18229baa0018982498231baa0018b20883048304930493045375400466e04c044dd5980e18221baa00130113756603860886ea8c070c110dd518238021823000c590441919800800810912cc004006297ae0899912cc0056600266ebcc124c118dd500100ec4c0e4c9660026074608c6ea80062900044dd6982518239baa001411464b3001303a3046375400314c0103d87a8000899198008009bab304b3048375400444b30010018a6103d87a8000899192cc004c0700062b3001301b0018981919826982580125eb82298103d87a80004125133004004304f00341246eb8c124004c13000504a208a3233001001375660946096608e6ea800c896600200314c103d87a8000899192cc004c0400062b3001300f0018981899826182500125eb82298103d87a80004121133004004304e00341206eb8c120004c12c0050494528208889982400119802002000c4cc01001000504418238009824000a08a8b20861820800981e1baa0118a5040e91598009817807c5284566002605660766ea8046264653001375c6082003375a60826084003375c60820049112cc004c114c8cc0040040a8896600200314bd7044cc8966002b30013375e6090608a6ea8c120c124c114dd500100e44c0e0c9660026072608a6ea80062900044dd6982498231baa001411064b300130393045375400314c0103d87a8000899198008009bab304a3047375400444b30010018a6103d87a8000899192cc004c06c0062b3001301a0018981899826182500125eb82298103d87a80004121133004004304e00341206eb8c120004c12c00504920883233001001375660926094608c6ea8c124c128c118dd5001912cc004006298103d87a8000899192cc004cdc8804800c56600266e3c0240062606066096609200497ae08a60103d87a8000411d133004004304d003411c6eb8c11c004c1280050484528208689982380119802002000c4cc01001000504318230009823800a0888acc0056600266e2120000028cc004c03400a29426466002002646600200204044b30010018a5eb82264664464660020026eacc12001089660020031003899198261ba73304c375200a66098609200266098609400297ae033003003304e002304c00141286eb8c110004cc00c00cc124008c11c005045112cc004006297ae0899912cc004cdc79bae30480020078998239ba700233004004001899802002000a0863758608c002608e002822122259800800c00a2b300130480018992cc004c054dd71824000c4cdc39bad304830490010048a50410c60906eb0c11c00600482290452294503f4566002646600200203844b30010018a508acc004cdc79bae304600103f8a518998010011823800a08241111332259800800c00a2b300130470018992cc004c050dd71823800c4c03cdd698239824000c528208430473758608c0030024110822052819198008009919800800810112cc004006297ae0899199119198008009bab30480042259800800c400e264660986e9ccc130dd4802998261824800998261825000a5eb80cc00c00cc138008c13000504a1bae30440013300300330490023047001411444b30010018a5eb8226644b30013371e6eb8c12000810a26608e6e9c008cc0100100062660080080028218dd618230009823800a0888a5040fd14a081fa2c8210608200260786ea8046294103a207440e881d103a20742068370290001b874800503220642232598009811800c4c8c8c8c8c8c8c8c8ca60026eb4c1040066eb8c1040266eb8c1040226eb4c10401a6eb4c10401664b3001303f0018acc004cdc4a4008607c0031689819181f000a07a8b208037546082009375a6082007375a6082004911111112cc004c128026264b3001303530463754003132323259800982700144cc070c13400c4c9660026072003132598009828000c4c8c9660026078003132598009829800c4cc084c1480040722c8280c138dd500145660026082003132323298009bad30540019bad30540039bad305400248896600260b00090218b20aa182a000982980098271baa0028b2098413060986ea8004c13c0062c8268c12cdd50014566002607c00315980098259baa00280c45904c45904920923049375400316412c60980026098002608e6ea80062c8228c12403e2c823860820026080002607e002607c002607a002607800260760026074002606a6ea800e2b300130280018991919194c004dd6981e000cdd7181e0024dd7181e001cdd6981e00124444b3001304100580545903e0c0f0004c0ec004c0e8004c0d4dd5001c566002604a0031323232323298009bad303d0019bae303d0059bae303d0049bad303d0034888966002608400b132598009816981f1baa0018991919912cc004c11c00e0211641106eb4c110004dd718220011822000981f9baa0018b207a30410068b207e181e800981e000981d800981d000981a9baa0038acc004c09000626464653001375a6076003375c6076007375c60760049112cc004c0fc0120111640f0303b001303a001303537540071640cc8199033206630333754004464b300130273033375400314800226eb4c0dcc0d0dd5000a0643259800981398199baa0018a6103d87a8000899198008009bab30383035375400444b30010018a6103d87a8000899192cc004c0240062b300130080018980f9981d181c00125eb82298103d87a800040d9133004004303c00340d86eb8c0d8004c0e4005037206432330010010022259800800c5300103d87a8000899192cc004c0200062b300130070018980f1981c981b80125eb82298103d87a800040d5133004004303b00340d46eb8c0d4004c0e000503622c8168c8cc00400404c896600200314bd7044cc8966002b30013375e6062605c6ea8c0c4c0c8c0b8dd5001002c4c8cc004004c8cc004004dd59819981a18181baa303330343030375400844b30010018a5eb82264664464660020026eacc0d4010896600200310038991981c9ba733039375200a66072606c00266072606e00297ae033003003303b002303900140dc6eb8c0c4004cc00c00cc0d8008c0d0005032112cc00400629422b30013371e6eb8c0ccdd61819800816c528c4cc008008c0d000502e20628a5040b113303000233004004001899802002000a058302f001303000140b4605a60546ea8054c0b0c0a4dd5180098149baa0022302c302d0018b204c302a3027375400d1640943022302230223022001302100130203020001301f001301e301e003180b1baa00830170053017301800545900d0c038004c024dd5007452689b2b200e1", + "hash": "8cfed220dadcf07254f4fbc3fd3e86f555cbf777f54ad0bdc7592bc8" + }, + { + "title": "gcf_spend.gCf_spend.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action", + "schema": { + "$ref": "#/definitions/gov~1VGovernanceAction" + } + }, + { + "title": "delegate_pool_id", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "stake_register_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + { + "title": "gov_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + } + ], + "compiledCode": "592890010100222222229800aba2aba1aba0aab9faab9eaab9dab9a9bae0089bae0079bae0059bad0049bad0039bad002488888888888896600264653001300e00198071807800cdc3a4005300e00248889660026004601c6ea800e33001300f3754007370e90024dc3a400d370e90004c038dd5002244444664464b300130050048acc004c05cdd500640062c80c22b3001300a0048acc004c05cdd500640062c80c22b300130070048acc004c05cdd500640062c80c22b300130060048acc004c05cdd500640062c80c22b30013370e90040024566002602e6ea803200316406115980099b87480280122b3001301737540190018b20308acc004cdc3a4018009159800980b9baa00c800c59018456600266e1d200e0048acc004c05cdd500640062c80c22b30013370e90080024566002602e6ea803200316406116405480a9015202a405480a9015202a40542653001301b301b0019bac301a0019ba548001222323232323298009bab30220019bac302230230019919800800804112cc0040062980103d87a80008992cc004cdd7981298111baa00100e8980499812000a5eb82266006006604c0048100c0900050224dd618110044dd59811002cdd618110024c08800e6eb0c0880092222222259800980a98131baa0068992cc004c058c09cdd5009c4c8c8cc896600260600051980098178014c0acdd5010c88c966002603a0031323259800981a80140122c8190dd7181980098179baa0038acc004c08800626464b300130350028024590321bae3033001302f37540071640b48168c0b4dd50014dc8a45009b8f4881009b80480092222223322598009811003c566002604460666ea8026264646464646464653001375a607e003375a607e6080003323300100101b2259800800c52f5c11332259800acc004cdd7982198201baa0020178991980080099198008009bab304530463042375400844b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc00400629422b30013371e6eb8c114dd6182280081fc528c4cc008008c11800504020868a5040f913304200233004004001899802002000a07c3041001304200140fd375c607e011375c607e00f303f0069bad303f0059bad303f0049817981d9baa303f0039bad303f002488888888896600260940111329800980a1bab301f304737540033259800981c18239baa0018982598241baa0018b208c304a304b304b3047375400330143756603e608e6ea8c07cc11cdd500da444660300042b30013038304937540051332259800acc004cdc380099b81002009899b89482024bd004006294104a4566002b30010088a51899b8900200a41291598009919192cc004c108c138dd5000c5660026084609c6ea8c148c14c00a266e20dd6982918279baa00100a899b89375a60a4609e6ea800402904d4528209a30510013304f30500013304f9800982018261baa30503051001a60103d87a8000a60103d8798000412c97ae0304c3754609e60a060986ea809e2b30013375e00860666609c6ea4034cc138dd480619827005998271ba800a3304e375066e00024004cc13a60020114c103d87a8000a60103d879800041286609c6ea001ccc138dd4008198271ba800f4bd704566002607864b30010018a4001132301d32598008014520008980f19800800982980120a02259800800c520008980f99801001182a000a0a23051001413864660020026eacc094c134dd5003912cc004006297ae0899199119198008009bab30520042259800800c400e264660ac6e9ccc158dd48029982b18298009982b182a000a5eb80cc00c00cc160008c1580050541bae304e0013300300330530023051001413d1332259800800c00a2b30013052001899192cc004cdc79bae30530020108acc004c080dd71829800c4cdc39bad305330540010058a50413914a08270c14c004dd61828800c00904f209e14a0646600200205444b30010018a5eb82264664464660020026eacc148010896600200310038991982b1ba733056375200a660ac60a6002660ac60a800297ae0330030033058002305600141506eb8c138004cc00c00cc14c008c14400504f452820948a50412914a08252294104a45282094375a609a609c609c609c609c60946ea8008cdc0801800c528209018248044590470c0fc004c0f8004c0f4004c0f0004c0ec004c0e8004c0e4004c0d0dd5004c52820648acc004c09001e2b3001302230333754013132323232329800981e800cdd6981e000cdd6981e00124446464664530013232332259800981b98219baa0028acc004c0dcc10cdd518239824001c4cdc40009bad3047304437540051337120026eb4c11cc110dd500120848a504108608a00266e0000c010cc10cc110004cc10e6002606860806ea8c110c11400698103d87a8000a60103d879800040fc97ae030403754608660806ea806e646600200203e44b30010018a5eb8226644b30015980099baf304730443754004037132330010013233001001375660926094608c6ea8010896600200314bd7044c8cc88c8cc004004dd59825802112cc00400620071323304f374e6609e6ea4014cc13cc130004cc13cc1340052f5c06600600660a2004609e0028268dd718238009980180198260011825000a0902259800800c528456600266e3cdd718249bac30490010438a518998010011825000a088411d14a0821226608c004660080080031330040040014108608a002608c002821a6eb8c10c0326eb8c10c02e60860153371200c00b3033303f3754608600f375a60866088006911111112cc004c13001e264646644660340022b3001303a304b3754003159800acc0040322946200e82522b30010028acc004cdd78009819998271ba900a3304e37520126609c0106609c6ea0044cc138dd419b800120033304e98008035300103d87a8000a60103d879800041286609c6ea0034cc138dd4007198271ba80054bd704566002607864b30010018a4001132301d32598008014520008980f19800800982980120a02259800800c520008980f99801001182a000a0a23051001413864660020026eacc094c134dd5002912cc004006297ae0899199119198008009bab30520042259800800c400e264660ac6e9ccc158dd48029982b18298009982b182a000a5eb80cc00c00cc160008c1580050541bae304e0013300300330530023051001413d1332259800800c00a2b30013052001899192cc004cdc79bae305300200d8acc004c080dd71829800c4cdc39bad305330540010078a50413914a08270c14c004dd61828800c00904f209e14a0646600200205444b30010018a5eb82264664464660020026eacc148010896600200310038991982b1ba733056375200a660ac60a6002660ac60a800297ae0330030033058002305600141506eb8c138004cc00c00cc14c008c14400504f452820948a50412914a08252294104a45282094337100029000192cc004c0ecc128dd5000c4c138c12cdd5000c5904918269827182718251baa00233702602c6eacc084c124dd5000980b1bab302130493754604260926ea8074c12c01e2c82486eb4c104004dd69820801182080098200018c0f0004c0ec004c0e8004c0e4004c0d0dd5004c5282064899912cc004c0940262b30013024303537540171323298009bad303b0019bad303b303c303c0019bae303b002488966002646464b30013031303d37540031598009818981e9baa30413042002899b88005375a6082607c6ea8006266e24014dd69820981f1baa00140f114a081e0c100004cc0f8c0fc004cc0fa6002605e60766ea8c0fcc10000698103d87a8000a60103d879800040e897ae0303b3754607c60766ea805a2b30015980099b884800000e2b300198009803801c5284c8cc004004c8cc004004068896600200314bd7044c8cc88c8cc004004dd59821002112cc004006200713233046374e6608c6ea4014cc118c10c004cc118c1100052f5c0660060066090004608c0028220dd7181f0009980180198218011820800a07e2259800800c52f5c1133225980099b8f375c608400400b133041374e0046600800800313300400400140f46eb0c100004c10400503e2444b3001001801456600260840031325980098079bae3042001899b87375a6084608600200914a081e8c108dd61820800c00903f207e44cc89660020030028acc004c104006264b3001300e375c608200313009375a6082608400314a081e0c104dd61820000c00903e207c14a06466002002646600200203444b30010018a5eb82264664464660020026eacc10801089660020031003899198231ba733046375200a6608c60860026608c608800297ae0330030033048002304600141106eb8c0f8004cc00c00cc10c008c10400503f112cc004006297ae0899912cc004cdc79bae304200203c8998209ba700233004004001899802002000a07a37586080002608200281f2294103944cc89660020030028acc004c10400626464b30013371e6eb8c1080080f22b3001300f375c60840031300a375a6084608600314a081ea294103d18210009bac3040001801207c40f82940c8cc004004064896600200314bd7044c8cc88c8cc004004dd59820802112cc004006200713233045374e6608a6ea4014cc114c108004cc114c10c0052f5c066006006608e004608a0028218dd7181e8009980180198210011820000a07c40e5132330010010162259800800c528456600266e3cdd7182000081cc528c4cc008008c10400503b207c8a5040e514a081c86076607660760026074606c6ea802e294103446600244466e1ccdc098031bab301130393754004600c6eacc044c0e4dd51808981c9baa003001911919800800801912cc00400629422b30013375e607a00200714a3133002002303e00140e081da6e9520049ba54800a6e440ce6e3c0cd2222225980099b874802003e2b3001302a303b3754023132323298009bad30420019bad3042304330430019919800800814112cc004006297ae0899912cc0056600266ebcc118c10cdd51823182398219baa00201a8981b192cc004c0dcc10cdd5000c5200089bad3047304437540028210c966002606e60866ea80062980103d87a8000899198008009bab30483045375400444b30010018a6103d87a8000899192cc004c0640062b300130180018981799825182400125eb82298103d87a80004119133004004304c00341186eb8c118004c124005047208432330010013756608e609060886ea8c11cc120c110dd5001912cc004006298103d87a8000899192cc004c0340062b3001300c0018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c1200050464528208289982280119802002000c4cc01001000504118220009822800a0849bae30420039bae304200248888966002609000713259800981998221baa0018992cc004c0d0c114dd5000c4cc89660026098003132332233019001159800801456600266ebc004c048cc134dd4804998269ba90083304d37500186609a6ea002d2f5c1159800981d992cc0040062900044c8c070c9660020051480022603a6600200260a4004827889660020031480022603c6600400460a60028280c14000504d19198008009bab3024304c375400844b30010018a5eb82264664464660020026eacc144010896600200310038991982a9ba733055375200a660aa60a4002660aa60a600297ae03300300330570023055001414c6eb8c134004cc00c00cc148008c14000504e45660026602804e60646609a00a6609a98103d87a80004bd7045660026602804e66e9520083304d0053304d375008897ae08acc00566002b30013301402730133304d0053304d30123304d30323304d0054bd7025eb812f5c113301402730133304d0053304d30323304d375208c97ae04bd70452820928a5189980a013980999826802998269809998269ba90463304d30323304d0054bd7025eb812f5c0824a264607e646600200205a44b30010018a40011332259800acc004cdc39bad30533050375400409115980099baf30283050375400400b13371e6eccc14cc150c150c140dd50011bb305a8a50413914a082722603e0031001413860a20026600400460a40028278c048cc134dd4804a5eb822941049452820928a50412514a0824a294104945282092980098260044006602a66e00cdc0021821020a0263259800981d18249baa0018982698251baa0018b2090304c304d304d3049375400260960031641246092608c6ea8004c8cc004004094896600200314bd7044cc8966002b30013375e609a60946ea80080862607a64b3001303e304a375400314800226eb4c138c12cdd5000a0923259800981f18251baa0018a60103d87a8000899198008009bab304f304c375400444b30010018a6103d87a8000899192cc004c0800062b3001301f0018981b19828982780125eb82298103d87a80004135133004004305300341346eb8c134004c14000504e209232330010013756609c609e60966ea800c896600200314c103d87a8000899192cc004c0500062b300130130018981a99828182700125eb82298103d87a80004131133004004305200341306eb8c130004c13c00504d4528209089982600119802002000c4cc01001000504818258009826000a0928b208830483045375400316410c603860886ea806e2c8228608460846084002608200260786ea8046294103a456600266e1d200a00f8acc004c0bcc0ecdd5008c4c8c8ca60026eb4c1080066eb4c108c10c006646600200205044b30010018a5eb8226644b30015980099baf304630433754608c608e60866ea800806a2606c64b300130373043375400314800226eb4c11cc110dd5000a0843259800981b98219baa0018a60103d87a8000899198008009bab30483045375400444b30010018a6103d87a8000899192cc004c0640062b300130180018981799825182400125eb82298103d87a80004119133004004304c00341186eb8c118004c124005047208432330010013756608e609060886ea8c11cc120c110dd5001912cc004006298103d87a8000899192cc004c0340062b3001300c0018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c1200050464528208289982280119802002000c4cc01001000504118220009822800a0849bae30420039bae3042002488889660026090007132598009824800c4c8cc88cc0580044c96600200715980099baf00230113304b375200e660966ea4018cc12cdd400519825800998259ba80094bd704566002607264b30010018a4001132301a32598008014520008980d998008009828001209a2259800800c520008980e198010011828800a09c304e001412c64660020026eacc088c128dd5002912cc004006297ae0899199119198008009bab304f0042259800800c400e264660a66e9ccc14cdd4802998299828000998299828800a5eb80cc00c00cc154008c14c0050511bae304b001330030033050002304e00141311323259800981c98251baa001899199119801001000912cc00400629422b30013375e6e98cc140c1440052f5bded8c06e98cc14000d2f5bded8c114a3133002002305200141308278dd5982798261baa00233760006980103d87a80008b2092323300100102c2259800800c530103d87a80008992cc004cdd78021826000c4c0d0cc13cc1340052f5c11330030033051002412c609e0028268c040cc12cc040cc12cdd4803a5eb812f5c114a0823a29410474528208e302f3304a304b30483754609660906ea8084cc12930010100004bd7019baf301e30463754603c608c6ea8c124014c078c118dd5000992cc004c0dcc118dd5000c4c128c11cdd5000c5904518249825182518231baa00130480018b208c32330010010232259800800c52f5c11332259800acc004cdd7982598241baa00201f8981d992cc004c0f0c120dd5000c5200089bad304c304937540028238c966002607860906ea8006298103d87a8000899198008009bab304d304a375400444b30010018a6103d87a8000899192cc004c0780062b3001301d0018981a19827982680125eb82298103d87a8000412d1330040043051003412c6eb8c12c004c13800504c208e323300100137566098609a60926ea800c896600200314c103d87a8000899192cc004c0480062b300130110018981999827182600125eb82298103d87a80004129133004004305000341286eb8c128004c13400504b4528208c89982500119802002000c4cc01001000504618248009825000a08e8b208a18210009820800981e1baa0118a5040e915980099b874803003e2b3001302c303b3754023132323298009bad30420019bad3042304330430019919800800814112cc004006297ae0899912cc0056600266ebcc118c10cdd51823182398219baa00201a8981b192cc004c0dcc10cdd5000c5200089bad3047304437540028210c966002606e60866ea8006298103d87a8000899198008009bab30483045375400444b30010018a6103d87a8000899192cc004c0640062b300130180018981799825182400125eb82298103d87a80004119133004004304c00341186eb8c118004c124005047208432330010013756608e609060886ea8c11cc120c110dd5001912cc004006298103d87a8000899192cc004c0340062b3001300c0018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c1200050464528208289982280119802002000c4cc01001000504118220009822800a0849bae30420039bae304200248888966002609000713259800981998221baa0018992cc004c0d0c114dd5000c660026092608c6ea8006646464b3001303c30483754003159800981e18241baa304c304d002899b88009375a609860926ea8006266e24024dd6982618249baa001411d14a08238c12c004cc124c128004cc12660026074608c6ea8c128c12c00698103d87a8000a60103d8798000411497ae0304637546092608c6ea8086646600200204a44b30010018a5eb8226644b30015980099baf304d304a37540040431303d3259800981f18251baa0018a40011375a609c60966ea8005049192cc004c0f8c128dd5000c5300103d87a8000899198008009bab304f304c375400444b30010018a6103d87a8000899192cc004c0800062b3001301f0018981b19828982780125eb82298103d87a80004135133004004305300341346eb8c134004c14000504e209232330010013756609c609e60966ea800c896600200314c103d87a8000899192cc004c0500062b300130130018981a99828182700125eb82298103d87a80004131133004004305200341306eb8c130004c13c00504d4528209089982600119802002000c4cc01001000504818258009826000a092488966002609a00313233223301a001159800802c56600200515980099baf0013374a9003198271ba900a3304e37520126609c6ea00352f5c11598009980a81418099982700319827260103d87a80004bd7045660026602a05066e95200c3304e0063304e375008a97ae08981e192cc0040062900044c8c074c9660020051480022603c6600200260a6004828089660020031480022603e6600400460a80028288c14400504e19198008009bab3025304d375400844b30010018a5eb82264664464660020026eacc148010896600200310038991982b1ba733056375200a660ac60a6002660ac60a800297ae0330030033058002305600141506eb8c138004cc00c00cc14c008c14400504f452820948a50412914a08252294104a4528209498009826804c00666e00cdc002202182120283259800981d98251baa0018982718259baa0018b2092304d304e304e304a375400260980031641288b208830483045375400316410c603860886ea806e2c82286084002608200260786ea8046294103a456600266e1d200e00f8acc004c0acc0ecdd5008c4c8ca60026eb8c1040066eb4c104c108006646600200204e44b30010018a5eb8226644b30015980099baf304530423754608a608c60846ea80080662606a64b300130363042375400314800226eb4c118c10cdd5000a0823259800981b18211baa0018a6103d87a8000899198008009bab30473044375400444b30010018a6103d87a8000899192cc004c0600062b300130170018981719824982380125eb82298103d87a80004115133004004304b00341146eb8c114004c120005046208232330010013756608c608e60866ea8c118c11cc10cdd5001912cc004006298103d87a8000899192cc004c0300062b3001300b0018981699824182300125eb82298103d87a80004111133004004304a00341106eb8c110004c11c0050454528208089982200119802002000c4cc01001000504018218009822000a0829bae30410024888966002608c005132598009823800c4c8c8cc88cc05400456600200515980099baf0013374a9003198249ba9006330493752012660926ea0cdc0004001a5eb822b300130373259800800c52000899180c192cc00400a2900044c064cc004004c13800904b112cc0040062900044c068cc008008c13c00504c1826000a09232330010013756604060906ea8014896600200314bd7044c8cc88c8cc004004dd59826802112cc004006200713233051374e660a26ea4014cc144c138004cc144c13c0052f5c06600600660a600460a20028278dd718248009980180198270011826000a094899912cc0040060051598009826800c4c8c96600266e3cdd71827001006c56600260366eb8c138006266e1cdd698271827800803c52820928a504124609c0026eb0c130006004825104a0a5032330010010252259800800c52f5c1132332232330010013756609a00844b30010018801c4c8cc144dd3998289ba900533051304e00133051304f0014bd701980180198298011828800a09e375c609200266006006609c0046098002825229410454528208a8a50411466e2000520003259800981b18229baa0018982498231baa0018b20883048304930493045375400466e04c044dd5980e18221baa00130113756603860886ea8c070c110dd518238021823000c590441919800800810912cc004006297ae0899912cc0056600266ebcc124c118dd500100ec4c0e4c9660026074608c6ea80062900044dd6982518239baa001411464b3001303a3046375400314c0103d87a8000899198008009bab304b3048375400444b30010018a6103d87a8000899192cc004c0700062b3001301b0018981919826982580125eb82298103d87a80004125133004004304f00341246eb8c124004c13000504a208a3233001001375660946096608e6ea800c896600200314c103d87a8000899192cc004c0400062b3001300f0018981899826182500125eb82298103d87a80004121133004004304e00341206eb8c120004c12c0050494528208889982400119802002000c4cc01001000504418238009824000a08a8b20861820800981e1baa0118a5040e91598009817807c5284566002605660766ea8046264653001375c6082003375a60826084003375c60820049112cc004c114c8cc0040040a8896600200314bd7044cc8966002b30013375e6090608a6ea8c120c124c114dd500100e44c0e0c9660026072608a6ea80062900044dd6982498231baa001411064b300130393045375400314c0103d87a8000899198008009bab304a3047375400444b30010018a6103d87a8000899192cc004c06c0062b3001301a0018981899826182500125eb82298103d87a80004121133004004304e00341206eb8c120004c12c00504920883233001001375660926094608c6ea8c124c128c118dd5001912cc004006298103d87a8000899192cc004cdc8804800c56600266e3c0240062606066096609200497ae08a60103d87a8000411d133004004304d003411c6eb8c11c004c1280050484528208689982380119802002000c4cc01001000504318230009823800a0888acc0056600266e2120000028cc004c03400a29426466002002646600200204044b30010018a5eb82264664464660020026eacc12001089660020031003899198261ba73304c375200a66098609200266098609400297ae033003003304e002304c00141286eb8c110004cc00c00cc124008c11c005045112cc004006297ae0899912cc004cdc79bae30480020078998239ba700233004004001899802002000a0863758608c002608e002822122259800800c00a2b300130480018992cc004c054dd71824000c4cdc39bad304830490010048a50410c60906eb0c11c00600482290452294503f4566002646600200203844b30010018a508acc004cdc79bae304600103f8a518998010011823800a08241111332259800800c00a2b300130470018992cc004c050dd71823800c4c03cdd698239824000c528208430473758608c0030024110822052819198008009919800800810112cc004006297ae0899199119198008009bab30480042259800800c400e264660986e9ccc130dd4802998261824800998261825000a5eb80cc00c00cc138008c13000504a1bae30440013300300330490023047001411444b30010018a5eb8226644b30013371e6eb8c12000810a26608e6e9c008cc0100100062660080080028218dd618230009823800a0888a5040fd14a081fa2c8210608200260786ea8046294103a207440e881d103a20742068370290001b874800503220642232598009811800c4c8c8c8c8c8c8c8c8ca60026eb4c1040066eb8c1040266eb8c1040226eb4c10401a6eb4c10401664b3001303f0018acc004cdc4a4008607c0031689819181f000a07a8b208037546082009375a6082007375a6082004911111112cc004c128026264b3001303530463754003132323259800982700144cc070c13400c4c9660026072003132598009828000c4c8c9660026078003132598009829800c4cc084c1480040722c8280c138dd500145660026082003132323298009bad30540019bad30540039bad305400248896600260b00090218b20aa182a000982980098271baa0028b2098413060986ea8004c13c0062c8268c12cdd50014566002607c00315980098259baa00280c45904c45904920923049375400316412c60980026098002608e6ea80062c8228c12403e2c823860820026080002607e002607c002607a002607800260760026074002606a6ea800e2b300130280018991919194c004dd6981e000cdd7181e0024dd7181e001cdd6981e00124444b3001304100580545903e0c0f0004c0ec004c0e8004c0d4dd5001c566002604a0031323232323298009bad303d0019bae303d0059bae303d0049bad303d0034888966002608400b132598009816981f1baa0018991919912cc004c11c00e0211641106eb4c110004dd718220011822000981f9baa0018b207a30410068b207e181e800981e000981d800981d000981a9baa0038acc004c09000626464653001375a6076003375c6076007375c60760049112cc004c0fc0120111640f0303b001303a001303537540071640cc8199033206630333754004464b300130273033375400314800226eb4c0dcc0d0dd5000a0643259800981398199baa0018a6103d87a8000899198008009bab30383035375400444b30010018a6103d87a8000899192cc004c0240062b300130080018980f9981d181c00125eb82298103d87a800040d9133004004303c00340d86eb8c0d8004c0e4005037206432330010010022259800800c5300103d87a8000899192cc004c0200062b300130070018980f1981c981b80125eb82298103d87a800040d5133004004303b00340d46eb8c0d4004c0e000503622c8168c8cc00400404c896600200314bd7044cc8966002b30013375e6062605c6ea8c0c4c0c8c0b8dd5001002c4c8cc004004c8cc004004dd59819981a18181baa303330343030375400844b30010018a5eb82264664464660020026eacc0d4010896600200310038991981c9ba733039375200a66072606c00266072606e00297ae033003003303b002303900140dc6eb8c0c4004cc00c00cc0d8008c0d0005032112cc00400629422b30013371e6eb8c0ccdd61819800816c528c4cc008008c0d000502e20628a5040b113303000233004004001899802002000a058302f001303000140b4605a60546ea8054c0b0c0a4dd5180098149baa0022302c302d0018b204c302a3027375400d1640943022302230223022001302100130203020001301f001301e301e003180b1baa00830170053017301800545900d0c038004c024dd5007452689b2b200e1", + "hash": "8cfed220dadcf07254f4fbc3fd3e86f555cbf777f54ad0bdc7592bc8" + }, + { + "title": "gcf_stake.gCf_stake.publish", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1PublishRedeemer" + } + }, + "parameters": [ + { + "title": "_auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "_gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "5903cf01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e9000488c8c8cc004004010896600200314c0103d87a80008992cc004cdd78021805800c4cdd2a40006601c601800297ae089980180198080012014300e001403066e9520023300a300b3008375400297ae0919ba548000cc024cdd2a4004660126ea40052f5c06601298103d87a80004bd702444464653001300b37540032232598009804000c566002601e6ea800e00516404115980099b87480080062b3001300f37540070028b20208acc004cdc3a400800315980098079baa003801459010456600266e1d20060018acc004c03cdd5001c00a2c80822b30013370e9004000c566002601e6ea800e00516404115980099b87480280062b3001300f37540070028b20208acc004cdc3a401800315980098079baa003801459010456600266e1d200e0018acc004c03cdd5001c00a2c80822b30013370e9008000c566002601e6ea800e005164041164034806900d201a4034806900d201a4034601a6ea800a601e00d300f002488896600266e1d20060048994c004dd6980a000cc050c05400660206ea800a26464b300130170018992cc004c034c04cdd5000c4c8cc020004566002601c60286ea801a266ebc005300103d87d8000899baf0014c103d87f8000404c602e60286ea80062c8090cc02cdd5980b180b980b980b980b980b980b980b980b980b801180b000c5901419199119801001000912cc004006297ae0899912cc004cdd7980d180b9baa301a301b3017375400400b13301900233004004001899802002000a02a3018001301900140586eb0c058008c024038c044dd5001a4444b3001300e0028acc004c054dd500340062c80b22b30013370e90010014566002602a6ea801a00316405916404c809860206ea8016264b30013370e9005002c4ca60026eb4c054006602a602c003301237540089114c0040466eb0c0600066eacc060c064c064c064c064c064c064c064c064c064006980103d87d800040143011375400d15980099b874802001626645300100f9bac30160019bab3016301730173017301730173017301730173017001a60103d87e8000400c602860226ea8018c044dd5001c5900f201e22223259800980c800c4c966002601e602a6ea800626466014002266ebc004010c064c058dd5000c5901419806801980c000c59016191919800800802912cc004006297ae0899912cc004cdd7980e180c9baa301c301d3019375400400b13301b00233004004001899802002000a02e301a001301b001406060160088070601c601e002601c0088a4d13656401001", + "hash": "fdf36c6bd97992a1a2c1059b5e2543b3d49b752520360d4f4ed4817d" + }, + { + "title": "gcf_stake.gCf_stake.propose", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "_auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "_gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "5903cf01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e9000488c8c8cc004004010896600200314c0103d87a80008992cc004cdd78021805800c4cdd2a40006601c601800297ae089980180198080012014300e001403066e9520023300a300b3008375400297ae0919ba548000cc024cdd2a4004660126ea40052f5c06601298103d87a80004bd702444464653001300b37540032232598009804000c566002601e6ea800e00516404115980099b87480080062b3001300f37540070028b20208acc004cdc3a400800315980098079baa003801459010456600266e1d20060018acc004c03cdd5001c00a2c80822b30013370e9004000c566002601e6ea800e00516404115980099b87480280062b3001300f37540070028b20208acc004cdc3a401800315980098079baa003801459010456600266e1d200e0018acc004c03cdd5001c00a2c80822b30013370e9008000c566002601e6ea800e005164041164034806900d201a4034806900d201a4034601a6ea800a601e00d300f002488896600266e1d20060048994c004dd6980a000cc050c05400660206ea800a26464b300130170018992cc004c034c04cdd5000c4c8cc020004566002601c60286ea801a266ebc005300103d87d8000899baf0014c103d87f8000404c602e60286ea80062c8090cc02cdd5980b180b980b980b980b980b980b980b980b980b801180b000c5901419199119801001000912cc004006297ae0899912cc004cdd7980d180b9baa301a301b3017375400400b13301900233004004001899802002000a02a3018001301900140586eb0c058008c024038c044dd5001a4444b3001300e0028acc004c054dd500340062c80b22b30013370e90010014566002602a6ea801a00316405916404c809860206ea8016264b30013370e9005002c4ca60026eb4c054006602a602c003301237540089114c0040466eb0c0600066eacc060c064c064c064c064c064c064c064c064c064006980103d87d800040143011375400d15980099b874802001626645300100f9bac30160019bab3016301730173017301730173017301730173017001a60103d87e8000400c602860226ea8018c044dd5001c5900f201e22223259800980c800c4c966002601e602a6ea800626466014002266ebc004010c064c058dd5000c5901419806801980c000c59016191919800800802912cc004006297ae0899912cc004cdd7980e180c9baa301c301d3019375400400b13301b00233004004001899802002000a02e301a001301b001406060160088070601c601e002601c0088a4d13656401001", + "hash": "fdf36c6bd97992a1a2c1059b5e2543b3d49b752520360d4f4ed4817d" + }, + { + "title": "gcf_stake.gCf_stake.vote", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "_auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "_gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "5903cf01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e9000488c8c8cc004004010896600200314c0103d87a80008992cc004cdd78021805800c4cdd2a40006601c601800297ae089980180198080012014300e001403066e9520023300a300b3008375400297ae0919ba548000cc024cdd2a4004660126ea40052f5c06601298103d87a80004bd702444464653001300b37540032232598009804000c566002601e6ea800e00516404115980099b87480080062b3001300f37540070028b20208acc004cdc3a400800315980098079baa003801459010456600266e1d20060018acc004c03cdd5001c00a2c80822b30013370e9004000c566002601e6ea800e00516404115980099b87480280062b3001300f37540070028b20208acc004cdc3a401800315980098079baa003801459010456600266e1d200e0018acc004c03cdd5001c00a2c80822b30013370e9008000c566002601e6ea800e005164041164034806900d201a4034806900d201a4034601a6ea800a601e00d300f002488896600266e1d20060048994c004dd6980a000cc050c05400660206ea800a26464b300130170018992cc004c034c04cdd5000c4c8cc020004566002601c60286ea801a266ebc005300103d87d8000899baf0014c103d87f8000404c602e60286ea80062c8090cc02cdd5980b180b980b980b980b980b980b980b980b980b801180b000c5901419199119801001000912cc004006297ae0899912cc004cdd7980d180b9baa301a301b3017375400400b13301900233004004001899802002000a02a3018001301900140586eb0c058008c024038c044dd5001a4444b3001300e0028acc004c054dd500340062c80b22b30013370e90010014566002602a6ea801a00316405916404c809860206ea8016264b30013370e9005002c4ca60026eb4c054006602a602c003301237540089114c0040466eb0c0600066eacc060c064c064c064c064c064c064c064c064c064006980103d87d800040143011375400d15980099b874802001626645300100f9bac30160019bab3016301730173017301730173017301730173017001a60103d87e8000400c602860226ea8018c044dd5001c5900f201e22223259800980c800c4c966002601e602a6ea800626466014002266ebc004010c064c058dd5000c5901419806801980c000c59016191919800800802912cc004006297ae0899912cc004cdd7980e180c9baa301c301d3019375400400b13301b00233004004001899802002000a02e301a001301b001406060160088070601c601e002601c0088a4d13656401001", + "hash": "fdf36c6bd97992a1a2c1059b5e2543b3d49b752520360d4f4ed4817d" + }, + { + "title": "gcf_stake.gCf_stake.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "_auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "_gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "5903cf01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e9000488c8c8cc004004010896600200314c0103d87a80008992cc004cdd78021805800c4cdd2a40006601c601800297ae089980180198080012014300e001403066e9520023300a300b3008375400297ae0919ba548000cc024cdd2a4004660126ea40052f5c06601298103d87a80004bd702444464653001300b37540032232598009804000c566002601e6ea800e00516404115980099b87480080062b3001300f37540070028b20208acc004cdc3a400800315980098079baa003801459010456600266e1d20060018acc004c03cdd5001c00a2c80822b30013370e9004000c566002601e6ea800e00516404115980099b87480280062b3001300f37540070028b20208acc004cdc3a401800315980098079baa003801459010456600266e1d200e0018acc004c03cdd5001c00a2c80822b30013370e9008000c566002601e6ea800e005164041164034806900d201a4034806900d201a4034601a6ea800a601e00d300f002488896600266e1d20060048994c004dd6980a000cc050c05400660206ea800a26464b300130170018992cc004c034c04cdd5000c4c8cc020004566002601c60286ea801a266ebc005300103d87d8000899baf0014c103d87f8000404c602e60286ea80062c8090cc02cdd5980b180b980b980b980b980b980b980b980b980b801180b000c5901419199119801001000912cc004006297ae0899912cc004cdd7980d180b9baa301a301b3017375400400b13301900233004004001899802002000a02a3018001301900140586eb0c058008c024038c044dd5001a4444b3001300e0028acc004c054dd500340062c80b22b30013370e90010014566002602a6ea801a00316405916404c809860206ea8016264b30013370e9005002c4ca60026eb4c054006602a602c003301237540089114c0040466eb0c0600066eacc060c064c064c064c064c064c064c064c064c064006980103d87d800040143011375400d15980099b874802001626645300100f9bac30160019bab3016301730173017301730173017301730173017001a60103d87e8000400c602860226ea8018c044dd5001c5900f201e22223259800980c800c4c966002601e602a6ea800626466014002266ebc004010c064c058dd5000c5901419806801980c000c59016191919800800802912cc004006297ae0899912cc004cdd7980e180c9baa301c301d3019375400400b13301b00233004004001899802002000a02e301a001301b001406060160088070601c601e002601c0088a4d13656401001", + "hash": "fdf36c6bd97992a1a2c1059b5e2543b3d49b752520360d4f4ed4817d" + }, + { + "title": "share_token/mint.share_token.mint", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1MintPolarity" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + } + ], + "compiledCode": "590380010100229800aba2aba1aba0aab9faab9eaab9dab9a9bae0024888888896600264653001300900198049805000cdc3a400130090024888966002600460126ea800e266446644b300130060018acc004c038dd5004400a2c807a2b300130030018acc004c038dd5004400a2c807a2c806100c0992cc004c044006264b30013006300d3754011132598009809800c4c9660026010601e6ea80062646644b3001300b0018acc004c04cdd5001c00a2c80a22b300130080018acc004c04cdd5001c00a2c80a22b30013370e9002000c56600260266ea800e00516405115980099b87480180062b3001301337540070028b20288acc004cdc3a401000315980098099baa003801459014456600266e1d200a0018acc004c04cdd5001c00a2c80a22b30013370e9006000c56600260266ea800e00516405115980099b87480380062b3001301337540070028b20288acc004cdc3a402000315980098099baa003801459014459011202240448089011202240448089011099baf0014c103d879800030103754002602660206ea80062c8070c8c8cc004004dd5980a180a980a980a980a980a980a980a980a980a802112cc0040062980103d87a80008992cc004cdd78021809000c4cdd2a40006602a602600297ae0899801801980b80120223015001404c66e952002330113012300f3754602400297ae08b202032330010013758602400444b30010018a5eb8226644b3001323300100132330010013756602e603060286ea8c05cc060c050dd5002112cc004006297ae0899199119198008009bab30190042259800800c400e2646603a6e9ccc074dd48029980e980d0009980e980d800a5eb80cc00c00cc07c008c07400501b1bae301500133003003301a0023018001405844b30010018a508acc004cdc79bae30173758602e00202314a31330020023018001404880aa26602800466008008003133004004001404060260026028002808a266e20dd698071808801240008060c034dd500245900e192cc004c008c030dd5000c52f5bded8c1137566020601a6ea800500b19198008009bab30103011301130113011300d375400844b30010018a60103d87a8000899192cc004cdc8803000c56600266e3c018006266e9520003301230100024bd7045300103d87a80004039133004004301400340386eb8c038004c04400500f18059baa006375c601a60146ea800cdc3a4005164020300900130043754013149a26cac8011", + "hash": "04b3f2f84b2728dbcafcf64d06e182b812b826df6b3a246b3065dc66" + }, + { + "title": "share_token/mint.share_token.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + } + ], + "compiledCode": "590380010100229800aba2aba1aba0aab9faab9eaab9dab9a9bae0024888888896600264653001300900198049805000cdc3a400130090024888966002600460126ea800e266446644b300130060018acc004c038dd5004400a2c807a2b300130030018acc004c038dd5004400a2c807a2c806100c0992cc004c044006264b30013006300d3754011132598009809800c4c9660026010601e6ea80062646644b3001300b0018acc004c04cdd5001c00a2c80a22b300130080018acc004c04cdd5001c00a2c80a22b30013370e9002000c56600260266ea800e00516405115980099b87480180062b3001301337540070028b20288acc004cdc3a401000315980098099baa003801459014456600266e1d200a0018acc004c04cdd5001c00a2c80a22b30013370e9006000c56600260266ea800e00516405115980099b87480380062b3001301337540070028b20288acc004cdc3a402000315980098099baa003801459014459011202240448089011202240448089011099baf0014c103d879800030103754002602660206ea80062c8070c8c8cc004004dd5980a180a980a980a980a980a980a980a980a980a802112cc0040062980103d87a80008992cc004cdd78021809000c4cdd2a40006602a602600297ae0899801801980b80120223015001404c66e952002330113012300f3754602400297ae08b202032330010013758602400444b30010018a5eb8226644b3001323300100132330010013756602e603060286ea8c05cc060c050dd5002112cc004006297ae0899199119198008009bab30190042259800800c400e2646603a6e9ccc074dd48029980e980d0009980e980d800a5eb80cc00c00cc07c008c07400501b1bae301500133003003301a0023018001405844b30010018a508acc004cdc79bae30173758602e00202314a31330020023018001404880aa26602800466008008003133004004001404060260026028002808a266e20dd698071808801240008060c034dd500245900e192cc004c008c030dd5000c52f5bded8c1137566020601a6ea800500b19198008009bab30103011301130113011300d375400844b30010018a60103d87a8000899192cc004cdc8803000c56600266e3c018006266e9520003301230100024bd7045300103d87a80004039133004004301400340386eb8c038004c04400500f18059baa006375c601a60146ea800cdc3a4005164020300900130043754013149a26cac8011", + "hash": "04b3f2f84b2728dbcafcf64d06e182b812b826df6b3a246b3065dc66" + } + ], + "definitions": { + "Bool": { + "title": "Bool", + "anyOf": [ + { + "title": "False", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "True", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "ByteArray": { + "dataType": "bytes" + }, + "Data": { + "title": "Data", + "description": "Any Plutus data." + }, + "Int": { + "dataType": "integer" + }, + "List$cardano/address/Credential": { + "dataType": "list", + "items": { + "$ref": "#/definitions/cardano~1address~1Credential" + } + }, + "Option$aiken/crypto/ScriptHash": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Option$cardano/address/StakeCredential": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1address~1StakeCredential" + } + ] + }, + { + "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$cardano/address/Credential_cardano/assets/Lovelace": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + "Pairs$cardano/address/Credential_cardano/governance/Mandate": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/cardano~1governance~1Mandate" + } + }, + "Pairs$gov/ProtocolParametersIndex_Data": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/gov~1ProtocolParametersIndex" + }, + "values": { + "$ref": "#/definitions/Data" + } + }, + "aiken/collection/Index": { + "title": "Index", + "dataType": "integer" + }, + "aiken/crypto/ScriptHash": { + "title": "ScriptHash", + "dataType": "bytes" + }, + "aiken/crypto/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/cardano~1address~1PaymentCredential" + }, + { + "title": "stake_credential", + "$ref": "#/definitions/Option$cardano~1address~1StakeCredential" + } + ] + } + ] + }, + "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/aiken~1crypto~1VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/address/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/aiken~1crypto~1VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/address/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" + } + ] + } + ] + }, + "cardano/assets/Lovelace": { + "title": "Lovelace", + "dataType": "integer" + }, + "cardano/assets/PolicyId": { + "title": "PolicyId", + "dataType": "bytes" + }, + "cardano/governance/Constitution": { + "title": "Constitution", + "anyOf": [ + { + "title": "Constitution", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "guardrails", + "$ref": "#/definitions/Option$aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/governance/GovernanceActionId": { + "title": "GovernanceActionId", + "anyOf": [ + { + "title": "GovernanceActionId", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "transaction", + "$ref": "#/definitions/cardano~1governance~1TransactionId" + }, + { + "title": "proposal_procedure", + "$ref": "#/definitions/aiken~1collection~1Index" + } + ] + } + ] + }, + "cardano/governance/Mandate": { + "title": "Mandate", + "dataType": "integer" + }, + "cardano/governance/ProtocolVersion": { + "title": "ProtocolVersion", + "anyOf": [ + { + "title": "ProtocolVersion", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "major", + "$ref": "#/definitions/Int" + }, + { + "title": "minor", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "cardano/governance/TransactionId": { + "title": "TransactionId", + "dataType": "bytes" + }, + "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" + } + ] + } + ] + }, + "gov/ProtocolParametersIndex": { + "title": "ProtocolParametersIndex", + "dataType": "integer" + }, + "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$aiken~1crypto~1ScriptHash" + } + ] + }, + { + "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_cardano~1assets~1Lovelace" + }, + { + "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$aiken~1crypto~1ScriptHash" + } + ] + }, + { + "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_cardano~1governance~1Mandate" + }, + { + "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$gov~1ProtocolParametersIndex_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": "Crowdfund", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "stake_hash", + "$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": "min_charge", + "$ref": "#/definitions/Int" + } + ] + }, + { + "title": "Proposed", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "title": "stake_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": "stake_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": "stake_hash", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "share_token", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "funds_controlled", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "types/CrowdfundGovRedeemer": { + "title": "CrowdfundGovRedeemer", + "anyOf": [ + { + "title": "ContributeFund", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "CompleteCrowdfund", + "dataType": "constructor", + "index": 1, + "fields": [] + }, + { + "title": "PreMatureContributorWithdrawal", + "dataType": "constructor", + "index": 2, + "fields": [] + }, + { + "title": "PreMatureRemoveEmptyInstance", + "dataType": "constructor", + "index": 3, + "fields": [] + }, + { + "title": "RegisterCerts", + "dataType": "constructor", + "index": 4, + "fields": [] + }, + { + "title": "VoteOnGovAction", + "dataType": "constructor", + "index": 5, + "fields": [] + }, + { + "title": "DeregisterCerts", + "dataType": "constructor", + "index": 6, + "fields": [] + }, + { + "title": "AfterCompleteContributorWithdrawal", + "dataType": "constructor", + "index": 7, + "fields": [] + }, + { + "title": "AfterCompleteRemoveEmptyInstance", + "dataType": "constructor", + "index": 8, + "fields": [] + } + ] + }, + "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-crowdfundV2/specs/1_gCf_spend.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/1_gCf_spend.md new file mode 100644 index 000000000..aedc267a5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/1_gCf_spend.md @@ -0,0 +1,277 @@ +# Specification - gCf_spend + +## Overview + +The `gCf_spend` validator is a unified spending validator that handles both crowdfunding operations and governance operations. It merges functionality from `aiken-crowdfund` and `gov-crowdfund` into a single contract. + +## Parameters + +- `auth_token`: PolicyId - The policy ID of the crowdfunding authentication token +- `proposer_key_hash`: ByteArray - The hash of the proposer's public key for authorization +- `gov_action`: VGovernanceAction - The governance action to be proposed +- `delegate_pool_id`: ByteArray - The stake pool ID to delegate to during governance +- `stake_register_deposit`: Lovelace - Dynamic stake registration deposit amount +- `drep_register_deposit`: Lovelace - Dynamic DRep registration deposit amount +- `gov_deposit`: Lovelace - Dynamic governance proposal deposit amount + +## Datum + +The validator accepts `CrowdfundGovDatum` which can be in one of four states. The main user-facing states are `Crowdfund`, `Proposed`, and `Voted`. The `Refundable` state is an intermediate state used for post-governance fund withdrawals: + +```rs +pub type CrowdfundGovDatum { + // Crowdfunding phase - active crowdfunding campaign + Crowdfund { + stake_hash: ByteArray, + share_token: ByteArray, + crowdfund_address: Address, + fundraise_target: Int, + current_fundraised_amount: Int, + allow_over_subscription: Bool, + deadline: Int, + expiry_buffer: Int, + min_charge: Int + } + // Governance phase - proposal submitted + Proposed { + stake_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + // Governance phase - proposal voted on + Voted { + stake_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + gov_tx_id: GovernanceActionId, + deadline: Int, + } + // Governance phase - ready for refunds + Refundable { + stake_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + } +} +``` + +## User Actions + +### 1. ContributeFund + +**Phase**: Crowdfunding +**Datum State**: `Crowdfund` → `Crowdfund` + +Allows contributors to add funds to an active crowdfunding campaign. + +**Requirements**: +- Exactly one input with `auth_token` (empty token name) from current address +- Exactly one output with `auth_token` (empty token name) to current address +- Minimum contribution: 2 ADA (2,000,000 lovelace) +- The increase in output lovelace equals the increase in `current_fundraised_amount` +- If `allow_over_subscription` is `False`, `current_fundraised_amount` must not exceed `fundraise_target` +- Transaction must occur before `deadline` +- Output value must contain exactly 2 assets (`auth_token` + lovelace) +- Share tokens minted: exactly `fundraise_added` amount of `share_token` with empty token name (`""`) + +**Validation**: +- Lovelace difference matches datum update +- Fundraise target constraint respected +- Deadline not passed +- Output datum correctly updated +- Share tokens minted proportionally + +### 2. PreMatureContributorWithdrawal + +**Phase**: Crowdfunding +**Datum State**: `Crowdfund` → `Crowdfund` + +Allows contributors to withdraw funds before crowdfunding completion if campaign failed or deadline expired. + +**Requirements**: +- Exactly one input with `auth_token` (empty token name) from current address +- Exactly one output with `auth_token` (empty token name) to current address +- Either: + - `deadline + expiry_buffer` has passed, OR + - `current_fundraised_amount <= fundraise_target` (campaign failed) +- Lovelace withdrawn (negative difference) equals share tokens burned +- Output value must contain exactly 2 assets +- Share tokens burned: exactly `|lovelace_withdrawn|` amount of `share_token` with empty token name (`""`) + +**Validation**: +- Validity period check OR fundraise failure check +- Lovelace withdrawn matches share tokens burned +- Output datum correctly updated with reduced `current_fundraised_amount` + +### 3. PreMatureRemoveEmptyInstance + +**Phase**: Crowdfunding +**Datum State**: `Crowdfund` → (consumed) + +Allows proposer to remove an empty crowdfunding instance after deadline. + +**Requirements**: +- `deadline` has passed +- Exactly one input with `auth_token` (empty token name) from current address +- If `current_fundraised_amount > 0`: + - Burn all `share_token` tokens (amount: `-current_fundraised_amount`, empty token name `""`) + - Burn `auth_token` (amount: -1, empty token name `""`) +- If `current_fundraised_amount == 0`: + - Burn only `auth_token` (amount: -1, empty token name `""`) +- Must be signed by `proposer_key_hash` + +**Validation**: +- Deadline passed +- Appropriate tokens burned +- Proposer authorization + +### 4. RegisterCerts + +**Phase**: Governance +**Datum State**: `Crowdfund` → `Proposed` + +Registers stake and DRep certificates, delegates, and submits governance proposal. Can be called directly from the crowdfunding phase. + +**Requirements**: +- Exactly one input with `auth_token` (empty token name) from current address +- Exactly one output with `auth_token` (empty token name) to current address +- Input datum must be `Crowdfund` state +- Output datum must be `Proposed` state with: + - `stake_hash` from input datum + - `share_token` from input datum + - `funds_controlled` set to `current_fundraised_amount` from input datum + - `deadline` from input datum +- Output value deducted by exactly `stake_register_deposit + drep_register_deposit + gov_deposit` +- Output value must contain exactly 2 assets (`auth_token` + lovelace) +- Current address must have inline stake credential + +**Certificates Required**: +- Register stake certificate (no deposit required) +- Register DRep certificate with `drep_register_deposit` +- Delegate vote to own DRep (Registered credential) +- Delegate stake to `delegate_pool_id` + - OR delegate both vote and stake in single certificate +- Submit governance proposal with: + - Deposit: `gov_deposit` + - Return address: Script(`stake_hash` from datum) + - Governance action: `gov_action` + +**Validation**: +- Lovelace deduction matches deposits +- Datum state transition correct +- All required certificates present +- Proposal procedure valid + +### 5. VoteOnGovAction + +**Phase**: Governance +**Datum State**: `Proposed` → `Voted` + +Records that the governance action has been voted on. + +**Requirements**: +- Exactly one input with `auth_token` (empty token name) from current address +- Exactly one output with `auth_token` (empty token name) to current address +- Input datum must be `Proposed` state +- Output datum must be `Voted` state with: + - Same fields as input except `gov_tx_id` added + - `gov_tx_id` constructed from own input's `transaction_id` + `proposal_procedure: 0` +- Input and output values must be identical +- Output value must contain exactly 2 assets + +**Vote Required**: +- DRep (Script(`stake_hash` from datum)) must vote `Yes` on the governance action identified by `gov_tx_id` + +**Validation**: +- Value preservation +- Datum state transition correct +- Vote recorded correctly + +### 6. DeregisterCerts + +**Phase**: Governance +**Datum State**: `Voted` → `Refundable` + +Deregisters certificates and transitions to refundable state after governance period. + +**Requirements**: +- `deadline` has passed +- Exactly one input with `auth_token` (empty token name) from current address +- Exactly one output with `auth_token` (empty token name) to current address +- Input datum must be `Voted` state +- Output datum must be `Refundable` state with same fields (excluding `gov_tx_id` and `deadline`) +- Output value increased by exactly `stake_register_deposit + drep_register_deposit + gov_deposit` (refunds) +- Output value must contain exactly 2 assets +- Current address must have inline stake credential + +**Certificates Required**: +- Unregister stake certificate (refund received) +- Unregister DRep certificate with `drep_register_deposit` refund + +**Validation**: +- Deadline passed +- Lovelace increase matches refunds +- Datum state transition correct +- Certificates deregistered + +### 7. AfterCompleteContributorWithdrawal + +**Phase**: Post-Governance +**Datum State**: `Refundable` → `Refundable` + +Allows contributors to withdraw funds after governance completion by burning share tokens. + +**Requirements**: +- Exactly one input with `auth_token` (empty token name) from current address +- Exactly one output with `auth_token` (empty token name) to current address +- Input datum must be `Refundable` state +- Output datum must be `Refundable` state with `funds_controlled` increased by `lovelace_withdrawn` +- Lovelace withdrawn (negative difference) equals share tokens burned +- Output value must contain exactly 2 assets +- Share tokens burned: exactly `|lovelace_withdrawn|` amount of `share_token` with empty token name (`""`) + +**Validation**: +- Lovelace withdrawn matches share tokens burned +- Output datum correctly updated + +### 8. AfterCompleteRemoveEmptyInstance + +**Phase**: Post-Governance +**Datum State**: `Refundable` → (consumed) + +Allows proposer to remove empty instance after all funds withdrawn. + +**Requirements**: +- Exactly one input with token of policy `stake_hash` (from datum, empty token name) from current address +- If `funds_controlled > 0`: + - Burn all remaining `share_token` tokens (amount: `-funds_controlled`, empty token name `""`) +- Burn `auth_token` (amount: -1, empty token name `""`) +- Must be signed by `proposer_key_hash` + +**Validation**: +- Appropriate tokens burned +- Proposer authorization + +## State Transition Flow + +**Main Flow:** +``` +Crowdfund → RegisterCerts → Proposed +Proposed → VoteOnGovAction → Voted +Voted → DeregisterCerts → Refundable +``` + +**Post-Governance:** +``` +Refundable → AfterCompleteContributorWithdrawal → Refundable (loop until empty) +Refundable → AfterCompleteRemoveEmptyInstance → (consumed) +``` + +The `Refundable` state is an intermediate state that allows contributors to withdraw funds after governance completion. From a user perspective, withdrawals happen after the governance proposal is voted on (Voted state), but internally the contract transitions through `Refundable` for fund management. + +## Token Usage + +- **`auth_token`**: Used throughout all phases (Phases 1-4) to identify UTxOs. Token name is empty string (`""`) in all phases +- **`share_token`**: Minted/burned proportionally to contributions/withdrawals. Token name is empty string (`""`) in all phases +- **`stake_hash`**: Stored in all datum states (`Crowdfund`, `Proposed`, `Voted`, `Refundable`). This is the stake validator script hash, used as the return address for governance proposals and as the DRep credential for voting diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/2_gCf_stake.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/2_gCf_stake.md new file mode 100644 index 000000000..9e990d26e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/2_gCf_stake.md @@ -0,0 +1,89 @@ +# Specification - gCf_stake + +## Overview + +The `gCf_stake` validator is a stake script validator that coordinates publishing operations (certificate registration/deregistration) and governance proposal/vote validation. It works in conjunction with `gCf_spend` to provide governance capabilities. The validator no longer handles token minting/burning - `auth_token` is used throughout all phases. + +## Parameters + +- `auth_token`: PolicyId - The policy ID of the crowdfunding authentication token (used for reference) +- `spend`: ByteArray - The script hash of the `gCf_spend` validator +- `gov_action_period`: Int - The buffer period added to crowdfund deadline for governance operations (currently unused but reserved for future use) + +## User Actions + +### 1. Publish - Register + +**Purpose**: Validate that stake/DRep registration is happening via the spend validator. + +**Requirements**: +- Redeemer: `Register` +- Exactly one input from the `spend` script address +- The spend validator input must have redeemer `RegisterCerts` + +**Validation**: +- Spend script input redeemer check: Ensures `RegisterCerts` is being used in spend validator + +**Usage**: Called when registering certificates and submitting governance proposal. + +### 2. Publish - Deregister + +**Purpose**: Validate that stake/DRep deregistration is happening via the spend validator. + +**Requirements**: +- Redeemer: `Deregister` +- Exactly one input from the `spend` script address +- The spend validator input must have redeemer `DeregisterCerts` + +**Validation**: +- Spend script input redeemer check: Ensures `DeregisterCerts` is being used in spend validator + +**Usage**: Called when deregistering certificates after governance period. + +### 3. Propose + +**Purpose**: Validate that a governance proposal is being submitted via the spend validator. + +**Requirements**: +- Exactly one input from the `spend` script address +- The spend validator input must have redeemer `RegisterCerts` + +**Validation**: +- Spend script input redeemer check: Ensures `RegisterCerts` is being used in spend validator + +**Usage**: Called when submitting a governance proposal. The proposal itself is validated in the spend validator's `RegisterCerts` case. + +### 4. Vote + +**Purpose**: Validate that a governance vote is being cast via the spend validator. + +**Requirements**: +- Exactly one input from the `spend` script address +- The spend validator input must have redeemer `VoteOnGovAction` + +**Validation**: +- Spend script input redeemer check: Ensures `VoteOnGovAction` is being used in spend validator + +**Usage**: Called when voting on a governance action. The vote itself is validated in the spend validator's `VoteOnGovAction` case. + +## Relationship with gCf_spend + +The `gCf_stake` validator acts as a coordination layer that: + +1. **Publishing**: Validates that certificate registration/deregistration operations are properly coordinated through the spend validator + +2. **Governance**: Ensures that proposal submission and voting operations are properly coordinated through the spend validator + +The actual business logic and state transitions are handled by `gCf_spend`, while `gCf_stake` ensures these operations are authorized and coordinated correctly. + +## Token Usage + +- **`auth_token`**: Used throughout all phases to identify UTxOs. The same `auth_token` policy is used consistently across crowdfunding and governance phases, with empty token name (`""`) +- **`stake_hash`**: The stake validator's script hash is stored in all datum states (`Crowdfund`, `Proposed`, `Voted`, and `Refundable` for post-governance withdrawals) and used as: + - The return address for governance proposals + - The DRep credential for voting + +## Integration Points + +- **Spend Validator Coordination**: All governance operations must be coordinated through the spend validator with appropriate redeemers +- **No Token Minting/Burning**: The stake validator no longer handles token lifecycle - `auth_token` is used throughout all phases diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/_scripts.md new file mode 100644 index 000000000..59e754d5f --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/_scripts.md @@ -0,0 +1,127 @@ +# Gov Crowdfund V2 - Scripts Overview + +## Overview + +The `gov-crowdfundV2` contract is a unified system that merges crowdfunding and governance functionality into a single integrated contract. This design addresses usability challenges present in the modular contract architecture. + +## Scripts + +### 1. gCf_spend + +The spending validator that guards both crowdfunded funds and governance operations. + +**Responsibilities**: +- Manages crowdfunding contributions and withdrawals +- Handles governance certificate registration/deregistration +- Validates governance proposal submission and voting +- Manages state transitions through the complete lifecycle + +**Key Features**: +- Unified datum type (`CrowdfundGovDatum`) supporting both crowdfunding and governance states +- Eight distinct redeemer types covering all operations: + 1. `ContributeFund`: Add funds during crowdfunding + 2. `PreMatureContributorWithdrawal`: Withdraw funds if campaign fails/expires + 3. `PreMatureRemoveEmptyInstance`: Remove empty instance after deadline + 4. `RegisterCerts`: Register certificates and submit governance proposal + 5. `VoteOnGovAction`: Vote on governance proposal + 6. `DeregisterCerts`: Deregister certificates after governance period + 7. `AfterCompleteContributorWithdrawal`: Withdraw funds after governance completion + 8. `AfterCompleteRemoveEmptyInstance`: Remove empty instance after all funds withdrawn +- Dynamic deposit parameters (`stake_register_deposit`, `drep_register_deposit`, `gov_deposit`) to avoid hardcoding values +- Integrated validation for both crowdfunding and governance phases + +**States Managed**: +- `Crowdfunding`: Active crowdfunding campaign (can transition directly to governance) +- `Proposed`: Governance proposal submitted and voted on +- `Refundable`: Post-governance state ready for contributor withdrawals + +### 2. gCf_stake + +The stake script validator that coordinates governance operations. + +**Responsibilities**: +- Validates publishing operations (certificate registration/deregistration) +- Coordinates governance proposal submission +- Coordinates governance voting + +**Key Features**: +- Publishing operations coordinated with spend validator +- Governance operations coordinated with spend validator +- No token minting/burning - `auth_token` used throughout all phases + +**Integration**: +- Works in conjunction with `gCf_spend` to provide complete governance functionality +- Validates that spend validator operations are properly coordinated +- Stake validator script hash (`stake_hash`) stored in all datum states (`Crowdfund`, `Proposed`, `Voted`, `Refundable`) and used for proposal return address and DRep credential + +## Contract Lifecycle + +The contract follows a simplified lifecycle flow: + +### Crowdfunding Phase +- **Start**: Propose Governance Action to Crowdfund (campaign initialization) +- **Crowdfunding**: Active crowdfunding state +- **Contribute**: Contributors can add funds repeatedly, looping back to crowdfunding state +- **Contributor Withdrawal**: Contributors can withdraw funds if campaign fails or expires, looping back to crowdfunding state +- **Remove Empty**: Proposer can remove empty instance (from crowdfunding or refundable state), transitioning to End +- **If Funded**: When funding target is reached, transition to governance proposal and vote (Proposed state) + +### Governance Phase +- **Propose Governance Action & Vote**: When funding target is reached, register certificates, submit governance proposal, and vote on it, transitioning to Proposed state +- **Proposed**: Governance proposal has been submitted and voted on +- **After 6 Epochs**: Governance voting period completes, transitioning from Proposed to Deregister +- **Deregister**: Deregister certificates after governance period, transitioning to Refundable state + +### Completion Phase +- **Refundable**: Post-governance state ready for contributor withdrawals +- **Contributor Withdrawal**: Contributors can withdraw funds by burning share tokens, looping back to Refundable state +- **Remove Empty**: Proposer can remove empty instance from Refundable state, transitioning to End state +- **End**: Final state when instance is removed + +## State Transition Diagram + +```mermaid +--- +config: + theme: default + look: classic +--- +flowchart LR + A(["Propose
Governance Action
to Crowdfund"]) --> B(("Crowdfunding")) + B --> C(["Contribute"]) & D(["Contributer
Withdrawal"]) & n3(["Remove Empty"]) + B -- if Funded --> F(["Propose
Governance Action
& Vote"]) + C --> B + G(("Refundable")) --> I(["Contributer
Withdrawal"]) & n3 + F --> n1(("Proposed")) + I --> G + n2(["Deregister"]) --> G + n1 -- after
6 epochs --> n2 + D --> B + n3 --> H["End"] + H@{ shape: dbl-circ} +``` + +The diagram illustrates the simplified user-facing flow: +- **Propose Governance Action to Crowdfund**: Initial step to create and initialize the crowdfunding campaign +- **Crowdfunding**: The active phase where contributors can repeatedly contribute or withdraw funds, looping back to the crowdfunding state +- **Remove Empty**: Proposer can remove empty instances from either Crowdfunding or Refundable states, transitioning to End +- **Propose Governance Action & Vote**: When funding target is reached, governance proposal is submitted and voted on in a single transaction, transitioning to Proposed state +- **Proposed**: The governance proposal has been submitted and voted on, awaiting the governance period completion +- **Deregister**: After 6 epochs (governance voting period), certificates are deregistered, transitioning to Refundable state +- **Refundable**: Post-governance state where contributors can withdraw funds +- **Contributor Withdrawal**: Contributors can withdraw funds by burning share tokens, looping back to Refundable state until empty +- **End**: Final state when instance is removed (reached via Remove Empty action) + +### gCf_spend Parameters +- `auth_token`: PolicyId for crowdfunding authentication +- `proposer_key_hash`: Authorization for instance removal +- `gov_action`: The governance action to propose +- `delegate_pool_id`: Stake pool for delegation +- `stake_register_deposit`: Dynamic stake registration deposit +- `drep_register_deposit`: Dynamic DRep registration deposit +- `gov_deposit`: Dynamic governance proposal deposit + +### gCf_stake Parameters +- `auth_token`: Reference to crowdfunding token (for coordination) +- `spend`: Script hash of `gCf_spend` validator +- `gov_action_period`: Buffer period for governance operations diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/user_action_doc.md new file mode 100644 index 000000000..64dabc4da --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/specs/user_action_doc.md @@ -0,0 +1,116 @@ +# User Actions Documentation + +## Contributors (Normal Users) + +### Phase 1: Crowdfunding + +1. **ContributeFund** - Add funds to active crowdfunding campaign + - **Redeemer**: `ContributeFund` + - **Datum State**: `Crowdfund` → `Crowdfund` + - **Requirements**: + - Minimum contribution: 2 ADA (2,000,000 lovelace) + - Transaction must occur before `deadline` + - Share tokens minted proportionally to contribution amount + - **Validation**: Lovelace difference matches datum update, fundraise target respected, deadline not passed + +2. **PreMatureContributorWithdrawal** - Withdraw funds if campaign failed or expired + - **Redeemer**: `PreMatureContributorWithdrawal` + - **Datum State**: `Crowdfund` → `Crowdfund` + - **Requirements**: + - Either `deadline + expiry_buffer` has passed, OR campaign failed (`current_fundraised_amount <= fundraise_target`) + - Share tokens burned equal to lovelace withdrawn + - **Validation**: Validity period check OR fundraise failure check, share tokens burned match withdrawal + +### Phase 3: Post-Governance Refunds + +3. **AfterCompleteContributorWithdrawal** - Withdraw funds after governance completion + - **Redeemer**: `AfterCompleteContributorWithdrawal` + - **Datum State**: `Refundable` → `Refundable` + - **Requirements**: + - Burn `share_token` tokens (empty token name `""`) + - Lovelace withdrawn equals share tokens burned + - **Validation**: Lovelace withdrawn matches share tokens burned, datum correctly updated + +## Proposer + +### Phase 1: Crowdfunding + +1. **PreMatureRemoveEmptyInstance** - Remove empty crowdfunding instance after deadline + - **Redeemer**: `PreMatureRemoveEmptyInstance` + - **Datum State**: `Crowdfund` → (consumed) + - **Requirements**: + - `deadline` has passed + - If `current_fundraised_amount > 0`: Burn all `share_token` tokens and `auth_token` + - If `current_fundraised_amount == 0`: Burn only `auth_token` + - Must be signed by `proposer_key_hash` + - **Validation**: Deadline passed, appropriate tokens burned, proposer authorization + +### Phase 2: Governance + +2. **RegisterCerts & VoteOnGovAction** - Register certificates, delegate, submit governance proposal, and vote on it + - **Redeemers**: `RegisterCerts` followed by `VoteOnGovAction` (typically happen together or immediately sequentially) + - **Datum State**: `Crowdfund` → `Proposed` (via RegisterCerts), then `Proposed` → `Voted` (via VoteOnGovAction) + - **Requirements for RegisterCerts**: + - Exactly one input/output with `auth_token` (empty token name) from current address + - Register stake certificate (no deposit) + - Register DRep certificate (deposit: `drep_register_deposit`) + - Delegate vote to own DRep (Registered credential) + - Delegate stake to `delegate_pool_id` + - Submit governance proposal: + - Deposit: `gov_deposit` + - Return address: Script(`stake_hash` from datum) + - Governance action: `gov_action` + - Output value deducted by `stake_register_deposit + drep_register_deposit + gov_deposit` + - **Requirements for VoteOnGovAction**: + - Exactly one input/output with `auth_token` (empty token name) from current address + - DRep (Script(`stake_hash` from datum)) votes `Yes` on the governance action + - `gov_tx_id` recorded in output datum + - Input and output values identical + - **Validation**: Lovelace deduction matches deposits, all certificates present, proposal procedure valid, vote recorded correctly + - **Note**: From a user perspective, these actions happen together, transitioning from `Crowdfund` through `Proposed` to `Voted` state + +3. **DeregisterCerts** - Deregister certificates after governance period + - **Redeemer**: `DeregisterCerts` + - **Datum State**: `Voted` → `Refundable` + - **Requirements**: + - `deadline` has passed + - Exactly one input/output with `auth_token` (empty token name) from current address + - Unregister stake certificate (refund received) + - Unregister DRep certificate (refund: `drep_register_deposit`) + - Output value increased by `stake_register_deposit + drep_register_deposit + gov_deposit` + - **Validation**: Deadline passed, lovelace increase matches refunds, certificates deregistered + +### Phase 3: Post-Governance Cleanup + +4. **AfterCompleteRemoveEmptyInstance** - Remove empty instance after all funds withdrawn + - **Redeemer**: `AfterCompleteRemoveEmptyInstance` + - **Datum State**: `Refundable` → (consumed) + - **Requirements**: + - Exactly one input with token of policy `stake_hash` (from datum, empty token name) from current address + - If `funds_controlled > 0`: Burn all remaining `share_token` tokens (empty token name `""`) + - Burn `auth_token` (empty token name `""`) + - Must be signed by `proposer_key_hash` + - **Validation**: Appropriate tokens burned, proposer authorization + +## State Transitions Summary + +**Main Flow:** +``` +Crowdfund → RegisterCerts → Proposed +Proposed → VoteOnGovAction → Voted +Voted → DeregisterCerts → Refundable (after 6 epochs) +``` + +**Post-Governance:** +``` +Refundable → AfterCompleteContributorWithdrawal → Refundable (loop until empty) +Refundable → AfterCompleteRemoveEmptyInstance → (consumed) +``` + +**Note**: From a user perspective, `RegisterCerts` and `VoteOnGovAction` typically happen together (or immediately sequentially), quickly transitioning from `Crowdfund` through `Proposed` to `Voted` state. The `Voted` state then transitions to `Refundable` via `DeregisterCerts` after the governance period (6 epochs). The simplified diagram may show `Proposed` as representing the post-vote state for clarity. + +## Token Usage + +- **auth_token**: Identifies UTxOs throughout all phases (Phases 1-4). Token name is empty string (`""`) in all phases. Used consistently across crowdfunding and governance phases +- **share_token**: Proportional tokens minted/burned with contributions/withdrawals. Token name is empty string (`""`) in all phases +- **stake_hash**: Stored in all datum states (`Crowdfund`, `Proposed`, `Voted`, `Refundable`). This is the stake validator script hash, used as the return address for governance proposals and as the DRep credential for voting diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/auth_token/mint.ak new file mode 100644 index 000000000..b9389c8b5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/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 gcf_auth_mint(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/gov-crowdfundV2/validators/gcf_spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/gcf_spend.ak new file mode 100644 index 000000000..e9000604e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/gcf_spend.ak @@ -0,0 +1,463 @@ +use cardano/address.{Address, Inline, Script} +use cardano/assets.{Lovelace, PolicyId, lovelace_of} +use cardano/certificate.{Registered} +use cardano/governance.{DelegateRepresentative, GovernanceActionId} +use cardano/transaction.{Output, OutputReference, Transaction, find_input} +use cocktail.{ + inputs_at_with, inputs_at_with_policy, key_signed, only_minted_token, + output_inline_datum, outputs_at_with, outputs_at_with_policy, + policy_only_minted_token, valid_after, valid_before, value_length, +} +use gov.{VGovernanceAction} +use types.{ + AfterCompleteContributorWithdrawal, AfterCompleteRemoveEmptyInstance, + CompleteCrowdfund, ContributeFund, Crowdfund, CrowdfundGovDatum, + CrowdfundGovRedeemer, DeregisterCerts, PreMatureContributorWithdrawal, + PreMatureRemoveEmptyInstance, Proposed, Refundable, RegisterCerts, + VoteOnGovAction, Voted, +} +use utils.{ + check_fundraise_target, 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, +} + +// Unified spending validator handling both crowdfunding and governance operations +validator gCf_spend( + auth_token: PolicyId, + proposer_key_hash: ByteArray, + gov_action: VGovernanceAction, + delegate_pool_id: ByteArray, + // dynamic deposit parameters to avoid hardcoding values + stake_register_deposit: Lovelace, + drep_register_deposit: Lovelace, + gov_deposit: Lovelace, +) { + spend( + datum_opt: Option, + redeemer: CrowdfundGovRedeemer, + input: OutputReference, + self: Transaction, + ) { + let Transaction { + inputs, + validity_range, + mint, + outputs, + extra_signatories, + certificates, + proposal_procedures, + votes, + .. + } = 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 token input from current address + expect [auth_input] = + inputs_at_with_policy(inputs, current_address, auth_token) + + when redeemer is { + // Crowdfunding: Add funds to active campaign, mint proportional share tokens + ContributeFund -> + when auth_input_datum is { + Crowdfund { + stake_hash, + share_token, + crowdfund_address, + fundraise_target, + current_fundraised_amount: input_current_fundraised_amount, + allow_over_subscription, + deadline, + expiry_buffer, + min_charge, + } -> { + 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_raw: CrowdfundGovDatum = + output_inline_datum(auth_output) + + when auth_output_datum_raw is { + Crowdfund { + current_fundraised_amount: output_current_fundraised_amount, + .. + } -> { + let fundraise_added = + lovelace_from_auth_output - lovelace_from_auth_input + let fundraise_check = + (fundraise_added == output_current_fundraised_amount - input_current_fundraised_amount)? && (fundraise_added >= 2000000)? + + let fundraise_target_check = + check_fundraise_target( + allow_over_subscription, + fundraise_target, + output_current_fundraised_amount, + ) + + let validity_check = valid_before(validity_range, deadline) + + let output_datum_check = + auth_output_datum_raw == Crowdfund { + stake_hash, + share_token, + crowdfund_address, + fundraise_target, + current_fundraised_amount: input_current_fundraised_amount + fundraise_added, + allow_over_subscription, + deadline, + expiry_buffer, + min_charge, + } + + 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, + "", + fundraise_added, + )? + } + _ -> False + } + } + _ -> False + } + + // Crowdfunding: Withdraw funds before completion (failed campaign or expired) + PreMatureContributorWithdrawal -> + when auth_input_datum is { + Crowdfund { + stake_hash, + share_token, + crowdfund_address, + fundraise_target, + current_fundraised_amount: input_current_fundraised_amount, + allow_over_subscription, + deadline, + expiry_buffer, + min_charge, + } -> { + let validity_check = + valid_after(validity_range, deadline + expiry_buffer) + let fund_check = input_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_raw: CrowdfundGovDatum = + output_inline_datum(auth_output) + when auth_output_datum_raw is { + Crowdfund { current_fundraised_amount: _, .. } -> { + let output_datum_check = + auth_output_datum_raw == Crowdfund { + stake_hash, + share_token, + crowdfund_address, + fundraise_target, + current_fundraised_amount: input_current_fundraised_amount + lovelace_withdrawn, + allow_over_subscription, + deadline, + expiry_buffer, + min_charge, + } + + 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, + "", + lovelace_withdrawn, + )? + } + _ -> False + } + } + _ -> False + } + // Crowdfunding: Remove empty instance after deadline, burn tokens + PreMatureRemoveEmptyInstance -> + when auth_input_datum is { + Crowdfund { share_token, current_fundraised_amount, deadline, .. } -> { + let validity_check = valid_after(validity_range, deadline) + + let token_burnt_check = + if current_fundraised_amount > 0 { + policy_only_minted_token( + mint, + share_token, + "", + -current_fundraised_amount, + )? && policy_only_minted_token(mint, auth_token, "", -1)? + } else { + only_minted_token(mint, auth_token, "", -1)? + } + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + validity_check? && token_burnt_check? && proposer_key_signed_check? + } + _ -> False + } + + // Governance: Register certificates, delegate, submit proposal (Crowdfund → Proposed) + RegisterCerts -> + when auth_input_datum is { + Crowdfund { + stake_hash, + share_token, + current_fundraised_amount, + deadline, + .. + } -> { + // check only 1 input with token from current address + expect [only_input] = + inputs_at_with(inputs, current_address, auth_token, "") + expect Some(current_stake_credential) = + current_address.stake_credential + + expect Inline(current_credential) = current_stake_credential + + expect [only_output] = + outputs_at_with(outputs, current_address, auth_token, "") + + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + -(stake_register_deposit + drep_register_deposit + gov_deposit), + ) + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Proposed { + stake_hash, + share_token, + funds_controlled: current_fundraised_amount, + 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 = + check_proposal_procedure( + proposal_procedures, + gov_deposit, + Script(stake_hash), + 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 + } + // Governance: Record vote on proposal (Proposed → Voted) + VoteOnGovAction -> + when auth_input_datum is { + Proposed { stake_hash, share_token, funds_controlled, deadline } -> { + // check only 1 input with authtoken residing at current address + expect [only_input] = + inputs_at_with(inputs, current_address, auth_token, "") + expect [only_output] = + outputs_at_with(outputs, current_address, auth_token, "") + + 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 { + stake_hash, + share_token, + funds_controlled, + gov_tx_id, + deadline, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + + value_check? && output_datum_check? && is_only_output_value_clean? && check_vote( + votes, + DelegateRepresentative(Script(stake_hash)), + gov_tx_id, + ) + } + _ -> False + } + // Governance: Deregister certificates after governance period (Voted → Refundable) + DeregisterCerts -> + when auth_input_datum is { + Voted { stake_hash, share_token, funds_controlled, deadline, .. } -> { + // check only 1 input with token from current address + expect [only_input] = + inputs_at_with(inputs, current_address, auth_token, "") + 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_with(outputs, current_address, auth_token, "") + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + stake_register_deposit + drep_register_deposit + gov_deposit, + ) + + expect only_output_datum: CrowdfundGovDatum = + output_inline_datum(only_output) + let output_datum_check = + only_output_datum == Refundable { + stake_hash, + share_token, + funds_controlled, + } + + 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, + ) + + 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 + } + + // Post-governance: Withdraw funds by burning share tokens + AfterCompleteContributorWithdrawal -> + when auth_input_datum is { + Refundable { stake_hash, share_token, funds_controlled } -> { + // check only 1 input with token from current address + expect [only_input] = + inputs_at_with(inputs, current_address, auth_token, "") + expect [only_output] = + outputs_at_with(outputs, current_address, auth_token, "") + + 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 { + stake_hash, + share_token, + funds_controlled: funds_controlled + lovelace_withdrawn, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + + lovelace_withdrawn_check? && output_datum_check? && is_only_output_value_clean? && only_minted_token( + mint, + share_token, + "", + lovelace_withdrawn, + )? + } + _ -> False + } + + // CompleteCrowdfund - Not implemented in gov-crowdfundV2 (uses governance flow instead) + CompleteCrowdfund -> False + + // Post-governance: Remove empty instance after all funds withdrawn + AfterCompleteRemoveEmptyInstance -> + when auth_input_datum is { + Refundable { stake_hash, share_token, funds_controlled } -> { + // check only 1 input with token from current address + expect [_] = inputs_at_with(inputs, current_address, stake_hash, "") + let token_burnt_check = + if funds_controlled > 0 { + policy_only_minted_token( + mint, + share_token, + "", + -funds_controlled, + ) + } else { + True + } + + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + token_burnt_check? && proposer_key_signed_check? && policy_only_minted_token( + mint, + auth_token, + "", + -1, + )? + } + _ -> False + } + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/gcf_stake.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/gcf_stake.ak new file mode 100644 index 000000000..53bc2174e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/gcf_stake.ak @@ -0,0 +1,58 @@ +use cardano/address.{from_script} +use cardano/assets.{PolicyId} +use cardano/transaction.{Transaction} +use cocktail.{inputs_at} +use types.{ + CrowdfundGovRedeemer, Deregister, DeregisterCerts, PublishRedeemer, Register, + RegisterCerts, VoteOnGovAction, +} +use utils.{check_spend_script_input_redeemer, redeemer_with_input} + +// Stake validator coordinating governance operations and token lifecycle +validator gCf_stake( + _auth_token: PolicyId, + spend: ByteArray, + _gov_action_period: Int, +) { + // Publish: Validate certificate registration/deregistration coordination + 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: CrowdfundGovRedeemer = only_inpuy_redeemer_data + + when redeemer is { + // Register: Validate spend validator is registering certificates + Register -> { + let redeemer_check = only_input_redeemer == RegisterCerts + + redeemer_check? + } + // Deregister: Validate spend validator is deregistering certificates + Deregister -> { + let redeemer_check = only_input_redeemer == DeregisterCerts + + redeemer_check? + } + } + } + + // Propose: Validate governance proposal submission coordination + propose(_r, _p, self: Transaction) { + let Transaction { inputs, redeemers, .. } = self + check_spend_script_input_redeemer(spend, inputs, redeemers, RegisterCerts)? + } + + // Vote: Validate governance vote coordination + vote(_r, _v, self: Transaction) { + let Transaction { inputs, redeemers, .. } = self + check_spend_script_input_redeemer(spend, inputs, redeemers, VoteOnGovAction)? + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/share_token/mint.ak new file mode 100644 index 000000000..01df88ab6 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/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, CrowdfundGovRedeemer, 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: CrowdfundGovRedeemer = auth_token_redeemer_data + + let redeemer_check = auth_token_redeemer == ContributeFund + + redeemer_check? + } + RBurn -> quantity < 0 + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/integration_test/complete_crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/integration_test/complete_crowdfund.ak new file mode 100644 index 000000000..dfdb3dbfc --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/integration_test/complete_crowdfund.ak @@ -0,0 +1,198 @@ +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction} +use gcf_spend as gcf_spend_validator +use mocktail.{ + add_redeemer, complete, mint, mock_policy_id, mock_tx_hash, + mock_utxo_ref, mocktail_tx, script_withdrawal, tx_in, tx_in_inline_datum, + tx_out, tx_out_inline_datum, +} +use share_token/mint as share_token_mint +use tests/test_utils.{ + mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_crowdfund_datum, mock_current_fundraised_amount, + mock_delegate_pool_id, mock_drep_register_deposit, mock_fee_address, + mock_fundraise_target, mock_gov_action, mock_gov_deposit, + mock_gov_address, mock_min_charge, mock_proposer_key_hash, mock_share_token, + mock_stake_hash, mock_stake_register_deposit, +} +use types.{CompleteCrowdfund, CrowdfundGovRedeemer, RegisterCerts, RMint} + +// Note: CompleteCrowdfund is not implemented in V2 (returns False) +// This test file is kept for reference but tests will fail as expected +// The actual completion flow uses RegisterCerts instead + +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: CrowdfundGovRedeemer, +) -> 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_stake_hash, "", 1) + } else { + from_lovelace(mock_fundraise_target - 1000000) + |> add(mock_stake_hash, "", 1) + } + let fundraise_output_datum = + if is_fundraise_output_datum_correct { + mock_crowdfund_datum(current_fundraised_amount, False) + } else { + mock_crowdfund_datum(current_fundraised_amount + 1000000, False) + } + let input_value = + from_lovelace(current_fundraised_amount + mock_min_charge) + |> add(mock_auth_token, "", 1) + + let output_value = from_lovelace(mock_min_charge) + + 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_current_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, "") + |> mint(is_token_minted, 1, mock_stake_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: CrowdfundGovRedeemer, + _stake_hash: ByteArray, +) { + let tx = + mock_complete_crowdfund_tx( + test_case, + current_fundraised_amount, + auth_token_redeemer, + ) + + let check_auth_spend = + gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(mock_crowdfund_datum(mock_current_fundraised_amount, False)), + auth_token_redeemer, + mock_utxo_ref(0, 0), + tx, + ) + let check_token_mint = + share_token_mint.share_token.mint( + mock_auth_token, + RMint, + mock_share_token, + tx, + ) + + // Note: V2 doesn't have withdraw/mint for stake validator like V1 + // The stake validator only handles publish/propose/vote + check_auth_spend? && check_token_mint? +} + +// These tests will fail as CompleteCrowdfund returns False in V2 +// They are kept for reference/documentation purposes + +test complete_crowdfund_fail_not_implemented() { + 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, + } + + // CompleteCrowdfund is not implemented in V2 + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + CompleteCrowdfund, + mock_stake_hash, + ) +} + +test complete_crowdfund_fail_with_input_wrong_redeemer() { + 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, + } + + // Using RegisterCerts instead - this should also fail for CompleteCrowdfund flow + !check_all_scripts( + test_case, + mock_current_fundraised_amount, + RegisterCerts, + mock_stake_hash, + ) +} + diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_spend.ak new file mode 100644 index 000000000..04ac3d5cd --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_spend.ak @@ -0,0 +1,650 @@ +use cardano/address.{Script} +use cardano/assets.{add, from_lovelace} +use cardano/certificate.{ + DelegateBlockProduction, DelegateCredential, DelegateVote, RegisterCredential, + RegisterDelegateRepresentative, Registered, +} +use cardano/governance.{NoConfidence, ProposalProcedure} +use cardano/transaction.{Transaction} +use gcf_spend as gcf_spend_validator +use mocktail.{ + add_certificate, complete, mock_policy_id, mock_tx_hash, mock_utxo_ref, + mocktail_tx, tx_in, tx_in_inline_datum, tx_out, tx_out_inline_datum, +} +use tests/test_utils.{ + add_proposal_procedure, mock_auth_token, mock_crowdfund_address, mock_deadline, + mock_delegate_pool_id, mock_drep_register_deposit, mock_fundraise_target, + mock_funds_controlled, mock_gov_action, mock_gov_action_period, + mock_gov_address, mock_gov_deposit, mock_proposer_key_hash, mock_share_token, + mock_stake_hash, mock_stake_register_deposit, +} +use types.{Crowdfund, CrowdfundGovDatum, Proposed, RegisterCerts} + +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_stake_hash, "", 1) + |> add(mock_auth_token, "", 1) + + let input_datum: CrowdfundGovDatum = + Crowdfund { + stake_hash: mock_stake_hash, + share_token: mock_share_token, + crowdfund_address: mock_crowdfund_address, + fundraise_target: mock_fundraise_target, + current_fundraised_amount: mock_funds_controlled, + allow_over_subscription: False, + deadline: mock_deadline + mock_gov_action_period, + expiry_buffer: 3600 * 24, + min_charge: 10, + } + let output_value = + if is_output_value_correct { + from_lovelace( + mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit - mock_gov_deposit, + ) + |> add(mock_stake_hash, "", 1) + |> add(mock_auth_token, "", 1) + } else { + from_lovelace( + mock_funds_controlled - mock_stake_register_deposit - mock_drep_register_deposit - mock_gov_deposit + 10, + ) + |> add(mock_stake_hash, "", 1) + |> add(mock_auth_token, "", 1) + } + + let output_datum: CrowdfundGovDatum = + if is_output_datum_correct { + Proposed { + stake_hash: mock_stake_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + } + } else { + Proposed { + stake_hash: mock_stake_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_stake_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_stake_hash), + deposit: Never, + }, + ) + |> add_certificate( + is_drep_cert_register, + RegisterDelegateRepresentative { + delegate_representative: Script(mock_stake_hash), + deposit: drep_deposit, + }, + ) + |> add_certificate( + is_stake_delegated, + DelegateCredential { + credential: Script(mock_stake_hash), + delegate: DelegateBlockProduction { + stake_pool: mock_delegate_pool_id, + }, + }, + ) + |> add_certificate( + is_vote_delegated, + DelegateCredential { + credential: Script(mock_stake_hash), + delegate: DelegateVote { + delegate_representative: Registered(Script(mock_stake_hash)), + }, + }, + ) + |> add_proposal_procedure( + is_gov_proposed, + ProposalProcedure { + deposit: mock_gov_deposit, + return_address: Script(mock_stake_hash), + governance_action: NoConfidence { ancestor: None }, + }, + ) +} + +test s1_spend_success_reg_cert() { + let input_datum: CrowdfundGovDatum = + Crowdfund { + stake_hash: mock_stake_hash, + share_token: mock_share_token, + crowdfund_address: mock_crowdfund_address, + fundraise_target: mock_fundraise_target, + current_fundraised_amount: mock_funds_controlled, + allow_over_subscription: False, + deadline: mock_deadline + mock_gov_action_period, + expiry_buffer: 3600 * 24, + min_charge: 10, + } + 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, + }, + ) + + gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_not_crowdfund_state() { + let input_datum: CrowdfundGovDatum = + Proposed { + stake_hash: mock_stake_hash, + share_token: mock_share_token, + funds_controlled: mock_funds_controlled, + deadline: mock_deadline + mock_gov_action_period, + } + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_more_than_one_input() fail { + let input_datum: CrowdfundGovDatum = + Crowdfund { + stake_hash: mock_stake_hash, + share_token: mock_share_token, + crowdfund_address: mock_crowdfund_address, + fundraise_target: mock_fundraise_target, + current_fundraised_amount: mock_funds_controlled, + allow_over_subscription: False, + deadline: mock_deadline + mock_gov_action_period, + expiry_buffer: 3600 * 24, + min_charge: 10, + } + 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, + }, + ) + + gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +fn mock_crowdfund_datum_for_tests() -> CrowdfundGovDatum { + Crowdfund { + stake_hash: mock_stake_hash, + share_token: mock_share_token, + crowdfund_address: mock_crowdfund_address, + fundraise_target: mock_fundraise_target, + current_fundraised_amount: mock_funds_controlled, + allow_over_subscription: False, + deadline: mock_deadline + mock_gov_action_period, + expiry_buffer: 3600 * 24, + min_charge: 10, + } +} + +test s1_spend_fail_reg_cert_with_more_than_one_output() fail { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_incorrect_output_datum() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_output_value_not_clean() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_incorrect_output_value() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_stake_cert_not_reg() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_drep_cert_not_reg() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_drep_deposit_incorrect() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_stake_not_delegated() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_vote_not_delegated() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_spend_fail_reg_cert_with_gov_not_proposed() { + let input_datum = mock_crowdfund_datum_for_tests() + 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, + }, + ) + + !gcf_spend_validator.gCf_spend.spend( + mock_auth_token, + mock_proposer_key_hash, + mock_gov_action, + mock_delegate_pool_id, + mock_stake_register_deposit, + mock_drep_register_deposit, + mock_gov_deposit, + Some(input_datum), + RegisterCerts, + mock_utxo_ref(0, 0), + tx, + ) +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_start.ak new file mode 100644 index 000000000..20998ff46 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_start.ak @@ -0,0 +1,249 @@ +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction} +use gcf_stake as gcf_stake_validator +use mocktail.{ + add_redeemer, complete, mock_tx_hash, mocktail_tx, + tx_in, +} +use tests/test_utils.{ + mock_auth_token, mock_crowdfund_gov_address, + mock_fundraise_target, mock_gov_action_period, + mock_spend_script_hash, mock_stake_hash, +} +use types.{ + Deregister, DeregisterCerts, Register, RegisterCerts, + VoteOnGovAction, +} + +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_stake_hash, "", 1) + |> add(mock_auth_token, "", 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_publish_with_reg() { + let only_input_redeemer: Data = RegisterCerts + + let tx = + mock_start_tx( + StartTestCase { is_only_one_spend_inputed: True }, + only_input_redeemer, + ) + gcf_stake_validator.gCf_stake.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, + ) + gcf_stake_validator.gCf_stake.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, + ) + !gcf_stake_validator.gCf_stake.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, + ) + !gcf_stake_validator.gCf_stake.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, + ) + gcf_stake_validator.gCf_stake.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, + ) + gcf_stake_validator.gCf_stake.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, + ) + !gcf_stake_validator.gCf_stake.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, + ) + gcf_stake_validator.gCf_stake.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, + ) + gcf_stake_validator.gCf_stake.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, + ) + !gcf_stake_validator.gCf_stake.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, + ) + gcf_stake_validator.gCf_stake.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-crowdfundV2/validators/tests/test_utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_utils.ak new file mode 100644 index 000000000..595f16dbe --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfundV2/validators/tests/test_utils.ak @@ -0,0 +1,123 @@ +use aiken/collection/list +use cardano/address.{Address, Inline, Script, from_script} +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_tx_hash, +} +use types.{Crowdfund, CrowdfundGovDatum} + +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_extra_fundraised_amount = 4000000 + +pub const mock_min_charge = 10 + +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 fn mock_crowdfund_datum( + current_fundraised_amount: Int, + allow_over_subscription: Bool, +) -> CrowdfundGovDatum { + Crowdfund { + stake_hash: mock_stake_hash, + 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, + min_charge: mock_min_charge, + } +} + +pub const mock_stake_hash = mock_script_hash(0) + +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_gov_address = + Address { + payment_credential: Script(mock_spend_script_hash), + stake_credential: Some(Inline(Script(mock_stake_hash))), + } + +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_gov_deposit = 50000000 + +pub const mock_funds_controlled = + 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, + condition: Bool, + proposal_procedure: ProposalProcedure, +) -> Transaction { + if !condition { + tx + } else { + Transaction { + ..tx, + proposal_procedures: tx.proposal_procedures + |> list.concat([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]), + } + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/.github/workflows/continuous-integration.yml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/.github/workflows/continuous-integration.yml new file mode 100644 index 000000000..ba419b4a2 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/.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-extension/.gitignore b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/.gitignore new file mode 100644 index 000000000..ff7811b15 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/.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-extension/README.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/README.md new file mode 100644 index 000000000..de5ef005b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/README.md @@ -0,0 +1 @@ +Implement separately & publish SDK diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/aiken.lock b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/aiken.lock new file mode 100644 index 000000000..2e65bd164 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/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-extension/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/aiken.toml new file mode 100644 index 000000000..bff202272 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/aiken.toml @@ -0,0 +1,23 @@ +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 = "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-extension/lib/gov.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/gov.ak new file mode 100644 index 000000000..a1cf32eed --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/gov.ak @@ -0,0 +1,87 @@ +use aiken/cbor +use aiken/crypto.{ScriptHash} +use cardano/address.{Credential} +use cardano/assets.{Lovelace} +use cardano/governance.{ + Constitution, GovernanceActionId, Mandate, ProtocolVersion, +} + +type ProtocolParametersIndex = + Int + +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 + /// 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: VRational, + } + 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 +} + +test action_test() { + trace cbor.serialise(NicePoll) + "" == "" +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/types.ak new file mode 100644 index 000000000..90eb956d5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/types.ak @@ -0,0 +1,60 @@ +use cardano/address.{Address} +use cardano/governance.{GovernanceActionId} + +pub type CrowdfundRedeemer { + RegisterCerts + VoteOnGovAction + DeregisterCerts + 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, +} + +pub type CrowdfundGovDatum { + Init { + start_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + Proposed { + 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 { + start_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + } +} + +pub type MintPolarity { + RMint + RBurn +} + +pub type PublishRedeemer { + Register + Deregister +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/utils.ak new file mode 100644 index 000000000..0d66337fe --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/lib/utils.ak @@ -0,0 +1,168 @@ +use aiken/cbor +use aiken/collection/list +use aiken/collection/pairs.{get_first} +use cardano/address.{Credential, from_script} +use cardano/assets.{Lovelace, lovelace_of} +use cardano/certificate.{ + Certificate, DelegateBlockProduction, DelegateBoth, DelegateCredential, + DelegateRepresentative, DelegateVote, RegisterCredential, + 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( + redeemers: Pairs, + input: Input, +) -> Option { + 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 +} + +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 +} + +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-extension/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/plutus.json new file mode 100644 index 000000000..ea69aa018 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/plutus.json @@ -0,0 +1,1088 @@ +{ + "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": "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/cardano~1assets~1PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "5911d60101002229800aba2aba1aba0aab9faab9eaab9dab9a9bae0039bae00248888888896600264653001300a00198051805800cdc3a4005300a0024888966002600460146ea800e33001300b3754007370e90024dc3a4001300a375400891111991192cc004c0140122b3001301237540170018b20268acc004c0240122b3001301237540170018b20268acc004c0180122b3001301237540170018b20268acc004cdc3a400c00915980098091baa00b800c590134590102020404080804ca6002602c602c0033758602a003374a900024446464653001301b0019919800800803112cc004006298103d87a80008992cc004cdd7980f180d9baa00100c898039980e800a5eb82266006006603e00480c8c07400501b4dd6180d8034dd5980d801a4444b3001300f301b37540071598009807980d9baa00c8991919912cc004c09000a33001302300298101baa001980f9baa01991192cc004c05800626464b300130290028024590261bae302700130233754007159800980d000c4c8c96600260520050048b204c375c604e00260466ea800e2c810902118109baa0029b91489009b8f4881009b80480092222222980098158034dd7181500348966002603860506ea800a2646464b3001303000289980498178018992cc004c080006264b30013032001899192cc004c08c006264b30013035001899807181a000804c5903218181baa0028acc004c09c00626464653001375a606c003375a606c007375a606c0049112cc004c0e801201d1640dc30360013035001303037540051640b88170c0b8dd50009818800c5902f18169baa0028acc004c0900062b3001302d37540050058b205c8b205640ac60566ea80062c8168c0b8004c0b8004c0a4dd500145902748c966002604060506ea80062900044dd6981618149baa001409c64b300130203028375400314c103d87a8000899198008009bab302d302a375400444b30010018a6103d87a8000899192cc004c0240062b300130080018980c99817981680125eb82298103d87a800040ad133004004303100340ac6eb8c0ac004c0b800502c204e32330010010022259800800c5300103d87a8000899192cc004c0200062b300130070018980c19817181600125eb82298103d87a800040a9133004004303000340a86eb8c0a8004c0b400502b24444646464646465300130340019bad30343035001912cc004c098c0c8dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c1000066eb8c10002a6eb8c1000266eb4c10001e6eb4c10001a64b3001303e0018acc004cdc4a4008607a003168981a981e800a0788b207e3754608000b375a6080009375a60800073040002488888888966002609401513301d304901113301d0010148b208e1820000981f800981f000981e800981e000981d800981d000981c800981c00098199baa0028b20629bae303400a9bad30340069bad3034005981418181baa30340049bad303400348888888966002605802f13259800981f000c4ca600260226eacc07cc0ecdd5000cc966002606060766ea80062607e60786ea80062c81d0c0f8c0fcc0fcc0ecdd5000cc044dd5980f981d9baa301f303b375403691119805801099912cc0056600266e1c008cdc09bad3001304037540080151337129040497a008014528207c8acc0056600201314a31337126eb4c004c100dd5002005a07c8acc004c8c8c966002607460846ea80062b3001303a30423754608c608e0051337106eb4c118c10cdd5000805c4cdc49bad304630433754002016820a2941041182280099821982200099821cc004c0e0c100dd518221822800d300103d87a8000a60103d879800040fc97ae0304037546086608860806ea80a22b30013375e0086464646460606608c608e0086608c608e0066608c608e0046608c608e0026608c6ea0cdc00070031824182400098238009823000982280098201baa0218acc004c0d0c966002003148002264603864b30010028a40011301d330010013047002411044b30010018a40011301e3300200230480014114608a0028210c8cc004004dd5981298209baa0072259800800c52f5c1132332232330010013756608c00844b30010018801c4c8cc128dd3998251ba90053304a30470013304a30480014bd701980180198260011825000a090375c608400266006006608e004608a002821a26644b30010018014566002608c003132325980099b8f375c608e00402115980099b8f375c608e00203913370e6eb4c11cc12000401a29410424528208430470013758608a003002410c82185281919800800813112cc004006297ae0899199119198008009bab30460042259800800c400e264660946e9ccc128dd4802998251823800998251824000a5eb80cc00c00cc130008c1280050481bae30420013300300330470023045001410d14a081f2294103e4528207c8a5040f914a081f0cdc08018009182118219821982198218008c0f40062c81d8c8cc004004080896600200314bd7044cc8966002b30013375e6080607a6ea80080822646600200264660020026eacc108c10cc0fcdd5002112cc004006297ae0899199119198008009bab30440042259800800c400e264660906e9ccc120dd4802998241822800998241823000a5eb80cc00c00cc128008c1200050461bae30400013300300330450023043001410444b30010018a508acc004cdc79bae30423758608400207914a3133002002304300140f48202294103b44cc0fc008cc01001000626600800800281d8c0f8004c0fc00503c44c9660026062031159800acc004c0b40222946264b3001303f0018992cc004cdc480518091bab3020303c375400313375e6e98c8cc004004dd59810981e9baa0022259800800c52f5bded8c113298009bae303e0019bab303f00198218012444b3001301e0038acc004c07400e200310054101133044337606ea400cdd300119803003000a0801820800a07e4c101a0008a5040e8607c0031640f0646600200204244b30010018a5eb8226644b30013375e6082607c6ea80080362660800046600800800313300400400140f0607e002608000281e9038456600266e240140122b30013232330010013756607e04c44b30010018a508acc004cdd7801981e1820000c528c4cc008008c10400503b207c3374a90011981e1ba90124bd70456600266e24cdc000400218081bab301e303a3754603c60746ea806a26644b3001001801456600260800031325980099b8f375c608000202b13004375a6080608200314a081d8c100dd6181f800c00903d207a14a06466002002646600200204244b30010018a5eb82264664464660020026eacc10401089660020031003899198229ba733045375200a6608a60840026608a608600297ae03300300330470023045001410c6eb8c0f4004cc00c00cc108008c10000503e112cc004006297ae0899912cc004cdc79bae304100203b8998201ba700233004004001899802002000a0783758607e002608000281ea2941038452820708a5040e114a081c22b3001302e0188cc004c8c8cc8966002606a607a6ea800a2b30013035303d3754608260840071337100026eb4c104c0f8dd500144cdc48009bad3041303e375400481e2294103c181f80099b80004375a607e01a6607a607c0026607b30013032303a3754607c607e0034c0103d87a8000a60103d879800040e497ae0303a3754607a60746ea808a66e24010016646600200204244b30010018a5eb8226644b30015980099baf3041303e375400404313233001001323300100137566086608860806ea8010896600200314bd7044c8cc88c8cc004004dd59822802112cc004006200713233049374e660926ea4014cc124c118004cc124c11c0052f5c066006006609600460920028238dd718208009980180198230011822000a0842259800800c528456600266e3cdd718219bac304300103d8a518998010011822000a07c410514a081e22660800046600800800313300400400140f0607e002608000281e9222598009820800c4c8c8cc88cc038004566002b30010078a518803207e8acc00400a2b30013375e0026464646460626608e60900086608e60900066608e60900046608e60900026608e6ea0cdc00078039824982480098240009823800982300098209baa0228acc004c0d4c966002003148002264603a64b30010028a40011301e330010013048002411444b30010018a40011301f3300200230490014118608c0028218c8cc004004dd5981318211baa0052259800800c52f5c1132332232330010013756608e00844b30010018801c4c8cc12cdd3998259ba90053304b30480013304b30490014bd701980180198268011825800a092375c6086002660060066090004608c002822226644b30010018014566002608e003132325980099b8f375c609000402315980099b8f375c609000203b13370e6eb4c120c12400401e29410434528208630480013758608c003002411082205281919800800813912cc004006297ae0899199119198008009bab30470042259800800c400e264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c0050491bae30430013300300330480023046001411114a081fa294103f4528207e8a5040fc66e2000520003259800981a181f9baa0018982198201baa0018b207c304230433043303f375400466e04c050dd59811181f1baa001301437566044607c6ea8c088c0f8dd500f1820000c5903e22b300132323259800981a181e1baa0018acc004c0d0c0f0dd51820182080144cdc40029bad3040303d375400313371200a6eb4c100c0f4dd5000a0768a5040ec607e0026607a607c0026607b30013032303a3754607c607e0034c0103d87a8000a60103d879800040e497ae0303a3754607a60746ea808a2b30015980099b88480000122b3001980099b814800001229426466002002646600200204244b30010018a5eb82264664464660020026eacc10401089660020031003899198229ba733045375200a6608a60840026608a608600297ae03300300330470023045001410c6eb8c0f4004cc00c00cc108008c10000503e112cc004006297ae0899912cc004cdc79bae304100200a8998201ba700233004004001899802002000a0783758607e002608000281e922259800800c00a2b300130410018992cc004cdc79bae3041001016899b87375a6082608400200914a081e0c104dd61820000c00903e207c44cc89660020030028acc004c100006264b30013371e6eb8c100004056260086eb4c100c104006294103b18201bac303f001801207a40f42940c8cc004004c8cc004004084896600200314bd7044c8cc88c8cc004004dd59820802112cc004006200713233045374e6608a6ea4014cc114c108004cc114c10c0052f5c066006006608e004608a0028218dd7181e8009980180198210011820000a07c2259800800c52f5c1133225980099b8f375c6082004077133040374e0046600800800313300400400140f06eb0c0fc004c10000503d45282070899912cc0040060051598009820000c4c8c96600266e3cdd7182080101dc56600266e3cdd7182080080b44c014dd698209821000c52820788a5040f060820026eb0c0fc00600481e903d0a5032330010010202259800800c52f5c1132332232330010013756608000844b30010018801c4c8cc110dd3998221ba90053304430410013304430420014bd701980180198230011822000a084375c6078002660060066082004607e00281e903844c8cc004004dd6181f181f812112cc00400629422b30013371e6eb8c0fc0040e22946266004004608000281d103d452820708a5040e081c10381b87480050370c0d0004c0cc004c0c8004c0c4004c0c0004c0bcc0bc0108b2042323300100100c2259800800c52f5c11332259800acc004cdd7981298111baa302530263022375400400b1323300100132330010013756604e605060486ea8c09cc0a0c090dd5002112cc004006297ae0899199119198008009bab30290042259800800c400e2646605a6e9ccc0b4dd4802998169815000998169815800a5eb80cc00c00cc0bc008c0b400502b1bae302500133003003302a0023028001409844b30010018a508acc004cdc79bae30273758604e00204314a313300200230280014088812a294102044cc090008cc0100100062660080080028100c08c004c0900050211810980f1baa00e3020301d37546002603a6ea8c080c074dd5002118101810800c5901a45901a0c06c004c068c068004c064c06400c60226ea801cc048010c048c04c011164024300a00130053754015149a26cac8019", + "hash": "329ae820b7bc0d7e59e16fca08631bb79dd7817fb5d1a50941e2cd6b" + }, + { + "title": "crowdfund.crowdfund.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "5911d60101002229800aba2aba1aba0aab9faab9eaab9dab9a9bae0039bae00248888888896600264653001300a00198051805800cdc3a4005300a0024888966002600460146ea800e33001300b3754007370e90024dc3a4001300a375400891111991192cc004c0140122b3001301237540170018b20268acc004c0240122b3001301237540170018b20268acc004c0180122b3001301237540170018b20268acc004cdc3a400c00915980098091baa00b800c590134590102020404080804ca6002602c602c0033758602a003374a900024446464653001301b0019919800800803112cc004006298103d87a80008992cc004cdd7980f180d9baa00100c898039980e800a5eb82266006006603e00480c8c07400501b4dd6180d8034dd5980d801a4444b3001300f301b37540071598009807980d9baa00c8991919912cc004c09000a33001302300298101baa001980f9baa01991192cc004c05800626464b300130290028024590261bae302700130233754007159800980d000c4c8c96600260520050048b204c375c604e00260466ea800e2c810902118109baa0029b91489009b8f4881009b80480092222222980098158034dd7181500348966002603860506ea800a2646464b3001303000289980498178018992cc004c080006264b30013032001899192cc004c08c006264b30013035001899807181a000804c5903218181baa0028acc004c09c00626464653001375a606c003375a606c007375a606c0049112cc004c0e801201d1640dc30360013035001303037540051640b88170c0b8dd50009818800c5902f18169baa0028acc004c0900062b3001302d37540050058b205c8b205640ac60566ea80062c8168c0b8004c0b8004c0a4dd500145902748c966002604060506ea80062900044dd6981618149baa001409c64b300130203028375400314c103d87a8000899198008009bab302d302a375400444b30010018a6103d87a8000899192cc004c0240062b300130080018980c99817981680125eb82298103d87a800040ad133004004303100340ac6eb8c0ac004c0b800502c204e32330010010022259800800c5300103d87a8000899192cc004c0200062b300130070018980c19817181600125eb82298103d87a800040a9133004004303000340a86eb8c0a8004c0b400502b24444646464646465300130340019bad30343035001912cc004c098c0c8dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c1000066eb8c10002a6eb8c1000266eb4c10001e6eb4c10001a64b3001303e0018acc004cdc4a4008607a003168981a981e800a0788b207e3754608000b375a6080009375a60800073040002488888888966002609401513301d304901113301d0010148b208e1820000981f800981f000981e800981e000981d800981d000981c800981c00098199baa0028b20629bae303400a9bad30340069bad3034005981418181baa30340049bad303400348888888966002605802f13259800981f000c4ca600260226eacc07cc0ecdd5000cc966002606060766ea80062607e60786ea80062c81d0c0f8c0fcc0fcc0ecdd5000cc044dd5980f981d9baa301f303b375403691119805801099912cc0056600266e1c008cdc09bad3001304037540080151337129040497a008014528207c8acc0056600201314a31337126eb4c004c100dd5002005a07c8acc004c8c8c966002607460846ea80062b3001303a30423754608c608e0051337106eb4c118c10cdd5000805c4cdc49bad304630433754002016820a2941041182280099821982200099821cc004c0e0c100dd518221822800d300103d87a8000a60103d879800040fc97ae0304037546086608860806ea80a22b30013375e0086464646460606608c608e0086608c608e0066608c608e0046608c608e0026608c6ea0cdc00070031824182400098238009823000982280098201baa0218acc004c0d0c966002003148002264603864b30010028a40011301d330010013047002411044b30010018a40011301e3300200230480014114608a0028210c8cc004004dd5981298209baa0072259800800c52f5c1132332232330010013756608c00844b30010018801c4c8cc128dd3998251ba90053304a30470013304a30480014bd701980180198260011825000a090375c608400266006006608e004608a002821a26644b30010018014566002608c003132325980099b8f375c608e00402115980099b8f375c608e00203913370e6eb4c11cc12000401a29410424528208430470013758608a003002410c82185281919800800813112cc004006297ae0899199119198008009bab30460042259800800c400e264660946e9ccc128dd4802998251823800998251824000a5eb80cc00c00cc130008c1280050481bae30420013300300330470023045001410d14a081f2294103e4528207c8a5040f914a081f0cdc08018009182118219821982198218008c0f40062c81d8c8cc004004080896600200314bd7044cc8966002b30013375e6080607a6ea80080822646600200264660020026eacc108c10cc0fcdd5002112cc004006297ae0899199119198008009bab30440042259800800c400e264660906e9ccc120dd4802998241822800998241823000a5eb80cc00c00cc128008c1200050461bae30400013300300330450023043001410444b30010018a508acc004cdc79bae30423758608400207914a3133002002304300140f48202294103b44cc0fc008cc01001000626600800800281d8c0f8004c0fc00503c44c9660026062031159800acc004c0b40222946264b3001303f0018992cc004cdc480518091bab3020303c375400313375e6e98c8cc004004dd59810981e9baa0022259800800c52f5bded8c113298009bae303e0019bab303f00198218012444b3001301e0038acc004c07400e200310054101133044337606ea400cdd300119803003000a0801820800a07e4c101a0008a5040e8607c0031640f0646600200204244b30010018a5eb8226644b30013375e6082607c6ea80080362660800046600800800313300400400140f0607e002608000281e9038456600266e240140122b30013232330010013756607e04c44b30010018a508acc004cdd7801981e1820000c528c4cc008008c10400503b207c3374a90011981e1ba90124bd70456600266e24cdc000400218081bab301e303a3754603c60746ea806a26644b3001001801456600260800031325980099b8f375c608000202b13004375a6080608200314a081d8c100dd6181f800c00903d207a14a06466002002646600200204244b30010018a5eb82264664464660020026eacc10401089660020031003899198229ba733045375200a6608a60840026608a608600297ae03300300330470023045001410c6eb8c0f4004cc00c00cc108008c10000503e112cc004006297ae0899912cc004cdc79bae304100203b8998201ba700233004004001899802002000a0783758607e002608000281ea2941038452820708a5040e114a081c22b3001302e0188cc004c8c8cc8966002606a607a6ea800a2b30013035303d3754608260840071337100026eb4c104c0f8dd500144cdc48009bad3041303e375400481e2294103c181f80099b80004375a607e01a6607a607c0026607b30013032303a3754607c607e0034c0103d87a8000a60103d879800040e497ae0303a3754607a60746ea808a66e24010016646600200204244b30010018a5eb8226644b30015980099baf3041303e375400404313233001001323300100137566086608860806ea8010896600200314bd7044c8cc88c8cc004004dd59822802112cc004006200713233049374e660926ea4014cc124c118004cc124c11c0052f5c066006006609600460920028238dd718208009980180198230011822000a0842259800800c528456600266e3cdd718219bac304300103d8a518998010011822000a07c410514a081e22660800046600800800313300400400140f0607e002608000281e9222598009820800c4c8c8cc88cc038004566002b30010078a518803207e8acc00400a2b30013375e0026464646460626608e60900086608e60900066608e60900046608e60900026608e6ea0cdc00078039824982480098240009823800982300098209baa0228acc004c0d4c966002003148002264603a64b30010028a40011301e330010013048002411444b30010018a40011301f3300200230490014118608c0028218c8cc004004dd5981318211baa0052259800800c52f5c1132332232330010013756608e00844b30010018801c4c8cc12cdd3998259ba90053304b30480013304b30490014bd701980180198268011825800a092375c6086002660060066090004608c002822226644b30010018014566002608e003132325980099b8f375c609000402315980099b8f375c609000203b13370e6eb4c120c12400401e29410434528208630480013758608c003002411082205281919800800813912cc004006297ae0899199119198008009bab30470042259800800c400e264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c0050491bae30430013300300330480023046001411114a081fa294103f4528207e8a5040fc66e2000520003259800981a181f9baa0018982198201baa0018b207c304230433043303f375400466e04c050dd59811181f1baa001301437566044607c6ea8c088c0f8dd500f1820000c5903e22b300132323259800981a181e1baa0018acc004c0d0c0f0dd51820182080144cdc40029bad3040303d375400313371200a6eb4c100c0f4dd5000a0768a5040ec607e0026607a607c0026607b30013032303a3754607c607e0034c0103d87a8000a60103d879800040e497ae0303a3754607a60746ea808a2b30015980099b88480000122b3001980099b814800001229426466002002646600200204244b30010018a5eb82264664464660020026eacc10401089660020031003899198229ba733045375200a6608a60840026608a608600297ae03300300330470023045001410c6eb8c0f4004cc00c00cc108008c10000503e112cc004006297ae0899912cc004cdc79bae304100200a8998201ba700233004004001899802002000a0783758607e002608000281e922259800800c00a2b300130410018992cc004cdc79bae3041001016899b87375a6082608400200914a081e0c104dd61820000c00903e207c44cc89660020030028acc004c100006264b30013371e6eb8c100004056260086eb4c100c104006294103b18201bac303f001801207a40f42940c8cc004004c8cc004004084896600200314bd7044c8cc88c8cc004004dd59820802112cc004006200713233045374e6608a6ea4014cc114c108004cc114c10c0052f5c066006006608e004608a0028218dd7181e8009980180198210011820000a07c2259800800c52f5c1133225980099b8f375c6082004077133040374e0046600800800313300400400140f06eb0c0fc004c10000503d45282070899912cc0040060051598009820000c4c8c96600266e3cdd7182080101dc56600266e3cdd7182080080b44c014dd698209821000c52820788a5040f060820026eb0c0fc00600481e903d0a5032330010010202259800800c52f5c1132332232330010013756608000844b30010018801c4c8cc110dd3998221ba90053304430410013304430420014bd701980180198230011822000a084375c6078002660060066082004607e00281e903844c8cc004004dd6181f181f812112cc00400629422b30013371e6eb8c0fc0040e22946266004004608000281d103d452820708a5040e081c10381b87480050370c0d0004c0cc004c0c8004c0c4004c0c0004c0bcc0bc0108b2042323300100100c2259800800c52f5c11332259800acc004cdd7981298111baa302530263022375400400b1323300100132330010013756604e605060486ea8c09cc0a0c090dd5002112cc004006297ae0899199119198008009bab30290042259800800c400e2646605a6e9ccc0b4dd4802998169815000998169815800a5eb80cc00c00cc0bc008c0b400502b1bae302500133003003302a0023028001409844b30010018a508acc004cdc79bae30273758604e00204314a313300200230280014088812a294102044cc090008cc0100100062660080080028100c08c004c0900050211810980f1baa00e3020301d37546002603a6ea8c080c074dd5002118101810800c5901a45901a0c06c004c068c068004c064c06400c60226ea801cc048010c048c04c011164024300a00130053754015149a26cac8019", + "hash": "329ae820b7bc0d7e59e16fca08631bb79dd7817fb5d1a50941e2cd6b" + }, + { + "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/cardano~1assets~1Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + { + "title": "gov_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + } + ], + "compiledCode": "591a6201010022222229800aba2aba1aba0aab9faab9eaab9dab9a9bae0079bae0059bad0049bad0039bad00248888888888896600264653001300d00198069807000cdc3a4005300d00248889660026004601a6ea800e33001300e3754007370e90024dc3a4001370e90034c034dd5002244444664464b300130060048acc004c058dd500640062c80ba2b3001300a0048acc004c058dd500640062c80ba2b300130070048acc004c058dd500640062c80ba2b300130050048acc004c058dd500640062c80ba2b30013370e90040024566002602c6ea803200316405d16405080a1014202840502653001301a301a0019bac30190019ba548001222323232323298009bab30210019bac302130220019919800800804112cc004006298103d87a80008992cc004cdd7981218109baa00100e8980499811800a5eb82266006006604a00480f8c08c0050214dd618108044dd59810802cdd618108022444444b300130143023375400913259800980a98121baa0118cc004c0a0c094dd5008c8c0a4c0a800660486ea806e4464b300130180018991919194c004dd69817800cdd718178024dd71817801cdd6981780124444b300130340058054590310c0bc004c0b8004c0b4004c0a0dd5001c566002603800313232323298009bad302f0019bae302f0049bae302f0039bad302f0024888966002606800b00a8b206218178009817000981680098141baa0038acc004c064006264646464653001375a6060003375c606000b375c6060009375a606000691112cc004c0d4016264b300130223031375400313232332259800981d001c0422c81b8dd6981b8009bae30370023037001303237540031640c0606800d1640c83030001302f001302e001302d00130283754007159800980b800c4c8c8ca60026eb4c0b80066eb8c0b800e6eb8c0b800922259800981900240222c8178605c002605a00260506ea800e2c8131026204c4098604c6ea800a6e452201009b8f488100911919800800801912cc00400629422b30013375e605800200714a3133002002302d001409c81526e9520049ba54800a6e01200248888888888c8cc89660026044017159800981118189baa00d8991991194c004dd6981c800cdd6981c981d000cc8cc004004080896600200314bd7044cc8966002b30013375e607a60746ea8c0f4c0f8c0e8dd5001004c4c0b8c966002605e60746ea80062900044dd6981f181d9baa00140e464b3001302f303a375400314c103d87a8000899198008009bab303f303c375400444b30010018a6103d87a8000899192cc004c0580062b300130150018981399820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e207232330010013756607c607e60766ea8c0f8c0fcc0ecdd5001912cc004006298103d87a8000899192cc004cdc8805000c56600266e3c0280062604c66080607c00497ae08a60103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d4528207089981e00119802002000c4cc010010005038181d800981e000a0729bae30390034888966002607c005132598009815981d1baa0018992cc004c0b0c0ecdd5000c4cc89660026084003132332233019001159800801456600266ebc004c050cc10cdd4806998219ba9008330433750016660866ea00292f5c11598009819192cc0040062900044c8c054c9660020051480022602c660020026090004822889660020031480022602e6600400460920028230c11800504319198008009bab301c3042375400844b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c11800504445660026602c03c60526608600a6608698103d87a80004bd7045660026602c03c66e9520083304300533043375007697ae08acc00566002b30013301601e301533043005330433014330433029330430054bd7025eb812f5c113301601e30153304300533043302933043375207c97ae04bd704528207e8a5189980b00f180a9982180299821980a998219ba903e330433029330430054bd7025eb812f5c081fa264606c646600200204844b30010018a40011332259800acc004cdc39bad30493046375400407f15980099baf30203046375400400b13371e6eccc124c128c128c118dd50011bb30508a50411114a082222603000310014110608e0026600400460900028228c050cc10cdd4806a5eb82294103f4528207e8a5040fd14a081fa294103f4528207e98009821003c00666e0520003370066e000e80e40e100f192cc004c0c4c0fcdd5000c4c10cc100dd5000c5903e182118219821981f9baa00130410018b207e303f303c3754002646600200203844b30010018a5eb8226644b30015980099baf30433040375400401f130343259800981a98201baa0018a40011375a608860826ea800503f192cc004c0d4c100dd5000c5300103d87a8000899198008009bab30453042375400444b30010018a6103d87a8000899192cc004c0700062b3001301b0018981699823982280125eb82298103d87a8000410d1330040043049003410c6eb8c10c004c118005044207e323300100137566088608a60826ea800c896600200314c103d87a8000899192cc004cdc8808000c56600266e3c040006260586608c608800497ae08a60103d87a80004109133004004304800341086eb8c108004c1140050434528207c89982100119802002000c4cc01001000503e18208009821000a07e8b2074303e303b37540031640e4602860746ea80262c81d86072004606e0026eb8c0d8004c0c8dd5006c52820608acc004c09802e2b300130263031375401b13233223298009bad30390019bad3039303a0019919800800810112cc004006297ae0899912cc0056600266ebcc0f4c0e8dd5181e981f181d1baa00200989817192cc004c0bcc0e8dd5000c5200089bad303e303b375400281c8c966002605e60746ea80062980103d87a8000899198008009bab303f303c375400444b30010018a6103d87a8000899192cc004c0580062b300130150018981399820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e207232330010013756607c607e60766ea8c0f8c0fcc0ecdd5001912cc004006298103d87a8000899192cc004cdc8805000c56600266e3c0280062604c66080607c00497ae08a60103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d4528207089981e00119802002000c4cc010010005038181d800981e000a0729bae30390034888966002607c00513259800981f800c4c8cc88cc0580044c96600200715980099baf0023013330413752016660826ea4018cc104dd400499820800998209ba80084bd704566002606064b30010018a4001132301332598008014520008980a19800800982300120862259800800c520008980a998010011823800a0883044001410464660020026eacc068c100dd5002912cc004006297ae0899199119198008009bab30450042259800800c400e264660926e9ccc124dd4802998249823000998249823800a5eb80cc00c00cc12c008c1240050471bae3041001330030033046002304400141091323259800981898201baa001899199119801001000912cc00400629422b30013375e6e98cc118c11c0052f5bded8c06e98cc11800d2f5bded8c114a3133002002304800141088228dd5982298211baa00233760006980103d87a80008b207e32330010010232259800800c530103d87a80008992cc004cdd78021821000c4c0accc114c10c0052f5c113300300330470024104608a0028218c048cc104c048cc104dd4805a5eb812f5c114a081ea294103d4528207a3026330403041303e37546082607c6ea8068cc10130010100004bd7019baf3016303c3754602c60786ea8c0fc010c058c0f0dd5000992cc004c0b8c0f0dd5000c4c100c0f4dd5000c5903b181f98201820181e1baa001303e0018b2078323300100101a2259800800c52f5c11332259800acc004cdd79820981f1baa00200d89819192cc004c0ccc0f8dd5000c5200089bad3042303f375400281e8c9660026066607c6ea8006298103d87a8000899198008009bab30433040375400444b30010018a6103d87a8000899192cc004c0680062b300130190018981599822982180125eb82298103d87a80004105133004004304700341046eb8c104004c110005042207a3233001001375660846086607e6ea800c896600200314c103d87a8000899192cc004cdc8807000c56600266e3c0380062605466088608400497ae08a60103d87a80004101133004004304600341006eb8c100004c10c0050414528207889982000119802002000c4cc01001000503c181f8009820000a07a8b2076181c801181b8009bae30360013032375401b14a081822b3001302300b8acc004c08cc0c4dd5006c4c8cc88ca60026eb4c0e40066eb4c0e4c0e8c0e8006646600200204044b30010018a5eb8226644b30015980099baf303d303a3754607a607c60746ea80080262605c64b3001302f303a375400314800226eb4c0f8c0ecdd5000a07232598009817981d1baa0018a60103d87a8000899198008009bab303f303c375400444b30010018a6103d87a8000899192cc004c0580062b300130150018981399820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e207232330010013756607c607e60766ea8c0f8c0fcc0ecdd5001912cc004006298103d87a8000899192cc004cdc8805000c56600266e3c0280062604c66080607c00497ae08a60103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d4528207089981e00119802002000c4cc010010005038181d800981e000a0729bae30390034888966002607c005132598009815981d1baa0018992cc004c0b0c0ecdd5000c66002607e60786ea8006646464b30013033303e37540031598009819981f1baa30423043002899b88008375a6084607e6ea8006266e24020dd69821181f9baa00140f514a081e8c104004cc0fcc100004cc0fe6002606260786ea8c100c10400698103d87a8000a60103d879800040ec97ae0303c3754607e60786ea8c0fc086646600200203844b30010018a5eb8226644b30015980099baf30433040375400401f130343259800981a98201baa0018a40011375a608860826ea800503f192cc004c0d4c100dd5000c5300103d87a8000899198008009bab30453042375400444b30010018a6103d87a8000899192cc004c0700062b3001301b0018981699823982280125eb82298103d87a8000410d1330040043049003410c6eb8c10c004c118005044207e323300100137566088608a60826ea800c896600200314c103d87a8000899192cc004cdc8808000c56600266e3c040006260586608c608800497ae08a60103d87a80004109133004004304800341086eb8c108004c1140050434528207c89982100119802002000c4cc01001000503e18208009821000a07e488966002608600313233223301a001159800802c56600200515980099baf0013374a9003198221ba900e330443752012660886ea00312f5c11598009980b80f980a9982200319822260103d87a80004bd7045660026602e03e66e95200c3304400633044375007897ae089819992cc0040062900044c8c058c9660020051480022602e66002002609200482308966002003148002260306600400460940028238c11c00504419198008009bab301d3043375400844b30010018a5eb82264664464660020026eacc12001089660020031003899198261ba73304c375200a66098609200266098609400297ae033003003304e002304c00141286eb8c110004cc00c00cc124008c11c005045452820808a50410114a0820229410404528208098009821804400666e00cdc001d81d01ca0203259800981918201baa0018982218209baa0018b207e3043304430443040375400260840031641008b2074303e303b37540031640e4602860746ea80262c81d86072004606e0026eb8c0d8004c0c8dd5006c52820608acc004c08402e2b300130213031375401b132332298009bae30380029bad30383039002991980080080f912cc004006297ae0899912cc0056600266ebcc0f0c0e4dd5181e181e981c9baa00200889816992cc004c0b8c0e4dd5000c5200089bad303d303a375400281c0c966002605c60726ea8006298103d87a8000899198008009bab303e303b375400444b30010018a6103d87a8000899192cc004c0540062b300130140018981319820181f00125eb82298103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d207032330010013756607a607c60746ea8c0f4c0f8c0e8dd5001912cc004006298103d87a8000899192cc004cdc8804800c56600266e3c0240062604a6607e607a00497ae08a60103d87a800040ed133004004304100340ec6eb8c0ec004c0f800503c4528206e89981d80119802002000c4cc010010005037181d000981d800a070488966002607800313259800981e800c4c8c8cc88cc05400456600200515980099baf0013374a90031981f9ba90093303f37520106607e6ea0cdc0003801a5eb822b3001302e3259800800c520008991808992cc00400a2900044c048cc004004c110009041112cc0040062900044c04ccc008008c1140050421821000a07e323300100137566030607c6ea8014896600200314bd7044c8cc88c8cc004004dd59821802112cc004006200713233047374e6608e6ea4014cc11cc110004cc11cc1140052f5c0660060066092004608e0028228dd7181f8009980180198220011821000a080899912cc0040060051598009821800c4c8c96600266e3cdd71822001006456600266e3cdd71822000806c4cdc39bad304430450010078a5040fd14a081f8c110004dd61821000c009040208014a0646600200203844b30010018a5eb82264664464660020026eacc10c01089660020031003899198239ba733047375200a6608e60880026608e608a00297ae0330030033049002304700141146eb8c0fc004cc00c00cc110008c108005040452820768a5040ed14a081d8cdc4000a400064b3001302d303b37540031303f303c37540031640e8607c607e607e60766ea8008cdc098059bab3014303a375400260166eacc050c0e8dd5180a181d1baa303d003303c0018b207432330010010182259800800c52f5c11332259800acc004cdd7981f981e1baa00200b89818192cc004c0c4c0f0dd5000c5200089bad3040303d375400281d8c966002606260786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0600062b300130170018981499821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806000c56600266e3c0300062605066084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a0768b2072181b8009bae30360013032375401b14a081822b300130213031375401b1323298009bae30370019bad303730380019bae30370024889660026076646600200204244b30010018a5eb8226644b30015980099baf303e303b3754607c607e60766ea800802a2605e64b30013030303b375400314800226eb4c0fcc0f0dd5000a07432598009818181d9baa0018a6103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c05c0062b300130160018981419821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8c0fcc100c0f0dd5001912cc004006298103d87a8000899192cc004cdc8804800c56600266e3c0240062604e66082607e00497ae08a60103d87a800040f5133004004304300340f46eb8c0f4004c10000503e4528207289981e80119802002000c4cc010010005039181e000981e800a0748acc0056600266e2120000028cc004cdc0a400000514a1323300100132330010010172259800800c52f5c1132332232330010013756607c00844b30010018801c4c8cc108dd3998211ba900533042303f0013304230400014bd701980180198220011821000a080375c607400266006006607e004607a00281d8896600200314bd7044cc896600266e3cdd7181f001003c4cc0f4dd380119802002000c4cc0100100050391bac303c001303d00140e89112cc004006005159800981f000c4c96600266e3cdd7181f000802c4cdc39bad303e303f0010048a5040e4607c6eb0c0f400600481d903b22945035456600264660020026eb0c0ec070896600200314a115980099b8f375c607800206b14a3133002002303d00140dc81d226644b30010018014566002607a0031325980098081bae303d001899b87375a607a607c0029000c5282070303d3758607800300240e881d05281919800800991980080080b912cc004006297ae0899199119198008009bab303e0042259800800c400e264660846e9ccc108dd480299821181f800998211820000a5eb80cc00c00cc110008c1080050401bae303a00133003003303f002303d00140ec44b30010018a5eb8226644b30013371e6eb8c0f800801626607a6e9c008cc01001000626600800800281c8dd6181e000981e800a0748a5040d514a081aa2c81c0606e00260646ea80362941030206040c0818103011119b873370260086eacc034c0ccdd500118021bab300d30333754601a60666ea800c004c0ccc0c0dd5180518181baa00c23259800981298181baa0018a40011375a606860626ea800502f192cc004c094c0c0dd5000c5300103d87a8000899198008009bab30353032375400444b30010018a6103d87a8000899192cc004c0300062b3001300b0018980e9981b981a80125eb82298103d87a800040cd133004004303900340cc6eb8c0cc004c0d8005034205e32330010010022259800800c5300103d87a8000899192cc004c02c0062b3001300a0018980e1981b181a00125eb82298103d87a800040c9133004004303800340c86eb8c0c8004c0d400503322c8118c09cc090dd50024590220c084c084c084c084004c080004c07cc07c004c078004c074c07400c602a6ea8020c058014c058c05c015164030300d0013008375401b149a26cac8031", + "hash": "f707e28ef1513c76e3ce6d34644bf721c1996de346546db71120831f" + }, + { + "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/cardano~1assets~1Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + { + "title": "gov_deposit", + "schema": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + } + ], + "compiledCode": "591a6201010022222229800aba2aba1aba0aab9faab9eaab9dab9a9bae0079bae0059bad0049bad0039bad00248888888888896600264653001300d00198069807000cdc3a4005300d00248889660026004601a6ea800e33001300e3754007370e90024dc3a4001370e90034c034dd5002244444664464b300130060048acc004c058dd500640062c80ba2b3001300a0048acc004c058dd500640062c80ba2b300130070048acc004c058dd500640062c80ba2b300130050048acc004c058dd500640062c80ba2b30013370e90040024566002602c6ea803200316405d16405080a1014202840502653001301a301a0019bac30190019ba548001222323232323298009bab30210019bac302130220019919800800804112cc004006298103d87a80008992cc004cdd7981218109baa00100e8980499811800a5eb82266006006604a00480f8c08c0050214dd618108044dd59810802cdd618108022444444b300130143023375400913259800980a98121baa0118cc004c0a0c094dd5008c8c0a4c0a800660486ea806e4464b300130180018991919194c004dd69817800cdd718178024dd71817801cdd6981780124444b300130340058054590310c0bc004c0b8004c0b4004c0a0dd5001c566002603800313232323298009bad302f0019bae302f0049bae302f0039bad302f0024888966002606800b00a8b206218178009817000981680098141baa0038acc004c064006264646464653001375a6060003375c606000b375c6060009375a606000691112cc004c0d4016264b300130223031375400313232332259800981d001c0422c81b8dd6981b8009bae30370023037001303237540031640c0606800d1640c83030001302f001302e001302d00130283754007159800980b800c4c8c8ca60026eb4c0b80066eb8c0b800e6eb8c0b800922259800981900240222c8178605c002605a00260506ea800e2c8131026204c4098604c6ea800a6e452201009b8f488100911919800800801912cc00400629422b30013375e605800200714a3133002002302d001409c81526e9520049ba54800a6e01200248888888888c8cc89660026044017159800981118189baa00d8991991194c004dd6981c800cdd6981c981d000cc8cc004004080896600200314bd7044cc8966002b30013375e607a60746ea8c0f4c0f8c0e8dd5001004c4c0b8c966002605e60746ea80062900044dd6981f181d9baa00140e464b3001302f303a375400314c103d87a8000899198008009bab303f303c375400444b30010018a6103d87a8000899192cc004c0580062b300130150018981399820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e207232330010013756607c607e60766ea8c0f8c0fcc0ecdd5001912cc004006298103d87a8000899192cc004cdc8805000c56600266e3c0280062604c66080607c00497ae08a60103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d4528207089981e00119802002000c4cc010010005038181d800981e000a0729bae30390034888966002607c005132598009815981d1baa0018992cc004c0b0c0ecdd5000c4cc89660026084003132332233019001159800801456600266ebc004c050cc10cdd4806998219ba9008330433750016660866ea00292f5c11598009819192cc0040062900044c8c054c9660020051480022602c660020026090004822889660020031480022602e6600400460920028230c11800504319198008009bab301c3042375400844b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c11800504445660026602c03c60526608600a6608698103d87a80004bd7045660026602c03c66e9520083304300533043375007697ae08acc00566002b30013301601e301533043005330433014330433029330430054bd7025eb812f5c113301601e30153304300533043302933043375207c97ae04bd704528207e8a5189980b00f180a9982180299821980a998219ba903e330433029330430054bd7025eb812f5c081fa264606c646600200204844b30010018a40011332259800acc004cdc39bad30493046375400407f15980099baf30203046375400400b13371e6eccc124c128c128c118dd50011bb30508a50411114a082222603000310014110608e0026600400460900028228c050cc10cdd4806a5eb82294103f4528207e8a5040fd14a081fa294103f4528207e98009821003c00666e0520003370066e000e80e40e100f192cc004c0c4c0fcdd5000c4c10cc100dd5000c5903e182118219821981f9baa00130410018b207e303f303c3754002646600200203844b30010018a5eb8226644b30015980099baf30433040375400401f130343259800981a98201baa0018a40011375a608860826ea800503f192cc004c0d4c100dd5000c5300103d87a8000899198008009bab30453042375400444b30010018a6103d87a8000899192cc004c0700062b3001301b0018981699823982280125eb82298103d87a8000410d1330040043049003410c6eb8c10c004c118005044207e323300100137566088608a60826ea800c896600200314c103d87a8000899192cc004cdc8808000c56600266e3c040006260586608c608800497ae08a60103d87a80004109133004004304800341086eb8c108004c1140050434528207c89982100119802002000c4cc01001000503e18208009821000a07e8b2074303e303b37540031640e4602860746ea80262c81d86072004606e0026eb8c0d8004c0c8dd5006c52820608acc004c09802e2b300130263031375401b13233223298009bad30390019bad3039303a0019919800800810112cc004006297ae0899912cc0056600266ebcc0f4c0e8dd5181e981f181d1baa00200989817192cc004c0bcc0e8dd5000c5200089bad303e303b375400281c8c966002605e60746ea80062980103d87a8000899198008009bab303f303c375400444b30010018a6103d87a8000899192cc004c0580062b300130150018981399820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e207232330010013756607c607e60766ea8c0f8c0fcc0ecdd5001912cc004006298103d87a8000899192cc004cdc8805000c56600266e3c0280062604c66080607c00497ae08a60103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d4528207089981e00119802002000c4cc010010005038181d800981e000a0729bae30390034888966002607c00513259800981f800c4c8cc88cc0580044c96600200715980099baf0023013330413752016660826ea4018cc104dd400499820800998209ba80084bd704566002606064b30010018a4001132301332598008014520008980a19800800982300120862259800800c520008980a998010011823800a0883044001410464660020026eacc068c100dd5002912cc004006297ae0899199119198008009bab30450042259800800c400e264660926e9ccc124dd4802998249823000998249823800a5eb80cc00c00cc12c008c1240050471bae3041001330030033046002304400141091323259800981898201baa001899199119801001000912cc00400629422b30013375e6e98cc118c11c0052f5bded8c06e98cc11800d2f5bded8c114a3133002002304800141088228dd5982298211baa00233760006980103d87a80008b207e32330010010232259800800c530103d87a80008992cc004cdd78021821000c4c0accc114c10c0052f5c113300300330470024104608a0028218c048cc104c048cc104dd4805a5eb812f5c114a081ea294103d4528207a3026330403041303e37546082607c6ea8068cc10130010100004bd7019baf3016303c3754602c60786ea8c0fc010c058c0f0dd5000992cc004c0b8c0f0dd5000c4c100c0f4dd5000c5903b181f98201820181e1baa001303e0018b2078323300100101a2259800800c52f5c11332259800acc004cdd79820981f1baa00200d89819192cc004c0ccc0f8dd5000c5200089bad3042303f375400281e8c9660026066607c6ea8006298103d87a8000899198008009bab30433040375400444b30010018a6103d87a8000899192cc004c0680062b300130190018981599822982180125eb82298103d87a80004105133004004304700341046eb8c104004c110005042207a3233001001375660846086607e6ea800c896600200314c103d87a8000899192cc004cdc8807000c56600266e3c0380062605466088608400497ae08a60103d87a80004101133004004304600341006eb8c100004c10c0050414528207889982000119802002000c4cc01001000503c181f8009820000a07a8b2076181c801181b8009bae30360013032375401b14a081822b3001302300b8acc004c08cc0c4dd5006c4c8cc88ca60026eb4c0e40066eb4c0e4c0e8c0e8006646600200204044b30010018a5eb8226644b30015980099baf303d303a3754607a607c60746ea80080262605c64b3001302f303a375400314800226eb4c0f8c0ecdd5000a07232598009817981d1baa0018a60103d87a8000899198008009bab303f303c375400444b30010018a6103d87a8000899192cc004c0580062b300130150018981399820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e207232330010013756607c607e60766ea8c0f8c0fcc0ecdd5001912cc004006298103d87a8000899192cc004cdc8805000c56600266e3c0280062604c66080607c00497ae08a60103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d4528207089981e00119802002000c4cc010010005038181d800981e000a0729bae30390034888966002607c005132598009815981d1baa0018992cc004c0b0c0ecdd5000c66002607e60786ea8006646464b30013033303e37540031598009819981f1baa30423043002899b88008375a6084607e6ea8006266e24020dd69821181f9baa00140f514a081e8c104004cc0fcc100004cc0fe6002606260786ea8c100c10400698103d87a8000a60103d879800040ec97ae0303c3754607e60786ea8c0fc086646600200203844b30010018a5eb8226644b30015980099baf30433040375400401f130343259800981a98201baa0018a40011375a608860826ea800503f192cc004c0d4c100dd5000c5300103d87a8000899198008009bab30453042375400444b30010018a6103d87a8000899192cc004c0700062b3001301b0018981699823982280125eb82298103d87a8000410d1330040043049003410c6eb8c10c004c118005044207e323300100137566088608a60826ea800c896600200314c103d87a8000899192cc004cdc8808000c56600266e3c040006260586608c608800497ae08a60103d87a80004109133004004304800341086eb8c108004c1140050434528207c89982100119802002000c4cc01001000503e18208009821000a07e488966002608600313233223301a001159800802c56600200515980099baf0013374a9003198221ba900e330443752012660886ea00312f5c11598009980b80f980a9982200319822260103d87a80004bd7045660026602e03e66e95200c3304400633044375007897ae089819992cc0040062900044c8c058c9660020051480022602e66002002609200482308966002003148002260306600400460940028238c11c00504419198008009bab301d3043375400844b30010018a5eb82264664464660020026eacc12001089660020031003899198261ba73304c375200a66098609200266098609400297ae033003003304e002304c00141286eb8c110004cc00c00cc124008c11c005045452820808a50410114a0820229410404528208098009821804400666e00cdc001d81d01ca0203259800981918201baa0018982218209baa0018b207e3043304430443040375400260840031641008b2074303e303b37540031640e4602860746ea80262c81d86072004606e0026eb8c0d8004c0c8dd5006c52820608acc004c08402e2b300130213031375401b132332298009bae30380029bad30383039002991980080080f912cc004006297ae0899912cc0056600266ebcc0f0c0e4dd5181e181e981c9baa00200889816992cc004c0b8c0e4dd5000c5200089bad303d303a375400281c0c966002605c60726ea8006298103d87a8000899198008009bab303e303b375400444b30010018a6103d87a8000899192cc004c0540062b300130140018981319820181f00125eb82298103d87a800040f1133004004304200340f06eb8c0f0004c0fc00503d207032330010013756607a607c60746ea8c0f4c0f8c0e8dd5001912cc004006298103d87a8000899192cc004cdc8804800c56600266e3c0240062604a6607e607a00497ae08a60103d87a800040ed133004004304100340ec6eb8c0ec004c0f800503c4528206e89981d80119802002000c4cc010010005037181d000981d800a070488966002607800313259800981e800c4c8c8cc88cc05400456600200515980099baf0013374a90031981f9ba90093303f37520106607e6ea0cdc0003801a5eb822b3001302e3259800800c520008991808992cc00400a2900044c048cc004004c110009041112cc0040062900044c04ccc008008c1140050421821000a07e323300100137566030607c6ea8014896600200314bd7044c8cc88c8cc004004dd59821802112cc004006200713233047374e6608e6ea4014cc11cc110004cc11cc1140052f5c0660060066092004608e0028228dd7181f8009980180198220011821000a080899912cc0040060051598009821800c4c8c96600266e3cdd71822001006456600266e3cdd71822000806c4cdc39bad304430450010078a5040fd14a081f8c110004dd61821000c009040208014a0646600200203844b30010018a5eb82264664464660020026eacc10c01089660020031003899198239ba733047375200a6608e60880026608e608a00297ae0330030033049002304700141146eb8c0fc004cc00c00cc110008c108005040452820768a5040ed14a081d8cdc4000a400064b3001302d303b37540031303f303c37540031640e8607c607e607e60766ea8008cdc098059bab3014303a375400260166eacc050c0e8dd5180a181d1baa303d003303c0018b207432330010010182259800800c52f5c11332259800acc004cdd7981f981e1baa00200b89818192cc004c0c4c0f0dd5000c5200089bad3040303d375400281d8c966002606260786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0600062b300130170018981499821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806000c56600266e3c0300062605066084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a0768b2072181b8009bae30360013032375401b14a081822b300130213031375401b1323298009bae30370019bad303730380019bae30370024889660026076646600200204244b30010018a5eb8226644b30015980099baf303e303b3754607c607e60766ea800802a2605e64b30013030303b375400314800226eb4c0fcc0f0dd5000a07432598009818181d9baa0018a6103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c05c0062b300130160018981419821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8c0fcc100c0f0dd5001912cc004006298103d87a8000899192cc004cdc8804800c56600266e3c0240062604e66082607e00497ae08a60103d87a800040f5133004004304300340f46eb8c0f4004c10000503e4528207289981e80119802002000c4cc010010005039181e000981e800a0748acc0056600266e2120000028cc004cdc0a400000514a1323300100132330010010172259800800c52f5c1132332232330010013756607c00844b30010018801c4c8cc108dd3998211ba900533042303f0013304230400014bd701980180198220011821000a080375c607400266006006607e004607a00281d8896600200314bd7044cc896600266e3cdd7181f001003c4cc0f4dd380119802002000c4cc0100100050391bac303c001303d00140e89112cc004006005159800981f000c4c96600266e3cdd7181f000802c4cdc39bad303e303f0010048a5040e4607c6eb0c0f400600481d903b22945035456600264660020026eb0c0ec070896600200314a115980099b8f375c607800206b14a3133002002303d00140dc81d226644b30010018014566002607a0031325980098081bae303d001899b87375a607a607c0029000c5282070303d3758607800300240e881d05281919800800991980080080b912cc004006297ae0899199119198008009bab303e0042259800800c400e264660846e9ccc108dd480299821181f800998211820000a5eb80cc00c00cc110008c1080050401bae303a00133003003303f002303d00140ec44b30010018a5eb8226644b30013371e6eb8c0f800801626607a6e9c008cc01001000626600800800281c8dd6181e000981e800a0748a5040d514a081aa2c81c0606e00260646ea80362941030206040c0818103011119b873370260086eacc034c0ccdd500118021bab300d30333754601a60666ea800c004c0ccc0c0dd5180518181baa00c23259800981298181baa0018a40011375a606860626ea800502f192cc004c094c0c0dd5000c5300103d87a8000899198008009bab30353032375400444b30010018a6103d87a8000899192cc004c0300062b3001300b0018980e9981b981a80125eb82298103d87a800040cd133004004303900340cc6eb8c0cc004c0d8005034205e32330010010022259800800c5300103d87a8000899192cc004c02c0062b3001300a0018980e1981b181a00125eb82298103d87a800040c9133004004303800340c86eb8c0c8004c0d400503322c8118c09cc090dd50024590220c084c084c084c084004c080004c07cc07c004c078004c074c07400c602a6ea8020c058014c058c05c015164030300d0013008375401b149a26cac8031", + "hash": "f707e28ef1513c76e3ce6d34644bf721c1996de346546db71120831f" + }, + { + "title": "start.start.withdraw", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c4a01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e90004dc3a4005370e90024dc3a400d374a90004dd2a400491111114c004c04401e602000f2232598009804800c56600260206ea800e0051640451598009804000c56600260206ea800e0051640451598009803800c56600260206ea800e0051640451598009803000c56600260206ea800e00516404515980099b87480200062b3001301037540070028b20228b201c4038807100e201c300e3754005223232330010010042259800800c530103d87a80008992cc004cdd78021809000c4c020cc054c04c0052f5c113300300330170024044602a0028098c00ccc044c048c03cdd5000a5eb81222232332259800980580144c8c8ca60026eacc0680066034602e6ea801a64660020026eb0c06c010896600200314bd7044cc8966002646600200264660020026eacc080c084c074dd518101810980e9baa0042259800800c52f5c1132332232330010013756604400844b30010018801c4c8cc098dd3998131ba90053302630230013302630240014bd701980180198140011813000a048375c603c002660060066046004604200280f8896600200314a115980099b8f375c60406eb0c08000406a2946266004004604200280d901e44cc074008cc01001000626600800800280c8c070004c07400501a2444b3001301e0018999119912cc004c05cc074dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c0ac0066eb8c0ac02a6eb8c0ac0266eb4c0ac01e6eb4c0ac01a64b300130290018acc004cdc4a4008605000316898109814000a04e8b20543754605600b375a6056009375a6056007302b002488888888966002606a01513301430340111330140011329800981b000cdd7181a800cdc7a45009b9148810048888ca60026076003323322330020020012259800800c52f5c11332259800acc004cdd7981f981e1baa0020058981a192cc004c0d4c0f0dd5000c5200089bad3040303d375400281d8c966002606a60786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0300062b3001300d0018981b19821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806800c56600266e3c0340062606a66084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a076375860760466058660726056660726ea40cd2f5c0660726058660726058660726056660726ea40112f5c097ae04bd7025eb8266ebcc0accc0e4dd480225eb8007d22259800981f00144c8cc88cc8966002607000313232323298009bad30460019bae30460049bae30460039bad30460024888966002609600b00a8b2090182300098228009822000981f9baa0038acc004c0dc0062646464653001375a608c003375c608c009375c608c007375a608c00491112cc004c12c016015164120304600130450013044001303f3754007159800981b000c4c8c8c8c8ca60026eb4c11c0066eb8c11c0166eb8c11c0126eb4c11c00d2222598009826002c4c966002608460906ea8006264646644b3001305100380845904e1bad304e001375c609c004609c00260926ea80062c8238c12c01a2c8248608e002608c002608a0026088002607e6ea800e2b3001303500189919194c004dd69822800cdd71822801cdd718228012444b300130490048044590460c114004c110004c0fcdd5001c5903d207a40f481e84cc89660026070607c6ea8006264660620022b30010078acc0040162b30010038acc004cc89660020030028acc004c118006264b3001300f375c608c0031303b375a608c608e00314a08208c118dd61822800c009043208614a06466002002646600200205644b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc004006297ae0899912cc004cdc79bae30470020118998231ba700233004004001899802002000a0843758608a002608c002821a266ebc005300103d87a80008a5040f914a081f2294103e4528207c3042303f37540031640f466ebc004c0c8cc0fcdd48051981f98200059981f98200031981f9ba8337006eb4c100c104c1040180e12f5c06605a6eacc100c104c104c104c104c10409c08cc0f0dd500099b873259800981a181d9baa0018a40011375a607e60786ea800503a192cc004c0d0c0ecdd5000c530103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c02c0062b3001300c0018981a99821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8008896600200314c103d87a8000899192cc004c0280062b3001300b0018981a19820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e1bad303e00532598009819981d9baa0018981f981e1baa0018b2074303e303f303f303b3754002607a0051640ec303a303a00418189baa0158b2064181580098150009814800981400098138009813000981280098120009811800980f1baa0028b20383259800980a180e1baa00189810180e9baa0018b2036301f30203020301c3754603e604060386ea80088966002602e603a6ea800a2646464b3001302500289980318120018992cc004c06c006264b30013027001899192cc004c078006264b3001302a0018998059814800804c5902718129baa0028acc004c07400626464653001375a6056003375a6056007375a60560049112cc004c0bc01201d1640b0302b001302a0013025375400516408c8118c08cdd50009813000c5902418111baa0028acc004c0680062b3001302237540050058b20468b2040408060406ea80062c8110c08c004c08c004c078dd500145901c180e80091192cc004c05800626464b300130230028024590201bae3021001301d3754007159800980a800c4c8c96600260460050048b2040375c6042002603a6ea800e2c80d901b180d9baa0028b2036180d180d000980c980c800980a1baa006899192cc004c03c0122646644b300130120018acc004c064dd5003400a2c80d22b300130110018acc004c064dd5003400a2c80d22c80b9017099192cc004c048c060dd500344c8c8cc004004dd5980f001912cc00400629422b30013375e0066036603e00314a31330020023020001406880e8c034cc06cdd4801a5eb82330010159bac301c0029bab301c301d301d301d001a6103d87d8000401080b8c070c070c070c070c070c070004c05cdd5004980b1baa004375c6032602c6ea80162b3001300c0048994c004dd6980d000cc068c06c006602c6ea801226464b3001301d0018992cc004c04cc064dd5000c4c8cc030004566002602860346ea8022266ebc00530103d8798000899baf0014c103d87b80004064603a60346ea80062c80c0cc024dd5980e180e980e980e980e980e980e980e980e980e801180e000c5901a19199119801001000912cc004006297ae0899912cc004cdd79810180e9baa30203021301d375400400b13301f00233004004001899802002000a036301e001301f00140706eb0c070008c010050c05cdd5004a4444b300130140028acc004c06cdd500440062c80e22b300130130028acc004c06cdd500440062c80e22c80c90190c058dd5002c56600266e1d200a0048994c004dd6980d000cc068c06c006602e6ea8025222980080b4dd6180e800cdd5980e980f180f180f180f180f180f180f180f180f000d30103d879800040143016375400b15980099b87480200122664530010149bac301b0019bab301b301c301c301c301c301c301c301c301c301c001a60103d87a8000400c6032602c6ea8014c058dd50044590142028405080a08888c966002603c00313259800980a180d1baa00189919806800899baf001004301e301b375400316406466014006603a00316406c64646600200200a44b30010018a5eb8226644b30013375e6042603c6ea8c084c088c078dd5001002c4cc080008cc01001000626600800800280e0c07c004c08000501d1802802118051980b98049980b9ba90014bd701980ba60103d87a80004bd70202430113754002602a00a6028602a008452689b2b20081", + "hash": "55c2a7f6143ce2befd94139304436b30a0398f21cd2464c760455033" + }, + { + "title": "start.start.mint", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1MintPolarity" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c4a01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e90004dc3a4005370e90024dc3a400d374a90004dd2a400491111114c004c04401e602000f2232598009804800c56600260206ea800e0051640451598009804000c56600260206ea800e0051640451598009803800c56600260206ea800e0051640451598009803000c56600260206ea800e00516404515980099b87480200062b3001301037540070028b20228b201c4038807100e201c300e3754005223232330010010042259800800c530103d87a80008992cc004cdd78021809000c4c020cc054c04c0052f5c113300300330170024044602a0028098c00ccc044c048c03cdd5000a5eb81222232332259800980580144c8c8ca60026eacc0680066034602e6ea801a64660020026eb0c06c010896600200314bd7044cc8966002646600200264660020026eacc080c084c074dd518101810980e9baa0042259800800c52f5c1132332232330010013756604400844b30010018801c4c8cc098dd3998131ba90053302630230013302630240014bd701980180198140011813000a048375c603c002660060066046004604200280f8896600200314a115980099b8f375c60406eb0c08000406a2946266004004604200280d901e44cc074008cc01001000626600800800280c8c070004c07400501a2444b3001301e0018999119912cc004c05cc074dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c0ac0066eb8c0ac02a6eb8c0ac0266eb4c0ac01e6eb4c0ac01a64b300130290018acc004cdc4a4008605000316898109814000a04e8b20543754605600b375a6056009375a6056007302b002488888888966002606a01513301430340111330140011329800981b000cdd7181a800cdc7a45009b9148810048888ca60026076003323322330020020012259800800c52f5c11332259800acc004cdd7981f981e1baa0020058981a192cc004c0d4c0f0dd5000c5200089bad3040303d375400281d8c966002606a60786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0300062b3001300d0018981b19821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806800c56600266e3c0340062606a66084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a076375860760466058660726056660726ea40cd2f5c0660726058660726058660726056660726ea40112f5c097ae04bd7025eb8266ebcc0accc0e4dd480225eb8007d22259800981f00144c8cc88cc8966002607000313232323298009bad30460019bae30460049bae30460039bad30460024888966002609600b00a8b2090182300098228009822000981f9baa0038acc004c0dc0062646464653001375a608c003375c608c009375c608c007375a608c00491112cc004c12c016015164120304600130450013044001303f3754007159800981b000c4c8c8c8c8ca60026eb4c11c0066eb8c11c0166eb8c11c0126eb4c11c00d2222598009826002c4c966002608460906ea8006264646644b3001305100380845904e1bad304e001375c609c004609c00260926ea80062c8238c12c01a2c8248608e002608c002608a0026088002607e6ea800e2b3001303500189919194c004dd69822800cdd71822801cdd718228012444b300130490048044590460c114004c110004c0fcdd5001c5903d207a40f481e84cc89660026070607c6ea8006264660620022b30010078acc0040162b30010038acc004cc89660020030028acc004c118006264b3001300f375c608c0031303b375a608c608e00314a08208c118dd61822800c009043208614a06466002002646600200205644b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc004006297ae0899912cc004cdc79bae30470020118998231ba700233004004001899802002000a0843758608a002608c002821a266ebc005300103d87a80008a5040f914a081f2294103e4528207c3042303f37540031640f466ebc004c0c8cc0fcdd48051981f98200059981f98200031981f9ba8337006eb4c100c104c1040180e12f5c06605a6eacc100c104c104c104c104c10409c08cc0f0dd500099b873259800981a181d9baa0018a40011375a607e60786ea800503a192cc004c0d0c0ecdd5000c530103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c02c0062b3001300c0018981a99821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8008896600200314c103d87a8000899192cc004c0280062b3001300b0018981a19820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e1bad303e00532598009819981d9baa0018981f981e1baa0018b2074303e303f303f303b3754002607a0051640ec303a303a00418189baa0158b2064181580098150009814800981400098138009813000981280098120009811800980f1baa0028b20383259800980a180e1baa00189810180e9baa0018b2036301f30203020301c3754603e604060386ea80088966002602e603a6ea800a2646464b3001302500289980318120018992cc004c06c006264b30013027001899192cc004c078006264b3001302a0018998059814800804c5902718129baa0028acc004c07400626464653001375a6056003375a6056007375a60560049112cc004c0bc01201d1640b0302b001302a0013025375400516408c8118c08cdd50009813000c5902418111baa0028acc004c0680062b3001302237540050058b20468b2040408060406ea80062c8110c08c004c08c004c078dd500145901c180e80091192cc004c05800626464b300130230028024590201bae3021001301d3754007159800980a800c4c8c96600260460050048b2040375c6042002603a6ea800e2c80d901b180d9baa0028b2036180d180d000980c980c800980a1baa006899192cc004c03c0122646644b300130120018acc004c064dd5003400a2c80d22b300130110018acc004c064dd5003400a2c80d22c80b9017099192cc004c048c060dd500344c8c8cc004004dd5980f001912cc00400629422b30013375e0066036603e00314a31330020023020001406880e8c034cc06cdd4801a5eb82330010159bac301c0029bab301c301d301d301d001a6103d87d8000401080b8c070c070c070c070c070c070004c05cdd5004980b1baa004375c6032602c6ea80162b3001300c0048994c004dd6980d000cc068c06c006602c6ea801226464b3001301d0018992cc004c04cc064dd5000c4c8cc030004566002602860346ea8022266ebc00530103d8798000899baf0014c103d87b80004064603a60346ea80062c80c0cc024dd5980e180e980e980e980e980e980e980e980e980e801180e000c5901a19199119801001000912cc004006297ae0899912cc004cdd79810180e9baa30203021301d375400400b13301f00233004004001899802002000a036301e001301f00140706eb0c070008c010050c05cdd5004a4444b300130140028acc004c06cdd500440062c80e22b300130130028acc004c06cdd500440062c80e22c80c90190c058dd5002c56600266e1d200a0048994c004dd6980d000cc068c06c006602e6ea8025222980080b4dd6180e800cdd5980e980f180f180f180f180f180f180f180f180f000d30103d879800040143016375400b15980099b87480200122664530010149bac301b0019bab301b301c301c301c301c301c301c301c301c301c001a60103d87a8000400c6032602c6ea8014c058dd50044590142028405080a08888c966002603c00313259800980a180d1baa00189919806800899baf001004301e301b375400316406466014006603a00316406c64646600200200a44b30010018a5eb8226644b30013375e6042603c6ea8c084c088c078dd5001002c4cc080008cc01001000626600800800280e0c07c004c08000501d1802802118051980b98049980b9ba90014bd701980ba60103d87a80004bd70202430113754002602a00a6028602a008452689b2b20081", + "hash": "55c2a7f6143ce2befd94139304436b30a0398f21cd2464c760455033" + }, + { + "title": "start.start.publish", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1PublishRedeemer" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c4a01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e90004dc3a4005370e90024dc3a400d374a90004dd2a400491111114c004c04401e602000f2232598009804800c56600260206ea800e0051640451598009804000c56600260206ea800e0051640451598009803800c56600260206ea800e0051640451598009803000c56600260206ea800e00516404515980099b87480200062b3001301037540070028b20228b201c4038807100e201c300e3754005223232330010010042259800800c530103d87a80008992cc004cdd78021809000c4c020cc054c04c0052f5c113300300330170024044602a0028098c00ccc044c048c03cdd5000a5eb81222232332259800980580144c8c8ca60026eacc0680066034602e6ea801a64660020026eb0c06c010896600200314bd7044cc8966002646600200264660020026eacc080c084c074dd518101810980e9baa0042259800800c52f5c1132332232330010013756604400844b30010018801c4c8cc098dd3998131ba90053302630230013302630240014bd701980180198140011813000a048375c603c002660060066046004604200280f8896600200314a115980099b8f375c60406eb0c08000406a2946266004004604200280d901e44cc074008cc01001000626600800800280c8c070004c07400501a2444b3001301e0018999119912cc004c05cc074dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c0ac0066eb8c0ac02a6eb8c0ac0266eb4c0ac01e6eb4c0ac01a64b300130290018acc004cdc4a4008605000316898109814000a04e8b20543754605600b375a6056009375a6056007302b002488888888966002606a01513301430340111330140011329800981b000cdd7181a800cdc7a45009b9148810048888ca60026076003323322330020020012259800800c52f5c11332259800acc004cdd7981f981e1baa0020058981a192cc004c0d4c0f0dd5000c5200089bad3040303d375400281d8c966002606a60786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0300062b3001300d0018981b19821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806800c56600266e3c0340062606a66084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a076375860760466058660726056660726ea40cd2f5c0660726058660726058660726056660726ea40112f5c097ae04bd7025eb8266ebcc0accc0e4dd480225eb8007d22259800981f00144c8cc88cc8966002607000313232323298009bad30460019bae30460049bae30460039bad30460024888966002609600b00a8b2090182300098228009822000981f9baa0038acc004c0dc0062646464653001375a608c003375c608c009375c608c007375a608c00491112cc004c12c016015164120304600130450013044001303f3754007159800981b000c4c8c8c8c8ca60026eb4c11c0066eb8c11c0166eb8c11c0126eb4c11c00d2222598009826002c4c966002608460906ea8006264646644b3001305100380845904e1bad304e001375c609c004609c00260926ea80062c8238c12c01a2c8248608e002608c002608a0026088002607e6ea800e2b3001303500189919194c004dd69822800cdd71822801cdd718228012444b300130490048044590460c114004c110004c0fcdd5001c5903d207a40f481e84cc89660026070607c6ea8006264660620022b30010078acc0040162b30010038acc004cc89660020030028acc004c118006264b3001300f375c608c0031303b375a608c608e00314a08208c118dd61822800c009043208614a06466002002646600200205644b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc004006297ae0899912cc004cdc79bae30470020118998231ba700233004004001899802002000a0843758608a002608c002821a266ebc005300103d87a80008a5040f914a081f2294103e4528207c3042303f37540031640f466ebc004c0c8cc0fcdd48051981f98200059981f98200031981f9ba8337006eb4c100c104c1040180e12f5c06605a6eacc100c104c104c104c104c10409c08cc0f0dd500099b873259800981a181d9baa0018a40011375a607e60786ea800503a192cc004c0d0c0ecdd5000c530103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c02c0062b3001300c0018981a99821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8008896600200314c103d87a8000899192cc004c0280062b3001300b0018981a19820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e1bad303e00532598009819981d9baa0018981f981e1baa0018b2074303e303f303f303b3754002607a0051640ec303a303a00418189baa0158b2064181580098150009814800981400098138009813000981280098120009811800980f1baa0028b20383259800980a180e1baa00189810180e9baa0018b2036301f30203020301c3754603e604060386ea80088966002602e603a6ea800a2646464b3001302500289980318120018992cc004c06c006264b30013027001899192cc004c078006264b3001302a0018998059814800804c5902718129baa0028acc004c07400626464653001375a6056003375a6056007375a60560049112cc004c0bc01201d1640b0302b001302a0013025375400516408c8118c08cdd50009813000c5902418111baa0028acc004c0680062b3001302237540050058b20468b2040408060406ea80062c8110c08c004c08c004c078dd500145901c180e80091192cc004c05800626464b300130230028024590201bae3021001301d3754007159800980a800c4c8c96600260460050048b2040375c6042002603a6ea800e2c80d901b180d9baa0028b2036180d180d000980c980c800980a1baa006899192cc004c03c0122646644b300130120018acc004c064dd5003400a2c80d22b300130110018acc004c064dd5003400a2c80d22c80b9017099192cc004c048c060dd500344c8c8cc004004dd5980f001912cc00400629422b30013375e0066036603e00314a31330020023020001406880e8c034cc06cdd4801a5eb82330010159bac301c0029bab301c301d301d301d001a6103d87d8000401080b8c070c070c070c070c070c070004c05cdd5004980b1baa004375c6032602c6ea80162b3001300c0048994c004dd6980d000cc068c06c006602c6ea801226464b3001301d0018992cc004c04cc064dd5000c4c8cc030004566002602860346ea8022266ebc00530103d8798000899baf0014c103d87b80004064603a60346ea80062c80c0cc024dd5980e180e980e980e980e980e980e980e980e980e801180e000c5901a19199119801001000912cc004006297ae0899912cc004cdd79810180e9baa30203021301d375400400b13301f00233004004001899802002000a036301e001301f00140706eb0c070008c010050c05cdd5004a4444b300130140028acc004c06cdd500440062c80e22b300130130028acc004c06cdd500440062c80e22c80c90190c058dd5002c56600266e1d200a0048994c004dd6980d000cc068c06c006602e6ea8025222980080b4dd6180e800cdd5980e980f180f180f180f180f180f180f180f180f000d30103d879800040143016375400b15980099b87480200122664530010149bac301b0019bab301b301c301c301c301c301c301c301c301c301c001a60103d87a8000400c6032602c6ea8014c058dd50044590142028405080a08888c966002603c00313259800980a180d1baa00189919806800899baf001004301e301b375400316406466014006603a00316406c64646600200200a44b30010018a5eb8226644b30013375e6042603c6ea8c084c088c078dd5001002c4cc080008cc01001000626600800800280e0c07c004c08000501d1802802118051980b98049980b9ba90014bd701980ba60103d87a80004bd70202430113754002602a00a6028602a008452689b2b20081", + "hash": "55c2a7f6143ce2befd94139304436b30a0398f21cd2464c760455033" + }, + { + "title": "start.start.propose", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c4a01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e90004dc3a4005370e90024dc3a400d374a90004dd2a400491111114c004c04401e602000f2232598009804800c56600260206ea800e0051640451598009804000c56600260206ea800e0051640451598009803800c56600260206ea800e0051640451598009803000c56600260206ea800e00516404515980099b87480200062b3001301037540070028b20228b201c4038807100e201c300e3754005223232330010010042259800800c530103d87a80008992cc004cdd78021809000c4c020cc054c04c0052f5c113300300330170024044602a0028098c00ccc044c048c03cdd5000a5eb81222232332259800980580144c8c8ca60026eacc0680066034602e6ea801a64660020026eb0c06c010896600200314bd7044cc8966002646600200264660020026eacc080c084c074dd518101810980e9baa0042259800800c52f5c1132332232330010013756604400844b30010018801c4c8cc098dd3998131ba90053302630230013302630240014bd701980180198140011813000a048375c603c002660060066046004604200280f8896600200314a115980099b8f375c60406eb0c08000406a2946266004004604200280d901e44cc074008cc01001000626600800800280c8c070004c07400501a2444b3001301e0018999119912cc004c05cc074dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c0ac0066eb8c0ac02a6eb8c0ac0266eb4c0ac01e6eb4c0ac01a64b300130290018acc004cdc4a4008605000316898109814000a04e8b20543754605600b375a6056009375a6056007302b002488888888966002606a01513301430340111330140011329800981b000cdd7181a800cdc7a45009b9148810048888ca60026076003323322330020020012259800800c52f5c11332259800acc004cdd7981f981e1baa0020058981a192cc004c0d4c0f0dd5000c5200089bad3040303d375400281d8c966002606a60786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0300062b3001300d0018981b19821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806800c56600266e3c0340062606a66084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a076375860760466058660726056660726ea40cd2f5c0660726058660726058660726056660726ea40112f5c097ae04bd7025eb8266ebcc0accc0e4dd480225eb8007d22259800981f00144c8cc88cc8966002607000313232323298009bad30460019bae30460049bae30460039bad30460024888966002609600b00a8b2090182300098228009822000981f9baa0038acc004c0dc0062646464653001375a608c003375c608c009375c608c007375a608c00491112cc004c12c016015164120304600130450013044001303f3754007159800981b000c4c8c8c8c8ca60026eb4c11c0066eb8c11c0166eb8c11c0126eb4c11c00d2222598009826002c4c966002608460906ea8006264646644b3001305100380845904e1bad304e001375c609c004609c00260926ea80062c8238c12c01a2c8248608e002608c002608a0026088002607e6ea800e2b3001303500189919194c004dd69822800cdd71822801cdd718228012444b300130490048044590460c114004c110004c0fcdd5001c5903d207a40f481e84cc89660026070607c6ea8006264660620022b30010078acc0040162b30010038acc004cc89660020030028acc004c118006264b3001300f375c608c0031303b375a608c608e00314a08208c118dd61822800c009043208614a06466002002646600200205644b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc004006297ae0899912cc004cdc79bae30470020118998231ba700233004004001899802002000a0843758608a002608c002821a266ebc005300103d87a80008a5040f914a081f2294103e4528207c3042303f37540031640f466ebc004c0c8cc0fcdd48051981f98200059981f98200031981f9ba8337006eb4c100c104c1040180e12f5c06605a6eacc100c104c104c104c104c10409c08cc0f0dd500099b873259800981a181d9baa0018a40011375a607e60786ea800503a192cc004c0d0c0ecdd5000c530103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c02c0062b3001300c0018981a99821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8008896600200314c103d87a8000899192cc004c0280062b3001300b0018981a19820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e1bad303e00532598009819981d9baa0018981f981e1baa0018b2074303e303f303f303b3754002607a0051640ec303a303a00418189baa0158b2064181580098150009814800981400098138009813000981280098120009811800980f1baa0028b20383259800980a180e1baa00189810180e9baa0018b2036301f30203020301c3754603e604060386ea80088966002602e603a6ea800a2646464b3001302500289980318120018992cc004c06c006264b30013027001899192cc004c078006264b3001302a0018998059814800804c5902718129baa0028acc004c07400626464653001375a6056003375a6056007375a60560049112cc004c0bc01201d1640b0302b001302a0013025375400516408c8118c08cdd50009813000c5902418111baa0028acc004c0680062b3001302237540050058b20468b2040408060406ea80062c8110c08c004c08c004c078dd500145901c180e80091192cc004c05800626464b300130230028024590201bae3021001301d3754007159800980a800c4c8c96600260460050048b2040375c6042002603a6ea800e2c80d901b180d9baa0028b2036180d180d000980c980c800980a1baa006899192cc004c03c0122646644b300130120018acc004c064dd5003400a2c80d22b300130110018acc004c064dd5003400a2c80d22c80b9017099192cc004c048c060dd500344c8c8cc004004dd5980f001912cc00400629422b30013375e0066036603e00314a31330020023020001406880e8c034cc06cdd4801a5eb82330010159bac301c0029bab301c301d301d301d001a6103d87d8000401080b8c070c070c070c070c070c070004c05cdd5004980b1baa004375c6032602c6ea80162b3001300c0048994c004dd6980d000cc068c06c006602c6ea801226464b3001301d0018992cc004c04cc064dd5000c4c8cc030004566002602860346ea8022266ebc00530103d8798000899baf0014c103d87b80004064603a60346ea80062c80c0cc024dd5980e180e980e980e980e980e980e980e980e980e801180e000c5901a19199119801001000912cc004006297ae0899912cc004cdd79810180e9baa30203021301d375400400b13301f00233004004001899802002000a036301e001301f00140706eb0c070008c010050c05cdd5004a4444b300130140028acc004c06cdd500440062c80e22b300130130028acc004c06cdd500440062c80e22c80c90190c058dd5002c56600266e1d200a0048994c004dd6980d000cc068c06c006602e6ea8025222980080b4dd6180e800cdd5980e980f180f180f180f180f180f180f180f180f000d30103d879800040143016375400b15980099b87480200122664530010149bac301b0019bab301b301c301c301c301c301c301c301c301c301c001a60103d87a8000400c6032602c6ea8014c058dd50044590142028405080a08888c966002603c00313259800980a180d1baa00189919806800899baf001004301e301b375400316406466014006603a00316406c64646600200200a44b30010018a5eb8226644b30013375e6042603c6ea8c084c088c078dd5001002c4cc080008cc01001000626600800800280e0c07c004c08000501d1802802118051980b98049980b9ba90014bd701980ba60103d87a80004bd70202430113754002602a00a6028602a008452689b2b20081", + "hash": "55c2a7f6143ce2befd94139304436b30a0398f21cd2464c760455033" + }, + { + "title": "start.start.vote", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c4a01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e90004dc3a4005370e90024dc3a400d374a90004dd2a400491111114c004c04401e602000f2232598009804800c56600260206ea800e0051640451598009804000c56600260206ea800e0051640451598009803800c56600260206ea800e0051640451598009803000c56600260206ea800e00516404515980099b87480200062b3001301037540070028b20228b201c4038807100e201c300e3754005223232330010010042259800800c530103d87a80008992cc004cdd78021809000c4c020cc054c04c0052f5c113300300330170024044602a0028098c00ccc044c048c03cdd5000a5eb81222232332259800980580144c8c8ca60026eacc0680066034602e6ea801a64660020026eb0c06c010896600200314bd7044cc8966002646600200264660020026eacc080c084c074dd518101810980e9baa0042259800800c52f5c1132332232330010013756604400844b30010018801c4c8cc098dd3998131ba90053302630230013302630240014bd701980180198140011813000a048375c603c002660060066046004604200280f8896600200314a115980099b8f375c60406eb0c08000406a2946266004004604200280d901e44cc074008cc01001000626600800800280c8c070004c07400501a2444b3001301e0018999119912cc004c05cc074dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c0ac0066eb8c0ac02a6eb8c0ac0266eb4c0ac01e6eb4c0ac01a64b300130290018acc004cdc4a4008605000316898109814000a04e8b20543754605600b375a6056009375a6056007302b002488888888966002606a01513301430340111330140011329800981b000cdd7181a800cdc7a45009b9148810048888ca60026076003323322330020020012259800800c52f5c11332259800acc004cdd7981f981e1baa0020058981a192cc004c0d4c0f0dd5000c5200089bad3040303d375400281d8c966002606a60786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0300062b3001300d0018981b19821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806800c56600266e3c0340062606a66084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a076375860760466058660726056660726ea40cd2f5c0660726058660726058660726056660726ea40112f5c097ae04bd7025eb8266ebcc0accc0e4dd480225eb8007d22259800981f00144c8cc88cc8966002607000313232323298009bad30460019bae30460049bae30460039bad30460024888966002609600b00a8b2090182300098228009822000981f9baa0038acc004c0dc0062646464653001375a608c003375c608c009375c608c007375a608c00491112cc004c12c016015164120304600130450013044001303f3754007159800981b000c4c8c8c8c8ca60026eb4c11c0066eb8c11c0166eb8c11c0126eb4c11c00d2222598009826002c4c966002608460906ea8006264646644b3001305100380845904e1bad304e001375c609c004609c00260926ea80062c8238c12c01a2c8248608e002608c002608a0026088002607e6ea800e2b3001303500189919194c004dd69822800cdd71822801cdd718228012444b300130490048044590460c114004c110004c0fcdd5001c5903d207a40f481e84cc89660026070607c6ea8006264660620022b30010078acc0040162b30010038acc004cc89660020030028acc004c118006264b3001300f375c608c0031303b375a608c608e00314a08208c118dd61822800c009043208614a06466002002646600200205644b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc004006297ae0899912cc004cdc79bae30470020118998231ba700233004004001899802002000a0843758608a002608c002821a266ebc005300103d87a80008a5040f914a081f2294103e4528207c3042303f37540031640f466ebc004c0c8cc0fcdd48051981f98200059981f98200031981f9ba8337006eb4c100c104c1040180e12f5c06605a6eacc100c104c104c104c104c10409c08cc0f0dd500099b873259800981a181d9baa0018a40011375a607e60786ea800503a192cc004c0d0c0ecdd5000c530103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c02c0062b3001300c0018981a99821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8008896600200314c103d87a8000899192cc004c0280062b3001300b0018981a19820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e1bad303e00532598009819981d9baa0018981f981e1baa0018b2074303e303f303f303b3754002607a0051640ec303a303a00418189baa0158b2064181580098150009814800981400098138009813000981280098120009811800980f1baa0028b20383259800980a180e1baa00189810180e9baa0018b2036301f30203020301c3754603e604060386ea80088966002602e603a6ea800a2646464b3001302500289980318120018992cc004c06c006264b30013027001899192cc004c078006264b3001302a0018998059814800804c5902718129baa0028acc004c07400626464653001375a6056003375a6056007375a60560049112cc004c0bc01201d1640b0302b001302a0013025375400516408c8118c08cdd50009813000c5902418111baa0028acc004c0680062b3001302237540050058b20468b2040408060406ea80062c8110c08c004c08c004c078dd500145901c180e80091192cc004c05800626464b300130230028024590201bae3021001301d3754007159800980a800c4c8c96600260460050048b2040375c6042002603a6ea800e2c80d901b180d9baa0028b2036180d180d000980c980c800980a1baa006899192cc004c03c0122646644b300130120018acc004c064dd5003400a2c80d22b300130110018acc004c064dd5003400a2c80d22c80b9017099192cc004c048c060dd500344c8c8cc004004dd5980f001912cc00400629422b30013375e0066036603e00314a31330020023020001406880e8c034cc06cdd4801a5eb82330010159bac301c0029bab301c301d301d301d001a6103d87d8000401080b8c070c070c070c070c070c070004c05cdd5004980b1baa004375c6032602c6ea80162b3001300c0048994c004dd6980d000cc068c06c006602c6ea801226464b3001301d0018992cc004c04cc064dd5000c4c8cc030004566002602860346ea8022266ebc00530103d8798000899baf0014c103d87b80004064603a60346ea80062c80c0cc024dd5980e180e980e980e980e980e980e980e980e980e801180e000c5901a19199119801001000912cc004006297ae0899912cc004cdd79810180e9baa30203021301d375400400b13301f00233004004001899802002000a036301e001301f00140706eb0c070008c010050c05cdd5004a4444b300130140028acc004c06cdd500440062c80e22b300130130028acc004c06cdd500440062c80e22c80c90190c058dd5002c56600266e1d200a0048994c004dd6980d000cc068c06c006602e6ea8025222980080b4dd6180e800cdd5980e980f180f180f180f180f180f180f180f180f000d30103d879800040143016375400b15980099b87480200122664530010149bac301b0019bab301b301c301c301c301c301c301c301c301c301c001a60103d87a8000400c6032602c6ea8014c058dd50044590142028405080a08888c966002603c00313259800980a180d1baa00189919806800899baf001004301e301b375400316406466014006603a00316406c64646600200200a44b30010018a5eb8226644b30013375e6042603c6ea8c084c088c078dd5001002c4cc080008cc01001000626600800800280e0c07c004c08000501d1802802118051980b98049980b9ba90014bd701980ba60103d87a80004bd70202430113754002602a00a6028602a008452689b2b20081", + "hash": "55c2a7f6143ce2befd94139304436b30a0398f21cd2464c760455033" + }, + { + "title": "start.start.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c4a01010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bae0039bad0024888888888966003300130063754017370e90004dc3a4005370e90024dc3a400d374a90004dd2a400491111114c004c04401e602000f2232598009804800c56600260206ea800e0051640451598009804000c56600260206ea800e0051640451598009803800c56600260206ea800e0051640451598009803000c56600260206ea800e00516404515980099b87480200062b3001301037540070028b20228b201c4038807100e201c300e3754005223232330010010042259800800c530103d87a80008992cc004cdd78021809000c4c020cc054c04c0052f5c113300300330170024044602a0028098c00ccc044c048c03cdd5000a5eb81222232332259800980580144c8c8ca60026eacc0680066034602e6ea801a64660020026eb0c06c010896600200314bd7044cc8966002646600200264660020026eacc080c084c074dd518101810980e9baa0042259800800c52f5c1132332232330010013756604400844b30010018801c4c8cc098dd3998131ba90053302630230013302630240014bd701980180198140011813000a048375c603c002660060066046004604200280f8896600200314a115980099b8f375c60406eb0c08000406a2946266004004604200280d901e44cc074008cc01001000626600800800280c8c070004c07400501a2444b3001301e0018999119912cc004c05cc074dd500144c8c8c8c8c8c8c8c8c8ca60026eb4c0ac0066eb8c0ac02a6eb8c0ac0266eb4c0ac01e6eb4c0ac01a64b300130290018acc004cdc4a4008605000316898109814000a04e8b20543754605600b375a6056009375a6056007302b002488888888966002606a01513301430340111330140011329800981b000cdd7181a800cdc7a45009b9148810048888ca60026076003323322330020020012259800800c52f5c11332259800acc004cdd7981f981e1baa0020058981a192cc004c0d4c0f0dd5000c5200089bad3040303d375400281d8c966002606a60786ea80062980103d87a8000899198008009bab3041303e375400444b30010018a6103d87a8000899192cc004c0300062b3001300d0018981b19821982080125eb82298103d87a800040fd133004004304500340fc6eb8c0fc004c10800504020763233001001375660806082607a6ea800c896600200314c103d87a8000899192cc004cdc8806800c56600266e3c0340062606a66084608000497ae08a60103d87a800040f9133004004304400340f86eb8c0f8004c10400503f4528207489981f00119802002000c4cc01001000503a181e800981f000a076375860760466058660726056660726ea40cd2f5c0660726058660726058660726056660726ea40112f5c097ae04bd7025eb8266ebcc0accc0e4dd480225eb8007d22259800981f00144c8cc88cc8966002607000313232323298009bad30460019bae30460049bae30460039bad30460024888966002609600b00a8b2090182300098228009822000981f9baa0038acc004c0dc0062646464653001375a608c003375c608c009375c608c007375a608c00491112cc004c12c016015164120304600130450013044001303f3754007159800981b000c4c8c8c8c8ca60026eb4c11c0066eb8c11c0166eb8c11c0126eb4c11c00d2222598009826002c4c966002608460906ea8006264646644b3001305100380845904e1bad304e001375c609c004609c00260926ea80062c8238c12c01a2c8248608e002608c002608a0026088002607e6ea800e2b3001303500189919194c004dd69822800cdd71822801cdd718228012444b300130490048044590460c114004c110004c0fcdd5001c5903d207a40f481e84cc89660026070607c6ea8006264660620022b30010078acc0040162b30010038acc004cc89660020030028acc004c118006264b3001300f375c608c0031303b375a608c608e00314a08208c118dd61822800c009043208614a06466002002646600200205644b30010018a5eb82264664464660020026eacc11c01089660020031003899198259ba73304b375200a66096609000266096609200297ae033003003304d002304b00141246eb8c10c004cc00c00cc120008c118005044112cc004006297ae0899912cc004cdc79bae30470020118998231ba700233004004001899802002000a0843758608a002608c002821a266ebc005300103d87a80008a5040f914a081f2294103e4528207c3042303f37540031640f466ebc004c0c8cc0fcdd48051981f98200059981f98200031981f9ba8337006eb4c100c104c1040180e12f5c06605a6eacc100c104c104c104c104c10409c08cc0f0dd500099b873259800981a181d9baa0018a40011375a607e60786ea800503a192cc004c0d0c0ecdd5000c530103d87a8000899198008009bab3040303d375400444b30010018a6103d87a8000899192cc004c02c0062b3001300c0018981a99821182000125eb82298103d87a800040f9133004004304400340f86eb8c0f8004c10400503f207432330010013756607e608060786ea8008896600200314c103d87a8000899192cc004c0280062b3001300b0018981a19820981f80125eb82298103d87a800040f5133004004304300340f46eb8c0f4004c10000503e1bad303e00532598009819981d9baa0018981f981e1baa0018b2074303e303f303f303b3754002607a0051640ec303a303a00418189baa0158b2064181580098150009814800981400098138009813000981280098120009811800980f1baa0028b20383259800980a180e1baa00189810180e9baa0018b2036301f30203020301c3754603e604060386ea80088966002602e603a6ea800a2646464b3001302500289980318120018992cc004c06c006264b30013027001899192cc004c078006264b3001302a0018998059814800804c5902718129baa0028acc004c07400626464653001375a6056003375a6056007375a60560049112cc004c0bc01201d1640b0302b001302a0013025375400516408c8118c08cdd50009813000c5902418111baa0028acc004c0680062b3001302237540050058b20468b2040408060406ea80062c8110c08c004c08c004c078dd500145901c180e80091192cc004c05800626464b300130230028024590201bae3021001301d3754007159800980a800c4c8c96600260460050048b2040375c6042002603a6ea800e2c80d901b180d9baa0028b2036180d180d000980c980c800980a1baa006899192cc004c03c0122646644b300130120018acc004c064dd5003400a2c80d22b300130110018acc004c064dd5003400a2c80d22c80b9017099192cc004c048c060dd500344c8c8cc004004dd5980f001912cc00400629422b30013375e0066036603e00314a31330020023020001406880e8c034cc06cdd4801a5eb82330010159bac301c0029bab301c301d301d301d001a6103d87d8000401080b8c070c070c070c070c070c070004c05cdd5004980b1baa004375c6032602c6ea80162b3001300c0048994c004dd6980d000cc068c06c006602c6ea801226464b3001301d0018992cc004c04cc064dd5000c4c8cc030004566002602860346ea8022266ebc00530103d8798000899baf0014c103d87b80004064603a60346ea80062c80c0cc024dd5980e180e980e980e980e980e980e980e980e980e801180e000c5901a19199119801001000912cc004006297ae0899912cc004cdd79810180e9baa30203021301d375400400b13301f00233004004001899802002000a036301e001301f00140706eb0c070008c010050c05cdd5004a4444b300130140028acc004c06cdd500440062c80e22b300130130028acc004c06cdd500440062c80e22c80c90190c058dd5002c56600266e1d200a0048994c004dd6980d000cc068c06c006602e6ea8025222980080b4dd6180e800cdd5980e980f180f180f180f180f180f180f180f180f000d30103d879800040143016375400b15980099b87480200122664530010149bac301b0019bab301b301c301c301c301c301c301c301c301c301c001a60103d87a8000400c6032602c6ea8014c058dd50044590142028405080a08888c966002603c00313259800980a180d1baa00189919806800899baf001004301e301b375400316406466014006603a00316406c64646600200200a44b30010018a5eb8226644b30013375e6042603c6ea8c084c088c078dd5001002c4cc080008cc01001000626600800800280e0c07c004c08000501d1802802118051980b98049980b9ba90014bd701980ba60103d87a80004bd70202430113754002602a00a6028602a008452689b2b20081", + "hash": "55c2a7f6143ce2befd94139304436b30a0398f21cd2464c760455033" + } + ], + "definitions": { + "Bool": { + "title": "Bool", + "anyOf": [ + { + "title": "False", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "True", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "ByteArray": { + "dataType": "bytes" + }, + "Data": { + "title": "Data", + "description": "Any Plutus data." + }, + "Int": { + "dataType": "integer" + }, + "List$cardano/address/Credential": { + "dataType": "list", + "items": { + "$ref": "#/definitions/cardano~1address~1Credential" + } + }, + "Option$aiken/crypto/ScriptHash": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Option$cardano/address/StakeCredential": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1address~1StakeCredential" + } + ] + }, + { + "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$cardano/address/Credential_cardano/assets/Lovelace": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/cardano~1assets~1Lovelace" + } + }, + "Pairs$cardano/address/Credential_cardano/governance/Mandate": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/cardano~1governance~1Mandate" + } + }, + "Pairs$gov/ProtocolParametersIndex_Data": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/gov~1ProtocolParametersIndex" + }, + "values": { + "$ref": "#/definitions/Data" + } + }, + "aiken/collection/Index": { + "title": "Index", + "dataType": "integer" + }, + "aiken/crypto/ScriptHash": { + "title": "ScriptHash", + "dataType": "bytes" + }, + "aiken/crypto/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/cardano~1address~1PaymentCredential" + }, + { + "title": "stake_credential", + "$ref": "#/definitions/Option$cardano~1address~1StakeCredential" + } + ] + } + ] + }, + "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/aiken~1crypto~1VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/address/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/aiken~1crypto~1VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/address/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" + } + ] + } + ] + }, + "cardano/assets/Lovelace": { + "title": "Lovelace", + "dataType": "integer" + }, + "cardano/assets/PolicyId": { + "title": "PolicyId", + "dataType": "bytes" + }, + "cardano/governance/Constitution": { + "title": "Constitution", + "anyOf": [ + { + "title": "Constitution", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "guardrails", + "$ref": "#/definitions/Option$aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/governance/GovernanceActionId": { + "title": "GovernanceActionId", + "anyOf": [ + { + "title": "GovernanceActionId", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "transaction", + "$ref": "#/definitions/cardano~1governance~1TransactionId" + }, + { + "title": "proposal_procedure", + "$ref": "#/definitions/aiken~1collection~1Index" + } + ] + } + ] + }, + "cardano/governance/Mandate": { + "title": "Mandate", + "dataType": "integer" + }, + "cardano/governance/ProtocolVersion": { + "title": "ProtocolVersion", + "anyOf": [ + { + "title": "ProtocolVersion", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "major", + "$ref": "#/definitions/Int" + }, + { + "title": "minor", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "cardano/governance/TransactionId": { + "title": "TransactionId", + "dataType": "bytes" + }, + "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/ProtocolParametersIndex": { + "title": "ProtocolParametersIndex", + "dataType": "integer" + }, + "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$aiken~1crypto~1ScriptHash" + } + ] + }, + { + "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_cardano~1assets~1Lovelace" + }, + { + "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$aiken~1crypto~1ScriptHash" + } + ] + }, + { + "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_cardano~1governance~1Mandate" + }, + { + "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$gov~1ProtocolParametersIndex_Data" + } + ] + } + ] + }, + "gov/VRational": { + "title": "VRational", + "anyOf": [ + { + "title": "VRational", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "numerator", + "$ref": "#/definitions/Int" + }, + { + "title": "denominator", + "$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/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": [ + { + "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-extension/specs/1_spend.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/1_spend.md new file mode 100644 index 000000000..f3a7776d0 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/1_spend.md @@ -0,0 +1,82 @@ +# Specification - Spend + +## Parameter + +- `delegate_pool_id`: ByteArray +- `gov_action`: VGovernanceAction +- `proposer_key_hash`: ByteArray +- `stake_register_deposit`: Lovelace +- `drep_register_deposit`: Lovelace +- `gov_deposit`: Lovelace + +## Datum + +```rs +pub type Datum { + Init { + start_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + deadline: Int, + } + Proposed { + 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 { + start_hash: ByteArray, + share_token: ByteArray, + funds_controlled: Int, + } +} +``` + +## User Action + +1. RegisterCerts + - Only one input and output from current address with token of policy `start_hash` + - Input datum in state of `Init` + - Output value has deducted with 502 + 100k ADA exactly + - Output datum in state of `Proposed` + - fields exactly the same + - Registering stake cert + - Registering DRep cert with drep_register_deposit + - Delegate to current own DRep + stake pool `delegate_pool_id` + - Propose gov action + +2. VoteOnGovAction + - Only one input and output from current address with token of policy `start_hash` + - Input datum in state of `Proposed` + - Output datum in state of `Voted`, with `gov_tx_id` composed by own's input `TransactionId` + `proposal_procedure` as 0 + - fields exactly the same + - Voted yes by drep + +3. DeregisterCerts + - collecting 100k ada from reward address to spending address + - deadline is passed + - Only one input and output from current address with token of policy `start_hash` + - Input datum in state of `Voted` + - Output datum in state of `Refundable` + - fields exactly the same + - Deregistering both certs + - Refunds (502ADA) go into the output + +4. ContributorWithdrawal + - Input with token of policy `start_hash` + - Input datum in state of Refundable + - The lovelace unlocking from current equal exactly the amount that the `share_token` with token name of `completion_script` is burnt + +5. RemoveEmptyInstance + - Input with token of policy `start_hash`, which is burnt + - Input datum in state of Refundable + - 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-extension/specs/2_start.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/2_start.md new file mode 100644 index 000000000..6e2f79a27 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/2_start.md @@ -0,0 +1,58 @@ +# 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 `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: + + ```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-extension/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/_scripts.md new file mode 100644 index 000000000..94cedaeca --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/_scripts.md @@ -0,0 +1,19 @@ +# Aiken Gov Crowdfunding + +## 1. Spend + +The spending validator that guarding the crowdfunded + +## 2. Start + +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 + +2. Second layer + + - `start` - param `spend` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/specs/user_action_doc.md new file mode 100644 index 000000000..1dec29f5d --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/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 diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/crowdfund.ak new file mode 100644 index 000000000..15214850b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/crowdfund.ak @@ -0,0 +1,218 @@ +use aiken/collection/list +use aiken/collection/pairs.{has_key} +use cardano/address.{Address, Credential, Script} +use cardano/assets.{ + Lovelace, PolicyId, from_lovelace, is_zero, lovelace_of, without_lovelace, +} +use cardano/transaction.{Output, OutputReference, Transaction, find_input} +use cocktail.{ + 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, +} +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 + } +} + +pub fn outputs_at_with_lovelace( + outputs: List, + address: Address, + lovelace: Lovelace, +) -> List { + list.filter( + outputs, + fn(output) { + let is_lovelace_match = output.value == from_lovelace(lovelace) + is_lovelace_match && output.address == address + }, + ) +} + +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, + extra_signatories, + .. + } = 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 token 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 input_lovelace_check = + lovelace_of(auth_input.output.value) >= min_charge + current_fundraised_amount + + let fee_output_check = + when min_charge is { + 0 -> True + _ -> { + expect [fee_output] = + outputs + |> list.filter(fn(output) { output.address == fee_address }) + lovelace_of(fee_output.value) >= min_charge && ( + without_lovelace(fee_output.value) |> is_zero() + ) + } + } + + 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) + fee_output_check? && fundraise_check? && withdrawal_script_check? && input_lovelace_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)? + } + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + validity_check? && token_burnt_check? && proposer_key_signed_check? + } + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/spend.ak new file mode 100644 index 000000000..3314e3410 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/spend.ak @@ -0,0 +1,285 @@ +use cardano/address.{Inline, Script} +use cardano/assets.{Lovelace, lovelace_of} +use cardano/certificate.{Registered} +use cardano/governance.{DelegateRepresentative, GovernanceActionId} +use cardano/transaction.{OutputReference, Transaction, find_input} +use cocktail.{ + 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, 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: VGovernanceAction, + proposer_key_hash: ByteArray, + stake_register_deposit: Lovelace, + drep_register_deposit: Lovelace, + gov_deposit: Lovelace, +) { + spend( + datum_opt: Option, + redeemer: CrowdfundRedeemer, + input: OutputReference, + self: Transaction, + ) { + let Transaction { + inputs, + validity_range, + mint, + outputs, + extra_signatories, + certificates, + proposal_procedures, + votes, + .. + } = self + + expect Some(own_input) = find_input(inputs, input) + expect Some(only_input_datum) = datum_opt + + let current_address = own_input.output.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_with(outputs, current_address, start_hash, "") + + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + -(stake_register_deposit + drep_register_deposit + gov_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 = + check_proposal_procedure( + proposal_procedures, + gov_deposit, + Script(start_hash), + 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 } -> { + // 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 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, + deadline, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + + 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_with(outputs, current_address, start_hash, "") + let lovelace_check = + check_lovelace_diff( + only_input, + only_output, + stake_register_deposit + drep_register_deposit + gov_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, + } + + 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, + ) + + 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 + } + + ContributorWithdrawal -> + when only_input_datum is { + 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_with(outputs, current_address, start_hash, "") + + 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, + } + + let is_only_output_value_clean = + value_length(only_output.value) == 2 + + 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 } -> { + // 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( + mint, + share_token, + start_hash, + -funds_controlled, + ) + } else { + True + } + + let proposer_key_signed_check = + key_signed(extra_signatories, proposer_key_hash) + token_burnt_check? && proposer_key_signed_check? && policy_only_minted_token( + mint, + start_hash, + "", + -1, + )? + } + _ -> False + } + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/start.ak new file mode 100644 index 000000000..fc6cc226e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/start.ak @@ -0,0 +1,131 @@ +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_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, + RegisterCerts, RemoveEmptyInstance, VoteOnGovAction, +} +use utils.{check_spend_script_input_redeemer, redeemer_with_input} + +validator start( + auth_token: PolicyId, + spend: ByteArray, + gov_action_period: Int, +) { + withdraw(_r, account: Credential, self: Transaction) { + 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) + + 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(completion_script))), + } + + 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 + expect fundraise_output_datum: CrowdfundGovDatum = + output_inline_datum(fundraise_target_output) + let fundraise_output_datum_check = + fundraise_output_datum == Init { + start_hash: completion_script, + share_token, + 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) { + 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(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/intergration_test/complete_crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/intergration_test/complete_crowdfund.ak new file mode 100644 index 000000000..ba6360ca6 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/intergration_test/complete_crowdfund.ak @@ -0,0 +1,434 @@ +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_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_fee_address, mock_fundraise_target, 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} + +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) + |> add(mock_auth_token, mock_completion_script, 1) + + let output_value = from_lovelace(mock_min_charge) + + 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_min_charge - 1), + ) + |> 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, + mock_proposer_key_hash, + 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-extension/validators/tests/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/spend.ak new file mode 100644 index 000000000..00e5aa4ad --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/spend.ak @@ -0,0 +1,2193 @@ +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_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_start_hash), + governance_action: NoConfidence { ancestor: None }, + }, + ) +} + +test s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 + mock_fundraise_target, + ) + |> add(mock_start_hash, "", 1) + } else { + from_lovelace( + mock_funds_controlled + mock_stake_register_deposit + mock_drep_register_deposit + mock_fundraise_target - 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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 { +// start_hash: mock_start_hash, +// share_token: mock_share_token, +// funds_controlled: mock_current_fundraised_amount, +// }, +// ), +// ContributorWithdrawal, +// mock_utxo_ref(0, 0), +// tx, +// ) +// } + +test s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + Some( + Refundable { + start_hash: mock_start_hash, + share_token: mock_share_token, + funds_controlled: 0, + }, + ), + RemoveEmptyInstance, + mock_utxo_ref(0, 0), + tx, + ) +} + +test s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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_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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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 s1_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, + mock_fundraise_target, + 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-extension/validators/tests/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/start.ak new file mode 100644 index 000000000..79410b8f2 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/start.ak @@ -0,0 +1,611 @@ +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, +} +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, + is_redeemer_correct: 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, + 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) + + 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() + |> add_redeemer( + is_redeemer_correct, + Pair( + Spend( + OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, + ), + auth_input_redeemer, + ), + ) +} + +test s2_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, + is_redeemer_correct: True, + }, + ) + + 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_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, + is_redeemer_correct: True, + }, + ) + + 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_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, + is_redeemer_correct: True, + }, + ) + + 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_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, + is_redeemer_correct: True, + }, + ) + + !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_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, + is_redeemer_correct: True, + }, + ) + + !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_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, + is_redeemer_correct: True, + }, + ) + + !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_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( + 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: 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-extension/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/utils.ak new file mode 100644 index 000000000..7d9e01d43 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-extension/validators/tests/utils.ak @@ -0,0 +1,122 @@ +use aiken/collection/list +use cardano/address.{Address, Inline, Script, from_script} +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_tx_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_extra_fundraised_amount = 4000000 + +pub const mock_min_charge = 10 + +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 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_start_hash = mock_script_hash(0) + +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_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_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 + 1000000 + +pub const mock_gov_action_id = + GovernanceActionId { transaction: mock_tx_hash(0), proposal_procedure: 0 } + +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_vote( + tx: Transaction, + condition: Bool, + vote: Pair>, +) -> Transaction { + if !condition { + tx + } else { + Transaction { + ..tx, + votes: tx.votes + |> list.concat([vote]), + } + } +}