diff --git a/Cargo.lock b/Cargo.lock index be011f45..09f7e034 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,6 +378,14 @@ dependencies = [ "half", ] +[[package]] +name = "cip-57" +version = "0.15.1" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "clap" version = "4.5.53" @@ -2350,6 +2358,7 @@ version = "0.15.1" dependencies = [ "assert-json-diff", "ciborium", + "cip-57", "hex", "miette", "paste", diff --git a/Cargo.toml b/Cargo.toml index fe487f58..9725280b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,13 @@ [workspace] resolver = "2" -members = ["bin/tx3c", - "crates/tx3-cardano", - "crates/tx3-lang", - "crates/tx3-resolver", - "crates/tx3-tir", + +members = [ + "bin/tx3c", + "crates/tx3-cardano", + "crates/tx3-lang", + "crates/tx3-resolver", + "crates/tx3-tir", + "crates/cip-57", ] [workspace.package] diff --git a/crates/cip-57/Cargo.toml b/crates/cip-57/Cargo.toml new file mode 100644 index 00000000..a339ae1f --- /dev/null +++ b/crates/cip-57/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "cip-57" +description = "CIP-57 compatibility (JSON parsing and serialization)" +publish.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true +keywords.workspace = true +documentation.workspace = true +homepage.workspace = true +readme.workspace = true + + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1.0.137" diff --git a/crates/cip-57/examples/plutus.json b/crates/cip-57/examples/plutus.json new file mode 100644 index 00000000..1a6de029 --- /dev/null +++ b/crates/cip-57/examples/plutus.json @@ -0,0 +1,634 @@ +{ + "preamble": { + "title": "txpipe/contract", + "description": "Aiken contracts for project 'txpipe/contract'", + "version": "0.0.0", + "plutusVersion": "v3", + "compiler": { + "name": "Aiken", + "version": "v1.1.21+42babe5" + }, + "license": "Apache-2.0" + }, + "validators": [ + { + "title": "githoney_contract.badges_contract.spend", + "datum": { + "title": "_datum", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1Datum" + } + }, + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1Redeemer" + } + }, + "parameters": [ + { + "title": "settings_policy_id", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + } + ], + "compiledCode": "590389010100229800aba2aba1aba0aab9faab9eaab9dab9a9bae0024888888896600264653001300900198049805000cdc3a400530090024888966002600460126ea800e266453001300f002980798080014c03cc030dd5180798061baa32332259800980980144c966003300130083259800980498081baa0018a40011375a602860226ea800500f192cc004c024c040dd5000c5300103d87a8000899198008009bab30153012375400444b30010018a6103d87a8000899192cc004cdc8a450b73657474696e67734e4654000018acc004cdc7a4410b73657474696e67734e465400001899ba548000cc05cc0540092f5c114c0103d87a8000404d1330040043019003404c6eb8c04c004c058005014201e32330010013756600a60226ea8c014c044dd5001112cc004006298103d87a8000899192cc004cdc8808800c56600266e3c044006266e9520003301630140024bd7045300103d87a80004049133004004301800340486eb8c048004c054005013528528a01c8b44c96600266e1d20043010375400313259800980b000c4c8c966002601260266ea800a26464646644b3001301d0038992cc004c03cc064dd5000c4c8c8c966002604200513300f3020003132598009809800c4c96600260460031323259800980b000c4c966002604c003133014302500100f8b204630213754005159800980c800c4c8c8ca60026eb4c09c0066eb4c09c00e6eb4c09c00922259800981580240522c8140604e002604c00260426ea800a2c80f901f180f9baa00130220018b2040301e3754005159800980b000c566002603c6ea800a01716407d16407080e0c070dd5000c5901e180f800980f800980d1baa0018b2030301c0058b2034375a60340026eb4c068008c068004c064004c050dd50014590120800980a800c5901318089baa0018b201e30133014301430103754600860206ea800500e18090014590101bac3001300d37540084464b30013005001899192cc004c05800a00916404c6eb8c050004c040dd5001c56600260100031323259800980b00140122c8098dd7180a00098081baa0038b201c4038601c6ea80088c040c0440066eb0c03cc040c040c040c040c040c040c040c040c030dd5001a4444b30013005300f375400513232330010010032259800800c528456600266e3cdd7180b000801c528c4cc008008c05c0050112028375c602660206ea800a2c807060146ea800cdc3a4001164020300900130043754013149a26cac80101", + "hash": "691561f28bb3eb65568768048df9233a0b4cf87a5d2a0ce63da90ae3" + }, + { + "title": "githoney_contract.badges_contract.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "settings_policy_id", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + } + ], + "compiledCode": "590389010100229800aba2aba1aba0aab9faab9eaab9dab9a9bae0024888888896600264653001300900198049805000cdc3a400530090024888966002600460126ea800e266453001300f002980798080014c03cc030dd5180798061baa32332259800980980144c966003300130083259800980498081baa0018a40011375a602860226ea800500f192cc004c024c040dd5000c5300103d87a8000899198008009bab30153012375400444b30010018a6103d87a8000899192cc004cdc8a450b73657474696e67734e4654000018acc004cdc7a4410b73657474696e67734e465400001899ba548000cc05cc0540092f5c114c0103d87a8000404d1330040043019003404c6eb8c04c004c058005014201e32330010013756600a60226ea8c014c044dd5001112cc004006298103d87a8000899192cc004cdc8808800c56600266e3c044006266e9520003301630140024bd7045300103d87a80004049133004004301800340486eb8c048004c054005013528528a01c8b44c96600266e1d20043010375400313259800980b000c4c8c966002601260266ea800a26464646644b3001301d0038992cc004c03cc064dd5000c4c8c8c966002604200513300f3020003132598009809800c4c96600260460031323259800980b000c4c966002604c003133014302500100f8b204630213754005159800980c800c4c8c8ca60026eb4c09c0066eb4c09c00e6eb4c09c00922259800981580240522c8140604e002604c00260426ea800a2c80f901f180f9baa00130220018b2040301e3754005159800980b000c566002603c6ea800a01716407d16407080e0c070dd5000c5901e180f800980f800980d1baa0018b2030301c0058b2034375a60340026eb4c068008c068004c064004c050dd50014590120800980a800c5901318089baa0018b201e30133014301430103754600860206ea800500e18090014590101bac3001300d37540084464b30013005001899192cc004c05800a00916404c6eb8c050004c040dd5001c56600260100031323259800980b00140122c8098dd7180a00098081baa0038b201c4038601c6ea80088c040c0440066eb0c03cc040c040c040c040c040c040c040c040c030dd5001a4444b30013005300f375400513232330010010032259800800c528456600266e3cdd7180b000801c528c4cc008008c05c0050112028375c602660206ea800a2c807060146ea800cdc3a4001164020300900130043754013149a26cac80101", + "hash": "691561f28bb3eb65568768048df9233a0b4cf87a5d2a0ce63da90ae3" + }, + { + "title": "githoney_contract.badges_policy.mint", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1Redeemer" + } + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + }, + { + "title": "nonce", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "58980101002229800aba2aba1aab9faab9eaab9dab9a9bad002488888896600264646644b30013370e900018039baa0018992cc004c8cc004004dd6180618051baa300c0062259800800c528456600266ebcc034c02cdd51806800808c528c4cc008008c0380050092018899b894800001a29410071bae300a30083754003164018601000260106012002601000260086ea802229344d9590021", + "hash": "96b8e7848e41c82226a894a633bcdfd8f7fe73b24849288d1f0e47aa" + }, + { + "title": "githoney_contract.badges_policy.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + }, + { + "title": "nonce", + "schema": { + "$ref": "#/definitions/Int" + } + } + ], + "compiledCode": "58980101002229800aba2aba1aab9faab9eaab9dab9a9bad002488888896600264646644b30013370e900018039baa0018992cc004c8cc004004dd6180618051baa300c0062259800800c528456600266ebcc034c02cdd51806800808c528c4cc008008c0380050092018899b894800001a29410071bae300a30083754003164018601000260106012002601000260086ea802229344d9590021", + "hash": "96b8e7848e41c82226a894a633bcdfd8f7fe73b24849288d1f0e47aa" + }, + { + "title": "githoney_contract.githoney.spend", + "datum": { + "title": "datum", + "schema": { + "$ref": "#/definitions/types~1GithoneyDatum" + } + }, + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1GithoneyContractRedeemers" + } + }, + "parameters": [ + { + "title": "settings_policy_id", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + } + ], + "compiledCode": "5914b7010100229800aba4aba2aba1aba0aab9faab9eaab9dab9a9bae002488888888966003300130043754015230083009300930093009300930090019b874800246010601260126012003370e90014dd2a40012300830090019180418049804800cdc3a40092300830093009300930093009300930090019119198008008019119801800980100148c020c024c024c024c024c02400644b30010018a4d13259800800c5268992cc004cdc81bae3007300b003375c600e0031330040043300a001300c0028b200c300a00140206014002803a4b30010018a518a50401922232330010010042259800800c40122653001375c6012003375a601400333003003300e002401060180028052444646600200200844b3001001880244ca60026eb8c0240066eacc02800666006006601c0048020c03000500a48c020c024c024c024c0240066e1d2001488888888888888888a60026034025301901291111919800800802912cc00400626603c66ec0dd48029ba60044bd6f7b63044ca60026eb8c0700066eacc07400660420049112cc004cdc8004801c4cc088cdd81ba9009374c01000b15980099b8f0090038992cc004c06cc080dd5000c4cc08ccdd81ba900a3024302137540020051002407d3001009804400900744cc088cdd81ba9003374c0046600c00c00280f101e0c07c00501d488c96600260260031323259800980f80140122c80e0dd7180e800980c9baa0038acc004c04400626464b3001301f00280245901c1bae301d0013019375400716405c80b8c05cdd5001488c8cc00400400c896600200314c103d87a8000899192cc004cdc8802800c56600266e3c014006260266603c603800497ae08a60103d87a80004069133004004302000340686eb8c068004c07400501b488966002602600314bd6f7b63044c8c8cc0040052f5bded8c044b300100189980f19bb0375200c6e9800d2f5bded8c113298009bae301c0019bab301d00198108012444b300133720014007133022337606ea4028dd3003802c56600266e3c02800e26604466ec0dd48051ba600700189981119bb037520066e98008cc01801800501e203c180f800a03a32330010014bd6f7b630112cc00400626603a66ec0dd48021ba80034bd6f7b63044ca60026eb8c06c0066eb4c07000660400049112cc004cdc8004001c4cc084cdd81ba9008375000e00b15980099b8f00800389981099bb037520106ea001c00626604266ec0dd48019ba800233006006001407480e8603c00280e101749660026022602c6ea80062942294501548896600200514a11329800992cc004c054c068dd5000c4dd6980d980f1bab301e301b3754003148001019180e800cdd7980e980f000cdd5801a444b30010018acc004c00801a26600a0069000452820368992cc004cdd7980e800a610140008acc004cc018010dd6980f18109bab301e001898019ba630220028a5040711598009980300224001130030078a50407080e0c08000501e0ca6002003004911980f0011980f1ba60014bd7020022225980080144cc005300103d87a80004bd6f7b63044ca60026eb8c0700066eacc07400660420069112cc004cdc8a441000038acc004cdc7a44100003899802980b998111ba60024bd70000c4cc015300103d87a8000006407919800803c006446600e0046604866ec0dd48029ba6004001401c80f0603e00480ea29422942294101e488c966002602260306ea8006266e24dd6980e180c9baa0010028a50405c603660306ea8c038c060dd500148888c8cc004004014896600200313301e337606ea4014dd400225eb7bdb1822653001375c6038003375a603a003302100248896600266e4002400e26604466ec0dd48049ba80080058acc004cdc7804801c4c966002603660406ea800626604666ec0dd4805181218109baa0010028801203e9800804c022004803a26604466ec0dd48019ba800233006006001407880f0603e00280ea600c00d29800800d2f5c1222980080140064446603e6e9ccc07cdd48031980f9ba90033301f375000497ae000140208022444b30010028a6103d87a80008acc004c04c0062602066036603800497ae08cc00400e603a005337000029000a006405c80d1222222222222298009813006cc098c09c03644453001004801c00a4453001003800c009004201e912cc004c07cc090dd500144c8c8c966002605800513300f302b003132598009811800c4c966002605c00313232598009813000c4c966002606200313301430300010098b205c302c37540051598009812000c4c8c8ca60026eb4c0c80066eb4c0c800e6eb4c0c800922259800981b002403a2c81986064002606200260586ea800a2c815102a18151baa001302d0018b2056302937540051598009810800c56600260526ea800a00b1640a916409c8138c09cdd5000c590291815000981500098129baa0028b2046911192cc004c07cc098dd5000c5200089bad302a302737540028128c966002603e604c6ea8006298103d87a8000899198008009bab302b3028375400444b30010018a6103d87a8000899192cc004cdc8803000c56600266e3c018006260446605a605600497ae08a60103d87a800040a5133004004302f00340a46eb8c0a4004c0b000502a204a3300c00300294c005220100a44100800a0129192cc004c0a400626eb0c0a00062c8130c00cdd5980818121baa0019800800a444444453001302a375400f232330010010022259800800c52f5bded8c113298009bae302e0019bab302f00199801801981980124453001001801cc8c8010c8cc0040040108966002003149a264b30010018acc004c010dd6981b181c80145268b2068899912cc004cdc81bae3037002375c606e00315980098031bad30380028998028029981d000981e001c59036459036181c801181c800a06e303900140d853001302d001a50a5140c522264034303100140bd2232598009819000c4c9660033001302798009bab3025302f3754604a605e6ea800600748810b73657474696e67734e46540040214a14a2816a2d13259800981218179baa0018992cc004c0d4006264b3001302c303137540031323232332259800981d801c4cc044c0e8014401a2c81c0dd6981c0009bad303800230380013037001303237540031640c060680031640c860606ea80062c8170c090c0bcdd5181298179baa00140b460620031640bc6eb0c08cc0b4dd5001488c8cc004004008896600200314a313233223322330020020012259800800c400e2653001375c6068003375a606a00333003003303900248896600266e22600201b008801a0220028acc00400629422941036456600200314a314a081b10360c0dc0050351bab3032003375c605e002660060066068004606400281824b30013020302b3754003132598009818800c4c9660026050605a6ea80062646464646464653001375660700033038006981c002cdd6981c0024dd6981c001cc966002606c00315980099b8948010c0d40062d1302e303500140d11640dc6ea8c0e000922222259800981f803c4cc088c0f80344cc0540144cc8966002606e003132598009821000c4cc060c10400400e2c81f8c0f4dd50034566002606a003159800981e9baa00680145903e45903b207613302d00622598008014404226464660626eacc0fc00889660020051300530450068991991180218240029bae3041001375a608400260880048210dd7181e8009820001207c303a37540091640f0303800130370013036001303500130340013033001302e37540031640b060600031640b860586ea80062c81524444b300130290018802466002009003991900118080009981899bb037520046ea00052f5bded8c122232598009811000c530103d87a8000898151981a9ba60014bd7020629800801401600922232598009818000c530103d87a8000898169981c1ba80014bd70206833700002004809900a205a911192cc004c0a4c0b8dd5000c4c96600266ebcc0ccc0c0dd5000802440062c8170c0c8c0bcdd5000c5902d19802001800a444444464b3001302b008899194c004566002605e60686ea80062646644b30013030303737540051323259800981f000c4c8c96600260686eb4c0f000a264b300130370018992cc0066002606c607a6ea8c0bcc0f8dd5003d28528a0788acc004cdd780398079819981f1baa0018acc004cc080c0c4c0f8dd50139bad302a303e375400f159800998061bab3034303e37540026eacc0d0c0f8dd5004c4cdc49919800800980f1bab3035303f375400444b30010018a40011337009001198010011822000a0824807a294103c452820788a5040f114a081e260026eb0c0c8c0f4dd50134c100c0f4dd50045200040311332259800981b801c4c96600264b30013375e002646460746608a608c0046608a608c0026608a607060866ea800cc11cc11c004c118004c104dd500544c00cc0d8c104dd5000c528207e3011303530403754003159800cc004dd5981b18201baa0019ba6330033756606c60806ea802cc06120809bee029119b87002001408d15980099811181998201baa029375a605860806ea802626048606a60806ea8026294103e4528207c8a5040f9300137586068607e6ea80a26084607e6ea802a9000201c899912cc004c0d401626644b30019800981d98211baa3034304337540194a14a2820a2b3001330033758600860866ea80b0c118c10cdd5006456600266ebcc050c0e0c10cdd50011919191919181f998251825802998251825802198251825801998251825801198251825800998254c00528d30103d87a8000a60103d8798000411860986098002609600260940026092002609000260866ea80322b300198009bab30393043375400530460019119b87002001409915980099812981b18219baa02c375a605e60866ea80322b300130053038304337540191598009980a9bab30393043375530013758607060866ea80b2607260866ea803290022024301b482026fb80a26602a6eacc0e4c10cdd54c004dd6181c18219baa02c982318219baa3301602c040a40048090dd598231823800c52820828a50410514a0820a2941041452820828a50410514a0820a60026eb0c0d8c104dd50154c110c104dd500652000404064646608a608c0026608a608c608e00297ae09800998029bab30383042375401a6034907fdaee02ccc110dd319802cc00402a00f48009027180d2410137dc0466088980101a0004bd70488a60020050019112cc004cdc780300844006264660966e98cc030dd598260014c00401e009337020060028170cc12cdd3198061bab304c304d0029800803c01200281712f5c066e0ccdc1001003a414138028231033205e375a607460826ea802a2b30013370e9003002c4c8cc89660033001303c30433754606a60886ea80369429450424566002660086eb0c014c110dd5016982398221baa00d8acc004c966002607e60886ea80062b30013301737566076608a6eaa60026eb0c0e8c114dd50174c120c114dd5000d20024050603a90404df7014400a294104344009043181c98221baa00d8acc004c0bcdd698239824001456600266e3cdd71823801004c4cdc79bae304700300c8a50410914a082122941042452820848a504108608c002660286eacc0e0c108dd54c004dd6181b98211baa02b981c18211baa00ba40008088c058dd5981e98211baa00b301802a8992cc004c0f0c104dd5000c4c8c966002607860866ea8c0d4c110dd5006c566002b3001302f375a608e609000315980099b8f375c608e00201313371e6eb8c11c00803229410424528208489980b1bab303a3044375530013758607260886ea80b6608e60886ea800e9000202698009bab303a3044375401f00c804d2001405114a0821229410421823800980c815c59040181b18209baa00a40fc81f88c10cc110c110c110c110c110c110c110c1100048966002607660806ea8006264646600200200844b30010018a508acc004cdc79bae30470010038a518998010011824000a08441146eb8c110c104dd5000c5903f207a22329800800c00e00480088896600200510018994c004012608e00798008014dd71821000cdd59821800c888c966002606c00314c103d87a80008981f198249ba60014bd70208a329800800c00e00480088896600200510018994c004012609c00798008014dd71824800cdd69825000c888c966002609000314c103d87a800089822998281ba80014bd7020983370000400281590041826001209440ac8020c11400904312cc004c0e0c0f4dd5000c528c528207840ec60766ea80662c81d0dd7181d000981e800c5903b192cc004c0c8c0e4dd5000c52f5bded8c113756607a60746ea80050381980f9bab302f303937540080026eb8c0ecc0e0dd5001459036181c981b1baa3039303637540026072606c6ea8008c0acc0d4dd5192cc004c0e8006260720031640dc64660020026eb0c0e4c0d8dd500f912cc004006297ae0899912cc00566002606260706ea8c0f0c0e4dd5181e181c9baa302f3039375400514a314a081ba2660760046600800800313300400400140dc6074002607600281c22c819a60686ea804a60700049112cc004c0c800a2b30013038375402b0038b20728acc004c0c000a2b30013038375402b0038b20728acc004c0b000a2b30013038375402b0038b20728acc004cdc3a400c005159800981c1baa015801c59039456600266e1d20080028acc004c0e0dd500ac00e2c81ca2c81b1036206c40d881b0606e607000260666ea803e2b3001302d008899194c004dd7181c000cdd6981c181c800cdd7181c181a9baa0119bae30380024888966002604800714a313233225980099b89375a606460786ea800660026eacc0c8c0f0dd54c004dd61818981e1baa025981f981e1baa001a4004805a910100a441004055159800981a0034566002b300159800981a181d9baa302d303c375400514a119800a50a50a5140e881d22b30013301e302f303c375404a6eb4c0a0c0f0dd500145660026040606260786ea800a266e1cdd6981a981e1baa002375a606260786ea8006294103a452820748a5040e9159800998051bab3032303c375400730013014482026fb80a009007a400480623300130103756606e60786ea800a6e9a60026eacc0c8c0f0dd5001c01200f4800500c488cdc3801000a03e8a5040e914a081d2294103a45282074300b302f303a37540026601a04606f30013758605c60726ea808a60606607666e9520023303b375200297ae03303b4c103d87a80004bd7052000402081b8607000260140391640c4818889660026600c00400319800cc00400a6e980064466e1c008005017528528a0648a5040c81149a26cac8011", + "hash": "72f5c8da799d628b55f237451ae44b4311b8f4b2b06ab57b3fef5947" + }, + { + "title": "githoney_contract.githoney.mint", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1Redeemer" + } + }, + "parameters": [ + { + "title": "settings_policy_id", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + } + ], + "compiledCode": "5914b7010100229800aba4aba2aba1aba0aab9faab9eaab9dab9a9bae002488888888966003300130043754015230083009300930093009300930090019b874800246010601260126012003370e90014dd2a40012300830090019180418049804800cdc3a40092300830093009300930093009300930090019119198008008019119801800980100148c020c024c024c024c024c02400644b30010018a4d13259800800c5268992cc004cdc81bae3007300b003375c600e0031330040043300a001300c0028b200c300a00140206014002803a4b30010018a518a50401922232330010010042259800800c40122653001375c6012003375a601400333003003300e002401060180028052444646600200200844b3001001880244ca60026eb8c0240066eacc02800666006006601c0048020c03000500a48c020c024c024c024c0240066e1d2001488888888888888888a60026034025301901291111919800800802912cc00400626603c66ec0dd48029ba60044bd6f7b63044ca60026eb8c0700066eacc07400660420049112cc004cdc8004801c4cc088cdd81ba9009374c01000b15980099b8f0090038992cc004c06cc080dd5000c4cc08ccdd81ba900a3024302137540020051002407d3001009804400900744cc088cdd81ba9003374c0046600c00c00280f101e0c07c00501d488c96600260260031323259800980f80140122c80e0dd7180e800980c9baa0038acc004c04400626464b3001301f00280245901c1bae301d0013019375400716405c80b8c05cdd5001488c8cc00400400c896600200314c103d87a8000899192cc004cdc8802800c56600266e3c014006260266603c603800497ae08a60103d87a80004069133004004302000340686eb8c068004c07400501b488966002602600314bd6f7b63044c8c8cc0040052f5bded8c044b300100189980f19bb0375200c6e9800d2f5bded8c113298009bae301c0019bab301d00198108012444b300133720014007133022337606ea4028dd3003802c56600266e3c02800e26604466ec0dd48051ba600700189981119bb037520066e98008cc01801800501e203c180f800a03a32330010014bd6f7b630112cc00400626603a66ec0dd48021ba80034bd6f7b63044ca60026eb8c06c0066eb4c07000660400049112cc004cdc8004001c4cc084cdd81ba9008375000e00b15980099b8f00800389981099bb037520106ea001c00626604266ec0dd48019ba800233006006001407480e8603c00280e101749660026022602c6ea80062942294501548896600200514a11329800992cc004c054c068dd5000c4dd6980d980f1bab301e301b3754003148001019180e800cdd7980e980f000cdd5801a444b30010018acc004c00801a26600a0069000452820368992cc004cdd7980e800a610140008acc004cc018010dd6980f18109bab301e001898019ba630220028a5040711598009980300224001130030078a50407080e0c08000501e0ca6002003004911980f0011980f1ba60014bd7020022225980080144cc005300103d87a80004bd6f7b63044ca60026eb8c0700066eacc07400660420069112cc004cdc8a441000038acc004cdc7a44100003899802980b998111ba60024bd70000c4cc015300103d87a8000006407919800803c006446600e0046604866ec0dd48029ba6004001401c80f0603e00480ea29422942294101e488c966002602260306ea8006266e24dd6980e180c9baa0010028a50405c603660306ea8c038c060dd500148888c8cc004004014896600200313301e337606ea4014dd400225eb7bdb1822653001375c6038003375a603a003302100248896600266e4002400e26604466ec0dd48049ba80080058acc004cdc7804801c4c966002603660406ea800626604666ec0dd4805181218109baa0010028801203e9800804c022004803a26604466ec0dd48019ba800233006006001407880f0603e00280ea600c00d29800800d2f5c1222980080140064446603e6e9ccc07cdd48031980f9ba90033301f375000497ae000140208022444b30010028a6103d87a80008acc004c04c0062602066036603800497ae08cc00400e603a005337000029000a006405c80d1222222222222298009813006cc098c09c03644453001004801c00a4453001003800c009004201e912cc004c07cc090dd500144c8c8c966002605800513300f302b003132598009811800c4c966002605c00313232598009813000c4c966002606200313301430300010098b205c302c37540051598009812000c4c8c8ca60026eb4c0c80066eb4c0c800e6eb4c0c800922259800981b002403a2c81986064002606200260586ea800a2c815102a18151baa001302d0018b2056302937540051598009810800c56600260526ea800a00b1640a916409c8138c09cdd5000c590291815000981500098129baa0028b2046911192cc004c07cc098dd5000c5200089bad302a302737540028128c966002603e604c6ea8006298103d87a8000899198008009bab302b3028375400444b30010018a6103d87a8000899192cc004cdc8803000c56600266e3c018006260446605a605600497ae08a60103d87a800040a5133004004302f00340a46eb8c0a4004c0b000502a204a3300c00300294c005220100a44100800a0129192cc004c0a400626eb0c0a00062c8130c00cdd5980818121baa0019800800a444444453001302a375400f232330010010022259800800c52f5bded8c113298009bae302e0019bab302f00199801801981980124453001001801cc8c8010c8cc0040040108966002003149a264b30010018acc004c010dd6981b181c80145268b2068899912cc004cdc81bae3037002375c606e00315980098031bad30380028998028029981d000981e001c59036459036181c801181c800a06e303900140d853001302d001a50a5140c522264034303100140bd2232598009819000c4c9660033001302798009bab3025302f3754604a605e6ea800600748810b73657474696e67734e46540040214a14a2816a2d13259800981218179baa0018992cc004c0d4006264b3001302c303137540031323232332259800981d801c4cc044c0e8014401a2c81c0dd6981c0009bad303800230380013037001303237540031640c060680031640c860606ea80062c8170c090c0bcdd5181298179baa00140b460620031640bc6eb0c08cc0b4dd5001488c8cc004004008896600200314a313233223322330020020012259800800c400e2653001375c6068003375a606a00333003003303900248896600266e22600201b008801a0220028acc00400629422941036456600200314a314a081b10360c0dc0050351bab3032003375c605e002660060066068004606400281824b30013020302b3754003132598009818800c4c9660026050605a6ea80062646464646464653001375660700033038006981c002cdd6981c0024dd6981c001cc966002606c00315980099b8948010c0d40062d1302e303500140d11640dc6ea8c0e000922222259800981f803c4cc088c0f80344cc0540144cc8966002606e003132598009821000c4cc060c10400400e2c81f8c0f4dd50034566002606a003159800981e9baa00680145903e45903b207613302d00622598008014404226464660626eacc0fc00889660020051300530450068991991180218240029bae3041001375a608400260880048210dd7181e8009820001207c303a37540091640f0303800130370013036001303500130340013033001302e37540031640b060600031640b860586ea80062c81524444b300130290018802466002009003991900118080009981899bb037520046ea00052f5bded8c122232598009811000c530103d87a8000898151981a9ba60014bd7020629800801401600922232598009818000c530103d87a8000898169981c1ba80014bd70206833700002004809900a205a911192cc004c0a4c0b8dd5000c4c96600266ebcc0ccc0c0dd5000802440062c8170c0c8c0bcdd5000c5902d19802001800a444444464b3001302b008899194c004566002605e60686ea80062646644b30013030303737540051323259800981f000c4c8c96600260686eb4c0f000a264b300130370018992cc0066002606c607a6ea8c0bcc0f8dd5003d28528a0788acc004cdd780398079819981f1baa0018acc004cc080c0c4c0f8dd50139bad302a303e375400f159800998061bab3034303e37540026eacc0d0c0f8dd5004c4cdc49919800800980f1bab3035303f375400444b30010018a40011337009001198010011822000a0824807a294103c452820788a5040f114a081e260026eb0c0c8c0f4dd50134c100c0f4dd50045200040311332259800981b801c4c96600264b30013375e002646460746608a608c0046608a608c0026608a607060866ea800cc11cc11c004c118004c104dd500544c00cc0d8c104dd5000c528207e3011303530403754003159800cc004dd5981b18201baa0019ba6330033756606c60806ea802cc06120809bee029119b87002001408d15980099811181998201baa029375a605860806ea802626048606a60806ea8026294103e4528207c8a5040f9300137586068607e6ea80a26084607e6ea802a9000201c899912cc004c0d401626644b30019800981d98211baa3034304337540194a14a2820a2b3001330033758600860866ea80b0c118c10cdd5006456600266ebcc050c0e0c10cdd50011919191919181f998251825802998251825802198251825801998251825801198251825800998254c00528d30103d87a8000a60103d8798000411860986098002609600260940026092002609000260866ea80322b300198009bab30393043375400530460019119b87002001409915980099812981b18219baa02c375a605e60866ea80322b300130053038304337540191598009980a9bab30393043375530013758607060866ea80b2607260866ea803290022024301b482026fb80a26602a6eacc0e4c10cdd54c004dd6181c18219baa02c982318219baa3301602c040a40048090dd598231823800c52820828a50410514a0820a2941041452820828a50410514a0820a60026eb0c0d8c104dd50154c110c104dd500652000404064646608a608c0026608a608c608e00297ae09800998029bab30383042375401a6034907fdaee02ccc110dd319802cc00402a00f48009027180d2410137dc0466088980101a0004bd70488a60020050019112cc004cdc780300844006264660966e98cc030dd598260014c00401e009337020060028170cc12cdd3198061bab304c304d0029800803c01200281712f5c066e0ccdc1001003a414138028231033205e375a607460826ea802a2b30013370e9003002c4c8cc89660033001303c30433754606a60886ea80369429450424566002660086eb0c014c110dd5016982398221baa00d8acc004c966002607e60886ea80062b30013301737566076608a6eaa60026eb0c0e8c114dd50174c120c114dd5000d20024050603a90404df7014400a294104344009043181c98221baa00d8acc004c0bcdd698239824001456600266e3cdd71823801004c4cdc79bae304700300c8a50410914a082122941042452820848a504108608c002660286eacc0e0c108dd54c004dd6181b98211baa02b981c18211baa00ba40008088c058dd5981e98211baa00b301802a8992cc004c0f0c104dd5000c4c8c966002607860866ea8c0d4c110dd5006c566002b3001302f375a608e609000315980099b8f375c608e00201313371e6eb8c11c00803229410424528208489980b1bab303a3044375530013758607260886ea80b6608e60886ea800e9000202698009bab303a3044375401f00c804d2001405114a0821229410421823800980c815c59040181b18209baa00a40fc81f88c10cc110c110c110c110c110c110c110c1100048966002607660806ea8006264646600200200844b30010018a508acc004cdc79bae30470010038a518998010011824000a08441146eb8c110c104dd5000c5903f207a22329800800c00e00480088896600200510018994c004012608e00798008014dd71821000cdd59821800c888c966002606c00314c103d87a80008981f198249ba60014bd70208a329800800c00e00480088896600200510018994c004012609c00798008014dd71824800cdd69825000c888c966002609000314c103d87a800089822998281ba80014bd7020983370000400281590041826001209440ac8020c11400904312cc004c0e0c0f4dd5000c528c528207840ec60766ea80662c81d0dd7181d000981e800c5903b192cc004c0c8c0e4dd5000c52f5bded8c113756607a60746ea80050381980f9bab302f303937540080026eb8c0ecc0e0dd5001459036181c981b1baa3039303637540026072606c6ea8008c0acc0d4dd5192cc004c0e8006260720031640dc64660020026eb0c0e4c0d8dd500f912cc004006297ae0899912cc00566002606260706ea8c0f0c0e4dd5181e181c9baa302f3039375400514a314a081ba2660760046600800800313300400400140dc6074002607600281c22c819a60686ea804a60700049112cc004c0c800a2b30013038375402b0038b20728acc004c0c000a2b30013038375402b0038b20728acc004c0b000a2b30013038375402b0038b20728acc004cdc3a400c005159800981c1baa015801c59039456600266e1d20080028acc004c0e0dd500ac00e2c81ca2c81b1036206c40d881b0606e607000260666ea803e2b3001302d008899194c004dd7181c000cdd6981c181c800cdd7181c181a9baa0119bae30380024888966002604800714a313233225980099b89375a606460786ea800660026eacc0c8c0f0dd54c004dd61818981e1baa025981f981e1baa001a4004805a910100a441004055159800981a0034566002b300159800981a181d9baa302d303c375400514a119800a50a50a5140e881d22b30013301e302f303c375404a6eb4c0a0c0f0dd500145660026040606260786ea800a266e1cdd6981a981e1baa002375a606260786ea8006294103a452820748a5040e9159800998051bab3032303c375400730013014482026fb80a009007a400480623300130103756606e60786ea800a6e9a60026eacc0c8c0f0dd5001c01200f4800500c488cdc3801000a03e8a5040e914a081d2294103a45282074300b302f303a37540026601a04606f30013758605c60726ea808a60606607666e9520023303b375200297ae03303b4c103d87a80004bd7052000402081b8607000260140391640c4818889660026600c00400319800cc00400a6e980064466e1c008005017528528a0648a5040c81149a26cac8011", + "hash": "72f5c8da799d628b55f237451ae44b4311b8f4b2b06ab57b3fef5947" + }, + { + "title": "githoney_contract.githoney.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "settings_policy_id", + "schema": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + } + } + ], + "compiledCode": "5914b7010100229800aba4aba2aba1aba0aab9faab9eaab9dab9a9bae002488888888966003300130043754015230083009300930093009300930090019b874800246010601260126012003370e90014dd2a40012300830090019180418049804800cdc3a40092300830093009300930093009300930090019119198008008019119801800980100148c020c024c024c024c024c02400644b30010018a4d13259800800c5268992cc004cdc81bae3007300b003375c600e0031330040043300a001300c0028b200c300a00140206014002803a4b30010018a518a50401922232330010010042259800800c40122653001375c6012003375a601400333003003300e002401060180028052444646600200200844b3001001880244ca60026eb8c0240066eacc02800666006006601c0048020c03000500a48c020c024c024c024c0240066e1d2001488888888888888888a60026034025301901291111919800800802912cc00400626603c66ec0dd48029ba60044bd6f7b63044ca60026eb8c0700066eacc07400660420049112cc004cdc8004801c4cc088cdd81ba9009374c01000b15980099b8f0090038992cc004c06cc080dd5000c4cc08ccdd81ba900a3024302137540020051002407d3001009804400900744cc088cdd81ba9003374c0046600c00c00280f101e0c07c00501d488c96600260260031323259800980f80140122c80e0dd7180e800980c9baa0038acc004c04400626464b3001301f00280245901c1bae301d0013019375400716405c80b8c05cdd5001488c8cc00400400c896600200314c103d87a8000899192cc004cdc8802800c56600266e3c014006260266603c603800497ae08a60103d87a80004069133004004302000340686eb8c068004c07400501b488966002602600314bd6f7b63044c8c8cc0040052f5bded8c044b300100189980f19bb0375200c6e9800d2f5bded8c113298009bae301c0019bab301d00198108012444b300133720014007133022337606ea4028dd3003802c56600266e3c02800e26604466ec0dd48051ba600700189981119bb037520066e98008cc01801800501e203c180f800a03a32330010014bd6f7b630112cc00400626603a66ec0dd48021ba80034bd6f7b63044ca60026eb8c06c0066eb4c07000660400049112cc004cdc8004001c4cc084cdd81ba9008375000e00b15980099b8f00800389981099bb037520106ea001c00626604266ec0dd48019ba800233006006001407480e8603c00280e101749660026022602c6ea80062942294501548896600200514a11329800992cc004c054c068dd5000c4dd6980d980f1bab301e301b3754003148001019180e800cdd7980e980f000cdd5801a444b30010018acc004c00801a26600a0069000452820368992cc004cdd7980e800a610140008acc004cc018010dd6980f18109bab301e001898019ba630220028a5040711598009980300224001130030078a50407080e0c08000501e0ca6002003004911980f0011980f1ba60014bd7020022225980080144cc005300103d87a80004bd6f7b63044ca60026eb8c0700066eacc07400660420069112cc004cdc8a441000038acc004cdc7a44100003899802980b998111ba60024bd70000c4cc015300103d87a8000006407919800803c006446600e0046604866ec0dd48029ba6004001401c80f0603e00480ea29422942294101e488c966002602260306ea8006266e24dd6980e180c9baa0010028a50405c603660306ea8c038c060dd500148888c8cc004004014896600200313301e337606ea4014dd400225eb7bdb1822653001375c6038003375a603a003302100248896600266e4002400e26604466ec0dd48049ba80080058acc004cdc7804801c4c966002603660406ea800626604666ec0dd4805181218109baa0010028801203e9800804c022004803a26604466ec0dd48019ba800233006006001407880f0603e00280ea600c00d29800800d2f5c1222980080140064446603e6e9ccc07cdd48031980f9ba90033301f375000497ae000140208022444b30010028a6103d87a80008acc004c04c0062602066036603800497ae08cc00400e603a005337000029000a006405c80d1222222222222298009813006cc098c09c03644453001004801c00a4453001003800c009004201e912cc004c07cc090dd500144c8c8c966002605800513300f302b003132598009811800c4c966002605c00313232598009813000c4c966002606200313301430300010098b205c302c37540051598009812000c4c8c8ca60026eb4c0c80066eb4c0c800e6eb4c0c800922259800981b002403a2c81986064002606200260586ea800a2c815102a18151baa001302d0018b2056302937540051598009810800c56600260526ea800a00b1640a916409c8138c09cdd5000c590291815000981500098129baa0028b2046911192cc004c07cc098dd5000c5200089bad302a302737540028128c966002603e604c6ea8006298103d87a8000899198008009bab302b3028375400444b30010018a6103d87a8000899192cc004cdc8803000c56600266e3c018006260446605a605600497ae08a60103d87a800040a5133004004302f00340a46eb8c0a4004c0b000502a204a3300c00300294c005220100a44100800a0129192cc004c0a400626eb0c0a00062c8130c00cdd5980818121baa0019800800a444444453001302a375400f232330010010022259800800c52f5bded8c113298009bae302e0019bab302f00199801801981980124453001001801cc8c8010c8cc0040040108966002003149a264b30010018acc004c010dd6981b181c80145268b2068899912cc004cdc81bae3037002375c606e00315980098031bad30380028998028029981d000981e001c59036459036181c801181c800a06e303900140d853001302d001a50a5140c522264034303100140bd2232598009819000c4c9660033001302798009bab3025302f3754604a605e6ea800600748810b73657474696e67734e46540040214a14a2816a2d13259800981218179baa0018992cc004c0d4006264b3001302c303137540031323232332259800981d801c4cc044c0e8014401a2c81c0dd6981c0009bad303800230380013037001303237540031640c060680031640c860606ea80062c8170c090c0bcdd5181298179baa00140b460620031640bc6eb0c08cc0b4dd5001488c8cc004004008896600200314a313233223322330020020012259800800c400e2653001375c6068003375a606a00333003003303900248896600266e22600201b008801a0220028acc00400629422941036456600200314a314a081b10360c0dc0050351bab3032003375c605e002660060066068004606400281824b30013020302b3754003132598009818800c4c9660026050605a6ea80062646464646464653001375660700033038006981c002cdd6981c0024dd6981c001cc966002606c00315980099b8948010c0d40062d1302e303500140d11640dc6ea8c0e000922222259800981f803c4cc088c0f80344cc0540144cc8966002606e003132598009821000c4cc060c10400400e2c81f8c0f4dd50034566002606a003159800981e9baa00680145903e45903b207613302d00622598008014404226464660626eacc0fc00889660020051300530450068991991180218240029bae3041001375a608400260880048210dd7181e8009820001207c303a37540091640f0303800130370013036001303500130340013033001302e37540031640b060600031640b860586ea80062c81524444b300130290018802466002009003991900118080009981899bb037520046ea00052f5bded8c122232598009811000c530103d87a8000898151981a9ba60014bd7020629800801401600922232598009818000c530103d87a8000898169981c1ba80014bd70206833700002004809900a205a911192cc004c0a4c0b8dd5000c4c96600266ebcc0ccc0c0dd5000802440062c8170c0c8c0bcdd5000c5902d19802001800a444444464b3001302b008899194c004566002605e60686ea80062646644b30013030303737540051323259800981f000c4c8c96600260686eb4c0f000a264b300130370018992cc0066002606c607a6ea8c0bcc0f8dd5003d28528a0788acc004cdd780398079819981f1baa0018acc004cc080c0c4c0f8dd50139bad302a303e375400f159800998061bab3034303e37540026eacc0d0c0f8dd5004c4cdc49919800800980f1bab3035303f375400444b30010018a40011337009001198010011822000a0824807a294103c452820788a5040f114a081e260026eb0c0c8c0f4dd50134c100c0f4dd50045200040311332259800981b801c4c96600264b30013375e002646460746608a608c0046608a608c0026608a607060866ea800cc11cc11c004c118004c104dd500544c00cc0d8c104dd5000c528207e3011303530403754003159800cc004dd5981b18201baa0019ba6330033756606c60806ea802cc06120809bee029119b87002001408d15980099811181998201baa029375a605860806ea802626048606a60806ea8026294103e4528207c8a5040f9300137586068607e6ea80a26084607e6ea802a9000201c899912cc004c0d401626644b30019800981d98211baa3034304337540194a14a2820a2b3001330033758600860866ea80b0c118c10cdd5006456600266ebcc050c0e0c10cdd50011919191919181f998251825802998251825802198251825801998251825801198251825800998254c00528d30103d87a8000a60103d8798000411860986098002609600260940026092002609000260866ea80322b300198009bab30393043375400530460019119b87002001409915980099812981b18219baa02c375a605e60866ea80322b300130053038304337540191598009980a9bab30393043375530013758607060866ea80b2607260866ea803290022024301b482026fb80a26602a6eacc0e4c10cdd54c004dd6181c18219baa02c982318219baa3301602c040a40048090dd598231823800c52820828a50410514a0820a2941041452820828a50410514a0820a60026eb0c0d8c104dd50154c110c104dd500652000404064646608a608c0026608a608c608e00297ae09800998029bab30383042375401a6034907fdaee02ccc110dd319802cc00402a00f48009027180d2410137dc0466088980101a0004bd70488a60020050019112cc004cdc780300844006264660966e98cc030dd598260014c00401e009337020060028170cc12cdd3198061bab304c304d0029800803c01200281712f5c066e0ccdc1001003a414138028231033205e375a607460826ea802a2b30013370e9003002c4c8cc89660033001303c30433754606a60886ea80369429450424566002660086eb0c014c110dd5016982398221baa00d8acc004c966002607e60886ea80062b30013301737566076608a6eaa60026eb0c0e8c114dd50174c120c114dd5000d20024050603a90404df7014400a294104344009043181c98221baa00d8acc004c0bcdd698239824001456600266e3cdd71823801004c4cdc79bae304700300c8a50410914a082122941042452820848a504108608c002660286eacc0e0c108dd54c004dd6181b98211baa02b981c18211baa00ba40008088c058dd5981e98211baa00b301802a8992cc004c0f0c104dd5000c4c8c966002607860866ea8c0d4c110dd5006c566002b3001302f375a608e609000315980099b8f375c608e00201313371e6eb8c11c00803229410424528208489980b1bab303a3044375530013758607260886ea80b6608e60886ea800e9000202698009bab303a3044375401f00c804d2001405114a0821229410421823800980c815c59040181b18209baa00a40fc81f88c10cc110c110c110c110c110c110c110c1100048966002607660806ea8006264646600200200844b30010018a508acc004cdc79bae30470010038a518998010011824000a08441146eb8c110c104dd5000c5903f207a22329800800c00e00480088896600200510018994c004012608e00798008014dd71821000cdd59821800c888c966002606c00314c103d87a80008981f198249ba60014bd70208a329800800c00e00480088896600200510018994c004012609c00798008014dd71824800cdd69825000c888c966002609000314c103d87a800089822998281ba80014bd7020983370000400281590041826001209440ac8020c11400904312cc004c0e0c0f4dd5000c528c528207840ec60766ea80662c81d0dd7181d000981e800c5903b192cc004c0c8c0e4dd5000c52f5bded8c113756607a60746ea80050381980f9bab302f303937540080026eb8c0ecc0e0dd5001459036181c981b1baa3039303637540026072606c6ea8008c0acc0d4dd5192cc004c0e8006260720031640dc64660020026eb0c0e4c0d8dd500f912cc004006297ae0899912cc00566002606260706ea8c0f0c0e4dd5181e181c9baa302f3039375400514a314a081ba2660760046600800800313300400400140dc6074002607600281c22c819a60686ea804a60700049112cc004c0c800a2b30013038375402b0038b20728acc004c0c000a2b30013038375402b0038b20728acc004c0b000a2b30013038375402b0038b20728acc004cdc3a400c005159800981c1baa015801c59039456600266e1d20080028acc004c0e0dd500ac00e2c81ca2c81b1036206c40d881b0606e607000260666ea803e2b3001302d008899194c004dd7181c000cdd6981c181c800cdd7181c181a9baa0119bae30380024888966002604800714a313233225980099b89375a606460786ea800660026eacc0c8c0f0dd54c004dd61818981e1baa025981f981e1baa001a4004805a910100a441004055159800981a0034566002b300159800981a181d9baa302d303c375400514a119800a50a50a5140e881d22b30013301e302f303c375404a6eb4c0a0c0f0dd500145660026040606260786ea800a266e1cdd6981a981e1baa002375a606260786ea8006294103a452820748a5040e9159800998051bab3032303c375400730013014482026fb80a009007a400480623300130103756606e60786ea800a6e9a60026eacc0c8c0f0dd5001c01200f4800500c488cdc3801000a03e8a5040e914a081d2294103a45282074300b302f303a37540026601a04606f30013758605c60726ea808a60606607666e9520023303b375200297ae03303b4c103d87a80004bd7052000402081b8607000260140391640c4818889660026600c00400319800cc00400a6e980064466e1c008005017528528a0648a5040c81149a26cac8011", + "hash": "72f5c8da799d628b55f237451ae44b4311b8f4b2b06ab57b3fef5947" + }, + { + "title": "githoney_contract.settings.spend", + "datum": { + "title": "datum", + "schema": { + "$ref": "#/definitions/types~1SettingsDatum" + } + }, + "redeemer": { + "title": "redeemer", + "schema": { + "$ref": "#/definitions/types~1SettingsRedeemers" + } + }, + "compiledCode": "59052a01010029800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400530080024888966002600460106ea800e26466453001159800980098059baa0028994c004c004c034dd5192cc004c0480062602200316403c64660020026eb0c044c038dd5003112cc004006297ae0899912cc00566002601460206ea8c050c044dd5180a18089baa30053011375400514a314a0807a26602600466008008003133004004001403c6024002602600280824646600200200444b30010018a5eb7bdb1822653001375c602000337566022003301500248896600266e45221000038acc004cdc7a441000038800c401501244cc058cdd81ba9003374c0046600c00c00280906026002808a4646600200200444b30010018a5eb82264664466446600400400244b30010018801c4c8cc060dd39980c1ba90053301830150013301830160014bd7019801801980d001180c000a02c375660260066eb8c040004cc00c00cc054008c04c005011244464b30013015001899192cc004c030dd6980b180b980b80144c966002601260266ea803e2646464b3001301b0018992cc004c044dd6980d980e180e000c4c96600266e1d2004301837540031980091192cc004c04400626464b3001302200280245901f1bae3020001301c3754007159800980a800c4c8c96600260440050048b203e375c604000260386ea800e2c80d101a180d1baa002980e180c9baa0018acc00401a266e3cdd7180e001003c528202e488966002602260366ea800a26464646644b300130250038992cc004c05cc084dd5000c4c8c8c966002605200513300c302800313259800980d800c4c96600260560031323259800980f000c4c966002605c003133011302d00100f8b2056302937540051598009811000c4c8c8ca60026eb4c0bc0066eb4c0bc00e6eb4c0bc00922259800981980240522c8180605e002605c00260526ea800a2c813902718139baa001302a0018b205030263754005159800980f800c566002604c6ea800a01716409d1640908120c090dd5000c590261813800981380098111baa0018b204030240058b2044375a60440026eb4c088008c088004c084004c070dd500145901a22c80b8c010c060dd5001c590161bac301a0018b20303007300837566014602c6ea8004c8c9660026018602c6ea8006264b30013375e603660306ea8004c06cc060dd5005c40062c80b0c068c05cdd5000c590154c0040066eb0c008c058dd5007520004004444b30010028a60103d87a80008acc004c034006266e9520003301a301b0024bd70466002007301c00299b8000148005003202c406446030603260320031323259800acc004cdc39bad3019301a001480062b30013371e6eb8c0640052210b73657474696e67734e465400899b8f375c603200400914a080a229410144400e2941014180c800992cc004c06400626eb0c0600062c80b0c014dd5980b980c180c180c180c180a1baa00c40486644b3001300a3014375400313232330010010042259800800c528456600266e3cdd7180d800801c528c4cc008008c0700050162032375c6030602a6ea80062c8098dd6180b180b980b980b980b980b980b980b980b98099baa00b301630133754602c60266ea8c058c04cdd5004c590111bae301500137586028003164048600260046eacc010c040dd500188c040c0440062c805260166ea801e601e0069112cc004c01000a2b3001300f37540150038b20208acc004c02000a2b3001300f37540150038b20208b201a4034300d300e001370e900018049baa0038b200e180400098019baa0088a4d1365640041", + "hash": "e44c3a699837b5ff631a5aaaf9f32209d6194c8075b8d7dee62f3420" + }, + { + "title": "githoney_contract.settings.else", + "redeemer": { + "schema": {} + }, + "compiledCode": "59052a01010029800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400530080024888966002600460106ea800e26466453001159800980098059baa0028994c004c004c034dd5192cc004c0480062602200316403c64660020026eb0c044c038dd5003112cc004006297ae0899912cc00566002601460206ea8c050c044dd5180a18089baa30053011375400514a314a0807a26602600466008008003133004004001403c6024002602600280824646600200200444b30010018a5eb7bdb1822653001375c602000337566022003301500248896600266e45221000038acc004cdc7a441000038800c401501244cc058cdd81ba9003374c0046600c00c00280906026002808a4646600200200444b30010018a5eb82264664466446600400400244b30010018801c4c8cc060dd39980c1ba90053301830150013301830160014bd7019801801980d001180c000a02c375660260066eb8c040004cc00c00cc054008c04c005011244464b30013015001899192cc004c030dd6980b180b980b80144c966002601260266ea803e2646464b3001301b0018992cc004c044dd6980d980e180e000c4c96600266e1d2004301837540031980091192cc004c04400626464b3001302200280245901f1bae3020001301c3754007159800980a800c4c8c96600260440050048b203e375c604000260386ea800e2c80d101a180d1baa002980e180c9baa0018acc00401a266e3cdd7180e001003c528202e488966002602260366ea800a26464646644b300130250038992cc004c05cc084dd5000c4c8c8c966002605200513300c302800313259800980d800c4c96600260560031323259800980f000c4c966002605c003133011302d00100f8b2056302937540051598009811000c4c8c8ca60026eb4c0bc0066eb4c0bc00e6eb4c0bc00922259800981980240522c8180605e002605c00260526ea800a2c813902718139baa001302a0018b205030263754005159800980f800c566002604c6ea800a01716409d1640908120c090dd5000c590261813800981380098111baa0018b204030240058b2044375a60440026eb4c088008c088004c084004c070dd500145901a22c80b8c010c060dd5001c590161bac301a0018b20303007300837566014602c6ea8004c8c9660026018602c6ea8006264b30013375e603660306ea8004c06cc060dd5005c40062c80b0c068c05cdd5000c590154c0040066eb0c008c058dd5007520004004444b30010028a60103d87a80008acc004c034006266e9520003301a301b0024bd70466002007301c00299b8000148005003202c406446030603260320031323259800acc004cdc39bad3019301a001480062b30013371e6eb8c0640052210b73657474696e67734e465400899b8f375c603200400914a080a229410144400e2941014180c800992cc004c06400626eb0c0600062c80b0c014dd5980b980c180c180c180c180a1baa00c40486644b3001300a3014375400313232330010010042259800800c528456600266e3cdd7180d800801c528c4cc008008c0700050162032375c6030602a6ea80062c8098dd6180b180b980b980b980b980b980b980b980b98099baa00b301630133754602c60266ea8c058c04cdd5004c590111bae301500137586028003164048600260046eacc010c040dd500188c040c0440062c805260166ea801e601e0069112cc004c01000a2b3001300f37540150038b20208acc004c02000a2b3001300f37540150038b20208b201a4034300d300e001370e900018049baa0038b200e180400098019baa0088a4d1365640041", + "hash": "e44c3a699837b5ff631a5aaaf9f32209d6194c8075b8d7dee62f3420" + }, + { + "title": "githoney_contract.settings_minting.mint", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1Redeemer" + } + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + }, + { + "title": "settings_script_addr", + "schema": { + "$ref": "#/definitions/cardano~1address~1Address" + } + } + ], + "compiledCode": "5904230101002229800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400130080024888966002600460106ea800e26644b30013370e0029000c528c4cc88c8c96600266e1d2004300e3754003132980091192cc004c03000626464b300130190028024590161bae3017001301337540071598009802000c4c8c96600260320050048b202c375c602e00260266ea800e2c808901118089baa0028acc004c00401a2b300132330010013758602860226ea8024896600200314a115980099baf301530123754602a00203314a313300200230160014040809a2600264b300130023010375400314800226eb4c050c044dd5000a01e3259800980118081baa0018a60103d87a8000899198008009bab30153012375400444b30010018a6103d87a8000899192cc004cdc8a450b73657474696e67734e4654000018acc004cdc7a4410b73657474696e67734e465400001898049980b980a80125eb82298103d87a8000404d1330040043019003404c6eb8c04c004c058005014201e323300100137566028602a60226ea8010896600200314c103d87a8000899192cc004cdc8805800c56600266e3c02c006260106602c602800497ae08a60103d87a80004049133004004301800340486eb8c048004c0540050134528201c8a5040393013301037540049112cc004c030c048dd5000c4c8c8c8cc89660026038007132598009809180c1baa00189919192cc004c08000a266018603e006264b300130160018992cc004c08800626464b300130190018992cc004c094006266022604800202116408860406ea800a2b3001301100189919194c004dd69813000cdd69813001cdd698130012444b3001302a00480ac590270c098004c094004c080dd500145901e203c301e3754002604200316407c603a6ea800a2b3001300e0018acc004c074dd500140322c80f22c80d901b180d9baa0018b203a301e001301e0013019375400316405c603600b1640646eb4c064004dd6980c801180c800980c00098099baa0018b20221b874800a2c8068c00cc038dd500099192cc004c020c038dd5000c4c96600266ebcc04cc040dd500080b440062c8070c048c03cdd5000c5900d4c0040066eb0c00cc038dd5003520004004444b30010028a60103d87a80008acc004c0240062600866024602600497ae08cc00400e6028005337000029000a006403880888c03cc040c040004dd2a40008048dd7180618049baa003375a6018601a601a64b3001300e00189bac300d0018b201632330010013756601a601c601c601c601c60146ea8008896600200314bd7044c8cc88cc88cc00800800489660020031003899198099ba733013375200a66026602000266026602200297ae0330030033015002301300140446eacc03800cdd718058009980180198080011807000a0188b200e180400098019baa0088a4d1365640041", + "hash": "0cafde8c3dbac448e070c99beec59ac748faadb0dd75e456172602d7" + }, + { + "title": "githoney_contract.settings_minting.else", + "redeemer": { + "schema": {} + }, + "parameters": [ + { + "title": "utxo_ref", + "schema": { + "$ref": "#/definitions/cardano~1transaction~1OutputReference" + } + }, + { + "title": "settings_script_addr", + "schema": { + "$ref": "#/definitions/cardano~1address~1Address" + } + } + ], + "compiledCode": "5904230101002229800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400130080024888966002600460106ea800e26644b30013370e0029000c528c4cc88c8c96600266e1d2004300e3754003132980091192cc004c03000626464b300130190028024590161bae3017001301337540071598009802000c4c8c96600260320050048b202c375c602e00260266ea800e2c808901118089baa0028acc004c00401a2b300132330010013758602860226ea8024896600200314a115980099baf301530123754602a00203314a313300200230160014040809a2600264b300130023010375400314800226eb4c050c044dd5000a01e3259800980118081baa0018a60103d87a8000899198008009bab30153012375400444b30010018a6103d87a8000899192cc004cdc8a450b73657474696e67734e4654000018acc004cdc7a4410b73657474696e67734e465400001898049980b980a80125eb82298103d87a8000404d1330040043019003404c6eb8c04c004c058005014201e323300100137566028602a60226ea8010896600200314c103d87a8000899192cc004cdc8805800c56600266e3c02c006260106602c602800497ae08a60103d87a80004049133004004301800340486eb8c048004c0540050134528201c8a5040393013301037540049112cc004c030c048dd5000c4c8c8c8cc89660026038007132598009809180c1baa00189919192cc004c08000a266018603e006264b300130160018992cc004c08800626464b300130190018992cc004c094006266022604800202116408860406ea800a2b3001301100189919194c004dd69813000cdd69813001cdd698130012444b3001302a00480ac590270c098004c094004c080dd500145901e203c301e3754002604200316407c603a6ea800a2b3001300e0018acc004c074dd500140322c80f22c80d901b180d9baa0018b203a301e001301e0013019375400316405c603600b1640646eb4c064004dd6980c801180c800980c00098099baa0018b20221b874800a2c8068c00cc038dd500099192cc004c020c038dd5000c4c96600266ebcc04cc040dd500080b440062c8070c048c03cdd5000c5900d4c0040066eb0c00cc038dd5003520004004444b30010028a60103d87a80008acc004c0240062600866024602600497ae08cc00400e6028005337000029000a006403880888c03cc040c040004dd2a40008048dd7180618049baa003375a6018601a601a64b3001300e00189bac300d0018b201632330010013756601a601c601c601c601c60146ea8008896600200314bd7044c8cc88cc88cc00800800489660020031003899198099ba733013375200a66026602000266026602200297ae0330030033015002301300140446eacc03800cdd718058009980180198080011807000a0188b200e180400098019baa0088a4d1365640041", + "hash": "0cafde8c3dbac448e070c99beec59ac748faadb0dd75e456172602d7" + } + ], + "definitions": { + "Bool": { + "title": "Bool", + "anyOf": [ + { + "title": "False", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "True", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "ByteArray": { + "title": "ByteArray", + "dataType": "bytes" + }, + "Data": { + "title": "Data", + "description": "Any Plutus data." + }, + "Int": { + "dataType": "integer" + }, + "Option": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1address~1Address" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Option": { + "title": "Option", + "anyOf": [ + { + "title": "Some", + "description": "An optional value.", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1address~1StakeCredential" + } + ] + }, + { + "title": "None", + "description": "Nothing.", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, + "Pairs": { + "title": "Pairs", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1assets~1AssetName" + }, + "values": { + "$ref": "#/definitions/Int" + } + }, + "Pairs>": { + "title": "Pairs>", + "dataType": "map", + "keys": { + "$ref": "#/definitions/cardano~1assets~1PolicyId" + }, + "values": { + "$ref": "#/definitions/Pairs" + } + }, + "aiken/crypto/DataHash": { + "title": "DataHash", + "dataType": "bytes" + }, + "aiken/crypto/ScriptHash": { + "title": "ScriptHash", + "dataType": "bytes" + }, + "aiken/crypto/VerificationKeyHash": { + "title": "VerificationKeyHash", + "dataType": "bytes" + }, + "cardano/address/Address": { + "title": "Address", + "description": "A Cardano `Address` typically holding one or two credential references.\n\n Note that legacy bootstrap addresses (a.k.a. 'Byron addresses') are\n completely excluded from Plutus contexts. Thus, from an on-chain\n perspective only exists addresses of type 00, 01, ..., 07 as detailed\n in [CIP-0019 :: Shelley Addresses](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0019/#shelley-addresses).", + "anyOf": [ + { + "title": "Address", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "payment_credential", + "$ref": "#/definitions/cardano~1address~1PaymentCredential" + }, + { + "title": "stake_credential", + "$ref": "#/definitions/Option" + } + ] + } + ] + }, + "cardano/address/Credential": { + "title": "Credential", + "description": "A general structure for representing an on-chain `Credential`.\n\n Credentials are always one of two kinds: a direct public/private key\n pair, or a script (native or Plutus).", + "anyOf": [ + { + "title": "VerificationKey", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/address/PaymentCredential": { + "title": "PaymentCredential", + "description": "A general structure for representing an on-chain `Credential`.\n\n Credentials are always one of two kinds: a direct public/private key\n pair, or a script (native or Plutus).", + "anyOf": [ + { + "title": "VerificationKey", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1VerificationKeyHash" + } + ] + }, + { + "title": "Script", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1ScriptHash" + } + ] + } + ] + }, + "cardano/address/StakeCredential": { + "title": "StakeCredential", + "description": "Represent a type of object that can be represented either inline (by hash)\n or via a reference (i.e. a pointer to an on-chain location).\n\n This is mainly use for capturing pointers to a stake credential\n registration certificate in the case of so-called pointer addresses.", + "anyOf": [ + { + "title": "Inline", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "$ref": "#/definitions/cardano~1address~1Credential" + } + ] + }, + { + "title": "Pointer", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "title": "slot_number", + "$ref": "#/definitions/Int" + }, + { + "title": "transaction_index", + "$ref": "#/definitions/Int" + }, + { + "title": "certificate_index", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "cardano/assets/AssetName": { + "title": "AssetName", + "dataType": "bytes" + }, + "cardano/assets/PolicyId": { + "title": "PolicyId", + "dataType": "bytes" + }, + "cardano/transaction/Datum": { + "title": "Datum", + "description": "An output `Datum`.", + "anyOf": [ + { + "title": "NoDatum", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "DatumHash", + "description": "A datum referenced by its hash digest.", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/aiken~1crypto~1DataHash" + } + ] + }, + { + "title": "InlineDatum", + "description": "A datum completely inlined in the output.", + "dataType": "constructor", + "index": 2, + "fields": [ + { + "$ref": "#/definitions/Data" + } + ] + } + ] + }, + "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" + } + ] + } + ] + }, + "cardano/transaction/Redeemer": { + "title": "Redeemer", + "description": "Any Plutus data." + }, + "types/GithoneyContractRedeemers": { + "title": "GithoneyContractRedeemers", + "anyOf": [ + { + "title": "AddRewards", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "Assign", + "dataType": "constructor", + "index": 1, + "fields": [] + }, + { + "title": "Merge", + "dataType": "constructor", + "index": 2, + "fields": [] + }, + { + "title": "Close", + "dataType": "constructor", + "index": 3, + "fields": [] + }, + { + "title": "Claim", + "dataType": "constructor", + "index": 4, + "fields": [] + } + ] + }, + "types/GithoneyDatum": { + "title": "GithoneyDatum", + "anyOf": [ + { + "title": "GithoneyDatum", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "admin_payment_credential", + "$ref": "#/definitions/cardano~1address~1Credential" + }, + { + "title": "maintainer_address", + "$ref": "#/definitions/cardano~1address~1Address" + }, + { + "title": "contributor_address", + "$ref": "#/definitions/Option" + }, + { + "title": "bounty_reward_fee", + "$ref": "#/definitions/Int" + }, + { + "title": "deadline", + "$ref": "#/definitions/Int" + }, + { + "title": "merged", + "$ref": "#/definitions/Bool" + }, + { + "title": "initial_value", + "$ref": "#/definitions/Pairs>" + } + ] + } + ] + }, + "types/SettingsDatum": { + "title": "SettingsDatum", + "anyOf": [ + { + "title": "SettingsDatum", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "githoney_address", + "$ref": "#/definitions/cardano~1address~1Address" + }, + { + "title": "bounty_creation_fee", + "$ref": "#/definitions/Int" + }, + { + "title": "bounty_reward_fee", + "$ref": "#/definitions/Int" + } + ] + } + ] + }, + "types/SettingsRedeemers": { + "title": "SettingsRedeemers", + "anyOf": [ + { + "title": "UpdateSettings", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "CloseSettings", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + } + } +} diff --git a/crates/cip-57/src/lib.rs b/crates/cip-57/src/lib.rs new file mode 100644 index 00000000..d46fc5f8 --- /dev/null +++ b/crates/cip-57/src/lib.rs @@ -0,0 +1,186 @@ +//! This module defines the structures for a Blueprint, including its preamble, validators, and definitions. + +use serde::{Deserialize, Serialize}; +use serde_json::Number; +use std::collections::BTreeMap; +/// Represents a blueprint containing preamble, validators, and optional definitions. +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Blueprint { + pub preamble: Preamble, + pub validators: Vec, + pub definitions: Option, +} + +/// Represents the preamble of a blueprint, including metadata such as title, description, version, and compiler information. +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Preamble { + pub title: String, + pub description: Option, + pub version: String, + pub plutus_version: String, + pub compiler: Option, + pub license: Option, +} + +/// Represents the compiler information in the preamble. +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Compiler { + pub name: String, + pub version: Option, +} + +/// Represents a validator in the blueprint, including its title, description, compiled code, hash, datum, redeemer, and parameters. +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Validator { + pub title: String, + pub description: Option, + pub compiled_code: Option, + pub hash: Option, + pub datum: Option, + pub redeemer: Option, + pub parameters: Option>, +} + +/// Represents an argument in a validator, including its title, description, purpose, and schema reference. +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Argument { + pub title: Option, + pub description: Option, + pub purpose: Option, + pub schema: Reference, +} + +/// Represents a purpose which can be either a single purpose or an object with oneOf. +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum PurposeArray { + Single(Purpose), + OneOf(PurposeOneOf), +} + +/// Represents a purpose object with a oneOf field containing an array of purposes. +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PurposeOneOf { + pub one_of: Vec, +} + +/// Represents the purpose of an argument, which can be spend, mint, withdraw, or publish. +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum Purpose { + Spend, + Mint, + Withdraw, + Publish, +} + +/// Represents a reference to a schema. +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Reference { + #[serde(rename = "$ref")] + pub reference: Option, +} + +/// Represents a parameter in a validator, including its title, description, purpose, and schema reference. +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Parameter { + pub title: Option, + pub description: Option, + pub purpose: Option, + pub schema: Reference, +} + +/// Represents the definitions in a blueprint, which is a map of definition names to their corresponding definitions. +#[derive(Debug, Default, Deserialize, Serialize, Clone)] +pub struct Definitions { + #[serde(flatten, default)] + pub inner: BTreeMap, +} + +/// Represents a definition in the blueprint, including its title, description, data type, any_of schemas, items, keys, and values. +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Definition { + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub data_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub any_of: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub items: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub keys: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub values: Option, +} + +/// Represents an array of references which can be either a single reference or an array of references. +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum ReferencesArray { + Single(Reference), + Array(Vec), +} + +/// Represents a schema in a definition, including its title, description, data type, index, and fields. +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Schema { + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + pub data_type: DataType, + pub index: Number, + pub fields: Vec, +} + +/// Represents the data type of a schema, which can be integer, bytes, list, map, or constructor. +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum DataType { + Integer, + Bytes, + List, + Map, + Constructor, +} + +/// Represents a field in a schema, including its title and reference. +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Field { + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + #[serde(rename = "$ref")] + pub reference: String, +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use std::path::PathBuf; + + #[test] + fn deserialize_plutus_json_into_blueprint() { + let manifest = env!("CARGO_MANIFEST_DIR"); + let path = PathBuf::from(manifest).join("examples").join("plutus.json"); + + let failure_msg = format!("failed to read example file: {}", path.display()); + let json = fs::read_to_string(&path).expect(&failure_msg); + + let bp: Blueprint = serde_json::from_str(&json).expect("failed to deserialize blueprint"); + + assert!( + !bp.preamble.title.is_empty(), + "preamble.title should not be empty" + ); + assert!(!bp.validators.is_empty(), "expected at least one validator"); + } +} diff --git a/crates/tx3-lang/Cargo.toml b/crates/tx3-lang/Cargo.toml index b7389151..ee72f176 100644 --- a/crates/tx3-lang/Cargo.toml +++ b/crates/tx3-lang/Cargo.toml @@ -19,6 +19,8 @@ hex = { workspace = true } serde = { workspace = true } tx3-tir = { version = "0.15.1", path = "../tx3-tir" } +cip-57 = { path = "../cip-57" } +serde_json = "1.0.137" miette = { version = "7.4.0", features = ["fancy"] } pest = { version = "2.7.15", features = ["miette-error", "pretty-print"] } diff --git a/crates/tx3-lang/src/analyzing.rs b/crates/tx3-lang/src/analyzing.rs index 55e50b02..812595b0 100644 --- a/crates/tx3-lang/src/analyzing.rs +++ b/crates/tx3-lang/src/analyzing.rs @@ -645,6 +645,15 @@ impl Analyzable for StructConstructor { _ => unreachable!(), }; + if type_def.cases.len() == 1 { + let only_case_name = type_def.cases[0].name.value.clone(); + let requested_case = self.case.name.value.clone(); + + if requested_case == "Default" || requested_case == self.r#type.value { + self.case.name.value = only_case_name; + } + } + for case in type_def.cases.iter() { scope.track_variant_case(case); } diff --git a/crates/tx3-lang/src/ast.rs b/crates/tx3-lang/src/ast.rs index 54578928..85ad4280 100644 --- a/crates/tx3-lang/src/ast.rs +++ b/crates/tx3-lang/src/ast.rs @@ -173,6 +173,8 @@ impl AsRef for Identifier { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct Program { + #[serde(default)] + pub imports: Vec, pub env: Option, pub txs: Vec, pub types: Vec, @@ -187,6 +189,13 @@ pub struct Program { pub(crate) scope: Option>, } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct ImportDef { + pub path: StringLiteral, + pub alias: Option, + pub span: Span, +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct EnvField { pub name: String, @@ -934,6 +943,28 @@ impl TypeDef { pub(crate) fn find_case(&self, case: &str) -> Option<&VariantCase> { self.cases.iter().find(|x| x.name.value == case) } + + pub fn to_tx3_source(&self) -> String { + let name = &self.name.value; + // Implicit cases don't have an explicit constructor on its usage + if self.cases.len() == 1 && self.cases[0].name.value == "Default" { + let fields = &self.cases[0].fields; + let fields_str = fields + .iter() + .map(|f| format!("{}: {}", f.name.value, f.r#type)) + .collect::>() + .join(", "); + format!("type {} {{ {} }}", name, fields_str) + } else { + let cases_str = self + .cases + .iter() + .map(VariantCase::to_tx3_source) + .collect::>() + .join(", "); + format!("type {} {{ {} }}", name, cases_str) + } + } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -953,6 +984,59 @@ impl VariantCase { pub(crate) fn find_field(&self, field: &str) -> Option<&RecordField> { self.fields.iter().find(|x| x.name.value == field) } + + fn to_tx3_source(&self) -> String { + let name = &self.name.value; + if self.fields.is_empty() { + name.clone() + } else { + let fields_str = self + .fields + .iter() + .map(|f| format!("{}: {}", f.name.value, f.r#type)) + .collect::>() + .join(", "); + format!("{} {{ {} }}", name, fields_str) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn to_tx3_source_omits_braces_for_empty_default_case() { + let type_def = TypeDef { + name: Identifier::new("Data"), + cases: vec![VariantCase { + name: Identifier::new("Default"), + fields: vec![], + span: Span::DUMMY, + }], + span: Span::DUMMY, + }; + + assert_eq!(type_def.to_tx3_source(), "type Data"); + } + + #[test] + fn to_tx3_source_keeps_braces_for_default_with_fields() { + let type_def = TypeDef { + name: Identifier::new("OutputReference"), + cases: vec![VariantCase { + name: Identifier::new("Default"), + fields: vec![RecordField::new("transaction_id", Type::Bytes)], + span: Span::DUMMY, + }], + span: Span::DUMMY, + }; + + assert_eq!( + type_def.to_tx3_source(), + "type OutputReference { transaction_id: Bytes }" + ); + } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] diff --git a/crates/tx3-lang/src/cardano.rs b/crates/tx3-lang/src/cardano.rs index 036ab79f..985db0d9 100644 --- a/crates/tx3-lang/src/cardano.rs +++ b/crates/tx3-lang/src/cardano.rs @@ -845,10 +845,7 @@ impl IntoLower for CardanoBlock { #[cfg(test)] mod tests { use super::*; - use crate::{ - analyzing::analyze, - ast::{self, *}, - }; + use crate::{analyzing::analyze, ast::*}; use pest::Parser; macro_rules! input_to_ast_check { diff --git a/crates/tx3-lang/src/facade.rs b/crates/tx3-lang/src/facade.rs index 39f507d3..13d34eb7 100644 --- a/crates/tx3-lang/src/facade.rs +++ b/crates/tx3-lang/src/facade.rs @@ -1,8 +1,9 @@ use std::collections::{BTreeMap, HashMap}; +use std::path::PathBuf; use tx3_tir::reduce::{Apply, ArgValue}; -use crate::{analyzing, ast, lowering, parsing}; +use crate::{analyzing, ast, importing, lowering, parsing}; #[derive(Debug, thiserror::Error, miette::Diagnostic)] pub enum Error { @@ -16,6 +17,10 @@ pub enum Error { #[diagnostic(transparent)] Parsing(#[from] parsing::Error), + #[error("Import error: {0}")] + #[diagnostic(transparent)] + Importing(#[from] importing::Error), + #[error("Analyzing error")] Analyzing(#[from] analyzing::AnalyzeReport), @@ -27,6 +32,7 @@ pub type Code = String; pub struct Workspace { main: Option, + root: Option, ast: Option, analisis: Option, tir: HashMap, @@ -34,10 +40,13 @@ pub struct Workspace { impl Workspace { pub fn from_file(main: impl AsRef) -> Result { - let main = std::fs::read_to_string(main.as_ref())?; + let path = main.as_ref(); + let main = std::fs::read_to_string(path)?; + let root = path.parent().map(PathBuf::from); Ok(Self { main: Some(main), + root, ast: None, analisis: None, tir: HashMap::new(), @@ -47,6 +56,7 @@ impl Workspace { pub fn from_string(main: Code) -> Self { Self { main: Some(main), + root: None, ast: None, analisis: None, tir: HashMap::new(), @@ -63,7 +73,9 @@ impl Workspace { pub fn parse(&mut self) -> Result<(), Error> { let main = self.ensure_main()?; - let ast = parsing::parse_string(main)?; + let mut ast = parsing::parse_string(main)?; + let loader = self.root.clone().map(importing::FsLoader::new); + importing::resolve_imports(&mut ast, loader.as_ref())?; self.ast = Some(ast); Ok(()) } diff --git a/crates/tx3-lang/src/importing.rs b/crates/tx3-lang/src/importing.rs new file mode 100644 index 00000000..563cc9dc --- /dev/null +++ b/crates/tx3-lang/src/importing.rs @@ -0,0 +1,672 @@ +//! Resolves plutus.json (CIP-57) imports and maps blueprint definitions to tx3 types. + +use std::collections::{HashMap, HashSet}; +use std::path::PathBuf; + +use cip_57::{Blueprint, DataType, Definition, Definitions, Field, ReferencesArray, Schema}; + +use crate::ast::{Identifier, Program, RecordField, Span, Type, TypeDef, VariantCase}; + +#[derive(Debug, thiserror::Error, miette::Diagnostic)] +pub enum Error { + #[error("cannot resolve imports without a root path (use Workspace::from_file instead of from_string)")] + #[diagnostic(code(tx3::importing::missing_root))] + MissingRoot, + + #[error("I/O error reading import file: {0}")] + #[diagnostic(code(tx3::importing::io))] + Io(#[from] std::io::Error), + + #[error("invalid JSON in plutus file: {0}")] + #[diagnostic(code(tx3::importing::json))] + Json(#[from] serde_json::Error), + + #[error("duplicate type name: {name}")] + #[diagnostic(code(tx3::importing::duplicate_type))] + DuplicateType { + name: String, + + #[source_code] + src: Option, + + #[label("type already defined here or from another import")] + span: Span, + }, + + #[error("plutus schema error: {message}")] + #[diagnostic(code(tx3::importing::schema))] + Schema { message: String }, +} + +impl Error { + fn duplicate_type(name: String, span: Span) -> Self { + Error::DuplicateType { + name, + src: None, + span, + } + } +} + +pub trait ImportLoader { + fn load_source(&self, path: &str) -> std::io::Result; +} + +pub struct FsLoader { + root: PathBuf, +} + +impl FsLoader { + pub fn new(root: impl Into) -> Self { + Self { root: root.into() } + } +} + +impl ImportLoader for FsLoader { + fn load_source(&self, path: &str) -> std::io::Result { + let full_path = self.root.join(path); + std::fs::read_to_string(full_path) + } +} + +/// Resolves `#/definitions/cardano~1address~1Address` to definition key `cardano/address/Address`. +/// JSON pointer uses ~1 for / and ~0 for ~. +fn ref_to_key_owned(r: &str) -> String { + let prefix = "#/definitions/"; + let s = r + .strip_prefix(prefix) + .unwrap_or(r) + .replace("~1", "/") + .replace("~0", "~"); + s +} + +/// Normalize definition key to a single identifier: replace `/` and `$` with `_`. +fn key_to_normalized_name(key: &str) -> String { + key.replace('/', "_").replace('$', "_") +} + +fn import_type_name(key: &str, type_name_mapping: &HashMap) -> String { + type_name_mapping + .get(key) + .cloned() + .unwrap_or_else(|| key_to_normalized_name(key)) +} + +fn sanitize_identifier_part(raw: &str) -> String { + raw.chars() + .filter(|c| c.is_ascii_alphanumeric() || *c == '_') + .collect() +} + +fn decode_json_pointer_escapes(name: &str) -> String { + name.replace("~1", "/").replace("~0", "~") +} + +fn extract_last_segment(name: &str) -> String { + let segment = name.rsplit('/').next().unwrap_or(name); + sanitize_identifier_part(segment) +} + +fn path_to_upper_camel(key: &str) -> String { + let mut output = String::new(); + for part in key + .split(|c: char| !c.is_ascii_alphanumeric()) + .filter(|part| !part.is_empty()) + { + let mut chars = part.chars(); + if let Some(first) = chars.next() { + output.push(first.to_ascii_uppercase()); + output.extend(chars); + } + } + + if output.is_empty() { + sanitize_identifier_part(key) + } else { + output + } +} + +fn aiken_prettify_name(name: &str) -> String { + let decoded = decode_json_pointer_escapes(name); + + if let Some(inner) = decoded.strip_prefix("Option$") { + let inner_pretty = aiken_prettify_name(inner); + return format!("Option{}", inner_pretty); + } + + if let Some(inner) = decoded.strip_prefix("Option<") { + let inner = inner.strip_suffix('>').unwrap_or(inner); + let inner_pretty = aiken_prettify_name(inner); + return format!("Option{}", inner_pretty); + } + + if let Some(inner) = decoded.strip_prefix("Pairs$") { + let prettified: Vec = inner + .split('_') + .filter(|x| !x.is_empty()) + .map(aiken_prettify_name) + .collect(); + return format!("Pairs{}", prettified.join("")); + } + + if let Some(inner) = decoded.strip_prefix("Pairs<") { + let inner = inner.strip_suffix('>').unwrap_or(inner); + let prettified: Vec = inner + .split(',') + .map(|p| aiken_prettify_name(p.trim())) + .collect(); + return format!("Pairs{}", prettified.join("")); + } + + extract_last_segment(&decoded) +} + +fn build_aiken_name_mapping(definition_keys: &[&str]) -> HashMap { + let mut simple_to_originals: HashMap> = HashMap::new(); + + for &key in definition_keys { + let simple = aiken_prettify_name(key); + simple_to_originals + .entry(simple) + .or_default() + .push(key.to_string()); + } + + let mut result = HashMap::new(); + let mut used_names: HashSet = HashSet::new(); + + for &key in definition_keys { + let simple = aiken_prettify_name(key); + let originals = simple_to_originals.get(&simple).unwrap(); + + let final_name = if originals.len() == 1 { + simple + } else { + path_to_upper_camel(key) + }; + + let mut unique_name = final_name.clone(); + let mut counter = 1; + while used_names.contains(&unique_name) { + unique_name = format!("{}{}", final_name, counter); + counter += 1; + } + + used_names.insert(unique_name.clone()); + result.insert(key.to_string(), unique_name); + } + + result +} + +fn resolve_ref_to_type( + ref_str: &str, + definitions: &Definitions, + alias: Option<&str>, + type_name_mapping: &HashMap, +) -> Result { + let key = ref_to_key_owned(ref_str); + let def = definitions.inner.get(&key).ok_or_else(|| Error::Schema { + message: format!("definition not found: {}", key), + })?; + + if let Some(dt) = &def.data_type { + match dt { + DataType::Integer => return Ok(Type::Int), + DataType::Bytes => return Ok(Type::Bytes), + DataType::List => { + let inner = match &def.items { + Some(ReferencesArray::Single(r)) => r + .reference + .as_ref() + .map(|s| resolve_ref_to_type(s, definitions, alias, type_name_mapping)), + Some(ReferencesArray::Array(arr)) => arr.first().and_then(|r| { + r.reference + .as_ref() + .map(|s| resolve_ref_to_type(s, definitions, alias, type_name_mapping)) + }), + None => None, + }; + let inner = inner.ok_or_else(|| Error::Schema { + message: "list without items".to_string(), + })?; + return Ok(Type::List(Box::new(inner?))); + } + DataType::Map => { + let k = def + .keys + .as_ref() + .and_then(|r| r.reference.as_ref()) + .ok_or_else(|| Error::Schema { + message: "map without keys".to_string(), + })?; + let v = def + .values + .as_ref() + .and_then(|r| r.reference.as_ref()) + .ok_or_else(|| Error::Schema { + message: "map without values".to_string(), + })?; + let key_ty = resolve_ref_to_type(k, definitions, alias, type_name_mapping)?; + let val_ty = resolve_ref_to_type(v, definitions, alias, type_name_mapping)?; + return Ok(Type::Map(Box::new(key_ty), Box::new(val_ty))); + } + DataType::Constructor => {} + } + } + + Ok(Type::Custom(Identifier::new(import_type_name( + &key, + type_name_mapping, + )))) +} + +fn field_to_record_field( + f: &Field, + index: usize, + definitions: &Definitions, + alias: Option<&str>, + type_name_mapping: &HashMap, +) -> Result { + let name = f + .title + .as_deref() + .map(ToString::to_string) + .unwrap_or_else(|| format!("field_{}", index)); + let r#type = resolve_ref_to_type(&f.reference, definitions, alias, type_name_mapping)?; + Ok(RecordField { + name: Identifier::new(name), + r#type, + span: Span::DUMMY, + }) +} + +fn schema_to_variant_case( + schema: &Schema, + definitions: &Definitions, + alias: Option<&str>, + type_name_mapping: &HashMap, +) -> Result { + let name = schema.title.as_deref().unwrap_or("Variant").to_string(); + let fields: Vec = schema + .fields + .iter() + .enumerate() + .map(|(i, f)| field_to_record_field(f, i, definitions, alias, type_name_mapping)) + .collect::, _>>()?; + Ok(VariantCase { + name: Identifier::new(name), + fields, + span: Span::DUMMY, + }) +} + +fn definition_to_type_def( + key: &str, + def: &Definition, + definitions: &Definitions, + alias: Option<&str>, + type_name_mapping: &HashMap, +) -> Result, Error> { + if let Some(dt) = &def.data_type { + match dt { + DataType::Integer | DataType::Bytes => return Ok(None), + DataType::List | DataType::Map => return Ok(None), + DataType::Constructor => {} + } + } + + let cases = if let Some(any_of) = &def.any_of { + any_of + .iter() + .map(|s| schema_to_variant_case(s, definitions, alias, type_name_mapping)) + .collect::, _>>()? + } else { + // Data type has no structure but should still be imported. + // TODO: There is no Any for our type system, so for now we'll just import it as a single empty variant case. + if key == "Data" { + return Ok(Some(TypeDef { + name: Identifier::new(import_type_name(key, type_name_mapping)), + cases: vec![VariantCase { + name: Identifier::new("Default"), + fields: vec![], + span: Span::DUMMY, + }], + span: Span::DUMMY, + })); + } + return Ok(None); + }; + + if cases.is_empty() { + return Ok(None); + } + + let mut cases = cases; + if cases.len() == 1 { + cases[0].name = Identifier::new("Default"); + } + + let type_name = import_type_name(key, type_name_mapping); + Ok(Some(TypeDef { + name: Identifier::new(type_name), + cases, + span: Span::DUMMY, + })) +} + +pub fn type_defs_from_blueprint( + blueprint: &Blueprint, + alias: Option<&str>, +) -> Result, Error> { + let definitions = match &blueprint.definitions { + Some(d) => d, + None => return Ok(vec![]), + }; + + let definition_keys: Vec<&str> = definitions.inner.keys().map(String::as_str).collect(); + let type_name_mapping = build_aiken_name_mapping(&definition_keys); + + let mut type_defs = Vec::new(); + for (key, def) in &definitions.inner { + if let Some(type_def) = + definition_to_type_def(key, def, definitions, alias, &type_name_mapping)? + { + type_defs.push(type_def); + } + } + Ok(type_defs) +} + +pub fn types_from_plutus( + path: &str, + alias: Option<&str>, + loader: &impl ImportLoader, +) -> Result, Error> { + let json = loader.load_source(path)?; + let blueprint: Blueprint = serde_json::from_str(&json)?; + type_defs_from_blueprint(&blueprint, alias) +} + +pub fn resolve_imports( + program: &mut Program, + loader: Option<&impl ImportLoader>, +) -> Result<(), Error> { + if program.imports.is_empty() { + return Ok(()); + } + let loader = loader.ok_or(Error::MissingRoot)?; + + let existing_names: HashSet = program + .types + .iter() + .map(|t| t.name.value.clone()) + .chain(program.aliases.iter().map(|a| a.name.value.clone())) + .collect(); + let mut added_names = HashSet::::new(); + + for import in &program.imports { + let json = loader.load_source(import.path.value.as_str())?; + let blueprint: Blueprint = serde_json::from_str(&json)?; + let alias = import.alias.as_ref().map(|a| a.value.as_str()); + let type_defs = type_defs_from_blueprint(&blueprint, alias)?; + + for type_def in type_defs { + let name = type_def.name.value.clone(); + if existing_names.contains(&name) || added_names.contains(&name) { + return Err(Error::duplicate_type(name, import.span.clone())); + } + added_names.insert(name.clone()); + program.types.push(type_def); + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ast::{Identifier, ImportDef, Program, Span, StringLiteral}; + + #[derive(Default, Clone)] + pub struct InMemoryLoader { + map: std::collections::HashMap, + } + + impl InMemoryLoader { + pub fn new() -> Self { + Self { + map: std::collections::HashMap::new(), + } + } + + pub fn add(&mut self, path: impl Into, contents: impl Into) -> &mut Self { + self.map.insert(path.into(), contents.into()); + self + } + } + + impl ImportLoader for InMemoryLoader { + fn load_source(&self, path: &str) -> std::io::Result { + self.map.get(path).cloned().ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("import not found: {}", path), + ) + }) + } + } + + #[test] + fn resolve_imports_with_in_memory_loader() { + let mut program = Program { + imports: vec![ImportDef { + path: StringLiteral::new("test.json"), + alias: Some(Identifier::new("types")), + span: Span::DUMMY, + }], + env: None, + txs: vec![], + types: vec![], + aliases: vec![], + assets: vec![], + parties: vec![], + policies: vec![], + span: Span::DUMMY, + scope: None, + }; + + let json = r#"{ + "preamble": { "title": "test", "version": "0", "plutusVersion": "v3" }, + "validators": [], + "definitions": { + "Bool": { + "title": "Bool", + "anyOf": [ + { "title": "False", "dataType": "constructor", "index": 0, "fields": [] }, + { "title": "True", "dataType": "constructor", "index": 1, "fields": [] } + ] + } + } + }"#; + + let mut loader = InMemoryLoader::new(); + loader.add("test.json", json); + resolve_imports(&mut program, Some(&loader)).unwrap(); + + let type_names: Vec = program.types.iter().map(|t| t.name.value.clone()).collect(); + assert!( + type_names.contains(&"Bool".to_string()), + "expected Bool in program.types, got: {:?}", + type_names + ); + } + + #[test] + fn import_with_alias_adds_types() { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let root = std::path::Path::new(manifest_dir); + + let mut program = + crate::parsing::parse_string(r#"import "../cip-57/examples/plutus.json" as types;"#) + .unwrap(); + + let loader = FsLoader::new(root); + resolve_imports(&mut program, Some(&loader)).unwrap(); + + let type_names: Vec = program.types.iter().map(|t| t.name.value.clone()).collect(); + assert!( + type_names.contains(&"SettingsDatum".to_string()), + "expected friendly imported type names (e.g. SettingsDatum), got: {:?}", + type_names + ); + } + + #[test] + fn import_without_root_errors() { + let src = r#" + import "some/file.json"; + party X; + tx dummy() {} + "#; + let mut program = crate::parsing::parse_string(src).unwrap(); + let res = resolve_imports(&mut program, None::<&InMemoryLoader>); + + assert!(res.is_err(), "expected error when importing without root"); + let err = res.unwrap_err(); + let msg = err.to_string(); + assert!( + msg.contains("root") || msg.contains("import"), + "expected error about root or import, got: {}", + msg + ); + } + + #[test] + fn duplicate_type_name_from_imports_errors() { + let json = r#"{ + "preamble": { "title": "test", "version": "0", "plutusVersion": "v3" }, + "validators": [], + "definitions": { + "One": { + "title": "One", + "anyOf": [ { "title": "A", "dataType": "constructor", "index": 0, "fields": [] } ] + } + } + }"#; + + let src = r#" + import "schema1.json" as types; + import "schema2.json" as types; + "#; + + let mut program = crate::parsing::parse_string(src).unwrap(); + let mut loader = InMemoryLoader::new(); + loader.add("schema1.json", json); + loader.add("schema2.json", json); + let res = resolve_imports(&mut program, Some(&loader)); + + assert!( + res.is_err(), + "expected error for duplicate type names from two imports" + ); + let err = res.unwrap_err(); + assert!( + err.to_string().contains("duplicate") || err.to_string().contains("type"), + "expected duplicate/type error, got: {}", + err + ); + } + + #[test] + fn invalid_import_path_errors() { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let root = std::path::Path::new(manifest_dir); + let src = r#" + import "nonexistent/plutus.json" as types; + "#; + let mut program = crate::parsing::parse_string(src).unwrap(); + let loader = FsLoader::new(root); + + let res = resolve_imports(&mut program, Some(&loader)); + assert!(res.is_err(), "expected error for missing import file"); + } + + #[test] + fn single_variant_type_import_with_analyze() { + let dollar = "$"; + let hash = "#"; + let json = format!( + r#"{{ + "preamble": {{ "title": "test", "version": "0", "plutusVersion": "v3" }}, + "validators": [], + "definitions": {{ + "OutputReference": {{ + "title": "OutputReference", + "anyOf": [ + {{ + "title": "OutputReference", + "dataType": "constructor", + "index": 0, + "fields": [ + {{ + "title": "transaction_id", + "{}ref": "{}/definitions/ByteArray" + }}, + {{ + "title": "output_index", + "{}ref": "{}/definitions/Int" + }} + ] + }} + ] + }}, + "ByteArray": {{ + "title": "ByteArray", + "dataType": "bytes" + }}, + "Int": {{ + "title": "Int", + "dataType": "integer" + }} + }} + }}"#, + dollar, hash, dollar, hash + ); + + let src = r#" + import "test.json" as types; + party Alice; + tx test(outref: OutputReference) { + output my_output { + to: Alice, + amount: 1000000, + } + } + "#; + + let mut program = crate::parsing::parse_string(src).unwrap(); + let mut loader = InMemoryLoader::new(); + loader.add("test.json", json); + + resolve_imports(&mut program, Some(&loader)).unwrap(); + + let output_ref_type = program + .types + .iter() + .find(|t| t.name.value == "OutputReference") + .expect("OutputReference should be imported"); + assert_eq!(output_ref_type.cases.len(), 1); + assert_eq!(output_ref_type.cases[0].name.value, "Default"); + + let report = crate::analyzing::analyze(&mut program); + assert!( + report.errors.is_empty(), + "expected no analysis errors, got: {:?}", + report.errors + ); + } +} diff --git a/crates/tx3-lang/src/lib.rs b/crates/tx3-lang/src/lib.rs index 9d044437..ec6686c3 100644 --- a/crates/tx3-lang/src/lib.rs +++ b/crates/tx3-lang/src/lib.rs @@ -26,6 +26,7 @@ pub mod analyzing; pub mod ast; +pub mod importing; pub mod lowering; pub mod parsing; diff --git a/crates/tx3-lang/src/parsing.rs b/crates/tx3-lang/src/parsing.rs index 2b34fc1c..116ede21 100644 --- a/crates/tx3-lang/src/parsing.rs +++ b/crates/tx3-lang/src/parsing.rs @@ -12,10 +12,7 @@ use pest::{ }; use pest_derive::Parser; -use crate::{ - ast::*, - cardano::{PlutusWitnessBlock, PlutusWitnessField}, -}; +use crate::ast::*; #[derive(Parser)] #[grammar = "tx3.pest"] pub(crate) struct Tx3Grammar; @@ -87,6 +84,7 @@ impl AstNode for Program { let inner = pair.into_inner(); let mut program = Self { + imports: Vec::new(), env: None, txs: Vec::new(), assets: Vec::new(), @@ -100,6 +98,7 @@ impl AstNode for Program { for pair in inner { match pair.as_rule() { + Rule::import_def => program.imports.push(ImportDef::parse(pair)?), Rule::env_def => program.env = Some(EnvDef::parse(pair)?), Rule::tx_def => program.txs.push(TxDef::parse(pair)?), Rule::asset_def => program.assets.push(AssetDef::parse(pair)?), @@ -121,6 +120,22 @@ impl AstNode for Program { } } +impl AstNode for ImportDef { + const RULE: Rule = Rule::import_def; + + fn parse(pair: Pair) -> Result { + let span = pair.as_span().into(); + let mut inner = pair.into_inner(); + let path = StringLiteral::parse(inner.next().unwrap())?; + let alias = inner.next().map(Identifier::parse).transpose()?; + Ok(ImportDef { path, alias, span }) + } + + fn span(&self) -> &Span { + &self.span + } +} + impl AstNode for EnvField { const RULE: Rule = Rule::env_field; @@ -2587,6 +2602,7 @@ mod tests { "basic", "party Abc; tx my_tx() {}", Program { + imports: vec![], parties: vec![PartyDef { name: Identifier::new("Abc"), span: Span::DUMMY, @@ -2817,4 +2833,6 @@ mod tests { test_parsing!(list_concat); test_parsing!(buidler_fest_2026); + + test_parsing!(imported_datum); } diff --git a/crates/tx3-lang/src/tx3.pest b/crates/tx3-lang/src/tx3.pest index a01471ff..a1fe6987 100644 --- a/crates/tx3-lang/src/tx3.pest +++ b/crates/tx3-lang/src/tx3.pest @@ -439,6 +439,10 @@ tx_body_block = _{ validity_block } +import_def = { + "import" ~ string ~ ("as" ~ identifier)? ~ ";" +} + env_field = { identifier ~ ":" ~ type } env_def = { @@ -453,6 +457,6 @@ tx_def = { // Program program = { SOI ~ - (env_def | asset_def | party_def | policy_def | type_def | tx_def)* ~ + (import_def | env_def | asset_def | party_def | policy_def | type_def | tx_def)* ~ EOI } diff --git a/examples/asteria.ast b/examples/asteria.ast index 4b556cb1..6e284ff7 100644 --- a/examples/asteria.ast +++ b/examples/asteria.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/buidler_fest_2026.ast b/examples/buidler_fest_2026.ast index c0c0f570..96b13316 100644 --- a/examples/buidler_fest_2026.ast +++ b/examples/buidler_fest_2026.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": { "fields": [ { diff --git a/examples/burn.ast b/examples/burn.ast index 6eafd087..1ed27f63 100644 --- a/examples/burn.ast +++ b/examples/burn.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/cardano_witness.ast b/examples/cardano_witness.ast index 9136d18d..4fe2ba60 100644 --- a/examples/cardano_witness.ast +++ b/examples/cardano_witness.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/cardano_witness.mint_from_plutus.tir b/examples/cardano_witness.mint_from_plutus.tir index c0f4530f..8ff6e2e2 100644 --- a/examples/cardano_witness.mint_from_plutus.tir +++ b/examples/cardano_witness.mint_from_plutus.tir @@ -202,9 +202,6 @@ { "name": "plutus_witness", "data": { - "version": { - "Number": 3 - }, "script": { "Bytes": [ 81, @@ -226,6 +223,9 @@ 174, 105 ] + }, + "version": { + "Number": 3 } } } diff --git a/examples/disordered.ast b/examples/disordered.ast index de9c48f3..0983c7f2 100644 --- a/examples/disordered.ast +++ b/examples/disordered.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/donation.ast b/examples/donation.ast index f82e5c24..0660f4f4 100644 --- a/examples/donation.ast +++ b/examples/donation.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/env_vars.ast b/examples/env_vars.ast index cef2b474..373b6ebc 100644 --- a/examples/env_vars.ast +++ b/examples/env_vars.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": { "fields": [ { diff --git a/examples/faucet.ast b/examples/faucet.ast index e961c1d4..f82b8247 100644 --- a/examples/faucet.ast +++ b/examples/faucet.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/imported_datum.ast b/examples/imported_datum.ast new file mode 100644 index 00000000..5b2abd96 --- /dev/null +++ b/examples/imported_datum.ast @@ -0,0 +1,414 @@ +{ + "imports": [ + { + "path": { + "value": "../crates/cip-57/examples/plutus.json", + "span": { + "dummy": false, + "start": 7, + "end": 46 + } + }, + "alias": { + "value": "plutus", + "span": { + "dummy": false, + "start": 50, + "end": 56 + } + }, + "span": { + "dummy": false, + "start": 0, + "end": 57 + } + } + ], + "env": null, + "txs": [ + { + "name": { + "value": "create_settings", + "span": { + "dummy": false, + "start": 76, + "end": 91 + } + }, + "parameters": { + "parameters": [ + { + "name": { + "value": "now", + "span": { + "dummy": false, + "start": 97, + "end": 100 + } + }, + "type": "Int" + } + ], + "span": { + "dummy": false, + "start": 91, + "end": 108 + } + }, + "locals": null, + "references": [], + "inputs": [ + { + "name": "fee_source", + "many": false, + "fields": [ + { + "From": { + "Identifier": { + "value": "Admin", + "span": { + "dummy": false, + "start": 148, + "end": 153 + } + } + } + }, + { + "MinAmount": { + "Number": 1000000 + } + } + ], + "span": { + "dummy": false, + "start": 115, + "end": 189 + } + } + ], + "outputs": [ + { + "name": { + "value": "settings", + "span": { + "dummy": false, + "start": 202, + "end": 210 + } + }, + "optional": false, + "fields": [ + { + "To": { + "Identifier": { + "value": "Admin", + "span": { + "dummy": false, + "start": 225, + "end": 230 + } + } + } + }, + { + "Datum": { + "StructConstructor": { + "type": { + "value": "plutus_types_SettingsDatum", + "span": { + "dummy": false, + "start": 247, + "end": 273 + } + }, + "case": { + "name": { + "value": "Default", + "span": { + "dummy": true, + "start": 0, + "end": 0 + } + }, + "fields": [ + { + "name": { + "value": "githoney_address", + "span": { + "dummy": false, + "start": 288, + "end": 304 + } + }, + "value": { + "StructConstructor": { + "type": { + "value": "plutus_cardano_address_Address", + "span": { + "dummy": false, + "start": 306, + "end": 336 + } + }, + "case": { + "name": { + "value": "Default", + "span": { + "dummy": true, + "start": 0, + "end": 0 + } + }, + "fields": [ + { + "name": { + "value": "payment_credential", + "span": { + "dummy": false, + "start": 355, + "end": 373 + } + }, + "value": { + "StructConstructor": { + "type": { + "value": "plutus_cardano_address_PaymentCredential", + "span": { + "dummy": false, + "start": 375, + "end": 415 + } + }, + "case": { + "name": { + "value": "VerificationKey", + "span": { + "dummy": false, + "start": 417, + "end": 432 + } + }, + "fields": [ + { + "name": { + "value": "field", + "span": { + "dummy": false, + "start": 455, + "end": 460 + } + }, + "value": { + "HexString": { + "value": "12345678901234567890123456789012345678901234567890123456", + "span": { + "dummy": false, + "start": 462, + "end": 520 + } + } + }, + "span": { + "dummy": false, + "start": 455, + "end": 520 + } + } + ], + "spread": null, + "span": { + "dummy": false, + "start": 415, + "end": 539 + } + }, + "span": { + "dummy": false, + "start": 375, + "end": 539 + } + } + }, + "span": { + "dummy": false, + "start": 355, + "end": 539 + } + }, + { + "name": { + "value": "stake_credential", + "span": { + "dummy": false, + "start": 557, + "end": 573 + } + }, + "value": { + "StructConstructor": { + "type": { + "value": "plutus_Option_cardano_address_StakeCredential", + "span": { + "dummy": false, + "start": 575, + "end": 620 + } + }, + "case": { + "name": { + "value": "None", + "span": { + "dummy": false, + "start": 622, + "end": 626 + } + }, + "fields": [], + "spread": null, + "span": { + "dummy": false, + "start": 620, + "end": 629 + } + }, + "span": { + "dummy": false, + "start": 575, + "end": 629 + } + } + }, + "span": { + "dummy": false, + "start": 557, + "end": 629 + } + } + ], + "spread": null, + "span": { + "dummy": false, + "start": 337, + "end": 644 + } + }, + "span": { + "dummy": false, + "start": 306, + "end": 644 + } + } + }, + "span": { + "dummy": false, + "start": 288, + "end": 644 + } + }, + { + "name": { + "value": "bounty_creation_fee", + "span": { + "dummy": false, + "start": 658, + "end": 677 + } + }, + "value": { + "Number": 500 + }, + "span": { + "dummy": false, + "start": 658, + "end": 682 + } + }, + { + "name": { + "value": "bounty_reward_fee", + "span": { + "dummy": false, + "start": 696, + "end": 713 + } + }, + "value": { + "Number": 100 + }, + "span": { + "dummy": false, + "start": 696, + "end": 718 + } + } + ], + "spread": null, + "span": { + "dummy": false, + "start": 274, + "end": 729 + } + }, + "span": { + "dummy": false, + "start": 247, + "end": 729 + } + } + } + }, + { + "Amount": { + "Number": 2000000 + } + } + ], + "span": { + "dummy": false, + "start": 195, + "end": 761 + } + } + ], + "validity": null, + "mints": [], + "burns": [], + "signers": null, + "adhoc": [], + "span": { + "dummy": false, + "start": 73, + "end": 763 + }, + "collateral": [], + "metadata": null + } + ], + "types": [], + "aliases": [], + "assets": [], + "parties": [ + { + "name": { + "value": "Admin", + "span": { + "dummy": false, + "start": 65, + "end": 70 + } + }, + "span": { + "dummy": false, + "start": 59, + "end": 71 + } + } + ], + "policies": [], + "span": { + "dummy": false, + "start": 0, + "end": 764 + } +} \ No newline at end of file diff --git a/examples/imported_datum.tx3 b/examples/imported_datum.tx3 new file mode 100644 index 00000000..a4550328 --- /dev/null +++ b/examples/imported_datum.tx3 @@ -0,0 +1,27 @@ +import "../crates/cip-57/examples/plutus.json" as plutus; + +party Admin; + +tx create_settings( + now: Int, +) { + input fee_source { + from: Admin, + min_amount: 1000000, + } + + output settings { + to: Admin, + datum: SettingsDatum::SettingsDatum { + githoney_address: Address::Address{ + payment_credential: PaymentCredential::VerificationKey { + field: 0x12345678901234567890123456789012345678901234567890123456, + }, + stake_credential: OptionStakeCredential::None {}, + }, + bounty_creation_fee: 500, + bounty_reward_fee: 100, + }, + amount: 2000000, + } +} diff --git a/examples/input_datum.ast b/examples/input_datum.ast index c0cb2672..55b334ae 100644 --- a/examples/input_datum.ast +++ b/examples/input_datum.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/lang_tour.ast b/examples/lang_tour.ast index cfe0e4cd..2a3b452b 100644 --- a/examples/lang_tour.ast +++ b/examples/lang_tour.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": { "fields": [ { diff --git a/examples/lang_tour.my_tx.tir b/examples/lang_tour.my_tx.tir index 525dcb75..f60eca2f 100644 --- a/examples/lang_tour.my_tx.tir +++ b/examples/lang_tour.my_tx.tir @@ -645,14 +645,6 @@ { "name": "vote_delegation_certificate", "data": { - "stake": { - "Bytes": [ - 135, - 101, - 67, - 33 - ] - }, "drep": { "Bytes": [ 18, @@ -660,6 +652,14 @@ 86, 120 ] + }, + "stake": { + "Bytes": [ + 135, + 101, + 67, + 33 + ] } } }, @@ -688,6 +688,9 @@ { "name": "plutus_witness", "data": { + "version": { + "Number": 2 + }, "script": { "Bytes": [ 171, @@ -696,9 +699,6 @@ 18, 52 ] - }, - "version": { - "Number": 2 } } }, diff --git a/examples/list_concat.ast b/examples/list_concat.ast index f8b6c17f..2708bb0d 100644 --- a/examples/list_concat.ast +++ b/examples/list_concat.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/local_vars.ast b/examples/local_vars.ast index 432bb4ff..8f52defe 100644 --- a/examples/local_vars.ast +++ b/examples/local_vars.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/map.ast b/examples/map.ast index 148694e0..224baad4 100644 --- a/examples/map.ast +++ b/examples/map.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/reference_script.ast b/examples/reference_script.ast index ccb5f6db..3764b1ab 100644 --- a/examples/reference_script.ast +++ b/examples/reference_script.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/reference_script.publish_native.tir b/examples/reference_script.publish_native.tir index 90fdd3b9..644738e7 100644 --- a/examples/reference_script.publish_native.tir +++ b/examples/reference_script.publish_native.tir @@ -147,6 +147,17 @@ 0 ] }, + "to": { + "EvalParam": { + "ExpectValue": [ + "receiver", + "Address" + ] + } + }, + "version": { + "Number": 0 + }, "amount": { "Assets": [ { @@ -162,17 +173,6 @@ } } ] - }, - "to": { - "EvalParam": { - "ExpectValue": [ - "receiver", - "Address" - ] - } - }, - "version": { - "Number": 0 } } } diff --git a/examples/reference_script.publish_plutus.tir b/examples/reference_script.publish_plutus.tir index 7506c0f5..7a17ad71 100644 --- a/examples/reference_script.publish_plutus.tir +++ b/examples/reference_script.publish_plutus.tir @@ -137,25 +137,6 @@ { "name": "cardano_publish", "data": { - "version": { - "Number": 3 - }, - "amount": { - "Assets": [ - { - "policy": "None", - "asset_name": "None", - "amount": { - "EvalParam": { - "ExpectValue": [ - "quantity", - "Int" - ] - } - } - } - ] - }, "script": { "Bytes": [ 81, @@ -178,6 +159,22 @@ 105 ] }, + "amount": { + "Assets": [ + { + "policy": "None", + "asset_name": "None", + "amount": { + "EvalParam": { + "ExpectValue": [ + "quantity", + "Int" + ] + } + } + } + ] + }, "to": { "EvalParam": { "ExpectValue": [ @@ -185,6 +182,9 @@ "Address" ] } + }, + "version": { + "Number": 3 } } } diff --git a/examples/swap.ast b/examples/swap.ast index 8d915d0f..db090bc7 100644 --- a/examples/swap.ast +++ b/examples/swap.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/transfer.ast b/examples/transfer.ast index a21a5413..0fce4dc3 100644 --- a/examples/transfer.ast +++ b/examples/transfer.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/vesting.ast b/examples/vesting.ast index dac2dfa9..1ae0698a 100644 --- a/examples/vesting.ast +++ b/examples/vesting.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/withdrawal.ast b/examples/withdrawal.ast index 0f0e7382..ce7cc4d1 100644 --- a/examples/withdrawal.ast +++ b/examples/withdrawal.ast @@ -1,4 +1,5 @@ { + "imports": [], "env": null, "txs": [ { diff --git a/examples/withdrawal.transfer.tir b/examples/withdrawal.transfer.tir index facdbb3c..48a914f8 100644 --- a/examples/withdrawal.transfer.tir +++ b/examples/withdrawal.transfer.tir @@ -165,6 +165,12 @@ { "name": "withdrawal", "data": { + "redeemer": { + "Struct": { + "constructor": 0, + "fields": [] + } + }, "credential": { "EvalParam": { "ExpectValue": [ @@ -175,12 +181,6 @@ }, "amount": { "Number": 0 - }, - "redeemer": { - "Struct": { - "constructor": 0, - "fields": [] - } } } }