diff --git a/Cargo.lock b/Cargo.lock index 188f60b..740adeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" version = "1.1.4" @@ -206,30 +191,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - -[[package]] -name = "backtrace-ext" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] - [[package]] name = "base58" version = "0.2.0" @@ -256,9 +217,9 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bech32" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "binary-layout" @@ -626,7 +587,7 @@ version = "0.12.0" dependencies = [ "anyhow", "backoff", - "bech32 0.9.1", + "bech32 0.11.1", "bip39", "chrono", "clap", @@ -657,11 +618,9 @@ dependencies = [ "tracing", "tracing-subscriber", "tui-tree-widget", - "tx3-cardano", - "tx3-lang", "tx3-sdk", "url", - "utxorpc 0.12.0", + "utxorpc", ] [[package]] @@ -1016,12 +975,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "gloo-net" version = "0.6.0" @@ -1485,12 +1438,6 @@ dependencies = [ "serde", ] -[[package]] -name = "is_ci" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1757,36 +1704,6 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "backtrace", - "backtrace-ext", - "cfg-if", - "miette-derive", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "unicode-width 0.1.14", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "mime" version = "0.3.17" @@ -1814,15 +1731,6 @@ dependencies = [ "syn", ] -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" version = "0.8.11" @@ -1926,15 +1834,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1953,12 +1852,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" -[[package]] -name = "owo-colors" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" - [[package]] name = "pallas" version = "1.0.0-alpha.3" @@ -2134,7 +2027,7 @@ dependencies = [ "pallas-traverse", "pallas-validate", "prost-types", - "utxorpc-spec 0.17.0", + "utxorpc-spec", ] [[package]] @@ -2228,52 +2121,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pest" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" -dependencies = [ - "memchr", - "miette", - "serde", - "serde_json", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" -dependencies = [ - "pest", - "sha2", -] - [[package]] name = "petgraph" version = "0.7.1" @@ -2621,9 +2468,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.24" +version = "0.12.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" dependencies = [ "base64 0.22.1", "bytes", @@ -2671,12 +2518,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -2823,6 +2664,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "0.9.0" @@ -2847,6 +2700,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2912,6 +2777,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_json" version = "1.0.145" @@ -2988,17 +2864,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -3169,27 +3034,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "supports-color" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" -dependencies = [ - "is_ci", -] - -[[package]] -name = "supports-hyperlinks" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" - -[[package]] -name = "supports-unicode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" - [[package]] name = "syn" version = "2.0.110" @@ -3240,26 +3084,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "terminal_size" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" -dependencies = [ - "rustix 1.1.2", - "windows-sys 0.60.2", -] - -[[package]] -name = "textwrap" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" -dependencies = [ - "unicode-linebreak", - "unicode-width 0.2.0", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -3539,9 +3363,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags 2.10.0", "bytes", @@ -3624,17 +3448,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -3652,51 +3465,33 @@ dependencies = [ ] [[package]] -name = "tx3-cardano" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e969e1c4846480e975fdaa0c2f6e19163ba74a0498fc67165deefaab20689f67" +name = "tx3-sdk" +version = "0.8.0" dependencies = [ + "base64 0.22.1", + "bech32 0.11.1", "hex", - "pallas", + "reqwest", + "schemars 0.8.22", "serde", + "serde_json", "thiserror 2.0.17", - "trait-variant", - "tx3-lang", - "utxorpc 0.10.0", + "tx3-tir", + "uuid", ] [[package]] -name = "tx3-lang" +name = "tx3-tir" version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db16c6bacd60f39a287b9276a6273074cae58a70d108834f94ce3b0b5bd87b4" -dependencies = [ - "ciborium", - "hex", - "miette", - "pest", - "pest_derive", - "serde", - "thiserror 2.0.17", - "trait-variant", -] - -[[package]] -name = "tx3-sdk" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e249299616f099372b45ff1605900671697547bd6691ca154f0aa36dc665cbc" +source = "git+https://github.com/tx3-lang/tx3.git#ac15a21145ff1385d4a6a1626b32cd5177ce1189" dependencies = [ "base64 0.22.1", - "bech32 0.11.0", + "bech32 0.11.1", + "ciborium", "hex", - "reqwest", "serde", "serde_json", "thiserror 2.0.17", - "tx3-lang", - "uuid", ] [[package]] @@ -3705,24 +3500,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - [[package]] name = "unicode-normalization" version = "0.1.25" @@ -3791,19 +3574,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "utxorpc" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea8f520897c0d0b8048413a2ad72044cc5cbc00c98219a750f048be616f3d7f" -dependencies = [ - "bytes", - "thiserror 1.0.69", - "tokio", - "tonic", - "utxorpc-spec 0.15.0", -] - [[package]] name = "utxorpc" version = "0.12.0" @@ -3814,23 +3584,7 @@ dependencies = [ "thiserror 2.0.17", "tokio", "tonic", - "utxorpc-spec 0.17.0", -] - -[[package]] -name = "utxorpc-spec" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c73cb3e15766a14cbc99fbd6dbbee04496fc9c64b47b088ae1d7698d43e357" -dependencies = [ - "bytes", - "futures-core", - "pbjson", - "pbjson-types", - "prost", - "prost-types", - "serde", - "tonic", + "utxorpc-spec", ] [[package]] @@ -3851,9 +3605,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "getrandom 0.3.4", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 0355796..fdc7f87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,23 +14,15 @@ keywords = ["cardano", "blockchain", "wallet"] categories = ["command-line-utilities", "blockchain", "cardano", "wallet"] [dependencies] -tx3-lang = "0.13.0" -tx3-cardano = "0.13.0" -tx3-sdk = "^0" - -# tx3-lang = { git = "https://github.com/tx3-lang/tx3.git" } -# tx3-cardano = { git = "https://github.com/tx3-lang/tx3.git" } +# tx3-sdk = "^0" # tx3-sdk = { git = "https://github.com/tx3-lang/rust-sdk.git" } - -# tx3-lang = { path = "../../tx3-lang/tx3/crates/tx3-lang" } -# tx3-cardano = { path = "../../tx3-lang/tx3/crates/tx3-cardano" } -# tx3-sdk = { path = "../../tx3-lang/rust-sdk/sdk" } +tx3-sdk = { path = "../../tx3-lang/rust-sdk/sdk" } # utxorpc = { git = "https://github.com/utxorpc/rust-sdk" } utxorpc = "0.12.0" # utxorpc = { path = "../../utxorpc/rust-sdk" } -bech32 = "0.9.1" +bech32 = "0.11.1" bip39 = { version = "2.0.0", features = ["rand_core"] } chrono = { version = "0.4.39", features = ["serde"] } clap = { version = "4.5.29", features = ["derive", "env"] } diff --git a/src/tx/common.rs b/src/tx/common.rs index 8582ce5..e9e7f90 100644 --- a/src/tx/common.rs +++ b/src/tx/common.rs @@ -6,15 +6,20 @@ use std::{ collections::{BTreeMap, HashMap}, path::Path, }; -use tx3_lang::{ArgValue, ProtoTx, Protocol, UtxoRef}; -use tx3_sdk::trp::{self, TxEnvelope}; + +use tx3_sdk::{ + tii::Invocation, + trp::{self, TxEnvelope}, + WellKnownType, +}; +use tx3_sdk::{ArgValue, UtxoRef}; use crate::provider::types::Provider; pub fn load_args( inline_args: Option<&str>, file_args: Option<&Path>, - params: &BTreeMap, + params: &BTreeMap, ) -> Result> { let json_string = match (inline_args, file_args) { (Some(inline_args), None) => inline_args.to_string(), @@ -33,7 +38,7 @@ pub fn load_args( for (key, ty) in params { if let Some(value) = value.remove(key) { - let arg_value = tx3_sdk::trp::args::from_json(value, ty)?; + let arg_value = tx3_sdk::interop::json::from_json(value, ty)?; args.insert(key.clone(), arg_value); } } @@ -41,30 +46,32 @@ pub fn load_args( Ok(args) } -pub fn load_prototx(tx3_file: &Path, tx3_template: Option) -> Result { - let protocol = Protocol::from_file(tx3_file) - .load() - .context("parsing tx3 file")?; +pub fn prepare_invocation(tii_file: &Path, tx: Option) -> Result { + let protocol = tx3_sdk::tii::Protocol::from_file(tii_file).context("parsing tii file")?; - let txs: Vec = protocol.txs().map(|x| x.name.value.to_string()).collect(); - - let template = match tx3_template { + let template = match tx { Some(template) => template, None => { - let template = if txs.len() == 1 { - txs.first().unwrap().clone() + let template = if protocol.txs().len() == 1 { + protocol.txs().keys().next().unwrap().clone() } else { - inquire::Select::new("What transaction do you want to build?", txs).prompt()? + let keys = protocol + .txs() + .keys() + .map(|x| x.to_string()) + .collect::>(); + + inquire::Select::new("What transaction do you want to build?", keys).prompt()? }; template } }; - Ok(protocol.new_tx(&template)?) + Ok(protocol.invoke(&template, None)?) } pub fn inquire_args( - params: &BTreeMap, + params: &BTreeMap, ctx: &crate::Context, provider: &Provider, ) -> Result> { @@ -74,7 +81,7 @@ pub fn inquire_args( let text_key = format!("{key}:"); match value { - tx3_lang::ir::Type::Address => { + WellKnownType::Address => { let custom_address = String::from("custom address"); let mut options = ctx .store @@ -104,7 +111,7 @@ pub fn inquire_args( argvalues.insert(key.clone(), trp::ArgValue::Address(address.to_vec())); } - tx3_lang::ir::Type::Int => { + WellKnownType::Int => { let value = inquire::Text::new(&text_key) .with_help_message("Enter an integer value") .prompt()? @@ -113,7 +120,7 @@ pub fn inquire_args( argvalues.insert(key.clone(), trp::ArgValue::Int(value.into())); } - tx3_lang::ir::Type::UtxoRef => { + WellKnownType::UtxoRef => { let value = inquire::Text::new(&text_key) .with_help_message("Enter the utxo reference as hash#idx") .prompt() @@ -130,12 +137,12 @@ pub fn inquire_args( let utxo_ref = UtxoRef::new(hash.as_slice(), idx); argvalues.insert(key.clone(), trp::ArgValue::UtxoRef(utxo_ref)); } - tx3_lang::ir::Type::Bool => { + WellKnownType::Bool => { let value = inquire::Confirm::new(&text_key).prompt()?; argvalues.insert(key.clone(), trp::ArgValue::Bool(value)); } - tx3_lang::ir::Type::Bytes => { + WellKnownType::Bytes => { let value = inquire::Text::new(&text_key) .with_help_message("Enter the bytes as hex string") .prompt()?; @@ -145,37 +152,37 @@ pub fn inquire_args( argvalues.insert(key.clone(), trp::ArgValue::Bytes(value)); } - tx3_lang::ir::Type::Undefined => { + WellKnownType::Undefined => { return Err(anyhow::anyhow!( "tx3 arg {key} is of type Undefined, not supported yet" )); } - tx3_lang::ir::Type::Unit => { + WellKnownType::Unit => { return Err(anyhow::anyhow!( "tx3 arg {key} is of type Unit, not supported yet", )); } - tx3_lang::ir::Type::Utxo => { + WellKnownType::Utxo => { return Err(anyhow::anyhow!( "tx3 arg {key} is of type Utxo, not supported yet" )); } - tx3_lang::ir::Type::AnyAsset => { + WellKnownType::AnyAsset => { return Err(anyhow::anyhow!( "tx3 arg {key} is of type AnyAsset, not supported yet" )); } - tx3_lang::ir::Type::List => { + WellKnownType::List => { return Err(anyhow::anyhow!( "tx3 arg {key} is of type List, not supported yet", )); } - tx3_lang::ir::Type::Custom(x) => { + WellKnownType::Custom(x) => { return Err(anyhow::anyhow!( "tx3 arg {key} is a custom type {x}, not supported yet" )); } - tx3_lang::ir::Type::Map => { + WellKnownType::Map => { return Err(anyhow::anyhow!( "tx3 arg {key} is of type Map, not supported yet", )); @@ -187,12 +194,14 @@ pub fn inquire_args( } pub fn define_args( - params: &BTreeMap, + invocation: &mut Invocation, inline_args: Option<&str>, file_args: Option<&Path>, ctx: &crate::Context, provider: &Provider, ) -> Result> { + let params = invocation.define_params()?; + let mut remaining_params = params.clone(); let mut loaded_args = super::common::load_args(inline_args, file_args, &remaining_params)?; @@ -211,19 +220,8 @@ pub fn define_args( Ok(loaded_args) } -pub async fn resolve_tx( - prototx: &ProtoTx, - args: HashMap, - provider: &Provider, -) -> Result { - let request = tx3_sdk::trp::ProtoTxRequest { - tir: tx3_sdk::trp::TirInfo { - version: tx3_lang::ir::IR_VERSION.to_string(), - encoding: "hex".to_string(), - bytecode: hex::encode(prototx.ir_bytes()), - }, - args, - }; +pub async fn resolve_tx(invocation: Invocation, provider: &Provider) -> Result { + let request = invocation.into_trp_request()?; provider.trp_resolve(request).await } diff --git a/src/tx/construct/add_input.rs b/src/tx/construct/add_input.rs deleted file mode 100644 index fbb3f07..0000000 --- a/src/tx/construct/add_input.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::{fs, path::PathBuf}; - -use anyhow::{Result, Context}; -use clap::Parser; -use tracing::instrument; - -#[derive(Parser, Clone)] -pub struct Args { - /// Path for tx3 file to create the transaction - #[arg(long)] - tx3_file: PathBuf, -} - -#[instrument("add-input", skip_all)] -pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> { - let ast_path_buf = args.tx3_file.with_extension("ast"); - - let mut tx_builder = super::common::TransactionBuilder::from_ast(&ast_path_buf)?; - - tx_builder.collect_inputs(true)?; - - // Serialize and write AST - let ast_json = serde_json::to_string_pretty(&tx_builder.ast) - .context("Failed to serialize tx3 AST")?; - - fs::write(&ast_path_buf, ast_json) - .with_context(|| format!("Failed to write tx3 AST file: {}", ast_path_buf.display()))?; - - println!("\nāœ… Input added successfully!"); - println!("šŸ“„ File saved to: {}", ast_path_buf.display()); - - Ok(()) -} \ No newline at end of file diff --git a/src/tx/construct/add_output.rs b/src/tx/construct/add_output.rs deleted file mode 100644 index 93cda06..0000000 --- a/src/tx/construct/add_output.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::{fs, path::PathBuf}; - -use anyhow::{Result, Context}; -use clap::Parser; -use tracing::instrument; - -#[derive(Parser, Clone)] -pub struct Args { - /// Path for tx3 file to create the transaction - #[arg(long)] - tx3_file: PathBuf, -} - -#[instrument("add-output", skip_all)] -pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> { - let ast_path_buf = args.tx3_file.with_extension("ast"); - - let mut tx_builder = super::common::TransactionBuilder::from_ast(&ast_path_buf)?; - - tx_builder.collect_outputs(true)?; - - // Serialize and write AST - let ast_json = serde_json::to_string_pretty(&tx_builder.ast) - .context("Failed to serialize tx3 AST")?; - - fs::write(&ast_path_buf, ast_json) - .with_context(|| format!("Failed to write tx3 AST file: {}", ast_path_buf.display()))?; - - println!("\nāœ… Output added successfully!"); - println!("šŸ“„ File saved to: {}", ast_path_buf.display()); - - Ok(()) -} \ No newline at end of file diff --git a/src/tx/construct/build.rs b/src/tx/construct/build.rs deleted file mode 100644 index 6f6f36b..0000000 --- a/src/tx/construct/build.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::{fs, path::PathBuf}; - -use anyhow::{Result, Context}; -use clap::Parser; -use tracing::instrument; - -#[derive(Parser, Clone)] -pub struct Args { - /// Path for tx3 file to create the transaction - #[arg(long)] - tx3_file: PathBuf, -} - -#[instrument("build", skip_all)] -pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> { - let ast_path_buf = args.tx3_file.with_extension("ast"); - - let tx_builder = super::common::TransactionBuilder::from_ast(&ast_path_buf)?; - - // Generate the tx3 content - let tx3_content = tx_builder.generate_tx3_content(); - - // Write to file - fs::write(&args.tx3_file, tx3_content) - .context("Failed to write tx3 file")?; - - println!("\nāœ… Transaction created successfully!"); - println!("šŸ“„ File saved to: {}", args.tx3_file.display()); - - Ok(()) -} \ No newline at end of file diff --git a/src/tx/construct/common.rs b/src/tx/construct/common.rs deleted file mode 100644 index b99a375..0000000 --- a/src/tx/construct/common.rs +++ /dev/null @@ -1,314 +0,0 @@ -use std::{fs, path::PathBuf, str::FromStr}; - -use anyhow::{Context, Result}; -use inquire::{Confirm, Text}; -use pallas::ledger::addresses::Address; -use serde_json::json; - -pub struct TransactionBuilder { - pub ast: tx3_lang::ast::Program, - pub def_index: usize, -} - -impl TransactionBuilder { - pub fn new(name: String, mut ast: tx3_lang::ast::Program) -> Result { - let mut def_index = ast.txs.iter().position(|tx| tx.name.value == name); - - if def_index.is_none() { - println!("Creating new transaction: {}", name); - // Create it as JSON and parse it as TxDef - // TODO: Make scope pub in tx3_lang and construct directly or implement `Default` - let value = json!({ - "name": tx3_lang::ast::Identifier::new(name), - "parameters": tx3_lang::ast::ParameterList { - parameters: Vec::new(), - span: tx3_lang::ast::Span::default(), - }, - "references": [], - "inputs": [], - "outputs": [], - "mints": [], - "burns": [], - "adhoc": [], - "span": tx3_lang::ast::Span::default(), - "collateral": [], - }); - let tx_def: tx3_lang::ast::TxDef = serde_json::from_value(value) - .context("Failed to materialize TxDef from JSON template")?; - - ast.txs.push(tx_def); - - def_index = Some(ast.txs.len() - 1); - } - - Ok(Self { - ast: ast.clone(), - def_index: def_index.unwrap(), - }) - } - - pub fn from_ast(ast_path_buf: &PathBuf) -> Result { - let ast = if ast_path_buf.exists() { - let ast_content = - fs::read_to_string(ast_path_buf).context("Failed to read existing AST file")?; - - serde_json::from_str(&ast_content).context("Failed to parse existing AST file")? - } else { - tx3_lang::ast::Program::default() - }; - - TransactionBuilder::new("new_transaction".to_string(), ast) - } - - pub fn collect_inputs(&mut self, skip_question: bool) -> Result<()> { - println!("\nšŸ“„ Transaction Inputs"); - println!("===================="); - - if !skip_question { - let add_inputs = Confirm::new("Do you want to add inputs to your transaction?") - .with_default(true) - .prompt()?; - - if !add_inputs { - return Ok(()); - } - } - - loop { - let input_name = Text::new("Input name:") - .with_help_message("Enter input name (or 'done' to finish)") - .prompt()?; - - if input_name.eq_ignore_ascii_case("done") { - break; - } - - let mut input_block = tx3_lang::ast::InputBlock { - name: input_name.clone(), - span: tx3_lang::ast::Span::default(), - many: false, - fields: Vec::new(), - }; - - let utxo_ref = Text::new("Utxo Ref:") - .with_help_message("Enter the Utxo for this input (txid#index)") - .prompt()?; - - let parts: Vec<&str> = utxo_ref.split('#').collect(); - if parts.len() != 2 { - println!("Invalid Utxo Ref format. Expected format: txid#index"); - continue; - } - - // input_block.fields.push(tx3_lang::ast::InputBlockField::From( - // tx3_lang::ast::DataExpr::String(tx3_lang::ast::StringLiteral::new(address.to_bech32().unwrap())), - // )); - - let txid = hex::decode(parts[0]).context("Invalid txid hex in UTxO reference")?; - - let index = parts[1].parse::().context("Invalid UTxO index")?; - - input_block.fields.push(tx3_lang::ast::InputBlockField::Ref( - tx3_lang::ast::DataExpr::UtxoRef(tx3_lang::ast::UtxoRef { - txid, - index, - span: tx3_lang::ast::Span::default(), - }), - )); - - let min_amount = Text::new("Minimum amount value:") - .with_default("1000000") - .prompt()?; - - let min_amount_value = min_amount - .parse::() - .context("Invalid minimum amount value")?; - - input_block - .fields - .push(tx3_lang::ast::InputBlockField::MinAmount( - tx3_lang::ast::DataExpr::StaticAssetConstructor( - tx3_lang::ast::StaticAssetConstructor { - amount: Box::new(tx3_lang::ast::DataExpr::Number(min_amount_value)), - span: tx3_lang::ast::Span::default(), - r#type: tx3_lang::ast::Identifier::new("Ada".to_string()), - }, - ), - )); - - self.ast.txs[self.def_index].inputs.push(input_block); - - let add_more = Confirm::new("Add another input?") - .with_default(false) - .prompt()?; - - if !add_more { - break; - } - } - - Ok(()) - } - - pub fn collect_outputs(&mut self, skip_question: bool) -> Result<()> { - println!("\nšŸ“¤ Transaction Outputs"); - println!("====================="); - - if !skip_question { - let add_outputs = Confirm::new("Do you want to add outputs to your transaction?") - .with_default(true) - .prompt()?; - - if !add_outputs { - return Ok(()); - } - } - - loop { - let has_name = Confirm::new("Does this output have a name?") - .with_default(true) - .prompt()?; - - let output_name = if has_name { - Some( - Text::new("Output name:") - .with_help_message("Enter output name") - .prompt()?, - ) - } else { - None - }; - - let mut output_block = tx3_lang::ast::OutputBlock { - name: output_name - .as_ref() - .map(|name| tx3_lang::ast::Identifier::new(name.clone())), - span: tx3_lang::ast::Span::default(), - fields: Vec::new(), - optional: false, - }; - - let to_address = Text::new("To address:") - .with_help_message("Enter the address this output goes to") - .prompt()?; - - // Validate address - let address = Address::from_str(&to_address).context("Invalid address")?; - - let bech32 = address - .to_bech32() - .context("Failed to encode bech32 address")?; - - output_block - .fields - .push(tx3_lang::ast::OutputBlockField::To(Box::new( - tx3_lang::ast::DataExpr::String(tx3_lang::ast::StringLiteral::new(bech32)), - ))); - - let amount = Text::new("Amount:").with_default("1000000").prompt()?; - - let amount_value = amount.parse::().context("Invalid Ada amount")?; - - output_block - .fields - .push(tx3_lang::ast::OutputBlockField::Amount(Box::new( - tx3_lang::ast::DataExpr::StaticAssetConstructor( - tx3_lang::ast::StaticAssetConstructor { - amount: Box::new(tx3_lang::ast::DataExpr::Number(amount_value)), - span: tx3_lang::ast::Span::default(), - r#type: tx3_lang::ast::Identifier::new("Ada".to_string()), - }, - ), - ))); - - self.ast.txs[self.def_index].outputs.push(output_block); - - let add_more = Confirm::new("Add another output?") - .with_default(true) - .prompt()?; - - if !add_more { - break; - } - } - - Ok(()) - } - - pub fn generate_tx3_content(self) -> String { - let mut content = String::new(); - - // Add transaction - content.push_str(&format!( - "tx {}() {{\n", - self.ast.txs[self.def_index].name.value - )); - - // Add inputs - for input in &self.ast.txs[self.def_index].inputs { - content.push_str(&format!("\tinput {} {{\n", input.name)); - input.fields.iter().for_each(|field| match field { - tx3_lang::ast::InputBlockField::From(tx3_lang::ast::DataExpr::String(literal)) => { - content.push_str(&format!("\t\tfrom: \"{}\",\n", literal.value)); - } - tx3_lang::ast::InputBlockField::Ref(tx3_lang::ast::DataExpr::UtxoRef(utxoref)) => { - content.push_str(&format!( - "\t\tref: 0x{}#{},\n", - hex::encode(&utxoref.txid), - utxoref.index - )); - } - tx3_lang::ast::InputBlockField::MinAmount( - tx3_lang::ast::DataExpr::StaticAssetConstructor(constructor), - ) => { - let amount = match *constructor.amount { - tx3_lang::ast::DataExpr::Number(num) => num.to_string(), - _ => "unknown".to_string(), - }; - content.push_str(&format!( - "\t\tmin_amount: {}({}),\n", - constructor.r#type.value, amount - )); - } - _ => {} - }); - content.push_str("\t}\n\n"); - } - - // Add outputs - for output in &self.ast.txs[self.def_index].outputs { - if let Some(name) = &output.name { - content.push_str(&format!("\toutput {} {{\n", name.value)); - } else { - content.push_str("\toutput {\n"); - } - - output.fields.iter().for_each(|field| match field { - tx3_lang::ast::OutputBlockField::To(expr) => { - if let tx3_lang::ast::DataExpr::String(literal) = expr.as_ref() { - content.push_str(&format!("\t\tto: \"{}\",\n", literal.value)); - } - } - tx3_lang::ast::OutputBlockField::Amount(expr) => { - if let tx3_lang::ast::DataExpr::StaticAssetConstructor(constructor) = - expr.as_ref() - { - let amount = match *constructor.amount { - tx3_lang::ast::DataExpr::Number(num) => num.to_string(), - _ => "unknown".to_string(), - }; - content.push_str(&format!( - "\t\tamount: {}({}),\n", - constructor.r#type.value, amount - )); - } - } - _ => {} - }); - content.push_str("\t}\n\n"); - } - - content.push_str("}\n"); - content - } -} diff --git a/src/tx/construct/mod.rs b/src/tx/construct/mod.rs deleted file mode 100644 index 9c356de..0000000 --- a/src/tx/construct/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -use clap::{Parser, Subcommand}; -use tracing::instrument; - -mod wizard; -mod common; -mod add_input; -mod add_output; -mod build; - -#[derive(Parser)] -pub struct Args { - #[command(subcommand)] - command: Commands, -} - -#[derive(Subcommand)] -enum Commands { - /// Generate a tx3 transaction using a wizard - Wizard(wizard::Args), - - /// Add input to transaction - #[command(name = "add-input")] - AddInput(add_input::Args), - - /// Add output to transaction - #[command(name = "add-output")] - AddOutput(add_output::Args), - - /// Build the transaction - Build(build::Args), -} - -#[instrument("construct", skip_all)] -pub async fn run(args: Args, ctx: &crate::Context) -> anyhow::Result<()> { - match args.command { - Commands::Wizard(args) => wizard::run(args, ctx).await, - Commands::AddInput(args) => add_input::run(args, ctx).await, - Commands::AddOutput(args) => add_output::run(args, ctx).await, - Commands::Build(args) => build::run(args, ctx).await, - } -} diff --git a/src/tx/construct/wizard.rs b/src/tx/construct/wizard.rs deleted file mode 100644 index 5ea5423..0000000 --- a/src/tx/construct/wizard.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::{fs, path::PathBuf}; - -use anyhow::{Result, Context}; -use clap::Parser; -use tracing::instrument; -use inquire::Confirm; - -#[derive(Parser, Clone)] -pub struct Args { - /// Path for tx3 file to create the transaction - #[arg(long)] - tx3_file: PathBuf, -} - -#[instrument("wizard", skip_all)] -pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> { - let ast_path_buf = args.tx3_file.with_extension("ast"); - - if args.tx3_file.exists() { - println!("āš ļø Warning: The specified tx3 file already exists and will be overwritten."); - let proceed = Confirm::new("Do you want to continue?") - .with_default(false) - .prompt()?; - - if !proceed { - println!("Operation cancelled by user."); - return Ok(()); - } - } - - let mut tx_builder = super::common::TransactionBuilder::from_ast(&ast_path_buf)?; - - tx_builder.collect_inputs(false)?; - - tx_builder.collect_outputs(false)?; - - let ast = tx_builder.ast.clone(); - - // Generate the tx3 content - let tx3_content = tx_builder.generate_tx3_content(); - - // Write to file - fs::write(&args.tx3_file, tx3_content) - .context("Failed to write tx3 file")?; - - // Serialize and write AST - let ast_json = serde_json::to_string_pretty(&ast) - .context("Failed to serialize tx3 AST")?; - - fs::write(&ast_path_buf, ast_json) - .with_context(|| format!("Failed to write tx3 AST file: {}", ast_path_buf.display()))?; - - println!("\nāœ… Transaction created successfully!"); - println!("šŸ“„ File saved to: {}", args.tx3_file.display()); - - Ok(()) -} diff --git a/src/tx/invoke.rs b/src/tx/invoke.rs index a9b9c49..f029a4f 100644 --- a/src/tx/invoke.rs +++ b/src/tx/invoke.rs @@ -9,21 +9,21 @@ use crate::output::OutputFormat; #[derive(Parser, Clone)] pub struct Args { - /// Path for Tx3 file describing transaction + /// Path for TII file describing transaction invoke interface #[arg(long)] - tx3_file: PathBuf, + tii_file: PathBuf, - /// Json string containing args for the Tx3 transaction + /// Json string containing the invoke args for the transaction #[arg(long)] - tx3_args_json: Option, + args_json: Option, - /// Path for file containing args for the Tx3 transaction + /// Path for file containing the invoke args for the transaction #[arg(long)] - tx3_args_file: Option, + args_file: Option, - /// Template for Tx3 file + /// Which transaction to invoke #[arg(long)] - tx3_template: Option, + tx_template: Option, /// Wallets that will sign the transaction #[arg(long)] @@ -53,17 +53,19 @@ pub async fn run(args: Args, ctx: &crate::Context) -> Result<()> { bail!("Provider not found") }; - let prototx = super::common::load_prototx(&args.tx3_file, args.tx3_template)?; + let mut invocation = super::common::prepare_invocation(&args.tii_file, args.tx_template)?; - let tx_args = super::common::define_args( - &prototx.find_params(), - args.tx3_args_json.as_deref(), - args.tx3_args_file.as_deref(), + let all_args = super::common::define_args( + &mut invocation, + args.args_json.as_deref(), + args.args_file.as_deref(), ctx, provider, )?; - let TxEnvelope { tx, hash } = super::common::resolve_tx(&prototx, tx_args, provider).await?; + invocation.set_args(all_args); + + let TxEnvelope { tx, hash } = super::common::resolve_tx(invocation, provider).await?; let cbor = hex::decode(tx).unwrap(); diff --git a/src/tx/mod.rs b/src/tx/mod.rs index da9bd82..bef0ea8 100644 --- a/src/tx/mod.rs +++ b/src/tx/mod.rs @@ -7,7 +7,6 @@ mod invoke; mod resolve; mod sign; mod submit; -mod construct; #[derive(Parser)] pub struct Args { @@ -28,9 +27,6 @@ enum Commands { /// Submit a CBOR transaction Submit(submit::Args), - - /// Construct a new transaction using tx3 - Construct(construct::Args), } #[instrument("transaction", skip_all)] @@ -40,6 +36,5 @@ pub async fn run(args: Args, ctx: &crate::Context) -> anyhow::Result<()> { Commands::Resolve(args) => resolve::run(args, ctx).await, Commands::Sign(args) => sign::run(args, ctx).await, Commands::Submit(args) => submit::run(args, ctx).await, - Commands::Construct(args) => construct::run(args, ctx).await, } } diff --git a/src/tx/resolve.rs b/src/tx/resolve.rs index 1c5242a..3e4bd55 100644 --- a/src/tx/resolve.rs +++ b/src/tx/resolve.rs @@ -10,21 +10,21 @@ use crate::output::OutputFormat; #[derive(Parser, Clone)] pub struct Args { - /// Path for Tx3 file describing transaction + /// Path for TII file describing transaction invoke interface #[arg(long)] - tx3_file: PathBuf, + tii_file: PathBuf, - /// Json string containing args for the Tx3 transaction + /// Json string containing the invoke args for the transaction #[arg(long)] - tx3_args_json: Option, + args_json: Option, - /// Path for file containing args for the Tx3 transaction + /// Path for file containing the invoke args for the transaction #[arg(long)] - tx3_args_file: Option, + args_file: Option, - /// Template for Tx3 file + /// Which transaction to invoke #[arg(long)] - tx3_template: Option, + tx_template: Option, /// Name of the provider to use. If undefined, will use default #[arg(long)] @@ -42,17 +42,19 @@ pub async fn run(args: Args, ctx: &crate::Context) -> Result<()> { bail!("Provider not found") }; - let prototx = super::common::load_prototx(&args.tx3_file, args.tx3_template)?; + let mut invocation = super::common::prepare_invocation(&args.tii_file, args.tx_template)?; - let tx_args = super::common::define_args( - &prototx.find_params(), - args.tx3_args_json.as_deref(), - args.tx3_args_file.as_deref(), + let all_args = super::common::define_args( + &mut invocation, + args.args_json.as_deref(), + args.args_file.as_deref(), ctx, provider, )?; - let TxEnvelope { tx, hash } = super::common::resolve_tx(&prototx, tx_args, provider).await?; + invocation.set_args(all_args); + + let TxEnvelope { tx, hash } = super::common::resolve_tx(invocation, provider).await?; let cbor = hex::decode(tx).unwrap(); diff --git a/src/wallet/types.rs b/src/wallet/types.rs index fbbb6ab..f18c36f 100644 --- a/src/wallet/types.rs +++ b/src/wallet/types.rs @@ -1,5 +1,5 @@ use anyhow::{bail, Context, Result}; -use bech32::{FromBase32, ToBase32}; +use bech32::Bech32; use bip39::{Language, Mnemonic}; use chrono::{DateTime, Local}; use comfy_table::Table; @@ -380,7 +380,7 @@ impl TryFrom<&[u8]> for PrivateKey { #[derive(Debug, PartialEq, Eq)] pub struct Bip32PrivateKey(ed25519_bip32::XPrv); impl Bip32PrivateKey { - const BECH32_HRP: &'static str = "xprv"; + const BECH32_HRP: bech32::Hrp = bech32::Hrp::parse_unchecked("xprv"); pub fn generate(mut rng: Rng) -> Self where @@ -459,20 +459,14 @@ impl Bip32PrivateKey { } pub fn to_bech32(&self) -> String { - bech32::encode( - Self::BECH32_HRP, - self.as_bytes().to_base32(), - bech32::Variant::Bech32, - ) - .unwrap() + bech32::encode::(Self::BECH32_HRP, &self.as_bytes()).unwrap() } pub fn from_bech32(bech32: String) -> Result { - let (hrp, data, _) = bech32::decode(&bech32).context("Invalid bech32")?; + let (hrp, data) = bech32::decode(&bech32).context("Invalid bech32")?; if hrp != Self::BECH32_HRP { bail!("Invalid bech32") } else { - let data = Vec::::from_base32(&data).context("Invalid bech32")?; match data.try_into() { Ok(bytes) => Self::from_bytes(bytes), Err(_) => bail!("Unexpected Bech32 length"), @@ -486,7 +480,7 @@ impl Bip32PrivateKey { pub struct Bip32PublicKey(ed25519_bip32::XPub); impl Bip32PublicKey { - const BECH32_HRP: &'static str = "xpub"; + const BECH32_HRP: bech32::Hrp = bech32::Hrp::parse_unchecked("xpub"); pub fn from_bytes(bytes: [u8; 64]) -> Self { Self(XPub::from_bytes(bytes)) @@ -512,20 +506,14 @@ impl Bip32PublicKey { } pub fn to_bech32(&self) -> String { - bech32::encode( - Self::BECH32_HRP, - self.as_bytes().to_base32(), - bech32::Variant::Bech32, - ) - .unwrap() + bech32::encode::(Self::BECH32_HRP, &self.as_bytes()).unwrap() } pub fn from_bech32(bech32: String) -> Result { - let (hrp, data, _) = bech32::decode(&bech32).context("Invalid Bech32")?; + let (hrp, data) = bech32::decode(&bech32).context("Invalid Bech32")?; if hrp != Self::BECH32_HRP { Err(anyhow::anyhow!("Invalid Bech32")) } else { - let data = Vec::::from_base32(&data).context("Invalid Bech32")?; match data.try_into() { Ok(bytes) => Ok(Self::from_bytes(bytes)), Err(_) => bail!("Unexpected Bech32 length"),