diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/README.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/README.md new file mode 100644 index 000000000..e76d22490 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/README.md @@ -0,0 +1 @@ +Implement in core mesh repo `mesh-contract` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.lock b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.lock new file mode 100644 index 000000000..2e65bd164 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.lock @@ -0,0 +1,26 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +[[requirements]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +source = "github" + +[[requirements]] +name = "sidan-lab/vodka" +version = "0.1.13" +source = "github" + +[[packages]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +requirements = [] +source = "github" + +[[packages]] +name = "sidan-lab/vodka" +version = "0.1.13" +requirements = [] +source = "github" + +[etags] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.toml new file mode 100644 index 000000000..62cb1af77 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/aiken.toml @@ -0,0 +1,23 @@ +name = "sidan-lab/crowdfund" +version = "0.0.0" +compiler = "v1.1.16" +plutus = "v3" +license = "Apache-2.0" +description = "Aiken contracts for project 'sidan-lab/crowdfund'" + +[repository] +user = "sidan-lab" +project = "crowdfund" +platform = "github" + +[[dependencies]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +source = "github" + +[[dependencies]] +name = "sidan-lab/vodka" +version = "0.1.13" +source = "github" + +[config] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/types.ak new file mode 100644 index 000000000..0232fc7aa --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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/aiken-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/lib/utils.ak new file mode 100644 index 000000000..75d90a275 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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/aiken-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/plutus.json new file mode 100644 index 000000000..4e0876c10 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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/aiken-crowdfund/specs/1_auth_token.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/1_auth_token.md new file mode 100644 index 000000000..86a689cd0 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/1_auth_token.md @@ -0,0 +1,15 @@ +# Auth Token - One Shot + +## Parameter + +- `utxo_ref`: UTxO to be spent at minting + +## User Action + +1. Mint - Redeemer `RMint` + + - Transaction hash as parameterized is included in input + +2. Burn - Redeemer `RBurn` + + - The current policy id only has negative minting value in transaction body. diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/2_shares.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/2_shares.md new file mode 100644 index 000000000..4492912d7 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/2_shares.md @@ -0,0 +1,15 @@ +# Share Token + +## Parameter + +- `auth_token`: The policy id of `AuthToken` + +## User Action + +1. Mint - Redeemer `RMint` + + - There is input with `auth_token` with redeemer `ContributeFund` + +2. Burn - Redeemer `RBurn` + + - The current policy id only has negative minting value in transaction body. diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/3_crowdfund.md new file mode 100644 index 000000000..a99dbcc26 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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 lovelave 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/aiken-crowdfund/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md new file mode 100644 index 000000000..72da5bb9a --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/_scripts.md @@ -0,0 +1,24 @@ +# Aiken Crowdfunding + +## 1. Auth Token + +The token that represent distinct crowdfunding campaign, attaching with distinct `completion_script` + +## 2. Shares + +The token that represents lovelace contributed to current crowdfunding campaign + +## 3. Crowdfund + +The validator that handles the crowdfunding campaign + +## Param dependency tree + +1. First layer + + - `auth_token` - `utxo_ref` + +2. Second layer + + - `shares` - param `auth_token` + - `crowdfund` - param `auth_token` diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/application_setup_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/application_setup_doc.md new file mode 100644 index 000000000..4cdb0de40 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/application_setup_doc.md @@ -0,0 +1,14 @@ +# Application Setup Documentation + +## Setup + +The are 2 steps of setting up the applications: + +1. Minting `auth_token`, one time minting policy with empty token name with quantity of 1. + + - Validation: 1.1 + +2. Sending the the `auth_token` to `crowdfund` + + - With inline datum `CrowdfundDatum` of proposal details, `completion_script` set to be `2_start` script hash from `gov_crowdfund`, `share_token` set to be `2_share` script hash, `crowdfund` set to be `3_crowdfund` script hash and `current_fundraised_amount` set to be the lovelace value of output + - Validation: N/A \ No newline at end of file diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md new file mode 100644 index 000000000..c2912625c --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/specs/user_action_doc.md @@ -0,0 +1,29 @@ +# User Actions Documentation + +## Normal Users + +1. Contribute fund. Minting `share_token` + + - Validation: 2.1, 3.1 + +2. Withdraw fund. Burning `share_token` + + - Validation: 2.2, 3.3 + +## Proposer + +1. Contribute fund. Minting `share_token` + + - Validation: 2.1, 3.1 + +2. Withdraw fund. Burning `share_token` + + - Validation: 2.2, 3.3 + +3. Complete Crowdfund. Sending `auth_token` and `fundraised_amount` to `1_spend` from `gov-aiken`. 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/aiken-crowdfund/validators/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/auth_token/mint.ak new file mode 100644 index 000000000..57706664d --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/auth_token/mint.ak @@ -0,0 +1,27 @@ +use aiken/collection/dict +use aiken/collection/list +use cardano/assets.{PolicyId} +use cardano/transaction.{OutputReference, Transaction} +use types.{MintPolarity, RBurn, RMint} + +validator auth_token(utxo_ref: OutputReference) { + mint(redeemer: MintPolarity, policy_id: PolicyId, self: Transaction) { + expect [Pair(_asset_name, quantity)] = + self.mint + |> assets.tokens(policy_id) + |> dict.to_pairs() + let Transaction { inputs, .. } = self + when redeemer is { + RMint -> { + let is_output_consumed = + list.any(inputs, fn(input) { input.output_reference == utxo_ref }) + is_output_consumed? && quantity == 1 + } + RBurn -> quantity == -1 + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/crowdfund/spend.ak new file mode 100644 index 000000000..544ee930b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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/aiken-crowdfund/validators/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/share_token/mint.ak new file mode 100644 index 000000000..01bad7385 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/share_token/mint.ak @@ -0,0 +1,35 @@ +use aiken/collection/dict +use cardano/assets.{PolicyId} +use cardano/transaction.{Transaction} +use cocktail.{inputs_with_policy} +use types.{ContributeFund, CrowdfundRedeemer, MintPolarity, RBurn, RMint} +use utils.{redeemer_with_input} + +validator share_token(auth_token: PolicyId) { + mint(redeemer: MintPolarity, policy_id: PolicyId, self: Transaction) { + expect [Pair(_asset_name, quantity)] = + self.mint + |> assets.tokens(policy_id) + |> dict.to_pairs() + let Transaction { inputs, redeemers, .. } = self + when redeemer is { + RMint -> { + expect [auth_token_input] = inputs_with_policy(inputs, auth_token) + + expect Some(auth_token_redeemer_data) = + redeemer_with_input(redeemers, auth_token_input) + + expect auth_token_redeemer: CrowdfundRedeemer = auth_token_redeemer_data + + let redeemer_check = auth_token_redeemer == ContributeFund + + redeemer_check? + } + RBurn -> quantity == -1 + } + } + + else(_) { + fail + } +} diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak new file mode 100644 index 000000000..b113dd1c5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/auth_token/mint.ak @@ -0,0 +1,63 @@ +use auth_token/mint as auth_token_mint +use cardano/assets.{add, from_asset, zero} +use cardano/transaction.{Transaction, placeholder} +use mocktail.{ + complete, mint, mock_policy_id, mock_pub_key_address, mock_tx_hash, + mock_utxo_ref, mocktail_tx, tx_in, +} +use tests/utils.{mock_auth_token} +use types.{RBurn, RMint} + +test 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/aiken-crowdfund/validators/tests/crowdfund/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/crowdfund/spend.ak new file mode 100644 index 000000000..2b68446f5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/integration_test/contribute_fund.ak new file mode 100644 index 000000000..1bbcc7e28 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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/aiken-crowdfund/validators/tests/share_token/mint.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak new file mode 100644 index 000000000..6ad5a815e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/share_token/mint.ak @@ -0,0 +1,93 @@ +use cardano/assets.{add, from_asset, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction, placeholder} +use mocktail.{ + add_redeemer, complete, mint, mock_policy_id, mock_tx_hash, mocktail_tx, tx_in, +} +use share_token/mint as share_token_mint +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_share_token, +} +use types.{ContributeFund, RBurn, RMint} + +test 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/aiken-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-crowdfund/validators/tests/utils.ak new file mode 100644 index 000000000..c2ee6a99b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/aiken-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-crowdfund/.github/workflows/continuous-integration.yml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.github/workflows/continuous-integration.yml new file mode 100644 index 000000000..ba419b4a2 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.github/workflows/continuous-integration.yml @@ -0,0 +1,18 @@ +name: Continuous Integration + +on: + push: + branches: ["main"] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: aiken-lang/setup-aiken@v1 + with: + version: v1.1.16 + - run: aiken fmt --check + - run: aiken check -D + - run: aiken build diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.gitignore b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.gitignore new file mode 100644 index 000000000..ff7811b15 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/.gitignore @@ -0,0 +1,6 @@ +# Aiken compilation artifacts +artifacts/ +# Aiken's project working directory +build/ +# Aiken's default documentation export +docs/ diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/README.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/README.md new file mode 100644 index 000000000..de5ef005b --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/README.md @@ -0,0 +1 @@ +Implement separately & publish SDK diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.lock b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.lock new file mode 100644 index 000000000..2e65bd164 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.lock @@ -0,0 +1,26 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +[[requirements]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +source = "github" + +[[requirements]] +name = "sidan-lab/vodka" +version = "0.1.13" +source = "github" + +[[packages]] +name = "aiken-lang/stdlib" +version = "v2.2.0" +requirements = [] +source = "github" + +[[packages]] +name = "sidan-lab/vodka" +version = "0.1.13" +requirements = [] +source = "github" + +[etags] diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/aiken.toml new file mode 100644 index 000000000..bff202272 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/lib/gov.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/gov.ak new file mode 100644 index 000000000..d29db7b58 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/lib/types.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/types.ak new file mode 100644 index 000000000..90eb956d5 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/lib/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/lib/utils.ak new file mode 100644 index 000000000..0d66337fe --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/plutus.json b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json new file mode 100644 index 000000000..3c9d7328d --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/plutus.json @@ -0,0 +1,1076 @@ +{ + "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/PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "59121c0101003232323232323223223225333006323232323253323300c3001300d3754004264664464646464a66602660060022a66602c602a6ea80280085854ccc04cc02000454ccc058c054dd50050010b0a99980998020008a99980b180a9baa00a00216153330133370e90030008a99980b180a9baa00a00216163013375401226464646464646464646464646464a66603e601e60406ea80044c94ccc080c040c084dd500909919191919299981418158010991919191919191919191919191919191919191919191929919981e9816803899192999821182280109919191980480089919191919192999824299982419b87006337026eb4c014c128dd500380c099b89482024bd0040185280a9998240020a9998240018a9998240010a9998240008991929998268008010a999826982800089919199911299982799b8f0030211533304f3371e004044266e1c0040345280a50375c60a20046eb8c144004dd69828982900098288009bac304f001002323300100103222533304e00114bd70099191919198008009bab3051004225333053001100313233055374e660aa6ea4014cc154c148004cc154c14c0052f5c06600600660ae00460aa0026600800860a60066eb8c134004c1400045280a5014a029405280a50303832533304b0011480004c8c034c94ccc134008520001300e33001001305000222533304e0011480004c03ccc008008c144004c138004c8cc004004dd5981398251baa00a22533304c00114bd70099191919198008009bab304f004225333051001100313233053374e660a66ea4014cc14cc140004cc14cc1440052f5c06600600660aa00460a60026600800860a20066eb8c12c004c138004cdd7802991919191816998271827802198271827801998271827801198271827800998271ba83370003401060a060a0002609e002609c002609a00260906ea8098c8c8c94ccc120c0f4c124dd50008a999824181e98249baa304d304e0021337106eb4c134c128dd500080b099b89375a609a60946ea8004058528182600099825182580099825199823181d98239baa304b304c0014c0103d87a80004c0103d87980004bd7018239baa304a304b3047375405664a66608a02829444cdc480080b1bad30013046375400646092609460946094609400266e0400800cc94ccc108c0ccc10cdd50008982398221baa0011630463047304730433754006600a6eacc07cc108dd500118021bab301e30413754603c60826ea806c58c10c004c8cc00400409c894ccc10800452f5c026644a666082a66608266ebcc118c10cdd500100f8991980080099198008009bab304830493045375400844a66608e002297ae0132323232330010013756609400844a66609800220062646609c6e9ccc138dd4802998271825800998271826000a5eb80cc00c00cc140008c138004cc010010c13000cdd7182300098248009129998230008a501332253330453371e6eb8c12800810c5288998020020009bac3048001304900114a026608a004660080080022660080080026088002608a0022a6466607c6066010264a666084608a646600200205244a666088002297ae013322533304353330433375e6044608a6ea8008dd3299982198198070a5eb7bdb1804c8c8cc0040052f5bded8c044a66609200226609466ec13001014000374c00697adef6c60132333222533304a3372091010000313304e337609801014000374c00e00a2a666094602000626609c66ec13001014000374c00e00226609c66ec0dd48019ba600233006006001375c60900026eacc124004c134008c12c004c8cc0040052f5bded8c044a66609000226609266ec13001014000375002097adef6c6013233322253330493372091010000313304d337609801014000375002800a2a666092601e00626609a66ec13001014000375002800226609a66ec0dd48019ba800233006006001375c608e0026eb4c120004c130008c1280044cdd7981398229baa00200f14a026608e00466008008002266008008002608c002608e002264a66608066e2404404054ccc10000454ccc1000084c8c94ccc11400400854ccc114c1200044c8cc894ccc114cdc780100c098040008a50375c60900026eb4c120c124004c120dd61823800801191980080099198008008159129998238008a5eb804c8c8c8c8cc004004dd598250021129998260008801899198271ba73304e375200a6609c60960026609c609800297ae0330030033050002304e00133004004304c003375c608c002609200244a66608c002297ae01332253330453371e6eb8c12800810c4cc124dd3801198020020008998020020009bac3048001304900114a029405280a5032323300100102822533304500114a026644a66608866ebc01400852889980200200098219823800982400099ba548008cc10cdd480925eb8058cdc499b8000900e30033756603a60806ea8c074c100dd500d0a99981f181780409919191929998229824001099191919806000899192999823a9998238048a51100815333047004153330470021533304700113232533304c0010021533304c304f00113232333222533304e3371e0060402a66609c66e3c0080844cdc38008060a5014a06eb8c140008dd718280009bad3050305100130500013758609c002004646600200206244a66609a002297ae013232323233001001375660a000844a6660a40022006264660a86e9ccc150dd48029982a18288009982a1829000a5eb80cc00c00cc158008c150004cc010010c14800cdd7182600098278008a5014a029405280a50303732533304a0011480004c8c030c94ccc130008520001300d33001001304f00222533304d0011480004c038cc008008c140004c134004c8cc004004dd5981318249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd7800991919191816198269827002198269827001998269827001198269827000998269ba83370003200e609e609e002609c002609a0026098002608e6ea8094c94ccc114c0d8c118dd50008982518239baa001163049304a304a3046375400666e20005200033702600e6eacc084c110dd500098039bab302130443754604260886ea807858c118004c8cc0040040a8894ccc11400452f5c026644a666088a66608866ebcc124c118dd50010110991980080099198008009bab304b304c3048375400844a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a501332253330483371e6eb8c1340081185288998020020009bac304b001304c00114a026609000466008008002266008008002608e002609000266e2403c040c8c8c8c94ccc108c0dcc10cdd50008a999821181b98219baa304730480021337100086eb4c11cc110dd5000899b89004375a608e60886ea8004528182300099822182280099822199820181a98209baa304530460014c103d87a80004c0103d87980004bd7018209baa30443041375404a66e0003002c4c8c94ccc100c8c8c94ccc10cc0e0c110dd50008a999821981c18221baa304830490021337100226eb4c120c114dd5000899b89011375a6090608a6ea8004528182380099822982300099822999820981b18211baa304630470014c0103d87a80004c0103d87980004bd7018211baa30453042375404c2a6660800042002294052819198008008129129998220008a501332253330433371e00407e29444cc010010004dd718230009823800a99981f19b884800003854ccc0f8c8c8c94ccc11000400854ccc110c11c0044c8cc894ccc110cdc780100b899b8700100614a06eb8c11c004dd69823982400098239bac30460010023233001001323300100102a22533304600114bd70099191919198008009bab304900422533304b00110031323304d374e6609a6ea4014cc134c128004cc134c12c0052f5c066006006609e004609a0026600800860960066eb8c114004c120004894ccc11400452f5c026644a66608866e3cdd7182480100b0998241ba7002330040040011330040040013758608e00260900022940cdc0a400001c26464a6660860020042a666086608c0022646644a66608666e3c0080584c0180045281bae3046001375a608c608e002608c6eb0c114004008c8cc004004c8cc0040040a4894ccc11400452f5c0264646464660020026eacc120010894ccc128004400c4c8cc130dd3998261ba90053304c30490013304c304a0014bd7019801801982700118260009980200218250019bae3044001304700122533304400114bd7009991299982199b8f375c609000408226608e6e9c008cc0100100044cc010010004dd6182300098238008a5014a026464a6660860020042a666086608c00226464666444a66608a66e3c00c10c54ccc114cdc780100c098040008a5014a06eb8c11c008dd718238009bad3047304800130470013758608a002004646600200205044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230008a50370e90009b80480088c94ccc0f4c0c8c0f8dd50008a400026eb4c108c0fcdd500099299981e9819181f1baa00114c0103d87a8000132330010013756608660806ea8008894ccc108004530103d87a8000132333222533304333722911000031533304330090031302633047375000497ae014c103d87a8000133006006001375c60820026eb4c108004c118008c110004c8cc004004008894ccc1040045300103d87a8000132333222533304233722911000031533304230080031302533046374c00497ae014c103d87a8000133006006001375c60800026eacc104004c114008c10c004dc7a450022533303b302b303c375400426464646464646464646464646464646464646464a6660a460aa00426602e01e26602e00602a2c6eb4c14c004c14c008c144004c144008dd6982780098278011bad304d001304d00232533304a30490011533304733712900218240008b0981e18240008b1baa304b001304b002375a609200260920046eb4c11c004c11c008c114004c114008dd7182180098218011bae3041001303d37540042c44a666074605460766ea80084c8c8c8c94ccc104c1100084cc01c00c4c94ccc0fcc0bc0044c8c94ccc110c11c0084c94ccc108c0c80044c8c94ccc11cc1280084cc03400402c58c120004c110dd50010a999821181b8008991919191919299982598270010078b1bad304c001304c002375a609400260940046eb4c120004c110dd50010b18211baa001163045001304137540042a66607e60680022a66608460826ea80080185858c0fcdd50008b182100098210011820000981e1baa002162232533303a302a00113232533303f304200200416375c608000260786ea800c54ccc0e8c0bc0044c8c94ccc0fcc10800801058dd71820000981e1baa00316303a3754004606e6ea80b4dd6981d181d804981c8041bad3038008375a606e010604c60646ea8c0d8020dd6981a8041bad3034008375c60660106eb8c0c8020c0c8004c0c4004c0c0004c0bc004c0b8004c0b4c0b4004c0b0004c09cdd50028b181480099198008008071129998140008a5eb804cc894ccc09d4ccc09ccdd7981618149baa302c302d3029375400400a2646600200264660020026eacc0b8c0bcc0acdd51817181798159baa00422533302d00114bd70099191919198008009bab3030004225333032001100313233034374e660686ea4014cc0d0c0c4004cc0d0c0c80052f5c066006006606c00460680026600800860640066eb8c0b0004c0bc004894ccc0b000452809991299981599b8f375c606000405229444cc010010004dd6181700098178008a5013302b00233004004001133004004001302a001302b001300630243754600260486ea800c8c09cc0a0004c094c088dd50090b181218109baa00116323300100100922533302300114c103d87a80001332253330223375e600c60486ea80080544c014cc0980092f5c0266008008002604a002604c0026e9520002302200137586040604200c603e00a6eacc078014dd5980e8029bac301c0053758603600a603600260346034002603260320026030603000260266ea8024dc3a40006e1d2004301200130123013001300e37540046e1d200216300f3010003300e002300d002300d0013008375400229309b2b1bae001375c002ae6955ceaab9e5573eae815d0aba201", + "hash": "c0f352bf5856e696038a0449a91382f35ba4a5741946736ca1480382" + }, + { + "title": "crowdfund.crowdfund.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + } + ], + "compiledCode": "59121c0101003232323232323223223225333006323232323253323300c3001300d3754004264664464646464a66602660060022a66602c602a6ea80280085854ccc04cc02000454ccc058c054dd50050010b0a99980998020008a99980b180a9baa00a00216153330133370e90030008a99980b180a9baa00a00216163013375401226464646464646464646464646464a66603e601e60406ea80044c94ccc080c040c084dd500909919191919299981418158010991919191919191919191919191919191919191919191929919981e9816803899192999821182280109919191980480089919191919192999824299982419b87006337026eb4c014c128dd500380c099b89482024bd0040185280a9998240020a9998240018a9998240010a9998240008991929998268008010a999826982800089919199911299982799b8f0030211533304f3371e004044266e1c0040345280a50375c60a20046eb8c144004dd69828982900098288009bac304f001002323300100103222533304e00114bd70099191919198008009bab3051004225333053001100313233055374e660aa6ea4014cc154c148004cc154c14c0052f5c06600600660ae00460aa0026600800860a60066eb8c134004c1400045280a5014a029405280a50303832533304b0011480004c8c034c94ccc134008520001300e33001001305000222533304e0011480004c03ccc008008c144004c138004c8cc004004dd5981398251baa00a22533304c00114bd70099191919198008009bab304f004225333051001100313233053374e660a66ea4014cc14cc140004cc14cc1440052f5c06600600660aa00460a60026600800860a20066eb8c12c004c138004cdd7802991919191816998271827802198271827801998271827801198271827800998271ba83370003401060a060a0002609e002609c002609a00260906ea8098c8c8c94ccc120c0f4c124dd50008a999824181e98249baa304d304e0021337106eb4c134c128dd500080b099b89375a609a60946ea8004058528182600099825182580099825199823181d98239baa304b304c0014c0103d87a80004c0103d87980004bd7018239baa304a304b3047375405664a66608a02829444cdc480080b1bad30013046375400646092609460946094609400266e0400800cc94ccc108c0ccc10cdd50008982398221baa0011630463047304730433754006600a6eacc07cc108dd500118021bab301e30413754603c60826ea806c58c10c004c8cc00400409c894ccc10800452f5c026644a666082a66608266ebcc118c10cdd500100f8991980080099198008009bab304830493045375400844a66608e002297ae0132323232330010013756609400844a66609800220062646609c6e9ccc138dd4802998271825800998271826000a5eb80cc00c00cc140008c138004cc010010c13000cdd7182300098248009129998230008a501332253330453371e6eb8c12800810c5288998020020009bac3048001304900114a026608a004660080080022660080080026088002608a0022a6466607c6066010264a666084608a646600200205244a666088002297ae013322533304353330433375e6044608a6ea8008dd3299982198198070a5eb7bdb1804c8c8cc0040052f5bded8c044a66609200226609466ec13001014000374c00697adef6c60132333222533304a3372091010000313304e337609801014000374c00e00a2a666094602000626609c66ec13001014000374c00e00226609c66ec0dd48019ba600233006006001375c60900026eacc124004c134008c12c004c8cc0040052f5bded8c044a66609000226609266ec13001014000375002097adef6c6013233322253330493372091010000313304d337609801014000375002800a2a666092601e00626609a66ec13001014000375002800226609a66ec0dd48019ba800233006006001375c608e0026eb4c120004c130008c1280044cdd7981398229baa00200f14a026608e00466008008002266008008002608c002608e002264a66608066e2404404054ccc10000454ccc1000084c8c94ccc11400400854ccc114c1200044c8cc894ccc114cdc780100c098040008a50375c60900026eb4c120c124004c120dd61823800801191980080099198008008159129998238008a5eb804c8c8c8c8cc004004dd598250021129998260008801899198271ba73304e375200a6609c60960026609c609800297ae0330030033050002304e00133004004304c003375c608c002609200244a66608c002297ae01332253330453371e6eb8c12800810c4cc124dd3801198020020008998020020009bac3048001304900114a029405280a5032323300100102822533304500114a026644a66608866ebc01400852889980200200098219823800982400099ba548008cc10cdd480925eb8058cdc499b8000900e30033756603a60806ea8c074c100dd500d0a99981f181780409919191929998229824001099191919806000899192999823a9998238048a51100815333047004153330470021533304700113232533304c0010021533304c304f00113232333222533304e3371e0060402a66609c66e3c0080844cdc38008060a5014a06eb8c140008dd718280009bad3050305100130500013758609c002004646600200206244a66609a002297ae013232323233001001375660a000844a6660a40022006264660a86e9ccc150dd48029982a18288009982a1829000a5eb80cc00c00cc158008c150004cc010010c14800cdd7182600098278008a5014a029405280a50303732533304a0011480004c8c030c94ccc130008520001300d33001001304f00222533304d0011480004c038cc008008c140004c134004c8cc004004dd5981318249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd7800991919191816198269827002198269827001998269827001198269827000998269ba83370003200e609e609e002609c002609a0026098002608e6ea8094c94ccc114c0d8c118dd50008982518239baa001163049304a304a3046375400666e20005200033702600e6eacc084c110dd500098039bab302130443754604260886ea807858c118004c8cc0040040a8894ccc11400452f5c026644a666088a66608866ebcc124c118dd50010110991980080099198008009bab304b304c3048375400844a666094002297ae0132323232330010013756609a00844a66609e0022006264660a26e9ccc144dd4802998289827000998289827800a5eb80cc00c00cc14c008c144004cc010010c13c00cdd7182480098260009129998248008a501332253330483371e6eb8c1340081185288998020020009bac304b001304c00114a026609000466008008002266008008002608e002609000266e2403c040c8c8c8c94ccc108c0dcc10cdd50008a999821181b98219baa304730480021337100086eb4c11cc110dd5000899b89004375a608e60886ea8004528182300099822182280099822199820181a98209baa304530460014c103d87a80004c0103d87980004bd7018209baa30443041375404a66e0003002c4c8c94ccc100c8c8c94ccc10cc0e0c110dd50008a999821981c18221baa304830490021337100226eb4c120c114dd5000899b89011375a6090608a6ea8004528182380099822982300099822999820981b18211baa304630470014c0103d87a80004c0103d87980004bd7018211baa30453042375404c2a6660800042002294052819198008008129129998220008a501332253330433371e00407e29444cc010010004dd718230009823800a99981f19b884800003854ccc0f8c8c8c94ccc11000400854ccc110c11c0044c8cc894ccc110cdc780100b899b8700100614a06eb8c11c004dd69823982400098239bac30460010023233001001323300100102a22533304600114bd70099191919198008009bab304900422533304b00110031323304d374e6609a6ea4014cc134c128004cc134c12c0052f5c066006006609e004609a0026600800860960066eb8c114004c120004894ccc11400452f5c026644a66608866e3cdd7182480100b0998241ba7002330040040011330040040013758608e00260900022940cdc0a400001c26464a6660860020042a666086608c0022646644a66608666e3c0080584c0180045281bae3046001375a608c608e002608c6eb0c114004008c8cc004004c8cc0040040a4894ccc11400452f5c0264646464660020026eacc120010894ccc128004400c4c8cc130dd3998261ba90053304c30490013304c304a0014bd7019801801982700118260009980200218250019bae3044001304700122533304400114bd7009991299982199b8f375c609000408226608e6e9c008cc0100100044cc010010004dd6182300098238008a5014a026464a6660860020042a666086608c00226464666444a66608a66e3c00c10c54ccc114cdc780100c098040008a5014a06eb8c11c008dd718238009bad3047304800130470013758608a002004646600200205044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230008a50370e90009b80480088c94ccc0f4c0c8c0f8dd50008a400026eb4c108c0fcdd500099299981e9819181f1baa00114c0103d87a8000132330010013756608660806ea8008894ccc108004530103d87a8000132333222533304333722911000031533304330090031302633047375000497ae014c103d87a8000133006006001375c60820026eb4c108004c118008c110004c8cc004004008894ccc1040045300103d87a8000132333222533304233722911000031533304230080031302533046374c00497ae014c103d87a8000133006006001375c60800026eacc104004c114008c10c004dc7a450022533303b302b303c375400426464646464646464646464646464646464646464a6660a460aa00426602e01e26602e00602a2c6eb4c14c004c14c008c144004c144008dd6982780098278011bad304d001304d00232533304a30490011533304733712900218240008b0981e18240008b1baa304b001304b002375a609200260920046eb4c11c004c11c008c114004c114008dd7182180098218011bae3041001303d37540042c44a666074605460766ea80084c8c8c8c94ccc104c1100084cc01c00c4c94ccc0fcc0bc0044c8c94ccc110c11c0084c94ccc108c0c80044c8c94ccc11cc1280084cc03400402c58c120004c110dd50010a999821181b8008991919191919299982598270010078b1bad304c001304c002375a609400260940046eb4c120004c110dd50010b18211baa001163045001304137540042a66607e60680022a66608460826ea80080185858c0fcdd50008b182100098210011820000981e1baa002162232533303a302a00113232533303f304200200416375c608000260786ea800c54ccc0e8c0bc0044c8c94ccc0fcc10800801058dd71820000981e1baa00316303a3754004606e6ea80b4dd6981d181d804981c8041bad3038008375a606e010604c60646ea8c0d8020dd6981a8041bad3034008375c60660106eb8c0c8020c0c8004c0c4004c0c0004c0bc004c0b8004c0b4c0b4004c0b0004c09cdd50028b181480099198008008071129998140008a5eb804cc894ccc09d4ccc09ccdd7981618149baa302c302d3029375400400a2646600200264660020026eacc0b8c0bcc0acdd51817181798159baa00422533302d00114bd70099191919198008009bab3030004225333032001100313233034374e660686ea4014cc0d0c0c4004cc0d0c0c80052f5c066006006606c00460680026600800860640066eb8c0b0004c0bc004894ccc0b000452809991299981599b8f375c606000405229444cc010010004dd6181700098178008a5013302b00233004004001133004004001302a001302b001300630243754600260486ea800c8c09cc0a0004c094c088dd50090b181218109baa00116323300100100922533302300114c103d87a80001332253330223375e600c60486ea80080544c014cc0980092f5c0266008008002604a002604c0026e9520002302200137586040604200c603e00a6eacc078014dd5980e8029bac301c0053758603600a603600260346034002603260320026030603000260266ea8024dc3a40006e1d2004301200130123013001300e37540046e1d200216300f3010003300e002300d002300d0013008375400229309b2b1bae001375c002ae6955ceaab9e5573eae815d0aba201", + "hash": "c0f352bf5856e696038a0449a91382f35ba4a5741946736ca1480382" + }, + { + "title": "spend.spend.spend", + "datum": { + "title": "datum_opt", + "schema": { + "$ref": "#/definitions/types~1CrowdfundGovDatum" + } + }, + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1CrowdfundRedeemer" + } + }, + "parameters": [ + { + "title": "delegate_pool_id", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action", + "schema": { + "$ref": "#/definitions/gov~1VGovernanceAction" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "stake_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + } + ], + "compiledCode": "591a430101003232323232323223222322322322533300b323232323253323301130013012375400426466446464646464a66603260080022a66603860366ea802c0085854ccc064c02400454ccc070c06cdd50058010b0a99980c98028008a99980e180d9baa00b002161533301930030011533301c301b37540160042c2a66603266e1d20080011533301c301b37540160042c2c60326ea80284c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0a4c050c0a8dd50008992999815180a98159baa0171323232323232323232325323232333037302200a1533303730223038375401a2646464666644446464a666086608c004264a666082605860846ea80044c94ccc108c0b4c10cdd5000899191929998241825801099191980c800899191919191929998268040a9998268030a9998268028a9998268020a9998268018a99982680108008a5014a029405280a5014a064607a646600200205244a6660a400229000099912999828a99982899b87375a605660a66ea80092080a0b787e905153330513375e604c60a66ea80080144cdc79bb3305630573057305337540046ecc1385280a501301b001100130540013300200230550013026304e3754040a666096a66609666030054602e6609e0126609e602c6609e60486609e01297ae04bd7025eb804cc0600a8c05ccc13c024cc13cc090cc13cdd4824a5eb812f5c0294052889980c015180b9982780499827980b998279ba90493304f30243304f0094bd7025eb812f5c06602e05266e9520083304e0083304e375008297ae03301602830223304d0073304d4c103d87a80004bd70181a1929998260008a4000264602864a66609c004290000980a9980080098288011129998278008a40002602c6600400460a4002609e00264660020026eacc078c12cdd50029129998268008a5eb804c8c8c8c8cc004004dd5982800211299982900088018991982a1ba733054375200a660a860a2002660a860a400297ae03300300330560023054001330040043052003375c6098002609e00266ebc004c048cc12cdd4806998259ba900c3304b3750016660966ea00292f5c064a66608e606660906ea80044c130c124dd50008b18259826182618241baa00233301300600133702900019b803370007c0789040505bc3f4828b182480099198008008129129998240008a5eb804cc894ccc11d4ccc11ccdd7982618249baa00201b130373253330483038304937540022900009bad304d304a375400264a666090607060926ea80045300103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e301f0031533304e301e0031302733052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c098cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c1380045280998258011980200200089980200200098250009825800982398221baa001163046304337540022c602a60846ea805058c110004c8cc004004084894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd51823982418221baa002016130323253330433033304437540022900009bad30483045375400264a666086606660886ea80045300103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e604e0142a66606e604e60706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c8c94ccc114c1200084c8c8cc0580044c8c8c94ccc11c01454ccc11c00854ccc11c0044c8c94ccc124c0d0c128dd50008999119198008008019129998280008a5013322533304f3375e6e98cc14c0092f5bded8c06e98cc14c0152f5bded8c029444cc010010004c148004c14c004dd5982718259baa0013376000a980103d87a800016323300100102522533304d00114c0103d87a8000132333222533304e3375e00e0062604e660a46e980092f5c026600c00c00260980026eacc134004c144008c13c004c048cc12cc048cc12cdd4806a5eb812f5c029405280a50303232533304a0011480004c8c048c94ccc130008520001301333001001304f00222533304d0011480004c050cc008008c140004c134004c8cc004004dd5980e18249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd78011808998249ba900b330493752014660926ea0024cc124004cc124dd400425eb80c074cc120c078c118dd5180f18231baa01b330484c010100004bd70192999822181818229baa00113049304637540022c609060926092608a6ea8008cdd7980b98221baa301730443754006602e60886ea800458c118004c8cc004004088894ccc11400452f5c026644a666088a66608866ebcc124c118dd500100c0981a192999822981a98231baa0011480004dd6982518239baa0013253330453035304637540022980103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b301c0031533304b301b003130243304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00322533304900114c103d87a8000132333222533304a337220200062a66609466e3c04000c4c08ccc138dd300125eb80530103d87a8000133006006001375c60900026eacc124004c134008c12c00452809982400119802002000899802002000982380098240008b182200099198008008109129998218008a5eb804cc894ccc1094ccc108cdd7982398221baa304730483044375400402c2606464a666086606660886ea8004520001375a6090608a6ea8004c94ccc10cc0ccc110dd50008a6103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e60460142a66606e604660706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c94ccc104c0b0c108dd50008992999821181698219baa0011323232325333049304c002132323301a001132323232533304c0091533304c0061533304c0041533304c0031533304c002100114a029405280a5014a0606e64a66609e00229000099180b9929998288010a4000260306600200260a800444a6660a4002290000980c99801001182a800982900099198008009bab3021304e375400e44a6660a0002297ae013232323233001001375660a600844a6660aa0022006264660ae6e9ccc15cdd48029982b982a0009982b982a800a5eb80cc00c00cc164008c15c004cc010010c15400cdd7182780098290009980b81499ba548030cc138020cc138dd4020a5eb80cc0580a0c050cc13401ccc13530103d87a80004bd7019baf0013374a9003198261ba900e3304c375201a660986ea00312f5c064a666090606860926ea80044c134c128dd50008b18261826982698249baa0023330140070013370007e07a2c6094002646600200204c44a666092002297ae013322533304853330483375e609a60946ea80080704c0e0c94ccc124c0e4c128dd50008a400026eb4c138c12cdd5000992999824981c98251baa00114c0103d87a8000132330010013756609e60986ea8008894ccc138004530103d87a8000132333222533304f30200031533304f301f0031302833053375000497ae014c103d87a8000133006006001375c609a0026eb4c138004c148008c140004c8cc004004dd59827182798259baa00322533304d00114c103d87a8000132333222533304e337220280062a66609c66e3c05000c4c09ccc148dd300125eb80530103d87a8000133006006001375c60980026eacc134004c144008c13c00452809982600119802002000899802002000982580098260009919192999823181b18239baa0011533304630363047375460966098004266e20024dd6982598241baa0011337120126eb4c12cc120dd50008a50304a001330483049001330483330443034304537546092609400298103d87a80004c0103d87980004bd7018229baa304830453754042608e60886ea800458c118c10cdd50008b180a98211baa014163044001323300100102122533304300114bd70099912999821299982119baf304730443754608e609060886ea80080584c0c8c94ccc10cc0ccc110dd50008a400026eb4c120c114dd5000992999821981998221baa00114c0103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f98201820000981f800981f000981c9baa00d14a02a66606e60420142a66606e604260706ea80344c8c8ccc888c8c94ccc104c1100084c8c94ccc10cc1180084c8c8c8cc0540044c8c94ccc11401054ccc11400854ccc1140044c8c94ccc12800400854ccc128c1340044c8c8ccc8894ccc130cdc78018090a99982619b8f00201313370e00201829405281bae304e002375c609c0026eb4c138c13c004c138004dd6182600080119198008008139129998258008a5eb804c8c8c8c8cc004004dd598270021129998280008801899198291ba733052375200a660a4609e002660a460a000297ae03300300330540023052001330040043050003375c6094002609a00229405280a5014a0606064a6660900022900009918081929998250010a40002602266002002609a00444a6660960022900009809198010011827000982580099198008009bab301a3047375400c44a666092002297ae0132323232330010013756609800844a66609c0022006264660a06e9ccc140dd4802998281826800998281827000a5eb80cc00c00cc148008c140004cc010010c13800cdd71824000982580099baf0013374a9003198239ba900a3304737520126608e6ea0cdc0004001a5eb80c94ccc10cc0bcc110dd50008982418229baa001163047304830483044375400666e20005200033702601e6eacc054c108dd500098079bab301530423754602a60846ea800c58c110004c8cc004004080894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd500100b09819192999821981998221baa0011480004dd6982418229baa001325333043303330443754002298103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa00322533304700114c103d87a800013233322253330483372201e0062a66609066e3c03c00c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230008b1821000991980080080f9129998208008a5eb804cc894ccc1014ccc100cdd7982298211baa30453046304237540040282606064a666082606260846ea8004520001375a608c60866ea8004c94ccc104c0c4c108dd50008a6103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c00452809982200119802002000899802002000982180098220009bae303e002375c607c0026eb4c0f8c0fc004c0f8004c0e4dd50068a501533303730213038375401a26464666444a66607e6084646600200203e44a666082002297ae013322533304053330403375e608a60846ea8c114c118c108dd500100a09818192999820981898211baa0011480004dd6982318219baa001325333041303130423754002298103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c0045280998220011980200200089980200200098218009822000899299981ea99981e99b88480000084c8c8c94ccc10c00400854ccc10cc1180044c8cc894ccc10ccdc7801005099b8700100614a06eb8c118004dd69823182380098231bac30450010023233001001323300100102122533304500114bd70099191919198008009bab304800422533304a00110031323304c374e660986ea4014cc130c124004cc130c1280052f5c066006006609c00460980026600800860940066eb8c110004c11c004894ccc11000452f5c026644a66608666e3cdd718240010048998239ba7002330040040011330040040013758608c002608e0022940cdc0a4000004294454ccc0f40044c8c94ccc10800400854ccc108c1140044c8cc894ccc108c0480084cdc3800a40022940dd718228009bad304530460013045375860880020046466002002646600200204044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230009129998218008a5eb804cc894ccc108cdc79bae3047002009133046374e004660080080022660080080026eb0c114004c1180045280a5014a0646600200203444a66608200229404cc894ccc100cdc780101d8a51133004004001375c608600260880022c6eb8c0f8008dd7181f0009bad303e303f001303e0013039375401a2940dc0240046e952002374a900211191980080080191299981d0008a501332253330393375e00400a29444cc010010004c0f0004c0f4004888cdc399b81300437566014606e6ea8008c010dd59805181b9baa300a30373754006002464a666066604660686ea8004520001375a6070606a6ea8004c94ccc0ccc08cc0d0dd50008a60103d87a80001323300100137566072606c6ea8008894ccc0e0004530103d87a80001323332225333039300a003153330393009003130123303d375000497ae014c103d87a8000133006006001375c606e0026eb4c0e0004c0f0008c0e8004c8cc004004008894ccc0dc0045300103d87a800013233322253330383009003153330383008003130113303c374c00497ae014c103d87a8000133006006001375c606c0026eacc0dc004c0ec008c0e4004dc7a4500372291010022325333031301c00113232323232323232533303c303f00200a16375a607a002607a0046eb4c0ec004c0ec008dd7181c800981c8011bae3037001303337540062a666062604200226464646464646464a666078607e0040142c6eb4c0f4004c0f4008dd6981d800981d8011bae30390013039002375c606e00260666ea800c54ccc0c4c0740044c8c8c8c8c8c8c8c8c8c94ccc0f8c10400854ccc0ecc098c0f0dd5001899191919299982118228010080b1bad30430013043002375c6082002607a6ea800c5858dd6981f800981f801181e800981e8011bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018a999818980d8008991919191919299981d181e8010040b1bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018b18189baa002302e375403e600c605c6ea8c004c0b8dd5001918189819000981798161baa01716302e302b37540022c646600200201644a66605a002298103d87a800013322533302c3375e600c605c6ea80080684c014cc0c00092f5c0266008008002605e00260600026e9520002302c0013758605460560106eacc0a401cdd6181400398138039bac30260073756604a00e6eb0c09001cdd6181180398119811981198118009811000981098108009810000980f980f800980f180f000980c9baa00a370e90031b8748000dc3a4008602e002602e603000260266ea8008dc3a40042c6028602a006602600460240046024002601a6ea800452613656375a0026eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d11", + "hash": "b77e4f80ee4d5887de1f3954470f392f455198ff4372c4c7d0d6480c" + }, + { + "title": "spend.spend.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "delegate_pool_id", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action", + "schema": { + "$ref": "#/definitions/gov~1VGovernanceAction" + } + }, + { + "title": "proposer_key_hash", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "stake_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + }, + { + "title": "drep_register_deposit", + "schema": { + "$ref": "#/definitions/Lovelace" + } + } + ], + "compiledCode": "591a430101003232323232323223222322322322533300b323232323253323301130013012375400426466446464646464a66603260080022a66603860366ea802c0085854ccc064c02400454ccc070c06cdd50058010b0a99980c98028008a99980e180d9baa00b002161533301930030011533301c301b37540160042c2a66603266e1d20080011533301c301b37540160042c2c60326ea80284c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0a4c050c0a8dd50008992999815180a98159baa0171323232323232323232325323232333037302200a1533303730223038375401a2646464666644446464a666086608c004264a666082605860846ea80044c94ccc108c0b4c10cdd5000899191929998241825801099191980c800899191919191929998268040a9998268030a9998268028a9998268020a9998268018a99982680108008a5014a029405280a5014a064607a646600200205244a6660a400229000099912999828a99982899b87375a605660a66ea80092080a0b787e905153330513375e604c60a66ea80080144cdc79bb3305630573057305337540046ecc1385280a501301b001100130540013300200230550013026304e3754040a666096a66609666030054602e6609e0126609e602c6609e60486609e01297ae04bd7025eb804cc0600a8c05ccc13c024cc13cc090cc13cdd4824a5eb812f5c0294052889980c015180b9982780499827980b998279ba90493304f30243304f0094bd7025eb812f5c06602e05266e9520083304e0083304e375008297ae03301602830223304d0073304d4c103d87a80004bd70181a1929998260008a4000264602864a66609c004290000980a9980080098288011129998278008a40002602c6600400460a4002609e00264660020026eacc078c12cdd50029129998268008a5eb804c8c8c8c8cc004004dd5982800211299982900088018991982a1ba733054375200a660a860a2002660a860a400297ae03300300330560023054001330040043052003375c6098002609e00266ebc004c048cc12cdd4806998259ba900c3304b3750016660966ea00292f5c064a66608e606660906ea80044c130c124dd50008b18259826182618241baa00233301300600133702900019b803370007c0789040505bc3f4828b182480099198008008129129998240008a5eb804cc894ccc11d4ccc11ccdd7982618249baa00201b130373253330483038304937540022900009bad304d304a375400264a666090607060926ea80045300103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e301f0031533304e301e0031302733052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c098cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c1380045280998258011980200200089980200200098250009825800982398221baa001163046304337540022c602a60846ea805058c110004c8cc004004084894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd51823982418221baa002016130323253330433033304437540022900009bad30483045375400264a666086606660886ea80045300103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e604e0142a66606e604e60706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c8c94ccc114c1200084c8c8cc0580044c8c8c94ccc11c01454ccc11c00854ccc11c0044c8c94ccc124c0d0c128dd50008999119198008008019129998280008a5013322533304f3375e6e98cc14c0092f5bded8c06e98cc14c0152f5bded8c029444cc010010004c148004c14c004dd5982718259baa0013376000a980103d87a800016323300100102522533304d00114c0103d87a8000132333222533304e3375e00e0062604e660a46e980092f5c026600c00c00260980026eacc134004c144008c13c004c048cc12cc048cc12cdd4806a5eb812f5c029405280a50303232533304a0011480004c8c048c94ccc130008520001301333001001304f00222533304d0011480004c050cc008008c140004c134004c8cc004004dd5980e18249baa00622533304b00114bd70099191919198008009bab304e004225333050001100313233052374e660a46ea4014cc148c13c004cc148c1400052f5c06600600660a800460a40026600800860a00066eb8c128004c134004cdd78011808998249ba900b330493752014660926ea0024cc124004cc124dd400425eb80c074cc120c078c118dd5180f18231baa01b330484c010100004bd70192999822181818229baa00113049304637540022c609060926092608a6ea8008cdd7980b98221baa301730443754006602e60886ea800458c118004c8cc004004088894ccc11400452f5c026644a666088a66608866ebcc124c118dd500100c0981a192999822981a98231baa0011480004dd6982518239baa0013253330453035304637540022980103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b301c0031533304b301b003130243304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00322533304900114c103d87a8000132333222533304a337220200062a66609466e3c04000c4c08ccc138dd300125eb80530103d87a8000133006006001375c60900026eacc124004c134008c12c00452809982400119802002000899802002000982380098240008b182200099198008008109129998218008a5eb804cc894ccc1094ccc108cdd7982398221baa304730483044375400402c2606464a666086606660886ea8004520001375a6090608a6ea8004c94ccc10cc0ccc110dd50008a6103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f9820000981f800981f000981c9baa00d14a02a66606e60460142a66606e604660706ea80344c8c8c8cccc8888c8c94ccc10cc1180084c94ccc104c0b0c108dd50008992999821181698219baa0011323232325333049304c002132323301a001132323232533304c0091533304c0061533304c0041533304c0031533304c002100114a029405280a5014a0606e64a66609e00229000099180b9929998288010a4000260306600200260a800444a6660a4002290000980c99801001182a800982900099198008009bab3021304e375400e44a6660a0002297ae013232323233001001375660a600844a6660aa0022006264660ae6e9ccc15cdd48029982b982a0009982b982a800a5eb80cc00c00cc164008c15c004cc010010c15400cdd7182780098290009980b81499ba548030cc138020cc138dd4020a5eb80cc0580a0c050cc13401ccc13530103d87a80004bd7019baf0013374a9003198261ba900e3304c375201a660986ea00312f5c064a666090606860926ea80044c134c128dd50008b18261826982698249baa0023330140070013370007e07a2c6094002646600200204c44a666092002297ae013322533304853330483375e609a60946ea80080704c0e0c94ccc124c0e4c128dd50008a400026eb4c138c12cdd5000992999824981c98251baa00114c0103d87a8000132330010013756609e60986ea8008894ccc138004530103d87a8000132333222533304f30200031533304f301f0031302833053375000497ae014c103d87a8000133006006001375c609a0026eb4c138004c148008c140004c8cc004004dd59827182798259baa00322533304d00114c103d87a8000132333222533304e337220280062a66609c66e3c05000c4c09ccc148dd300125eb80530103d87a8000133006006001375c60980026eacc134004c144008c13c00452809982600119802002000899802002000982580098260009919192999823181b18239baa0011533304630363047375460966098004266e20024dd6982598241baa0011337120126eb4c12cc120dd50008a50304a001330483049001330483330443034304537546092609400298103d87a80004c0103d87980004bd7018229baa304830453754042608e60886ea800458c118c10cdd50008b180a98211baa014163044001323300100102122533304300114bd70099912999821299982119baf304730443754608e609060886ea80080584c0c8c94ccc10cc0ccc110dd50008a400026eb4c120c114dd5000992999821981998221baa00114c0103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa304830493045375400644a66608e002298103d87a800013233322253330483372201c0062a66609066e3c03800c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230009bae303f003375c607e0046eb4c0fc004dd6981f98201820000981f800981f000981c9baa00d14a02a66606e60420142a66606e604260706ea80344c8c8ccc888c8c94ccc104c1100084c8c94ccc10cc1180084c8c8c8cc0540044c8c94ccc11401054ccc11400854ccc1140044c8c94ccc12800400854ccc128c1340044c8c8ccc8894ccc130cdc78018090a99982619b8f00201313370e00201829405281bae304e002375c609c0026eb4c138c13c004c138004dd6182600080119198008008139129998258008a5eb804c8c8c8c8cc004004dd598270021129998280008801899198291ba733052375200a660a4609e002660a460a000297ae03300300330540023052001330040043050003375c6094002609a00229405280a5014a0606064a6660900022900009918081929998250010a40002602266002002609a00444a6660960022900009809198010011827000982580099198008009bab301a3047375400c44a666092002297ae0132323232330010013756609800844a66609c0022006264660a06e9ccc140dd4802998281826800998281827000a5eb80cc00c00cc148008c140004cc010010c13800cdd71824000982580099baf0013374a9003198239ba900a3304737520126608e6ea0cdc0004001a5eb80c94ccc10cc0bcc110dd50008982418229baa001163047304830483044375400666e20005200033702601e6eacc054c108dd500098079bab301530423754602a60846ea800c58c110004c8cc004004080894ccc10c00452f5c026644a666084a66608466ebcc11cc110dd500100b09819192999821981998221baa0011480004dd6982418229baa001325333043303330443754002298103d87a80001323300100137566092608c6ea8008894ccc120004530103d87a80001323332225333049301a003153330493019003130223304d375000497ae014c103d87a8000133006006001375c608e0026eb4c120004c130008c128004c8cc004004dd59824182498229baa00322533304700114c103d87a800013233322253330483372201e0062a66609066e3c03c00c4c084cc130dd300125eb80530103d87a8000133006006001375c608c0026eacc11c004c12c008c12400452809982300119802002000899802002000982280098230008b1821000991980080080f9129998208008a5eb804cc894ccc1014ccc100cdd7982298211baa30453046304237540040282606064a666082606260846ea8004520001375a608c60866ea8004c94ccc104c0c4c108dd50008a6103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c00452809982200119802002000899802002000982180098220009bae303e002375c607c0026eb4c0f8c0fc004c0f8004c0e4dd50068a501533303730213038375401a26464666444a66607e6084646600200203e44a666082002297ae013322533304053330403375e608a60846ea8c114c118c108dd500100a09818192999820981898211baa0011480004dd6982318219baa001325333041303130423754002298103d87a8000132330010013756608e60886ea8008894ccc118004530103d87a800013233322253330473018003153330473017003130203304b375000497ae014c103d87a8000133006006001375c608a0026eb4c118004c128008c120004c8cc004004dd59823182398219baa304630473043375400644a66608a002298103d87a800013233322253330463372201a0062a66608c66e3c03400c4c07ccc128dd300125eb80530103d87a8000133006006001375c60880026eacc114004c124008c11c0045280998220011980200200089980200200098218009822000899299981ea99981e99b88480000084c8c8c94ccc10c00400854ccc10cc1180044c8cc894ccc10ccdc7801005099b8700100614a06eb8c118004dd69823182380098231bac30450010023233001001323300100102122533304500114bd70099191919198008009bab304800422533304a00110031323304c374e660986ea4014cc130c124004cc130c1280052f5c066006006609c00460980026600800860940066eb8c110004c11c004894ccc11000452f5c026644a66608666e3cdd718240010048998239ba7002330040040011330040040013758608c002608e0022940cdc0a4000004294454ccc0f40044c8c94ccc10800400854ccc108c1140044c8cc894ccc108c0480084cdc3800a40022940dd718228009bad304530460013045375860880020046466002002646600200204044a666088002297ae0132323232330010013756608e00844a6660920022006264660966e9ccc12cdd4802998259824000998259824800a5eb80cc00c00cc134008c12c004cc010010c12400cdd7182180098230009129998218008a5eb804cc894ccc108cdc79bae3047002009133046374e004660080080022660080080026eb0c114004c1180045280a5014a0646600200203444a66608200229404cc894ccc100cdc780101d8a51133004004001375c608600260880022c6eb8c0f8008dd7181f0009bad303e303f001303e0013039375401a2940dc0240046e952002374a900211191980080080191299981d0008a501332253330393375e00400a29444cc010010004c0f0004c0f4004888cdc399b81300437566014606e6ea8008c010dd59805181b9baa300a30373754006002464a666066604660686ea8004520001375a6070606a6ea8004c94ccc0ccc08cc0d0dd50008a60103d87a80001323300100137566072606c6ea8008894ccc0e0004530103d87a80001323332225333039300a003153330393009003130123303d375000497ae014c103d87a8000133006006001375c606e0026eb4c0e0004c0f0008c0e8004c8cc004004008894ccc0dc0045300103d87a800013233322253330383009003153330383008003130113303c374c00497ae014c103d87a8000133006006001375c606c0026eacc0dc004c0ec008c0e4004dc7a4500372291010022325333031301c00113232323232323232533303c303f00200a16375a607a002607a0046eb4c0ec004c0ec008dd7181c800981c8011bae3037001303337540062a666062604200226464646464646464a666078607e0040142c6eb4c0f4004c0f4008dd6981d800981d8011bae30390013039002375c606e00260666ea800c54ccc0c4c0740044c8c8c8c8c8c8c8c8c8c94ccc0f8c10400854ccc0ecc098c0f0dd5001899191919299982118228010080b1bad30430013043002375c6082002607a6ea800c5858dd6981f800981f801181e800981e8011bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018a999818980d8008991919191919299981d181e8010040b1bad303b001303b002375c607200260720046eb8c0dc004c0ccdd50018b18189baa002302e375403e600c605c6ea8c004c0b8dd5001918189819000981798161baa01716302e302b37540022c646600200201644a66605a002298103d87a800013322533302c3375e600c605c6ea80080684c014cc0c00092f5c0266008008002605e00260600026e9520002302c0013758605460560106eacc0a401cdd6181400398138039bac30260073756604a00e6eb0c09001cdd6181180398119811981198118009811000981098108009810000980f980f800980f180f000980c9baa00a370e90031b8748000dc3a4008602e002602e603000260266ea8008dc3a40042c6028602a006602600460240046024002601a6ea800452613656375a0026eb4004dd70009bae0015734aae7555cf2ab9f5740ae855d11", + "hash": "b77e4f80ee4d5887de1f3954470f392f455198ff4372c4c7d0d6480c" + }, + { + "title": "start.start.withdraw", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" + }, + { + "title": "start.start.mint", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1MintPolarity" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" + }, + { + "title": "start.start.publish", + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1PublishRedeemer" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" + }, + { + "title": "start.start.propose", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" + }, + { + "title": "start.start.vote", + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" + }, + { + "title": "start.start.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "auth_token", + "schema": { + "$ref": "#/definitions/PolicyId" + } + }, + { + "title": "spend", + "schema": { + "$ref": "#/definitions/ByteArray" + } + }, + { + "title": "gov_action_period", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "590c2001010032323232323232232232232253330083232323232323232323232323232533301630060091323232323232323232533302230250021323232533302230143023375400626464646464646464646464646464646464646464a666072607800426602a01e26602a00626464646464646464646464646464a66608e6094004264646464a666090607400226464646464646464a6660a660ac0040142c6eb4c150004c150008dd6982900098290011bae30500013050002375c609c00260946ea800c54ccc120c0e40044c8c8c8c8c8c8c8c94ccc14cc15800802858dd6982a000982a0011bad30520013052002375c60a000260a00046eb8c138004c128dd50018a999824181c000899191919191919191919299982a982c0010a999829182218299baa0031323232325333059305c00201016375a60b400260b40046eb8c160004c150dd50018b0b1bad3056001305600230540013054002375a60a400260a40046eb8c140004c140008dd7182700098251baa00315333048303700113232323232325333051305400200816375a60a400260a40046eb8c140004c140008dd7182700098251baa003163048375400426464a666090607460926ea80044c8cc0dc0044c94ccc12802c54ccc12801854ccc12801054ccc128c8c94ccc13c00400854ccc13cc1480044c8cc894ccc13cc0380084c1000045281bae3052001375a60a460a600260a46eb0c144004008c8cc004004c8cc0040040c8894ccc14400452f5c0264646464660020026eacc150010894ccc158004400c4c8cc160dd39982c1ba90053305830550013305830560014bd7019801801982d001182c00099802002182b0019bae3050001305300122533305000114bd7009991299982799b8f375c60a800402a2660a66e9c008cc0100100044cc010010004dd6182900098298008a50100114a029405280a503375e002980103d87a8000304d304a37540022c6606405605266ebc004c0cccc128dd4806198251ba900b3304a3750012660946ea0cdc000402025eb80c94ccc118c0d8c11cdd50008982598241baa00116304a304b304b3047375400466e1cc94ccc114c0d8c118dd50008a400026eb4c128c11cdd5000992999822981b18231baa00114c0103d87a8000132330010013756609660906ea8008894ccc128004530103d87a8000132333222533304b300b0031533304b300a003130383304f375000497ae014c103d87a8000133006006001375c60920026eb4c128004c138008c130004c8cc004004dd59825182598239baa00222533304900114c103d87a8000132333222533304a300a0031533304a3009003130373304e374c00497ae014c103d87a8000133006006001375c60900026eacc124004c134008c12c00402058c120004c8c8cc0040040a8894ccc12000452f5c026644a66608ea66608e66ebcc130c124dd50010028981c192999824181c98249baa0011480004dd6982698251baa001325333048303930493754002298103d87a8000132330010013756609c60966ea8008894ccc134004530103d87a8000132333222533304e300e0031533304e300d0031303b33052375000497ae014c103d87a8000133006006001375c60980026eb4c134004c144008c13c004c8cc004004dd59826982718251baa00322533304c00114c103d87a8000132333222533304d337220260062a66609a66e3c04c00c4c0e8cc144dd300125eb80530103d87a8000133006006001375c60960026eacc130004c140008c13800452809982580119802002000899802002000982500098258009817998231817198231ba903e4bd70198231817998231817998231817198231ba90084bd7025eb812f5c097ae0371e9110037229101003375e6056660866ea40152f5c00526eb4c10cc110c110014dd698210021bad3041004375c60800086eb8c0fc010c0fc004c0f8c0f8004c0f4004c0e0dd500b8b1bad303a001303a00230380013038002375a606c002606c0046eb4c0d0004c0d0008c94ccc0c4c0c000454ccc0b8cdc4a4008605e0022c2603e605e0022c6ea8c0c8004c0c8008dd6981800098180011bad302e001302e002302c001302c002375c605400260540046eb8c0a0004c090dd50018b112999811980a98121baa002132323232533302a302d0021330070031325333028301a00113232533302d3030002132533302b301d001132325333030303300213300d00100b163031001302d37540042a66605660380022646464646464a666068606e00401e2c6eb4c0d4004c0d4008dd6981980098198011bad3031001302d37540042c60566ea800458c0b8004c0a8dd50010a999814180c8008a99981598151baa0020061616302837540022c605600260560046052002604a6ea80085888c94ccc08cc0540044c8c94ccc0a0c0ac00801058dd7181480098129baa003153330233014001132325333028302b00200416375c6052002604a6ea800c58c08cdd5001192999810180818109baa00113025302237540022c6048604a604a60426ea8c090c094c084dd50008b181180099198008009bac302300722533302200114bd70099912999810991980080099198008009bab302830293025375460506052604a6ea8010894ccc09c00452f5c0264646464660020026eacc0a8010894ccc0b0004400c4c8cc0b8dd3998171ba90053302e302b0013302e302c0014bd7019801801981800118170009980200218160019bae3026001302900122533302600114a026644a66604a66e3cdd718150010118a5113300400400137586050002605200226604a004660080080022660080080026048002604a0026eacc084c088c088c088c088c08800cdd598100011bac301f002301f301f001301e301e0013019375401a603660306ea80284c8c94ccc060c02802c4c8c8c94ccc06cc03400454ccc078c074dd50080010b0a99980d98060008a99980f180e9baa0100021616301b375401e26464646464a66603c6020603e6ea804c4c8c8cc004004010894ccc09000452809991299981199baf00500214a22660080080026044604c002604e0026014660446ea40192f5c02666600e034006002980103d87d8000375660446046604660460066eacc084008dd61810001181018101810181018101810000980d9baa00f375c603a60346ea803054ccc060c01c02c4c8cc88c8c94ccc074c03c00454ccc080c07cdd50090010b0a99980e98070008a999810180f9baa0120021616301d3754022264646464a666044604a004264a666040602460426ea80044c8cc03c00454ccc084c04cc088dd500b099baf0014c0103d879800013375e00298103d87b80003025302237540022c660140060022c60460026644646600200200644a666048002297ae01332253330233375e6050604a6ea8c0a0c0a4c094dd500100289981380119802002000899802002000981300098138009bac3022002300701937566042604460446044604460446044604460446044002603a6ea8044dd6980f000980f180f800980d1baa00c153330183370e9005005899199119199980280c1bac30210013756604260446044604460446044604460446044604400298103d8798000301d37540226eb4c078004c078c07c004c068dd50060a99980c19b874802002c4c8c8cccc00c058dd6180f8009bab301f3020302030203020302030203020302030200014c0103d87a8000301b375401e603a60346ea8030588888c8c94ccc080c08c0084c94ccc078c040c07cdd500089919806800899baf0010053023302037540022c660100080022c604200264646600200200a44a666042002297ae01332253330203375e604a60446ea8c094c098c088dd500100289981200119802002000899802002000981180098120009802802118021980d98019980d9ba90014bd701980da60103d87a80004bd701119191980080080211299980e8008a6103d87a8000132333222533301e3375e00e006260166604400497ae0133006006001301c001301d0013021002301f00130033301b301c3019375400297ae0374a90011ba54800088c94ccc054c01c00454ccc060c05cdd50018010b0a99980a98030008a99980c180b9baa0030021615333015300500115333018301737540060042c2a66602a60080022a666030602e6ea800c0085854ccc054cdc3a40100022a666030602e6ea800c0085858c054dd50011b8748018dc3a40086e1d2002370e900018071baa001301130120033010002300f002300f001300a375400229309b2b1bad001375c0026eb80055cd2ab9d5573caae7d5d02ba15745", + "hash": "2cbea32ea6cd04837d0846fd7aa93b439238982029ddc09d09857f9d" + } + ], + "definitions": { + "Bool": { + "title": "Bool", + "anyOf": [ + { + "title": "False", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "True", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "ByteArray": { + "dataType": "bytes" + }, + "Data": { + "title": "Data", + "description": "Any Plutus data." + }, + "Index": { + "title": "Index", + "dataType": "integer" + }, + "Int": { + "dataType": "integer" + }, + "List$cardano/address/Credential": { + "dataType": "list", + "items": { + "$ref": "#/definitions/cardano~1address~1Credential" + } + }, + "Lovelace": { + "title": "Lovelace", + "dataType": "integer" + }, + "Mandate": { + "title": "Mandate", + "dataType": "integer" + }, + "Option$ScriptHash": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/ScriptHash" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Option$StakeCredential": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/StakeCredential" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Option$cardano/governance/GovernanceActionId": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1governance~1GovernanceActionId" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Pairs$ProtocolParametersIndex_Data": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/ProtocolParametersIndex" + }, + "values": { + "$ref": "#/definitions/Data" + } + }, + "Pairs$cardano/address/Credential_Lovelace": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/Lovelace" + } + }, + "Pairs$cardano/address/Credential_Mandate": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1address~1Credential" + }, + "values": { + "$ref": "#/definitions/Mandate" + } + }, + "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" + }, + "ProtocolParametersIndex": { + "title": "ProtocolParametersIndex", + "dataType": "integer" + }, + "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" + } + ] + } + ] + }, + "TransactionId": { + "title": "TransactionId", + "dataType": "bytes" + }, + "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/governance/Constitution": { + "title": "Constitution", + "anyOf": [ + { + "title": "Constitution", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "guardrails", + "$ref": "#/definitions/Option$ScriptHash" + } + ] + } + ] + }, + "cardano/governance/GovernanceActionId": { + "title": "GovernanceActionId", + "anyOf": [ + { + "title": "GovernanceActionId", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "transaction", + "$ref": "#/definitions/TransactionId" + }, + { + "title": "proposal_procedure", + "$ref": "#/definitions/Index" + } + ] + } + ] + }, + "cardano/governance/ProtocolVersion": { + "title": "ProtocolVersion", + "anyOf": [ + { + "title": "ProtocolVersion", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "major", + "$ref": "#/definitions/Int" + }, + { + "title": "minor", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "crowdfund/CrowdfundRedeemer": { + "title": "CrowdfundRedeemer", + "anyOf": [ + { + "title": "ContributeFund", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "CompleteCrowdfund", + "dataType": "constructor", + "index": 1, + "fields": [] + }, + { + "title": "ContributorWithdrawal", + "dataType": "constructor", + "index": 2, + "fields": [] + }, + { + "title": "RemoveEmptyInstance", + "dataType": "constructor", + "index": 3, + "fields": [] + } + ] + }, + "gov/VGovernanceAction": { + "title": "VGovernanceAction", + "anyOf": [ + { + "title": "VProtocolParameters", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type 'ProtocolParameters'. They must all\n form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "new_parameters", + "description": "The new proposed protocol parameters. Only values set to `Some` are relevant.", + "$ref": "#/definitions/gov~1VProtocolParametersUpdate" + }, + { + "title": "guardrails", + "description": "The optional guardrails script defined in the constitution. The script\n is executed by the ledger in addition to the hard-coded ledger rules.\n\n It must pass for the new protocol parameters to be deemed valid.", + "$ref": "#/definitions/Option$ScriptHash" + } + ] + }, + { + "title": "HardFork", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `HardFork`. They must all\n form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "new_version", + "description": "The new proposed version. Few rules apply to proposing new versions:\n\n - The `major` component, if incremented, must be exactly one more than the current.\n - The `minor` component, if incremented, must be exactly one more than the current.\n - If the `major` component is incremented, `minor` must be set to `0`.\n - Neither `minor` nor `major` can be decremented.", + "$ref": "#/definitions/cardano~1governance~1ProtocolVersion" + } + ] + }, + { + "title": "TreasuryWithdrawal", + "dataType": "constructor", + "index": 2, + "fields": [ + { + "title": "beneficiaries", + "description": "A collection of beneficiaries, which can be plain verification key\n hashes or script hashes (e.g. DAO).", + "$ref": "#/definitions/Pairs$cardano~1address~1Credential_Lovelace" + }, + { + "title": "guardrails", + "description": "The optional guardrails script defined in the constitution. The script\n is executed by the ledger in addition to the hard-coded ledger rules.\n\n It must pass for the withdrawals to be authorized.", + "$ref": "#/definitions/Option$ScriptHash" + } + ] + }, + { + "title": "NoConfidence", + "dataType": "constructor", + "index": 3, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `NoConfidence` or\n `ConstitutionalCommittee`. They must all / form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + } + ] + }, + { + "title": "ConstitutionalCommittee", + "dataType": "constructor", + "index": 4, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `NoConfidence` or\n `ConstitutionalCommittee`. They must all / form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "evicted_members", + "description": "Constitutional members to be removed.", + "$ref": "#/definitions/List$cardano~1address~1Credential" + }, + { + "title": "added_members", + "description": "Constitutional members to be added.", + "$ref": "#/definitions/Pairs$cardano~1address~1Credential_Mandate" + }, + { + "title": "quorum", + "description": "The new quorum value, as a ratio of a numerator and a denominator. The\n quorum specifies the threshold of 'Yes' votes necessary for the\n constitutional committee to accept a proposal procedure.", + "$ref": "#/definitions/gov~1VRational" + } + ] + }, + { + "title": "NewConstitution", + "dataType": "constructor", + "index": 5, + "fields": [ + { + "title": "ancestor", + "description": "The last governance action of type `Constitution` or\n `ConstitutionalCommittee`. They must all / form a chain.", + "$ref": "#/definitions/Option$cardano~1governance~1GovernanceActionId" + }, + { + "title": "constitution", + "description": "The new proposed constitution.", + "$ref": "#/definitions/cardano~1governance~1Constitution" + } + ] + }, + { + "title": "NicePoll", + "dataType": "constructor", + "index": 6, + "fields": [] + } + ] + }, + "gov/VProtocolParametersUpdate": { + "title": "VProtocolParametersUpdate", + "anyOf": [ + { + "title": "VProtocolParametersUpdate", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "inner", + "$ref": "#/definitions/Pairs$ProtocolParametersIndex_Data" + } + ] + } + ] + }, + "gov/VRational": { + "title": "VRational", + "anyOf": [ + { + "title": "VRational", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "numerator", + "$ref": "#/definitions/Int" + }, + { + "title": "denominator", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "types/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-crowdfund/specs/1_spend.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/1_spend.md new file mode 100644 index 000000000..f3a7776d0 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/specs/2_start.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/2_start.md new file mode 100644 index 000000000..6e2f79a27 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/specs/_scripts.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/_scripts.md new file mode 100644 index 000000000..94cedaeca --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/specs/user_action_doc.md b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/user_action_doc.md new file mode 100644 index 000000000..1dec29f5d --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/specs/user_action_doc.md @@ -0,0 +1,33 @@ +# User Actions Documentation + +## Normal Users + +1. Withdraw fund. Burning ``share_token`` + + - Validation: 1.4, 2.2 from `aiken_crowdfund` + +## Proposer + +1. Complete Crowdfund. Sending `auth_token` and `fundraised_amount` to start the proposal + + - Validation: 2.1 `Withdraw`, 2.1 `Mint`, 3.2 from `aiken_crowdfund` + +2. Register Certificates. Proposing `gov_action`, registering stake cert, registering drep cert, delegating vote to drep and delegating stake to `delegate_pool_id` + + - Validation: 1.1, 2.1 `Publish`, 2.1 `Propose` + +3. Vote Own Proposal. Voting `yes` to own proposal by drep + + - Validation: 1.2, 2.1 `Vote` + +4. Unregister Certificates. unregistering stake cert and unregistering drep cert + + - Validation: 1.3, 2.2 `Publish` + +5. Withdraw fund. Burning `share_token` + + - Validation: 1.4, 2.2 from `aiken_crowdfund` + +6. Remove Crowdfund. Burning the `only_token` + + - Validation: 1.4, 2.2 `Mint`, 2.2 from `aiken_crowdfund` \ No newline at end of file diff --git a/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak new file mode 100644 index 000000000..107f76017 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/crowdfund.ak @@ -0,0 +1,205 @@ +use aiken/collection/list +use aiken/collection/pairs.{has_key} +use cardano/address.{Address, Credential, Script} +use cardano/assets.{Lovelace, PolicyId, from_lovelace, lovelace_of} +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 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/gov-crowdfund/validators/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/spend.ak new file mode 100644 index 000000000..3314e3410 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/validators/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/start.ak new file mode 100644 index 000000000..fc6cc226e --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak new file mode 100644 index 000000000..aae163a0c --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/intergration_test/complete_crowdfund.ak @@ -0,0 +1,436 @@ +use cardano/address.{Script} +use cardano/assets.{add, from_lovelace} +use cardano/transaction.{OutputReference, Spend, Transaction} +use crowdfund.{ + CompleteCrowdfund, ContributeFund, CrowdfundRedeemer as ACrowdfundRedeemer, +} +use mocktail.{ + add_redeemer, complete, mint, mock_policy_id, mock_script_hash, mock_tx_hash, + mock_utxo_ref, mocktail_tx, script_withdrawal, tx_in, tx_in_inline_datum, + tx_out, tx_out_inline_datum, +} +use start +use tests/utils.{ + mock_auth_token, mock_completion_script, mock_crowdfund_address, + mock_crowdfund_datum, mock_current_fundraised_amount, mock_deadline, + mock_extra_fundraised_amount, mock_fee_address, mock_fundraise_target, + mock_gov_action_period, mock_gov_address, mock_min_charge, + mock_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_extra_fundraised_amount - 10) + |> add(mock_policy_id(999), mock_completion_script, 10), + ) + |> tx_out(is_fundraise_target_sent, mock_gov_address, fundraise_output) + |> tx_out_inline_datum(is_fundraise_target_sent, fundraise_output_datum) + |> script_withdrawal( + is_completion_script_executed, + mock_completion_script, + 2_000_000, + ) + |> mint(is_auth_burnt, -1, mock_auth_token, mock_completion_script) + |> mint(is_token_minted, 1, mock_start_hash, "") + |> complete() + |> add_redeemer( + True, + Pair( + Spend( + OutputReference { transaction_id: mock_tx_hash(0), output_index: 0 }, + ), + auth_token_redeemer_data, + ), + ) +} + +fn check_all_scripts( + test_case: CompleteCrowdfundTestCase, + current_fundraised_amount: Int, + auth_token_redeemer: ACrowdfundRedeemer, + start_hash: ByteArray, +) { + let tx = + mock_complete_crowdfund_tx( + test_case, + current_fundraised_amount, + auth_token_redeemer, + ) + + let check_auth_spend = + crowdfund.crowdfund.spend( + mock_auth_token, + 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-crowdfund/validators/tests/spend.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/spend.ak new file mode 100644 index 000000000..00e5aa4ad --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/validators/tests/start.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/start.ak new file mode 100644 index 000000000..79410b8f2 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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-crowdfund/validators/tests/utils.ak b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/validators/tests/utils.ak new file mode 100644 index 000000000..7d9e01d43 --- /dev/null +++ b/packages/mesh-contract/src/crowdfund/aiken-workspace-v3/gov-crowdfund/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]), + } + } +}