diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ea5cf5..2ea721be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Overhauled output format. All commands besides `quill sns` should have human-readable output instead of candid IDL. Candid IDL format can be forced with `--raw`. + ## [0.4.4] - 2024-03-21 - Fixed `quill sns make-proposal` setting some fields to null. diff --git a/Cargo.lock b/Cargo.lock index 68516824..af8fc9f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.12", + "getrandom", "once_cell", "version_check", ] @@ -234,7 +234,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ - "getrandom 0.2.12", + "getrandom", "instant", "rand", ] @@ -311,6 +311,19 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +[[package]] +name = "bigdecimal" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9324c8014cd04590682b34f1e9448d38f0674d0f7b2dc553331016ef0e4e9ebc" +dependencies = [ + "autocfg", + "libm", + "num-bigint 0.4.4", + "num-integer", + "num-traits", +] + [[package]] name = "bincode" version = "1.3.3" @@ -354,7 +367,7 @@ dependencies = [ "k256 0.11.6", "once_cell", "pbkdf2", - "rand_core 0.6.4", + "rand_core", "ripemd", "sha2 0.10.8", "subtle", @@ -428,7 +441,7 @@ dependencies = [ "ff 0.12.1", "group 0.12.1", "pairing", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -582,11 +595,12 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cached" -version = "0.41.0" +version = "0.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec6d20b3d24b6c74e2c5331d2d3d8d1976a9883c7da179aa851afa4c90d62e36" +checksum = "c7c8c50262271cdf5abc979a5f76515c234e764fa025d1ba4862c0f0bcda0e95" dependencies = [ - "hashbrown 0.12.3", + "ahash 0.8.7", + "hashbrown 0.14.3", "instant", "once_cell", "thiserror", @@ -594,11 +608,10 @@ dependencies = [ [[package]] name = "cached" -version = "0.46.1" +version = "0.49.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c8c50262271cdf5abc979a5f76515c234e764fa025d1ba4862c0f0bcda0e95" +checksum = "f251fd1e72720ca07bf5d8e310f54a193fd053479a1f6342c6663ee4fa01cf96" dependencies = [ - "ahash 0.8.7", "hashbrown 0.14.3", "instant", "once_cell", @@ -616,9 +629,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088c2e3d22a0fb1ada78b968946b0f7b96027ac8669973fe7c0815a98e8d13ef" +checksum = "965e86b1bd1c0c26df70cf0c92ae16c56204ab402eb915c26a541cf949d841cf" dependencies = [ "anyhow", "binread", @@ -719,8 +732,10 @@ checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-targets 0.52.0", ] @@ -917,7 +932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -929,7 +944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -967,17 +982,32 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "curve25519-dalek-ng" version = "4.1.1" @@ -986,7 +1016,7 @@ checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core 0.6.4", + "rand_core", "subtle-ng", "zeroize", ] @@ -994,7 +1024,7 @@ dependencies = [ [[package]] name = "cycles-minting-canister" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "base64 0.13.1", @@ -1009,8 +1039,8 @@ dependencies = [ "ic-certified-map", "ic-crypto-getrandom-for-wasm", "ic-crypto-tree-hash", - "ic-ic00-types", "ic-ledger-core", + "ic-management-canister-types", "ic-metrics-encoder", "ic-nervous-system-common-build-metadata", "ic-nervous-system-governance", @@ -1156,7 +1186,7 @@ dependencies = [ [[package]] name = "dfn_candid" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "dfn_core", @@ -1168,7 +1198,7 @@ dependencies = [ [[package]] name = "dfn_core" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-base-types", "on_wire", @@ -1177,7 +1207,7 @@ dependencies = [ [[package]] name = "dfn_http" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "dfn_candid", @@ -1189,7 +1219,7 @@ dependencies = [ [[package]] name = "dfn_http_metrics" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "dfn_candid", "dfn_core", @@ -1201,7 +1231,7 @@ dependencies = [ [[package]] name = "dfn_protobuf" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "on_wire", "prost", @@ -1316,6 +1346,16 @@ dependencies = [ "spki 0.7.3", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.0.0", +] + [[package]] name = "ed25519-consensus" version = "2.1.0" @@ -1324,13 +1364,30 @@ checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" dependencies = [ "curve25519-dalek-ng", "hex", - "rand_core 0.6.4", + "rand_core", "serde", "sha2 0.9.9", "thiserror", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "merlin", + "rand_core", + "serde", + "sha2 0.10.8", + "signature 2.0.0", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.9.0" @@ -1352,7 +1409,7 @@ dependencies = [ "group 0.12.1", "pem-rfc7468 0.6.0", "pkcs8 0.9.0", - "rand_core 0.6.4", + "rand_core", "sec1 0.3.0", "subtle", "zeroize", @@ -1372,7 +1429,7 @@ dependencies = [ "group 0.13.0", "pem-rfc7468 0.7.0", "pkcs8 0.10.2", - "rand_core 0.6.4", + "rand_core", "sec1 0.7.3", "subtle", "zeroize", @@ -1436,7 +1493,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fe-derive" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "hex", "num-bigint-dig", @@ -1452,7 +1509,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1462,10 +1519,16 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1618,17 +1681,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.12" @@ -1637,7 +1689,7 @@ checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -1659,7 +1711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff 0.12.1", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1670,7 +1722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1685,7 +1737,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.11", "indexmap 2.1.0", "slab", "tokio", @@ -1805,6 +1857,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1812,10 +1875,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.11", "pin-project-lite", ] +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + [[package]] name = "httparse" version = "1.8.0" @@ -1848,8 +1921,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.11", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1868,7 +1941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", + "http 0.2.11", "hyper", "rustls", "tokio", @@ -1900,8 +1973,8 @@ dependencies = [ [[package]] name = "ic-agent" -version = "0.32.0" -source = "git+https://github.com/dfinity/agent-rs?rev=73da09c1c553193c46d7edef73c8c20beaa8498c#73da09c1c553193c46d7edef73c8c20beaa8498c" +version = "0.34.0" +source = "git+https://github.com/dfinity/agent-rs?rev=8c39e26236e3e3db6db51ffa71e34140c19d207e#8c39e26236e3e3db6db51ffa71e34140c19d207e" dependencies = [ "backoff", "cached 0.46.1", @@ -1909,19 +1982,20 @@ dependencies = [ "ed25519-consensus", "futures-util", "hex", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.0", "ic-certification", "ic-transport-types", "ic-verify-bls-signature", "k256 0.13.3", "leb128", + "p256", "pem 2.0.1", "pkcs8 0.10.2", "rand", "rangemap", "reqwest", - "ring 0.16.20", + "ring", "rustls-webpki", "sec1 0.7.3", "serde", @@ -1939,7 +2013,7 @@ dependencies = [ [[package]] name = "ic-base-types" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "byte-unit", "bytes", @@ -1947,7 +2021,6 @@ dependencies = [ "comparable", "ic-crypto-sha2", "ic-protobuf", - "ic-stable-structures", "phantom_newtype", "prost", "serde", @@ -1955,8 +2028,8 @@ dependencies = [ [[package]] name = "ic-btc-interface" -version = "0.1.0" -source = "git+https://github.com/dfinity/bitcoin-canister?rev=9b239d1d67253eb14a35be6061e3967d5ec9db9d#9b239d1d67253eb14a35be6061e3967d5ec9db9d" +version = "0.2.0" +source = "git+https://github.com/dfinity/bitcoin-canister?rev=62a71e47c491fb842ccc257b1c675651501f4b82#62a71e47c491fb842ccc257b1c675651501f4b82" dependencies = [ "candid", "serde", @@ -1966,7 +2039,7 @@ dependencies = [ [[package]] name = "ic-btc-types-internal" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ic-btc-interface", @@ -1979,13 +2052,11 @@ dependencies = [ [[package]] name = "ic-canister-client-sender" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ - "ed25519-consensus", "ic-base-types", "ic-crypto-ecdsa-secp256k1", - "ic-crypto-internal-types", - "ic-crypto-utils-basic-sig", + "ic-crypto-ed25519", "ic-types", "rand", "rand_chacha", @@ -1994,7 +2065,7 @@ dependencies = [ [[package]] name = "ic-canister-log" version = "0.2.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "serde", ] @@ -2002,7 +2073,7 @@ dependencies = [ [[package]] name = "ic-canister-profiler" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-metrics-encoder", "ic0 0.18.11", @@ -2011,7 +2082,7 @@ dependencies = [ [[package]] name = "ic-canisters-http-types" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "serde", @@ -2020,9 +2091,9 @@ dependencies = [ [[package]] name = "ic-cdk" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3d204af0b11c45715169c997858edb58fa8407d08f4fae78a6b415dd39a362" +checksum = "c63a6fceb94127bda86bd6d05f859a0e2a67d128a8ffb5ddab17e1f15ac8f555" dependencies = [ "candid", "ic-cdk-macros", @@ -2033,9 +2104,9 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a618e4020cea88e933d8d2f8c7f86d570ec06213506a80d4f2c520a9bba512" +checksum = "2fde5ca6ef1e69825c68916ff1bf7256b8f7ed69ac5ea3f1756f6e57f1503e27" dependencies = [ "candid", "proc-macro2", @@ -2047,9 +2118,9 @@ dependencies = [ [[package]] name = "ic-cdk-timers" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c43b9706fef3ad10c4192a14801d16bd9539068239f0f06f257857441364329" +checksum = "054727a3a1c486528b96349817d54290ff70df6addf417def456ea708a16f7fb" dependencies = [ "futures", "ic-cdk", @@ -2085,7 +2156,7 @@ dependencies = [ [[package]] name = "ic-ckbtc-kyt" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "askama", "candid", @@ -2105,7 +2176,7 @@ dependencies = [ [[package]] name = "ic-ckbtc-minter" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "bech32", @@ -2123,9 +2194,9 @@ dependencies = [ "ic-crypto-extended-bip32", "ic-crypto-getrandom-for-wasm", "ic-crypto-sha2", - "ic-ic00-types", "ic-icrc1", "ic-ledger-core", + "ic-management-canister-types", "ic-metrics-encoder", "ic-stable-structures", "ic-utils-ensure", @@ -2146,12 +2217,12 @@ dependencies = [ [[package]] name = "ic-constants" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" [[package]] name = "ic-crypto-ecdsa-secp256k1" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "k256 0.13.3", "lazy_static", @@ -2162,10 +2233,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ic-crypto-ed25519" +version = "0.9.0" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" +dependencies = [ + "curve25519-dalek", + "ed25519-dalek", + "pem 1.1.1", + "rand", + "zeroize", +] + [[package]] name = "ic-crypto-extended-bip32" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-crypto-internal-threshold-sig-ecdsa", ] @@ -2173,26 +2256,25 @@ dependencies = [ [[package]] name = "ic-crypto-getrandom-for-wasm" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ - "getrandom 0.2.12", + "getrandom", ] [[package]] name = "ic-crypto-internal-basic-sig-der-utils" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "hex", "ic-types", "simple_asn1", - "zeroize", ] [[package]] name = "ic-crypto-internal-basic-sig-ed25519" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "base64 0.13.1", "curve25519-dalek", @@ -2214,7 +2296,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-bls12-381-type" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "hex", "ic_bls12_381", @@ -2232,7 +2314,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-hmac" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-crypto-internal-sha2", ] @@ -2240,7 +2322,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-multi-sig-bls12381" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "base64 0.13.1", "hex", @@ -2259,7 +2341,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-seed" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "hex", "ic-crypto-sha2", @@ -2272,7 +2354,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-sha2" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "sha2 0.10.8", ] @@ -2280,14 +2362,13 @@ dependencies = [ [[package]] name = "ic-crypto-internal-threshold-sig-bls12381" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "base64 0.13.1", - "cached 0.41.0", + "cached 0.49.2", "hex", "ic-crypto-internal-bls12-381-type", "ic-crypto-internal-seed", - "ic-crypto-internal-threshold-sig-bls12381-der", "ic-crypto-internal-types", "ic-crypto-secrets-containers", "ic-crypto-sha2", @@ -2304,18 +2385,10 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ic-crypto-internal-threshold-sig-bls12381-der" -version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" -dependencies = [ - "simple_asn1", -] - [[package]] name = "ic-crypto-internal-threshold-sig-ecdsa" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "fe-derive", "hex", @@ -2343,7 +2416,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-types" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "arrayvec 0.7.4", "hex", @@ -2360,7 +2433,7 @@ dependencies = [ [[package]] name = "ic-crypto-node-key-validation" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "hex", "ic-base-types", @@ -2378,7 +2451,7 @@ dependencies = [ [[package]] name = "ic-crypto-secrets-containers" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "serde", "zeroize", @@ -2387,7 +2460,7 @@ dependencies = [ [[package]] name = "ic-crypto-sha2" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-crypto-internal-sha2", ] @@ -2395,7 +2468,7 @@ dependencies = [ [[package]] name = "ic-crypto-test-utils-reproducible-rng" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "rand", "rand_chacha", @@ -2404,7 +2477,7 @@ dependencies = [ [[package]] name = "ic-crypto-tls-cert-validation" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "hex", "ic-crypto-internal-basic-sig-ed25519", @@ -2418,7 +2491,7 @@ dependencies = [ [[package]] name = "ic-crypto-tree-hash" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "assert_matches", "ic-crypto-internal-types", @@ -2432,22 +2505,17 @@ dependencies = [ [[package]] name = "ic-crypto-utils-basic-sig" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ - "base64 0.13.1", - "ed25519-consensus", "ic-base-types", - "ic-crypto-internal-basic-sig-der-utils", - "ic-crypto-internal-basic-sig-ed25519", - "ic-crypto-internal-types", + "ic-crypto-ed25519", "ic-protobuf", - "simple_asn1", ] [[package]] name = "ic-crypto-utils-ni-dkg" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-crypto-internal-types", "ic-protobuf", @@ -2457,7 +2525,7 @@ dependencies = [ [[package]] name = "ic-error-types" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-utils", "serde", @@ -2465,29 +2533,10 @@ dependencies = [ "strum_macros", ] -[[package]] -name = "ic-ic00-types" -version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" -dependencies = [ - "candid", - "ic-base-types", - "ic-btc-interface", - "ic-btc-types-internal", - "ic-error-types", - "ic-protobuf", - "num-traits", - "serde", - "serde_bytes", - "serde_cbor", - "strum", - "strum_macros", -] - [[package]] name = "ic-icrc1" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ciborium", @@ -2507,34 +2556,36 @@ dependencies = [ ] [[package]] -name = "ic-icrc1-index" +name = "ic-icrc1-index-ng" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ - "async-trait", "candid", "ciborium", "ic-base-types", + "ic-canister-log", "ic-canister-profiler", "ic-canisters-http-types", "ic-cdk", "ic-cdk-macros", "ic-cdk-timers", + "ic-crypto-sha2", "ic-icrc1", - "ic-icrc1-ledger", "ic-icrc1-tokens-u64", - "ic-ledger-hash-of", + "ic-ledger-core", "ic-metrics-encoder", + "ic-stable-structures", "icrc-ledger-types", "num-traits", "scopeguard", "serde", + "serde_json", ] [[package]] name = "ic-icrc1-ledger" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", @@ -2562,7 +2613,7 @@ dependencies = [ [[package]] name = "ic-icrc1-tokens-u64" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ic-ledger-core", @@ -2573,8 +2624,8 @@ dependencies = [ [[package]] name = "ic-identity-hsm" -version = "0.32.0" -source = "git+https://github.com/dfinity/agent-rs?rev=73da09c1c553193c46d7edef73c8c20beaa8498c#73da09c1c553193c46d7edef73c8c20beaa8498c" +version = "0.34.0" +source = "git+https://github.com/dfinity/agent-rs?rev=8c39e26236e3e3db6db51ffa71e34140c19d207e#8c39e26236e3e3db6db51ffa71e34140c19d207e" dependencies = [ "hex", "ic-agent", @@ -2587,16 +2638,16 @@ dependencies = [ [[package]] name = "ic-ledger-canister-core" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", "ic-base-types", "ic-canister-log", "ic-constants", - "ic-ic00-types", "ic-ledger-core", "ic-ledger-hash-of", + "ic-management-canister-types", "ic-utils", "num-traits", "serde", @@ -2605,7 +2656,7 @@ dependencies = [ [[package]] name = "ic-ledger-core" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ic-ledger-hash-of", @@ -2617,13 +2668,32 @@ dependencies = [ [[package]] name = "ic-ledger-hash-of" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "hex", "serde", ] +[[package]] +name = "ic-management-canister-types" +version = "0.9.0" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" +dependencies = [ + "candid", + "ic-base-types", + "ic-btc-interface", + "ic-btc-types-internal", + "ic-error-types", + "ic-protobuf", + "num-traits", + "serde", + "serde_bytes", + "serde_cbor", + "strum", + "strum_macros", +] + [[package]] name = "ic-metrics-encoder" version = "1.1.1" @@ -2633,14 +2703,14 @@ checksum = "8b5c7628eac357aecda461130f8074468be5aa4d258a002032d82d817f79f1f8" [[package]] name = "ic-nervous-system-clients" version = "0.0.1" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", "dfn_core", "ic-base-types", "ic-error-types", - "ic-ic00-types", + "ic-management-canister-types", "ic-nervous-system-proxied-canister-calls-tracker", "ic-nervous-system-runtime", "num-traits", @@ -2650,12 +2720,12 @@ dependencies = [ [[package]] name = "ic-nervous-system-collections-union-multi-map" version = "0.0.1" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" [[package]] name = "ic-nervous-system-common" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "build-info", @@ -2676,8 +2746,10 @@ dependencies = [ "icp-ledger", "icrc-ledger-types", "json5", + "lazy_static", "maplit", "mockall", + "num-traits", "priority-queue", "prost", "rust_decimal", @@ -2688,12 +2760,12 @@ dependencies = [ [[package]] name = "ic-nervous-system-common-build-metadata" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" [[package]] name = "ic-nervous-system-common-test-keys" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-base-types", "ic-canister-client-sender", @@ -2706,30 +2778,37 @@ dependencies = [ [[package]] name = "ic-nervous-system-governance" version = "0.0.1" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-base-types", "ic-stable-structures", + "ic_principal", "maplit", "num-traits", ] +[[package]] +name = "ic-nervous-system-lock" +version = "0.0.1" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" + [[package]] name = "ic-nervous-system-proto" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "comparable", "ic-base-types", "prost", + "rust_decimal", "serde", ] [[package]] name = "ic-nervous-system-proxied-canister-calls-tracker" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-base-types", ] @@ -2737,13 +2816,13 @@ dependencies = [ [[package]] name = "ic-nervous-system-root" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "dfn_core", "ic-cdk", "ic-crypto-sha2", - "ic-ic00-types", + "ic-management-canister-types", "ic-nervous-system-clients", "ic-nervous-system-runtime", "serde", @@ -2753,7 +2832,7 @@ dependencies = [ [[package]] name = "ic-nervous-system-runtime" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", @@ -2763,10 +2842,15 @@ dependencies = [ "ic-cdk", ] +[[package]] +name = "ic-nervous-system-string" +version = "0.0.1" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" + [[package]] name = "ic-neurons-fund" version = "0.0.1" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-nervous-system-common", "lazy_static", @@ -2779,7 +2863,7 @@ dependencies = [ [[package]] name = "ic-nns-common" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "comparable", @@ -2804,7 +2888,7 @@ dependencies = [ [[package]] name = "ic-nns-constants" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-base-types", ] @@ -2812,7 +2896,7 @@ dependencies = [ [[package]] name = "ic-nns-governance" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "build-info", @@ -2874,12 +2958,12 @@ dependencies = [ [[package]] name = "ic-nns-gtc-accounts" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" [[package]] name = "ic-nns-handler-root-interface" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", @@ -2894,7 +2978,7 @@ dependencies = [ [[package]] name = "ic-protobuf" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "bincode", "candid", @@ -2909,11 +2993,11 @@ dependencies = [ [[package]] name = "ic-registry-keys" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ic-base-types", - "ic-ic00-types", + "ic-management-canister-types", "ic-types", "serde", ] @@ -2921,7 +3005,7 @@ dependencies = [ [[package]] name = "ic-registry-routing-table" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ic-base-types", @@ -2932,10 +3016,10 @@ dependencies = [ [[package]] name = "ic-registry-subnet-features" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", - "ic-ic00-types", + "ic-management-canister-types", "ic-protobuf", "serde", ] @@ -2943,7 +3027,7 @@ dependencies = [ [[package]] name = "ic-registry-subnet-type" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ic-protobuf", @@ -2955,7 +3039,7 @@ dependencies = [ [[package]] name = "ic-registry-transport" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "ic-base-types", @@ -2967,7 +3051,7 @@ dependencies = [ [[package]] name = "ic-sns-governance" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "base64 0.13.1", @@ -2984,21 +3068,24 @@ dependencies = [ "ic-canister-profiler", "ic-canisters-http-types", "ic-crypto-sha2", - "ic-ic00-types", "ic-icrc1-ledger", "ic-ledger-core", + "ic-management-canister-types", "ic-metrics-encoder", "ic-nervous-system-clients", "ic-nervous-system-collections-union-multi-map", "ic-nervous-system-common", "ic-nervous-system-common-build-metadata", "ic-nervous-system-governance", + "ic-nervous-system-lock", "ic-nervous-system-proto", "ic-nervous-system-root", "ic-nervous-system-runtime", "ic-nns-constants", "ic-protobuf", "ic-sns-governance-proposal-criticality", + "ic-sns-governance-proposals-amount-total-limit", + "ic-sns-governance-token-valuation", "icp-ledger", "icrc-ledger-client", "icrc-ledger-types", @@ -3019,20 +3106,52 @@ dependencies = [ [[package]] name = "ic-sns-governance-proposal-criticality" version = "0.0.1" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "ic-nervous-system-proto", ] +[[package]] +name = "ic-sns-governance-proposals-amount-total-limit" +version = "0.0.1" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" +dependencies = [ + "ic-sns-governance-token-valuation", + "num-traits", + "rust_decimal", + "rust_decimal_macros", +] + +[[package]] +name = "ic-sns-governance-token-valuation" +version = "0.0.1" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" +dependencies = [ + "async-trait", + "candid", + "cycles-minting-canister", + "futures", + "ic-base-types", + "ic-cdk", + "ic-nervous-system-common", + "ic-nervous-system-runtime", + "ic-nervous-system-string", + "ic-nns-constants", + "ic-sns-swap-proto-library", + "icrc-ledger-types", + "mockall", + "rust_decimal", +] + [[package]] name = "ic-sns-init" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "base64 0.13.1", "candid", "ic-base-types", - "ic-icrc1-index", + "ic-icrc1-index-ng", "ic-icrc1-ledger", "ic-ledger-canister-core", "ic-ledger-core", @@ -3054,7 +3173,7 @@ dependencies = [ [[package]] name = "ic-sns-root" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "build-info", @@ -3067,7 +3186,7 @@ dependencies = [ "ic-canisters-http-types", "ic-cdk", "ic-cdk-macros", - "ic-ic00-types", + "ic-management-canister-types", "ic-metrics-encoder", "ic-nervous-system-clients", "ic-nervous-system-common", @@ -3083,7 +3202,7 @@ dependencies = [ [[package]] name = "ic-sns-swap" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "build-info", @@ -3112,13 +3231,27 @@ dependencies = [ "maplit", "prost", "rust_decimal", + "rust_decimal_macros", + "serde", +] + +[[package]] +name = "ic-sns-swap-proto-library" +version = "0.0.1" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" +dependencies = [ + "candid", + "comparable", + "ic-base-types", + "ic-nervous-system-proto", + "prost", "serde", ] [[package]] name = "ic-sns-wasm" version = "1.0.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", @@ -3130,7 +3263,7 @@ dependencies = [ "ic-base-types", "ic-cdk", "ic-crypto-sha2", - "ic-ic00-types", + "ic-management-canister-types", "ic-metrics-encoder", "ic-nervous-system-clients", "ic-nervous-system-common", @@ -3151,14 +3284,17 @@ dependencies = [ [[package]] name = "ic-stable-structures" -version = "0.5.6" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95dce29e3ceb0e6da3e78b305d95365530f2efd2146ca18590c0ef3aa6038568" +checksum = "a314297eb9edb4bbcc2e04d2e634e38d5900b68eadae661e927946d1aba3f9f7" +dependencies = [ + "ic_principal", +] [[package]] name = "ic-transport-types" -version = "0.32.0" -source = "git+https://github.com/dfinity/agent-rs?rev=73da09c1c553193c46d7edef73c8c20beaa8498c#73da09c1c553193c46d7edef73c8c20beaa8498c" +version = "0.34.0" +source = "git+https://github.com/dfinity/agent-rs?rev=8c39e26236e3e3db6db51ffa71e34140c19d207e#8c39e26236e3e3db6db51ffa71e34140c19d207e" dependencies = [ "candid", "hex", @@ -3174,7 +3310,7 @@ dependencies = [ [[package]] name = "ic-types" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "base64 0.13.1", "bincode", @@ -3189,7 +3325,7 @@ dependencies = [ "ic-crypto-sha2", "ic-crypto-tree-hash", "ic-error-types", - "ic-ic00-types", + "ic-management-canister-types", "ic-protobuf", "ic-utils", "maplit", @@ -3210,7 +3346,7 @@ dependencies = [ [[package]] name = "ic-utils" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "hex", "prost", @@ -3221,7 +3357,7 @@ dependencies = [ [[package]] name = "ic-utils-ensure" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" [[package]] name = "ic-verify-bls-signature" @@ -3267,7 +3403,7 @@ dependencies = [ "ff 0.12.1", "group 0.12.1", "pairing", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -3289,7 +3425,7 @@ dependencies = [ [[package]] name = "icp-ledger" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "comparable", @@ -3319,7 +3455,7 @@ dependencies = [ [[package]] name = "icrc-ledger-client" version = "0.1.2" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", @@ -3330,7 +3466,7 @@ dependencies = [ [[package]] name = "icrc-ledger-client-cdk" version = "0.1.2" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", @@ -3341,7 +3477,7 @@ dependencies = [ [[package]] name = "icrc-ledger-types" version = "0.1.5" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "base32", "candid", @@ -3589,7 +3725,7 @@ dependencies = [ [[package]] name = "ledger-canister" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "async-trait", "candid", @@ -3754,6 +3890,18 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + [[package]] name = "mime" version = "0.3.17" @@ -3812,7 +3960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] @@ -3945,6 +4093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3984,7 +4133,7 @@ dependencies = [ [[package]] name = "on_wire" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" [[package]] name = "once_cell" @@ -4164,7 +4313,7 @@ dependencies = [ [[package]] name = "phantom_newtype" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "candid", "serde", @@ -4234,6 +4383,12 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + [[package]] name = "portable-atomic" version = "1.6.0" @@ -4481,9 +4636,11 @@ version = "0.4.4" dependencies = [ "anyhow", "base64 0.13.1", + "bigdecimal", "bip32", "candid", "candid_parser", + "chrono", "clap", "crc32fast", "data-encoding", @@ -4516,7 +4673,6 @@ dependencies = [ "qrcodegen", "rand", "rpassword", - "rust_decimal", "scopeguard", "serde", "serde_bytes", @@ -4555,7 +4711,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -4565,16 +4721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -4583,7 +4730,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom", ] [[package]] @@ -4607,7 +4754,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.12", + "getrandom", "libredox", "thiserror", ] @@ -4656,7 +4803,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "registry-canister" version = "0.9.0" -source = "git+https://github.com/dfinity/ic?rev=0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5#0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" +source = "git+https://github.com/dfinity/ic?rev=9adada073bd245a8f9f435b8f9edbb2af990027b#9adada073bd245a8f9f435b8f9edbb2af990027b" dependencies = [ "build-info", "build-info-build", @@ -4673,7 +4820,7 @@ dependencies = [ "ic-crypto-sha2", "ic-crypto-utils-basic-sig", "ic-crypto-utils-ni-dkg", - "ic-ic00-types", + "ic-management-canister-types", "ic-metrics-encoder", "ic-nervous-system-common", "ic-nervous-system-common-build-metadata", @@ -4716,8 +4863,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.11", + "http-body 0.4.6", "hyper", "hyper-rustls", "ipnet", @@ -4767,21 +4914,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.7" @@ -4789,10 +4921,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.12", + "getrandom", "libc", "spin 0.9.8", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.48.0", ] @@ -4922,7 +5054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring", "rustls-webpki", "sct", ] @@ -4942,8 +5074,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -4976,8 +5108,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -5227,7 +5359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -5237,7 +5369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -5395,18 +5527,18 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.25.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck", "proc-macro2", @@ -5547,18 +5679,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -5817,12 +5949,6 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -5867,12 +5993,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -6188,12 +6308,11 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" dependencies = [ "asn1-rs", - "base64 0.13.1", "data-encoding", "der-parser", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index e5b202e1..8e780e9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,33 +8,31 @@ description = "Minimalistic ledger and governance toolkit for cold wallets." repository = "https://github.com/dfinity/quill" license = "Apache-2.0" -[[bin]] -name = "quill" -path = "src/main.rs" - [dependencies] -ic-base-types = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-ckbtc-minter = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-nervous-system-common = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-nns-common = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-nns-constants = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-nns-governance = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-sns-governance = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-sns-root = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-sns-swap = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ic-sns-wasm = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -icp-ledger = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -icrc-ledger-types = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } -ledger-canister = { git = "https://github.com/dfinity/ic", rev = "0cc5c19ecf2ecd8d51a20e970b25241f7f3bd8e5" } +ic-base-types = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-ckbtc-minter = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-nervous-system-common = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-nns-common = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-nns-constants = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-nns-governance = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-sns-governance = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-sns-root = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-sns-swap = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ic-sns-wasm = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +icp-ledger = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +icrc-ledger-types = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } +ledger-canister = { git = "https://github.com/dfinity/ic", rev = "9adada073bd245a8f9f435b8f9edbb2af990027b" } candid = "0.10.2" candid_parser = "0.1.2" -ic-agent = { git = "https://github.com/dfinity/agent-rs", rev = "73da09c1c553193c46d7edef73c8c20beaa8498c" } -ic-identity-hsm = { git = "https://github.com/dfinity/agent-rs", rev = "73da09c1c553193c46d7edef73c8c20beaa8498c", optional = true } +ic-agent = { git = "https://github.com/dfinity/agent-rs", rev = "8c39e26236e3e3db6db51ffa71e34140c19d207e" } +ic-identity-hsm = { git = "https://github.com/dfinity/agent-rs", rev = "8c39e26236e3e3db6db51ffa71e34140c19d207e", optional = true } anyhow = "1.0.34" base64 = "0.13.0" +bigdecimal = "0.4" bip32 = "0.4.0" +chrono = "0.4" clap = { version = "3.1.18", features = ["derive", "cargo"] } crc32fast = "1.3.2" data-encoding = "2.3.3" @@ -52,7 +50,6 @@ pem = "1.0.1" qrcodegen = "1.8" rand = { version = "0.8.4", features = ["getrandom"] } rpassword = "6.0.0" -rust_decimal = "1.26" simple_asn1 = "0.6.1" scopeguard = "1" serde = { version = "1.0.130", features = ["derive"] } diff --git a/candid/ckbtc_minter.did b/candid/ckbtc_minter.did index aadcaf5b..86d8eb0e 100644 --- a/candid/ckbtc_minter.did +++ b/candid/ckbtc_minter.did @@ -1,15 +1,48 @@ // Represents an account on the ckBTC ledger. type Account = record { owner : principal; subaccount : opt blob }; +type CanisterStatusResponse = record { + status : CanisterStatusType; + memory_size : nat; + cycles : nat; + settings : DefiniteCanisterSettings; + idle_cycles_burned_per_day : nat; + module_hash : opt vec nat8; + query_stats : QueryStats; + reserved_cycles : nat; +}; + +type QueryStats = record { + response_payload_bytes_total : nat; + num_instructions_total : nat; + num_calls_total : nat; + request_payload_bytes_total : nat; +}; + +type CanisterStatusType = variant { stopped; stopping; running }; + +type DefiniteCanisterSettings = record { + freezing_threshold : nat; + controllers : vec principal; + memory_allocation : nat; + compute_allocation : nat; + reserved_cycles_limit : nat; +}; + type RetrieveBtcArgs = record { // The address to which the ckBTC minter should deposit BTC. - // Currently, the minter understands only the following types of addresses: - // * P2WPKH addresses (they start with the "bc1q" prefix on the Bitcoin mainnet). - // * P2PKH addresses (they start with the "1" prefix on the Bitcoin mainnet). - // * P2SH addresses (they start with the "3" prefix on the Bitcoin mainnet). address : text; - // The amount of BTC in Satoshis that the client wants to withdraw. + // The amount of ckBTC in Satoshis that the client wants to withdraw. + amount : nat64; +}; + +type RetrieveBtcWithApprovalArgs = record { + // The address to which the ckBTC minter should deposit BTC. + address : text; + // The amount of ckBTC in Satoshis that the client wants to withdraw. amount : nat64; + // The subaccount to burn ckBTC from. + from_subaccount : opt blob; }; type RetrieveBtcError = variant { @@ -30,6 +63,26 @@ type RetrieveBtcError = variant { GenericError : record { error_message : text; error_code : nat64 }; }; +type RetrieveBtcWithApprovalError = variant { + // The minter failed to parse the destination address. + MalformedAddress : text; + // The minter is already processing another retrieval request for the same + // principal. + AlreadyProcessing; + // The withdrawal amount is too low. + // The payload contains the minimal withdrawal amount. + AmountTooLow : nat64; + // The ckBTC balance of the withdrawal account is too low. + InsufficientFunds : record { balance : nat64 }; + // The allowance given to the minter is too low. + InsufficientAllowance : record { allowance : nat64 }; + // The minter is overloaded, retry the request. + // The payload contains a human-readable message explaining what caused the unavailability. + TemporarilyUnavailable : text; + // A generic error reserved for future extensions. + GenericError : record { error_message : text; error_code : nat64 }; +}; + type RetrieveBtcOk = record { // Returns the burn transaction index corresponding to the withdrawal. // You can use this index to query the withdrawal status. @@ -42,7 +95,7 @@ type UtxoStatus = variant { // the KYT fees. This state is final, retrying [update_balance] call will // have no effect on this UTXO. ValueTooSmall : Utxo; - // The KYT provider considered this UTXO to be tained. This UTXO state is + // The KYT provider considered this UTXO to be tainted. This UTXO state is // final, retrying [update_balance] call will have no effect on this UTXO. Tainted : Utxo; // The UTXO passed the KYT check, but the minter failed to mint ckBTC @@ -57,11 +110,19 @@ type UtxoStatus = variant { }; }; +// Utxos that don't have enough confirmations to be processed. +type PendingUtxo = record { + outpoint : record { txid : vec nat8; vout : nat32 }; + value : nat64; + confirmations: nat32; +}; + type UpdateBalanceError = variant { // There are no new UTXOs to process. NoNewUtxos : record { current_confirmations: opt nat32; - required_confirmations: nat32 + required_confirmations: nat32; + pending_utxos: opt vec PendingUtxo; }; // The minter is already processing another update balance request for the caller. AlreadyProcessing; @@ -120,7 +181,7 @@ type InitArgs = record { /// The minter's operation mode. mode : Mode; - /// The fee paid per check by the KYT cansiter. + /// The fee paid per check by the KYT canister. kyt_fee : opt nat64; /// The canister id of the KYT canister. @@ -143,7 +204,7 @@ type UpgradeArgs = record { /// If set, overrides the current minter's operation mode. mode : opt Mode; - /// The fee per check by the KYT cansiter. + /// The fee per check by the KYT canister. kyt_fee : opt nat64; /// The principal of the KYT canister. @@ -181,6 +242,48 @@ type RetrieveBtcStatus = variant { Confirmed : record { txid : blob }; }; +type ReimbursementRequest = record { + account : Account; + amount : nat64; + reason : ReimbursementReason; +}; + +type ReimbursedDeposit = record { + account : Account; + mint_block_index : nat64; + amount : nat64; + reason : ReimbursementReason; +}; + +type RetrieveBtcStatusV2 = variant { + // The minter does not have any information on the specified + // retrieval request. It can be that nobody submitted the + // request or the minter pruned the relevant information from the + // history to save space. + Unknown; + // The minter did not send a Bitcoin transaction for this request yet. + Pending; + // The minter is obtaining all required ECDSA signatures on the + // Bitcoin transaction for this request. + Signing; + // The minter signed the transaction and is waiting for a reply + // from the Bitcoin canister. + Sending : record { txid : blob }; + // The minter sent a transaction for the retrieve request. + // The payload contains the identifier of the transaction on the Bitcoin network. + Submitted : record { txid : blob }; + // The amount was too low to cover the transaction fees. + AmountTooLow; + // The minter received enough confirmations for the Bitcoin + // transaction for this request. The payload contains the + // identifier of the transaction on the Bitcoin network. + Confirmed : record { txid : blob }; + /// The retrieve bitcoin request has been reimbursed. + Reimbursed : ReimbursedDeposit; + /// The minter will try to reimburse this transaction. + WillReimburse : ReimbursementRequest; +}; + type Utxo = record { outpoint : record { txid : vec nat8; vout : nat32 }; value : nat64; @@ -189,6 +292,8 @@ type Utxo = record { type BitcoinAddress = variant { p2wpkh_v0 : blob; + p2wsh_v0 : blob; + p2tr_v1 : blob; p2pkh : blob; p2sh : blob; }; @@ -199,16 +304,25 @@ type MinterInfo = record { kyt_fee : nat64; }; +type ReimbursementReason = variant { + CallFailed; + TaintedDestination : record { + kyt_fee : nat64; + kyt_provider: principal; + }; +}; + type Event = variant { init : InitArgs; upgrade : UpgradeArgs; - received_utxos : record { to_account : Account; utxos : vec Utxo }; + received_utxos : record { to_account : Account; mint_txid : opt nat64; utxos : vec Utxo }; accepted_retrieve_btc_request : record { amount : nat64; address : BitcoinAddress; block_index : nat64; received_at : nat64; kyt_provider : opt principal; + reimbursement_account : opt Account; }; distributed_kyt_fee : record { kyt_provider : principal; @@ -222,6 +336,14 @@ type Event = variant { utxos : vec Utxo; change_output : opt record { vout : nat32; value : nat64 }; submitted_at : nat64; + fee: opt nat64; + }; + replaced_transaction : record { + new_txid : blob; + old_txid : blob; + change_output : record { vout : nat32; value : nat64 }; + submitted_at : nat64; + fee: nat64; }; confirmed_transaction : record { txid : blob }; checked_utxo : record { @@ -234,10 +356,18 @@ type Event = variant { retrieve_btc_kyt_failed : record { address : text; amount : nat64; + owner : principal; kyt_provider : principal; uuid : text; block_index : nat64; }; + schedule_deposit_reimbursement : record { + account : Account; + burn_block_index : nat64; + amount : nat64; + reason : ReimbursementReason; + }; + reimbursed_failed_deposit : record { burn_block_index : nat64; mint_block_index : nat64 }; }; type MinterArg = variant { @@ -255,6 +385,12 @@ service : (minter_arg : MinterArg) -> { // If the owner is not set, it defaults to the caller's principal. get_btc_address : (record { owner: opt principal; subaccount : opt blob }) -> (text); + // Returns UTXOs of the given account known by the minter (with no + // guarantee in the ordering of the returned values). + // + // If the owner is not set, it defaults to the caller's principal. + get_known_utxos: (record { owner: opt principal; subaccount : opt blob }) -> (vec Utxo) query; + // Mints ckBTC for newly deposited UTXOs. // // If the owner is not set, it defaults to the caller's principal. @@ -296,14 +432,43 @@ service : (minter_arg : MinterArg) -> { // that the [get_withdrawal_account] endpoint returns. retrieve_btc : (RetrieveBtcArgs) -> (variant { Ok : RetrieveBtcOk; Err : RetrieveBtcError }); - /// Returns the status of a [retrieve_btc] request. + // Submits a request to convert ckBTC to BTC. + // + // # Note + // + // The BTC retrieval process is slow. Instead of + // synchronously waiting for a BTC transaction to settle, this + // method returns a request ([block_index]) that the caller can use + // to query the request status. + // + // # Preconditions + // + // * The caller allowed the minter's principal to spend its funds + // using [icrc2_approve] on the ckBTC ledger. + retrieve_btc_with_approval : (RetrieveBtcWithApprovalArgs) -> (variant { Ok : RetrieveBtcOk; Err : RetrieveBtcWithApprovalError }); + + /// [deprecated] Returns the status of a withdrawal request. + /// You should use retrieve_btc_status_v2 to retrieve the status of your withdrawal request. retrieve_btc_status : (record { block_index : nat64 }) -> (RetrieveBtcStatus) query; + /// Returns the status of a withdrawal request request using the RetrieveBtcStatusV2 type. + retrieve_btc_status_v2 : (record { block_index : nat64 }) -> (RetrieveBtcStatusV2) query; + + // Returns the withdrawal statues by account. + // + // # Note + // The _v2_ part indicates that you get a response in line with the retrieve_btc_status_v2 endpoint, + // i.e., you get a vector of RetrieveBtcStatusV2 and not RetrieveBtcStatus. + // + retrieve_btc_status_v2_by_account : (opt Account) -> (vec record { block_index: nat64; status_v2: opt RetrieveBtcStatusV2; }) query; + // }}} Section "Convert ckBTC to BTC" // Section "Minter Information" {{{ // Returns internal minter parameters. get_minter_info : () -> (MinterInfo) query; + + get_canister_status : () -> (CanisterStatusResponse); // }}} // Section "Event log" {{{ diff --git a/candid/governance.did b/candid/governance.did index 995e32fe..4e41467e 100644 --- a/candid/governance.did +++ b/candid/governance.did @@ -1,4 +1,4 @@ -type AccountIdentifier = record { hash : vec nat8 }; +type AccountIdentifier = record { hash : blob }; type Action = variant { RegisterKnownNeuron : KnownNeuron; ManageNeuron : ManageNeuron; @@ -33,7 +33,7 @@ type CanisterStatusResultV2 = record { memory_size : opt nat64; cycles : opt nat64; idle_cycles_burned_per_day : opt nat64; - module_hash : vec nat8; + module_hash : blob; }; type CanisterSummary = record { status : opt CanisterStatusResultV2; @@ -123,6 +123,7 @@ type CreateServiceNervousSystem = record { swap_parameters : opt SwapParameters; initial_token_distribution : opt InitialTokenDistribution; }; +type Decimal = record { human_readable : opt text }; type DerivedProposalInformation = record { swap_background_information : opt SwapBackgroundInformation; }; @@ -146,7 +147,7 @@ type DissolveState = variant { WhenDissolvedTimestampSeconds : nat64; }; type Duration = record { seconds : opt nat64 }; -type ExecuteNnsFunction = record { nns_function : int32; payload : vec nat8 }; +type ExecuteNnsFunction = record { nns_function : int32; payload : blob }; type Follow = record { topic : int32; followees : vec NeuronId }; type Followees = record { followees : vec NeuronId }; type Followers = record { followers : vec NeuronId }; @@ -172,6 +173,7 @@ type Governance = record { topic_followee_index : vec record { int32; FollowersMap }; migrations : opt Migrations; proposals : vec record { nat64; ProposalData }; + xdr_conversion_rate : opt XdrConversionRate; in_flight_commands : vec record { nat64; NeuronInFlightCommand }; neurons : vec record { nat64; Neuron }; genesis_timestamp_seconds : nat64; @@ -275,7 +277,10 @@ type ListProposalInfo = record { include_status : vec int32; }; type ListProposalInfoResponse = record { proposal_info : vec ProposalInfo }; -type MakeProposalResponse = record { proposal_id : opt NeuronId }; +type MakeProposalResponse = record { + message : opt text; + proposal_id : opt NeuronId; +}; type MakingSnsProposal = record { proposal : opt Proposal; caller : opt principal; @@ -322,6 +327,7 @@ type NetworkEconomics = record { neuron_spawn_dissolve_delay_seconds : nat64; minimum_icp_xdr_rate : nat64; maximum_node_provider_rewards_e8s : nat64; + neurons_fund_economics : opt NeuronsFundEconomics; }; type Neuron = record { id : opt NeuronId; @@ -337,7 +343,7 @@ type Neuron = record { auto_stake_maturity : opt bool; aging_since_timestamp_seconds : nat64; hot_keys : vec principal; - account : vec nat8; + account : blob; joined_community_fund_timestamp_seconds : opt nat64; dissolve_state : opt DissolveState; followees : vec record { int32; Followees }; @@ -362,10 +368,7 @@ type NeuronDistribution = record { stake : opt Tokens; }; type NeuronId = record { id : nat64 }; -type NeuronIdOrSubaccount = variant { - Subaccount : vec nat8; - NeuronId : NeuronId; -}; +type NeuronIdOrSubaccount = variant { Subaccount : blob; NeuronId : NeuronId }; type NeuronInFlightCommand = record { command : opt Command_2; timestamp : nat64; @@ -384,11 +387,11 @@ type NeuronInfo = record { age_seconds : nat64; }; type NeuronStakeTransfer = record { - to_subaccount : vec nat8; + to_subaccount : blob; neuron_stake_e8s : nat64; from : opt principal; memo : nat64; - from_subaccount : vec nat8; + from_subaccount : blob; transfer_timestamp : nat64; block_height : nat64; }; @@ -402,6 +405,17 @@ type NeuronsFundData = record { initial_neurons_fund_participation : opt NeuronsFundParticipation; neurons_fund_refunds : opt NeuronsFundSnapshot; }; +type NeuronsFundEconomics = record { + maximum_icp_xdr_rate : opt Percentage; + neurons_fund_matched_funding_curve_coefficients : opt NeuronsFundMatchedFundingCurveCoefficients; + max_theoretical_neurons_fund_participation_amount_xdr : opt Decimal; + minimum_icp_xdr_rate : opt Percentage; +}; +type NeuronsFundMatchedFundingCurveCoefficients = record { + contribution_threshold_xdr : opt Decimal; + one_third_participation_milestone_xdr : opt Decimal; + full_participation_milestone_xdr : opt Decimal; +}; type NeuronsFundNeuron = record { hotkey_principal : opt text; is_capped : opt bool; @@ -628,6 +642,10 @@ type VotingRewardParameters = record { final_reward_rate : opt Percentage; }; type WaitForQuietState = record { current_deadline_timestamp_seconds : nat64 }; +type XdrConversionRate = record { + xdr_permyriad_per_icp : opt nat64; + timestamp_seconds : opt nat64; +}; service : (Governance) -> { claim_gtc_neurons : (principal, vec NeuronId) -> (Result); claim_or_refresh_neuron_from_account : (ClaimOrRefreshNeuronFromAccount) -> ( diff --git a/candid/gtc.did b/candid/gtc.did index f798cf7b..f886bb13 100644 --- a/candid/gtc.did +++ b/candid/gtc.did @@ -27,4 +27,4 @@ service : { get_build_metadata : () -> (text) query; len : () -> (nat16) query; total : () -> (nat32) query; -} +} \ No newline at end of file diff --git a/candid/icrc1.did b/candid/icrc1.did index 242b6799..c8cc56b9 100644 --- a/candid/icrc1.did +++ b/candid/icrc1.did @@ -5,6 +5,53 @@ type Timestamp = nat64; // Number of nanoseconds between two [Timestamp]s. type Duration = nat64; type Tokens = nat; +type TxIndex = nat; +type Allowance = record { allowance : nat; expires_at : opt Timestamp }; +type AllowanceArgs = record { account : Account; spender : Account }; +type Approve = record { + fee : opt nat; + from : Account; + memo : opt blob; + created_at_time : opt Timestamp; + amount : nat; + expected_allowance : opt nat; + expires_at : opt Timestamp; + spender : Account; +}; +type ApproveArgs = record { + fee : opt nat; + memo : opt blob; + from_subaccount : opt blob; + created_at_time : opt Timestamp; + amount : nat; + expected_allowance : opt nat; + expires_at : opt Timestamp; + spender : Account; +}; +type ApproveError = variant { + GenericError : record { message : text; error_code : nat }; + TemporarilyUnavailable; + Duplicate : record { duplicate_of : BlockIndex }; + BadFee : record { expected_fee : nat }; + AllowanceChanged : record { current_allowance : nat }; + CreatedInFuture : record { ledger_time : Timestamp }; + TooOld; + Expired : record { ledger_time : Timestamp }; + InsufficientFunds : record { balance : nat }; +}; +type ApproveResult = variant { Ok : BlockIndex; Err : ApproveError }; + +type HttpRequest = record { + url : text; + method : text; + body : blob; + headers : vec record { text; text }; +}; +type HttpResponse = record { + body : blob; + headers : vec record { text; text }; + status_code : nat16; +}; type Account = record { owner : principal; @@ -25,7 +72,7 @@ type TransferError = variant { BadBurn : record { min_burn_amount : Tokens }; InsufficientFunds : record { balance : Tokens }; TooOld; - CreatedInFuture : record { ledger_time : nat64 }; + CreatedInFuture : record { ledger_time : Timestamp }; TemporarilyUnavailable; Duplicate : record { duplicate_of : BlockIndex }; GenericError : record { error_code : nat; message : text }; @@ -37,40 +84,335 @@ type TransferResult = variant { }; // The value returned from the [icrc1_metadata] endpoint. -type Value = variant { +type MetadataValue = variant { Nat : nat; Int : int; Text : text; Blob : blob; }; +type FeatureFlags = record { + icrc2 : bool; +}; + // The initialization parameters of the Ledger type InitArgs = record { minting_account : Account; - transfer_fee : nat64; + fee_collector_account : opt Account; + transfer_fee : nat; + decimals : opt nat8; + max_memo_length : opt nat16; token_symbol : text; token_name : text; - metadata : vec record { text; Value }; - initial_balances : vec record { Account; nat64 }; + metadata : vec record { text; MetadataValue }; + initial_balances : vec record { Account; nat }; + feature_flags : opt FeatureFlags; + maximum_number_of_accounts : opt nat64; + accounts_overflow_trim_quantity : opt nat64; archive_options : record { num_blocks_to_archive : nat64; + max_transactions_per_response : opt nat64; trigger_threshold : nat64; max_message_size_bytes : opt nat64; cycles_for_archive_creation : opt nat64; node_max_memory_size_bytes : opt nat64; controller_id : principal; + more_controller_ids : opt vec principal; + }; +}; + +type ChangeFeeCollector = variant { + Unset; SetTo: Account; +}; + +type UpgradeArgs = record { + metadata : opt vec record { text; MetadataValue }; + token_symbol : opt text; + token_name : opt text; + transfer_fee : opt nat; + change_fee_collector : opt ChangeFeeCollector; + max_memo_length : opt nat16; + feature_flags : opt FeatureFlags; + maximum_number_of_accounts: opt nat64; + accounts_overflow_trim_quantity: opt nat64; +}; + +type LedgerArg = variant { + Init: InitArgs; + Upgrade: opt UpgradeArgs; +}; + +type GetTransactionsRequest = record { + // The index of the first tx to fetch. + start : TxIndex; + // The number of transactions to fetch. + length : nat; +}; + +type GetTransactionsResponse = record { + // The total number of transactions in the log. + log_length : nat; + + // List of transaction that were available in the ledger when it processed the call. + // + // The transactions form a contiguous range, with the first transaction having index + // [first_index] (see below), and the last transaction having index + // [first_index] + len(transactions) - 1. + // + // The transaction range can be an arbitrary sub-range of the originally requested range. + transactions : vec Transaction; + + // The index of the first transaction in [transactions]. + // If the transaction vector is empty, the exact value of this field is not specified. + first_index : TxIndex; + + // Encoding of instructions for fetching archived transactions whose indices fall into the + // requested range. + // + // For each entry `e` in [archived_transactions], `[e.from, e.from + len)` is a sub-range + // of the originally requested transaction range. + archived_transactions : vec record { + // The index of the first archived transaction you can fetch using the [callback]. + start : TxIndex; + + // The number of transactions you can fetch using the callback. + length : nat; + + // The function you should call to fetch the archived transactions. + // The range of the transaction accessible using this function is given by [from] + // and [len] fields above. + callback : QueryArchiveFn; }; }; -service : (InitArgs) -> { + +// A prefix of the transaction range specified in the [GetTransactionsRequest] request. +type TransactionRange = record { + // A prefix of the requested transaction range. + // The index of the first transaction is equal to [GetTransactionsRequest.from]. + // + // Note that the number of transactions might be less than the requested + // [GetTransactionsRequest.length] for various reasons, for example: + // + // 1. The query might have hit the replica with an outdated state + // that doesn't have the whole range yet. + // 2. The requested range is too large to fit into a single reply. + // + // NOTE: the list of transactions can be empty if: + // + // 1. [GetTransactionsRequest.length] was zero. + // 2. [GetTransactionsRequest.from] was larger than the last transaction known to + // the canister. + transactions : vec Transaction; +}; + +// A function for fetching archived transaction. +type QueryArchiveFn = func (GetTransactionsRequest) -> (TransactionRange) query; + +type Transaction = record { + burn : opt Burn; + kind : text; + mint : opt Mint; + approve : opt Approve; + timestamp : Timestamp; + transfer : opt Transfer; +}; + +type Burn = record { + from : Account; + memo : opt blob; + created_at_time : opt Timestamp; + amount : nat; + spender : opt Account; +}; + +type Mint = record { + to : Account; + memo : opt blob; + created_at_time : opt Timestamp; + amount : nat; +}; + +type Transfer = record { + to : Account; + fee : opt nat; + from : Account; + memo : opt blob; + created_at_time : opt Timestamp; + amount : nat; + spender : opt Account; +}; + +type Value = variant { + Blob : blob; + Text : text; + Nat : nat; + Nat64: nat64; + Int : int; + Array : vec Value; + Map : Map; +}; + +type Map = vec record { text; Value }; + +type Block = Value; + +type GetBlocksArgs = record { + // The index of the first block to fetch. + start : BlockIndex; + // Max number of blocks to fetch. + length : nat; +}; + +// A prefix of the block range specified in the [GetBlocksArgs] request. +type BlockRange = record { + // A prefix of the requested block range. + // The index of the first block is equal to [GetBlocksArgs.start]. + // + // Note that the number of blocks might be less than the requested + // [GetBlocksArgs.length] for various reasons, for example: + // + // 1. The query might have hit the replica with an outdated state + // that doesn't have the whole range yet. + // 2. The requested range is too large to fit into a single reply. + // + // NOTE: the list of blocks can be empty if: + // + // 1. [GetBlocksArgs.length] was zero. + // 2. [GetBlocksArgs.start] was larger than the last block known to + // the canister. + blocks : vec Block; +}; + +// A function for fetching archived blocks. +type QueryBlockArchiveFn = func (GetBlocksArgs) -> (BlockRange) query; + +// The result of a "get_blocks" call. +type GetBlocksResponse = record { + // The index of the first block in "blocks". + // If the blocks vector is empty, the exact value of this field is not specified. + first_index : BlockIndex; + + // The total number of blocks in the chain. + // If the chain length is positive, the index of the last block is `chain_len - 1`. + chain_length : nat64; + + // System certificate for the hash of the latest block in the chain. + // Only present if `get_blocks` is called in a non-replicated query context. + certificate : opt blob; + + // List of blocks that were available in the ledger when it processed the call. + // + // The blocks form a contiguous range, with the first block having index + // [first_block_index] (see below), and the last block having index + // [first_block_index] + len(blocks) - 1. + // + // The block range can be an arbitrary sub-range of the originally requested range. + blocks : vec Block; + + // Encoding of instructions for fetching archived blocks. + archived_blocks : vec record { + // The index of the first archived block. + start : BlockIndex; + + // The number of blocks that can be fetched. + length : nat; + + // Callback to fetch the archived blocks. + callback : QueryBlockArchiveFn; + }; +}; + +// Certificate for the block at `block_index`. +type DataCertificate = record { + certificate : opt blob; + hash_tree : blob; +}; + +type StandardRecord = record { url : text; name : text }; + +type TransferFromArgs = record { + spender_subaccount : opt Subaccount; + from : Account; + to : Account; + amount : Tokens; + fee : opt Tokens; + memo : opt blob; + created_at_time: opt Timestamp; +}; + +type TransferFromResult = variant { + Ok : BlockIndex; + Err : TransferFromError; +}; + +type TransferFromError = variant { + BadFee : record { expected_fee : Tokens }; + BadBurn : record { min_burn_amount : Tokens }; + InsufficientFunds : record { balance : Tokens }; + InsufficientAllowance : record { allowance : Tokens }; + TooOld; + CreatedInFuture : record { ledger_time : Timestamp }; + Duplicate : record { duplicate_of : BlockIndex }; + TemporarilyUnavailable; + GenericError : record { error_code : nat; message : text }; +}; + +type ArchiveInfo = record { + canister_id: principal; + block_range_start: BlockIndex; + block_range_end: BlockIndex; +}; + +type GetArchivesArgs = record { + // The last archive seen by the client. + // The Ledger will return archives coming + // after this one if set, otherwise it + // will return the first archives. + from : opt principal; +}; + +type GetArchivesResult = vec record { + // The id of the archive + canister_id : principal; + + // The first block in the archive + start : nat; + + // The last block in the archive + end : nat; +}; + +type ICRC3DataCertificate = record { + // See https://internetcomputer.org/docs/current/references/ic-interface-spec#certification + certificate : blob; + + // CBOR encoded hash_tree + hash_tree : blob; +}; + +service : (ledger_arg : LedgerArg) -> { + archives : () -> (vec ArchiveInfo) query; + get_transactions : (GetTransactionsRequest) -> (GetTransactionsResponse) query; + get_blocks : (GetBlocksArgs) -> (GetBlocksResponse) query; + get_data_certificate : () -> (DataCertificate) query; + icrc1_name : () -> (text) query; icrc1_symbol : () -> (text) query; icrc1_decimals : () -> (nat8) query; - icrc1_metadata : () -> (vec record { text; Value }) query; + icrc1_metadata : () -> (vec record { text; MetadataValue }) query; icrc1_total_supply : () -> (Tokens) query; icrc1_fee : () -> (Tokens) query; icrc1_minting_account : () -> (opt Account) query; icrc1_balance_of : (Account) -> (Tokens) query; icrc1_transfer : (TransferArg) -> (TransferResult); - icrc1_supported_standards : () -> (vec record { name : text; url : text }) query; + icrc1_supported_standards : () -> (vec StandardRecord) query; + + icrc2_approve : (ApproveArgs) -> (ApproveResult); + icrc2_allowance : (AllowanceArgs) -> (Allowance) query; + icrc2_transfer_from : (TransferFromArgs) -> (TransferFromResult); + + icrc3_get_archives : (GetArchivesArgs) -> (GetArchivesResult) query; + icrc3_get_tip_certificate : () -> (opt ICRC3DataCertificate) query; + icrc3_supported_block_types : () -> (vec record { block_type : text; url : text }) query; } diff --git a/candid/ledger.did b/candid/ledger.did index bef3a0fe..124d40ad 100644 --- a/candid/ledger.did +++ b/candid/ledger.did @@ -104,6 +104,7 @@ type Operation = variant { }; Burn : record { from : AccountIdentifier; + spender : opt AccountIdentifier; amount : Tokens; }; Transfer : record { @@ -111,20 +112,17 @@ type Operation = variant { to : AccountIdentifier; amount : Tokens; fee : Tokens; + spender : opt vec nat8; }; Approve : record { from : AccountIdentifier; spender : AccountIdentifier; + // This field is deprecated and should not be used. allowance_e8s : int; + allowance: Tokens; fee : Tokens; expires_at : opt TimeStamp; - }; - TransferFrom : record { - from : AccountIdentifier; - to : AccountIdentifier; - spender : AccountIdentifier; - amount : Tokens; - fee : Tokens; + expected_allowance : opt Tokens; }; }; @@ -215,18 +213,36 @@ type QueryBlocksResponse = record { // // For each entry `e` in [archived_blocks], `[e.from, e.from + len)` is a sub-range // of the originally requested block range. - archived_blocks : vec record { - // The index of the first archived block that can be fetched using the callback. - start : BlockIndex; + archived_blocks : vec ArchivedBlocksRange; +}; - // The number of blocks that can be fetch using the callback. - length : nat64; +type ArchivedBlocksRange = record { + // The index of the first archived block that can be fetched using the callback. + start : BlockIndex; - // The function that should be called to fetch the archived blocks. - // The range of the blocks accessible using this function is given by [from] - // and [len] fields above. - callback : QueryArchiveFn; - }; + // The number of blocks that can be fetch using the callback. + length : nat64; + + // The function that should be called to fetch the archived blocks. + // The range of the blocks accessible using this function is given by [from] + // and [len] fields above. + callback : QueryArchiveFn; +}; + +type ArchivedEncodedBlocksRange = record { + callback : func (GetBlocksArgs) -> ( + variant { Ok : vec blob; Err : QueryArchiveError }, + ) query; + start : nat64; + length : nat64; +}; + +type QueryEncodedBlocksResponse = record { + certificate : opt blob; + blocks : vec blob; + chain_length : nat64; + first_block_index : nat64; + archived_blocks : vec ArchivedEncodedBlocksRange; }; type Archive = record { @@ -245,10 +261,12 @@ type Duration = record { type ArchiveOptions = record { trigger_threshold : nat64; num_blocks_to_archive : nat64; - node_max_memory_size_bytes: opt nat64; - max_message_size_bytes: opt nat64; - controller_id: principal; - cycles_for_archive_creation: opt nat64; + node_max_memory_size_bytes : opt nat64; + max_message_size_bytes : opt nat64; + controller_id : principal; + more_controller_ids: opt vec principal; + cycles_for_archive_creation : opt nat64; + max_transactions_per_response : opt nat64; }; // Account identifier encoded as a 64-byte ASCII hex string. @@ -268,8 +286,13 @@ type AccountBalanceArgsDfx = record { account: TextAccountIdentifier; }; -type LedgerCanisterInitPayload = record { +type FeatureFlags = record { + icrc2 : bool; +}; + +type InitArgs = record { minting_account: TextAccountIdentifier; + icrc1_minting_account: opt Account; initial_values: vec record {TextAccountIdentifier; Tokens}; max_message_size_bytes: opt nat64; transaction_window: opt Duration; @@ -278,6 +301,9 @@ type LedgerCanisterInitPayload = record { transfer_fee: opt Tokens; token_symbol: opt text; token_name: opt text; + feature_flags : opt FeatureFlags; + maximum_number_of_accounts : opt nat64; + accounts_overflow_trim_quantity: opt nat64; }; type Icrc1BlockIndex = nat; @@ -323,7 +349,83 @@ type Value = variant { Blob : blob; }; -service: (LedgerCanisterInitPayload) -> { +type UpgradeArgs = record { + maximum_number_of_accounts : opt nat64; + icrc1_minting_account : opt Account; + feature_flags : opt FeatureFlags; +}; + +type LedgerCanisterPayload = variant { + Init: InitArgs; + Upgrade: opt UpgradeArgs; +}; + +type ApproveArgs = record { + from_subaccount : opt SubAccount; + spender : Account; + amount : Icrc1Tokens; + expected_allowance : opt Icrc1Tokens; + expires_at : opt Icrc1Timestamp; + fee : opt Icrc1Tokens; + memo : opt blob; + created_at_time: opt Icrc1Timestamp; +}; + +type ApproveError = variant { + BadFee : record { expected_fee : Icrc1Tokens }; + InsufficientFunds : record { balance : Icrc1Tokens }; + AllowanceChanged : record { current_allowance : Icrc1Tokens }; + Expired : record { ledger_time : nat64 }; + TooOld; + CreatedInFuture : record { ledger_time : nat64 }; + Duplicate : record { duplicate_of : Icrc1BlockIndex }; + TemporarilyUnavailable; + GenericError : record { error_code : nat; message : text }; +}; + +type ApproveResult = variant { + Ok : Icrc1BlockIndex; + Err : ApproveError; +}; + +type AllowanceArgs = record { + account : Account; + spender : Account; +}; + +type Allowance = record { + allowance : Icrc1Tokens; + expires_at : opt Icrc1Timestamp; +}; + +type TransferFromArgs = record { + spender_subaccount : opt SubAccount; + from : Account; + to : Account; + amount : Icrc1Tokens; + fee : opt Icrc1Tokens; + memo : opt blob; + created_at_time: opt Icrc1Timestamp; +}; + +type TransferFromResult = variant { + Ok : Icrc1BlockIndex; + Err : TransferFromError; +}; + +type TransferFromError = variant { + BadFee : record { expected_fee : Icrc1Tokens }; + BadBurn : record { min_burn_amount : Icrc1Tokens }; + InsufficientFunds : record { balance : Icrc1Tokens }; + InsufficientAllowance : record { allowance : Icrc1Tokens }; + TooOld; + CreatedInFuture : record { ledger_time : Icrc1Timestamp }; + Duplicate : record { duplicate_of : Icrc1BlockIndex }; + TemporarilyUnavailable; + GenericError : record { error_code : nat; message : text }; +}; + +service: (LedgerCanisterPayload) -> { // Transfers tokens from a subaccount of the caller to the destination address. // The source address is computed from the principal of the caller and the specified subaccount. // When successful, returns the index of the block containing the transaction. @@ -332,12 +434,18 @@ service: (LedgerCanisterInitPayload) -> { // Returns the amount of Tokens on the specified account. account_balance : (AccountBalanceArgs) -> (Tokens) query; + // Returns the account identifier for the given Principal and subaccount. + account_identifier : (Account) -> (AccountIdentifier) query; + // Returns the current transfer_fee. transfer_fee : (TransferFeeArg) -> (TransferFee) query; // Queries blocks in the specified range. query_blocks : (GetBlocksArgs) -> (QueryBlocksResponse) query; + // Queries encoded blocks in the specified range + query_encoded_blocks : (GetBlocksArgs) -> (QueryEncodedBlocksResponse) query; + // Returns token symbol. symbol : () -> (record { symbol: text }) query; @@ -364,5 +472,8 @@ service: (LedgerCanisterInitPayload) -> { icrc1_minting_account : () -> (opt Account) query; icrc1_balance_of : (Account) -> (Icrc1Tokens) query; icrc1_transfer : (TransferArg) -> (Icrc1TransferResult); - icrc1_supported_standards : () -> (vec record { name : text; url : text }) query; + icrc1_supported_standards : () -> (vec record { name : text; url : text }) query; + icrc2_approve : (ApproveArgs) -> (ApproveResult); + icrc2_allowance : (AllowanceArgs) -> (Allowance) query; + icrc2_transfer_from : (TransferFromArgs) -> (TransferFromResult); } diff --git a/candid/registry.did b/candid/registry.did index 0d5aa827..f2fd1b6d 100644 --- a/candid/registry.did +++ b/candid/registry.did @@ -1,14 +1,10 @@ +type AddApiBoundaryNodePayload = record { node_id : principal; version : text }; type AddFirewallRulesPayload = record { expected_hash : text; scope : FirewallRulesScope; positions : vec int32; rules : vec FirewallRule; }; -type AddHostOsVersionPayload = record { - release_package_urls : vec text; - hostos_version_id : text; - release_package_sha256_hex : text; -}; type AddNodeOperatorPayload = record { ipv6 : opt text; node_operator_principal_id : opt principal; @@ -20,12 +16,15 @@ type AddNodeOperatorPayload = record { type AddNodePayload = record { prometheus_metrics_endpoint : text; http_endpoint : text; - idkg_dealing_encryption_pk : opt vec nat8; + idkg_dealing_encryption_pk : opt blob; + domain : opt text; + public_ipv4_config : opt IPv4Config; xnet_endpoint : text; - committee_signing_pk : vec nat8; - node_signing_pk : vec nat8; - transport_tls_cert : vec nat8; - ni_dkg_dealing_encryption_pk : vec nat8; + chip_id : opt blob; + committee_signing_pk : blob; + node_signing_pk : blob; + transport_tls_cert : blob; + ni_dkg_dealing_encryption_pk : blob; p2p_flow_endpoints : vec text; }; type AddNodesToSubnetPayload = record { @@ -131,13 +130,20 @@ type FirewallRulesScope = variant { Subnet : principal; Global; }; +type GetSubnetForCanisterRequest = record { "principal" : opt principal }; +type GetSubnetForCanisterResponse = record { subnet_id : opt principal }; type Gps = record { latitude : float32; longitude : float32 }; +type IPv4Config = record { + prefix_length : nat32; + gateway_ip_addr : text; + ip_addr : text; +}; type NodeOperatorRecord = record { ipv6 : opt text; - node_operator_principal_id : vec nat8; + node_operator_principal_id : blob; node_allowance : nat64; rewardable_nodes : vec record { text; nat32 }; - node_provider_principal_id : vec nat8; + node_provider_principal_id : blob; dc_id : text; }; type NodeProvidersMonthlyXdrRewards = record { @@ -159,9 +165,10 @@ type RecoverSubnetPayload = record { subnet_id : principal; registry_store_uri : opt record { text; text; nat64 }; ecdsa_config : opt EcdsaInitialConfig; - state_hash : vec nat8; + state_hash : blob; time_ns : nat64; }; +type RemoveApiBoundaryNodesPayload = record { node_ids : vec principal }; type RemoveFirewallRulesPayload = record { expected_hash : text; scope : FirewallRulesScope; @@ -169,7 +176,7 @@ type RemoveFirewallRulesPayload = record { }; type RemoveNodeDirectlyPayload = record { node_id : principal }; type RemoveNodeOperatorsPayload = record { - node_operators_to_remove : vec vec nat8; + node_operators_to_remove : vec blob; }; type RemoveNodesPayload = record { node_ids : vec principal }; type RerouteCanisterRangesPayload = record { @@ -184,26 +191,29 @@ type Result_2 = variant { Err : text; }; type Result_3 = variant { Ok : NodeProvidersMonthlyXdrRewards; Err : text }; +type Result_4 = variant { Ok : GetSubnetForCanisterResponse; Err : text }; type RetireReplicaVersionPayload = record { replica_version_ids : vec text }; type SetFirewallConfigPayload = record { ipv4_prefixes : vec text; firewall_config : text; ipv6_prefixes : vec text; }; -type SevFeatureStatus = variant { - SecureEnabled; - Disabled; - InsecureIntegrityEnabled; - SecureNoUpgradeEnabled; - InsecureEnabled; -}; type SubnetFeatures = record { canister_sandboxing : bool; - sev_status : opt SevFeatureStatus; http_requests : bool; - onchain_observability : opt bool; + sev_enabled : opt bool; }; type SubnetType = variant { application; verified_application; system }; +type UpdateApiBoundaryNodesVersionPayload = record { + version : text; + node_ids : vec principal; +}; +type UpdateElectedHostosVersionsPayload = record { + release_package_urls : vec text; + hostos_version_to_elect : opt text; + hostos_versions_to_unelect : vec text; + release_package_sha256_hex : opt text; +}; type UpdateElectedReplicaVersionsPayload = record { release_package_urls : vec text; replica_versions_to_unelect : vec text; @@ -212,7 +222,15 @@ type UpdateElectedReplicaVersionsPayload = record { release_package_sha256_hex : opt text; }; type UpdateNodeDirectlyPayload = record { - idkg_dealing_encryption_pk : opt vec nat8; + idkg_dealing_encryption_pk : opt blob; +}; +type UpdateNodeDomainDirectlyPayload = record { + node_id : principal; + domain : opt text; +}; +type UpdateNodeIPv4ConfigDirectlyPayload = record { + ipv4_config : opt IPv4Config; + node_id : principal; }; type UpdateNodeOperatorConfigDirectlyPayload = record { node_operator_id : opt principal; @@ -230,7 +248,7 @@ type UpdateNodeOperatorConfigPayload = record { type UpdateNodeRewardsTableProposalPayload = record { new_entries : vec record { text; NodeRewardRates }; }; -type UpdateNodesHostOsVersionPayload = record { +type UpdateNodesHostosVersionPayload = record { hostos_version_id : opt text; node_ids : vec principal; }; @@ -241,6 +259,7 @@ type UpdateSubnetPayload = record { features : opt SubnetFeatures; set_gossip_config_to_default : bool; max_instructions_per_message : opt nat64; + halt_at_cup_height : opt bool; pfn_evaluation_period_ms : opt nat32; subnet_id : principal; max_ingress_bytes_per_message : opt nat64; @@ -275,8 +294,8 @@ type UpdateUnassignedNodesConfigPayload = record { ssh_readonly_access : opt vec text; }; service : { + add_api_boundary_node : (AddApiBoundaryNodePayload) -> (); add_firewall_rules : (AddFirewallRulesPayload) -> (); - add_hostos_version : (AddHostOsVersionPayload) -> (); add_node : (AddNodePayload) -> (Result); add_node_operator : (AddNodeOperatorPayload) -> (); add_nodes_to_subnet : (AddNodesToSubnetPayload) -> (); @@ -292,8 +311,10 @@ service : { get_build_metadata : () -> (text) query; get_node_operators_and_dcs_of_node_provider : (principal) -> (Result_2) query; get_node_providers_monthly_xdr_rewards : () -> (Result_3) query; + get_subnet_for_canister : (GetSubnetForCanisterRequest) -> (Result_4) query; prepare_canister_migration : (PrepareCanisterMigrationPayload) -> (Result_1); recover_subnet : (RecoverSubnetPayload) -> (); + remove_api_boundary_nodes : (RemoveApiBoundaryNodesPayload) -> (); remove_firewall_rules : (RemoveFirewallRulesPayload) -> (); remove_node_directly : (RemoveNodeDirectlyPayload) -> (); remove_node_operators : (RemoveNodeOperatorsPayload) -> (); @@ -302,16 +323,24 @@ service : { reroute_canister_ranges : (RerouteCanisterRangesPayload) -> (Result_1); retire_replica_version : (RetireReplicaVersionPayload) -> (); set_firewall_config : (SetFirewallConfigPayload) -> (); + update_api_boundary_nodes_version : ( + UpdateApiBoundaryNodesVersionPayload, + ) -> (); + update_elected_hostos_versions : (UpdateElectedHostosVersionsPayload) -> (); update_elected_replica_versions : (UpdateElectedReplicaVersionsPayload) -> (); update_firewall_rules : (AddFirewallRulesPayload) -> (); update_node_directly : (UpdateNodeDirectlyPayload) -> (Result_1); + update_node_domain_directly : (UpdateNodeDomainDirectlyPayload) -> (Result_1); + update_node_ipv4_config_directly : (UpdateNodeIPv4ConfigDirectlyPayload) -> ( + Result_1, + ); update_node_operator_config : (UpdateNodeOperatorConfigPayload) -> (); update_node_operator_config_directly : ( UpdateNodeOperatorConfigDirectlyPayload, ) -> (); update_node_rewards_table : (UpdateNodeRewardsTableProposalPayload) -> (); - update_nodes_hostos_version : (UpdateNodesHostOsVersionPayload) -> (); + update_nodes_hostos_version : (UpdateNodesHostosVersionPayload) -> (); update_subnet : (UpdateSubnetPayload) -> (); update_subnet_replica_version : (UpdateSubnetReplicaVersionPayload) -> (); update_unassigned_nodes_config : (UpdateUnassignedNodesConfigPayload) -> (); -} +} \ No newline at end of file diff --git a/candid/sns-governance.did b/candid/sns-governance.did index 49074151..0fe231cb 100644 --- a/candid/sns-governance.did +++ b/candid/sns-governance.did @@ -16,6 +16,10 @@ type Action = variant { ManageLedgerParameters : ManageLedgerParameters; Motion : Motion; }; +type ActionAuxiliary = variant { + TransferSnsTreasuryFunds : MintSnsTokensActionAuxiliary; + MintSnsTokens : MintSnsTokensActionAuxiliary; +}; type AddNeuronPermissions = record { permissions_to_add : opt NeuronPermissionList; principal_id : opt principal; @@ -36,7 +40,7 @@ type CanisterStatusResultV2 = record { cycles : nat; settings : DefiniteCanisterSettingsArgs; idle_cycles_burned_per_day : nat; - module_hash : opt vec nat8; + module_hash : opt blob; }; type CanisterStatusType = variant { stopped; stopping; running }; type ChangeAutoStakeMaturity = record { @@ -97,6 +101,7 @@ type Command_2 = variant { Disburse : Disburse; }; type Configure = record { operation : opt Operation }; +type Decimal = record { human_readable : opt text }; type DefaultFollowees = record { followees : vec record { nat64; Followees } }; type DefiniteCanisterSettingsArgs = record { freezing_threshold : nat; @@ -130,7 +135,7 @@ type DissolveState = variant { }; type ExecuteGenericNervousSystemFunction = record { function_id : nat64; - payload : vec nat8; + payload : blob; }; type FinalizeDisburseMaturity = record { amount_to_be_disbursed_e8s : nat64; @@ -227,7 +232,10 @@ type ListProposals = record { exclude_type : vec nat64; include_status : vec int32; }; -type ListProposalsResponse = record { proposals : vec ProposalData }; +type ListProposalsResponse = record { + include_ballots_by_caller : opt bool; + proposals : vec ProposalData; +}; type ManageDappCanisterSettings = record { freezing_threshold : opt nat64; canister_ids : vec principal; @@ -237,7 +245,7 @@ type ManageDappCanisterSettings = record { compute_allocation : opt nat64; }; type ManageLedgerParameters = record { transfer_fee : opt nat64 }; -type ManageNeuron = record { subaccount : vec nat8; command : opt Command }; +type ManageNeuron = record { subaccount : blob; command : opt Command }; type ManageNeuronResponse = record { command : opt Command_1 }; type ManageSnsMetadata = record { url : opt text; @@ -261,6 +269,7 @@ type MintSnsTokens = record { memo : opt nat64; amount_e8s : opt nat64; }; +type MintSnsTokensActionAuxiliary = record { valuation : opt Valuation }; type Motion = record { motion_text : text }; type NervousSystemFunction = record { id : nat64; @@ -307,7 +316,7 @@ type Neuron = record { followees : vec record { nat64; Followees }; neuron_fees_e8s : nat64; }; -type NeuronId = record { id : vec nat8 }; +type NeuronId = record { id : blob }; type NeuronInFlightCommand = record { command : opt Command_2; timestamp : nat64; @@ -345,6 +354,7 @@ type ProposalData = record { payload_text_rendering : opt text; action : nat64; failure_reason : opt GovernanceError; + action_auxiliary : opt ActionAuxiliary; ballots : vec record { text; Ballot }; minimum_yes_proportion_of_total : opt Percentage; reward_event_round : nat64; @@ -389,7 +399,7 @@ type StakeMaturityResponse = record { maturity_e8s : nat64; staked_maturity_e8s : nat64; }; -type Subaccount = record { subaccount : vec nat8 }; +type Subaccount = record { subaccount : blob }; type SwapNeuron = record { id : opt NeuronId; status : int32 }; type Tally = record { no : nat64; @@ -397,6 +407,7 @@ type Tally = record { total : nat64; timestamp_seconds : nat64; }; +type Tokens = record { e8s : opt nat64 }; type TransferSnsTreasuryFunds = record { from_treasury : int32; to_principal : opt principal; @@ -411,18 +422,29 @@ type UpgradeInProgress = record { target_version : opt Version; }; type UpgradeSnsControlledCanister = record { - new_canister_wasm : vec nat8; + new_canister_wasm : blob; mode : opt int32; canister_id : opt principal; - canister_upgrade_arg : opt vec nat8; + canister_upgrade_arg : opt blob; +}; +type Valuation = record { + token : opt int32; + account : opt Account; + valuation_factors : opt ValuationFactors; + timestamp_seconds : opt nat64; +}; +type ValuationFactors = record { + xdrs_per_icp : opt Decimal; + icps_per_token : opt Decimal; + tokens : opt Tokens; }; type Version = record { - archive_wasm_hash : vec nat8; - root_wasm_hash : vec nat8; - swap_wasm_hash : vec nat8; - ledger_wasm_hash : vec nat8; - governance_wasm_hash : vec nat8; - index_wasm_hash : vec nat8; + archive_wasm_hash : blob; + root_wasm_hash : blob; + swap_wasm_hash : blob; + ledger_wasm_hash : blob; + governance_wasm_hash : blob; + index_wasm_hash : blob; }; type VotingRewardsParameters = record { final_reward_rate_basis_points : opt nat64; diff --git a/candid/sns-root.did b/candid/sns-root.did index 3c6eb677..a3fa61ad 100644 --- a/candid/sns-root.did +++ b/candid/sns-root.did @@ -1,11 +1,12 @@ type CanisterCallError = record { code : opt int32; description : text }; type CanisterIdRecord = record { canister_id : principal }; +type CanisterInstallMode = variant { reinstall; upgrade; install }; type CanisterStatusResult = record { - controller : principal; status : CanisterStatusType; memory_size : nat; + cycles : nat; settings : DefiniteCanisterSettings; - module_hash : opt vec nat8; + module_hash : opt blob; }; type CanisterStatusResultV2 = record { status : CanisterStatusType; @@ -13,13 +14,22 @@ type CanisterStatusResultV2 = record { cycles : nat; settings : DefiniteCanisterSettingsArgs; idle_cycles_burned_per_day : nat; - module_hash : opt vec nat8; + module_hash : opt blob; }; type CanisterStatusType = variant { stopped; stopping; running }; type CanisterSummary = record { status : opt CanisterStatusResultV2; canister_id : opt principal; }; +type ChangeCanisterRequest = record { + arg : blob; + wasm_module : blob; + stop_before_installing : bool; + mode : CanisterInstallMode; + canister_id : principal; + memory_allocation : opt nat; + compute_allocation : opt nat; +}; type DefiniteCanisterSettings = record { controllers : vec principal }; type DefiniteCanisterSettingsArgs = record { freezing_threshold : nat; @@ -50,6 +60,15 @@ type ListSnsCanistersResponse = record { dapps : vec principal; archives : vec principal; }; +type ManageDappCanisterSettingsRequest = record { + freezing_threshold : opt nat64; + canister_ids : vec principal; + reserved_cycles_limit : opt nat64; + log_visibility : opt int32; + memory_allocation : opt nat64; + compute_allocation : opt nat64; +}; +type ManageDappCanisterSettingsResponse = record { failure_reason : opt text }; type RegisterDappCanisterRequest = record { canister_id : opt principal }; type RegisterDappCanistersRequest = record { canister_ids : vec principal }; type SetDappControllersRequest = record { @@ -69,14 +88,18 @@ type SnsRootCanister = record { }; service : (SnsRootCanister) -> { canister_status : (CanisterIdRecord) -> (CanisterStatusResult); + change_canister : (ChangeCanisterRequest) -> (); get_build_metadata : () -> (text) query; get_sns_canisters_summary : (GetSnsCanistersSummaryRequest) -> ( GetSnsCanistersSummaryResponse, ); list_sns_canisters : (record {}) -> (ListSnsCanistersResponse) query; + manage_dapp_canister_settings : (ManageDappCanisterSettingsRequest) -> ( + ManageDappCanisterSettingsResponse, + ); register_dapp_canister : (RegisterDappCanisterRequest) -> (record {}); register_dapp_canisters : (RegisterDappCanistersRequest) -> (record {}); set_dapp_controllers : (SetDappControllersRequest) -> ( SetDappControllersResponse, ); -} +} \ No newline at end of file diff --git a/candid/sns-swap.did b/candid/sns-swap.did index 52a0fa12..8b5ca1b9 100644 --- a/candid/sns-swap.did +++ b/candid/sns-swap.did @@ -1,26 +1,29 @@ -type BuyerState = record { icp : opt TransferableAmount }; +type BuyerState = record { + icp : opt TransferableAmount; + has_created_neuron_recipes : opt bool; +}; type CanisterCallError = record { code : opt int32; description : text }; type CanisterStatusResultV2 = record { - controller : principal; status : CanisterStatusType; - freezing_threshold : nat; - balance : vec record { vec nat8; nat }; memory_size : nat; cycles : nat; settings : DefiniteCanisterSettingsArgs; idle_cycles_burned_per_day : nat; - module_hash : opt vec nat8; + module_hash : opt blob; }; type CanisterStatusType = variant { stopped; stopping; running }; type CfInvestment = record { hotkey_principal : text; nns_neuron_id : nat64 }; -type CfNeuron = record { nns_neuron_id : nat64; amount_icp_e8s : nat64 }; +type CfNeuron = record { + has_created_neuron_recipes : opt bool; + nns_neuron_id : nat64; + amount_icp_e8s : nat64; +}; type CfParticipant = record { hotkey_principal : text; cf_neurons : vec CfNeuron; }; type Countries = record { iso_codes : vec text }; type DefiniteCanisterSettingsArgs = record { - controller : principal; freezing_threshold : nat; controllers : vec principal; memory_allocation : nat; @@ -30,6 +33,8 @@ type DerivedState = record { sns_tokens_per_icp : float32; buyer_total_icp_e8s : nat64; cf_participant_count : opt nat64; + neurons_fund_participation_icp_e8s : opt nat64; + direct_participation_icp_e8s : opt nat64; direct_participant_count : opt nat64; cf_neuron_count : opt nat64; }; @@ -41,6 +46,7 @@ type Err_2 = record { existing_ticket : opt Ticket; error_type : int32; }; +type Error = record { message : opt text }; type ErrorRefundIcpRequest = record { source_principal_id : opt principal }; type ErrorRefundIcpResponse = record { result : opt Result }; type FailedUpdate = record { @@ -49,13 +55,20 @@ type FailedUpdate = record { }; type FinalizeSwapResponse = record { set_dapp_controllers_call_result : opt SetDappControllersCallResult; + create_sns_neuron_recipes_result : opt SweepResult; settle_community_fund_participation_result : opt SettleCommunityFundParticipationResult; error_message : opt text; + settle_neurons_fund_participation_result : opt SettleNeuronsFundParticipationResult; set_mode_call_result : opt SetModeCallResult; sweep_icp_result : opt SweepResult; claim_neuron_result : opt SweepResult; sweep_sns_result : opt SweepResult; }; +type GetAutoFinalizationStatusResponse = record { + auto_finalize_swap_response : opt FinalizeSwapResponse; + has_auto_finalize_been_attempted : opt bool; + is_auto_finalize_enabled : opt bool; +}; type GetBuyerStateRequest = record { principal_id : opt principal }; type GetBuyerStateResponse = record { buyer_state : opt BuyerState }; type GetBuyersTotalResponse = record { buyers_total : nat64 }; @@ -63,6 +76,8 @@ type GetDerivedStateResponse = record { sns_tokens_per_icp : opt float64; buyer_total_icp_e8s : opt nat64; cf_participant_count : opt nat64; + neurons_fund_participation_icp_e8s : opt nat64; + direct_participation_icp_e8s : opt nat64; direct_participant_count : opt nat64; cf_neuron_count : opt nat64; }; @@ -70,23 +85,43 @@ type GetInitResponse = record { init : opt Init }; type GetLifecycleResponse = record { decentralization_sale_open_timestamp_seconds : opt nat64; lifecycle : opt int32; + decentralization_swap_termination_timestamp_seconds : opt nat64; }; type GetOpenTicketResponse = record { result : opt Result_1 }; type GetSaleParametersResponse = record { params : opt Params }; type GetStateResponse = record { swap : opt Swap; derived : opt DerivedState }; type GovernanceError = record { error_message : text; error_type : int32 }; -type Icrc1Account = record { owner : opt principal; subaccount : opt vec nat8 }; +type Icrc1Account = record { owner : opt principal; subaccount : opt blob }; +type IdealMatchedParticipationFunction = record { + serialized_representation : opt text; +}; type Init = record { + nns_proposal_id : opt nat64; sns_root_canister_id : text; + neurons_fund_participation : opt bool; + min_participant_icp_e8s : opt nat64; + neuron_basket_construction_parameters : opt NeuronBasketConstructionParameters; fallback_controller_principal_ids : vec text; + max_icp_e8s : opt nat64; neuron_minimum_stake_e8s : opt nat64; confirmation_text : opt text; + swap_start_timestamp_seconds : opt nat64; + swap_due_timestamp_seconds : opt nat64; + min_participants : opt nat32; + sns_token_e8s : opt nat64; nns_governance_canister_id : text; transaction_fee_e8s : opt nat64; icp_ledger_canister_id : text; sns_ledger_canister_id : text; + neurons_fund_participation_constraints : opt NeuronsFundParticipationConstraints; + neurons_fund_participants : opt NeuronsFundParticipants; + should_auto_finalize : opt bool; + max_participant_icp_e8s : opt nat64; sns_governance_canister_id : text; + min_direct_participation_icp_e8s : opt nat64; restricted_countries : opt Countries; + min_icp_e8s : opt nat64; + max_direct_participation_icp_e8s : opt nat64; }; type InvalidUserAmount = record { min_amount_icp_e8s_included : nat64; @@ -96,13 +131,17 @@ type Investor = variant { CommunityFund : CfInvestment; Direct : DirectInvestment; }; +type LinearScalingCoefficient = record { + slope_numerator : opt nat64; + intercept_icp_e8s : opt nat64; + from_direct_participation_icp_e8s : opt nat64; + slope_denominator : opt nat64; + to_direct_participation_icp_e8s : opt nat64; +}; type ListCommunityFundParticipantsRequest = record { offset : opt nat64; limit : opt nat32; }; -type ListCommunityFundParticipantsResponse = record { - cf_participants : vec CfParticipant; -}; type ListDirectParticipantsRequest = record { offset : opt nat32; limit : opt nat32; @@ -124,14 +163,25 @@ type NeuronBasketConstructionParameters = record { dissolve_delay_interval_seconds : nat64; count : nat64; }; -type NeuronId = record { id : vec nat8 }; +type NeuronId = record { id : blob }; +type NeuronsFundParticipants = record { cf_participants : vec CfParticipant }; +type NeuronsFundParticipationConstraints = record { + coefficient_intervals : vec LinearScalingCoefficient; + max_neurons_fund_participation_icp_e8s : opt nat64; + min_direct_participation_threshold_icp_e8s : opt nat64; + ideal_matched_participation_function : opt IdealMatchedParticipationFunction; +}; type NewSaleTicketRequest = record { - subaccount : opt vec nat8; + subaccount : opt blob; amount_icp_e8s : nat64; }; type NewSaleTicketResponse = record { result : opt Result_2 }; type Ok = record { block_height : opt nat64 }; -type Ok_1 = record { ticket : opt Ticket }; +type Ok_1 = record { + neurons_fund_participation_icp_e8s : opt nat64; + neurons_fund_neurons_count : opt nat64; +}; +type Ok_2 = record { ticket : opt Ticket }; type OpenRequest = record { cf_participants : vec CfParticipant; params : opt Params; @@ -146,7 +196,9 @@ type Params = record { sns_token_e8s : nat64; sale_delay_seconds : opt nat64; max_participant_icp_e8s : nat64; + min_direct_participation_icp_e8s : opt nat64; min_icp_e8s : nat64; + max_direct_participation_icp_e8s : opt nat64; }; type Participant = record { participation : opt BuyerState; @@ -157,7 +209,8 @@ type Possibility = variant { Err : CanisterCallError; }; type Possibility_1 = variant { Ok : Response; Err : CanisterCallError }; -type Possibility_2 = variant { Ok : record {}; Err : CanisterCallError }; +type Possibility_2 = variant { Ok : Ok_1; Err : Error }; +type Possibility_3 = variant { Ok : record {}; Err : CanisterCallError }; type RefreshBuyerTokensRequest = record { confirmation_text : opt text; buyer : text; @@ -168,14 +221,17 @@ type RefreshBuyerTokensResponse = record { }; type Response = record { governance_error : opt GovernanceError }; type Result = variant { Ok : Ok; Err : Err }; -type Result_1 = variant { Ok : Ok_1; Err : Err_1 }; -type Result_2 = variant { Ok : Ok_1; Err : Err_2 }; +type Result_1 = variant { Ok : Ok_2; Err : Err_1 }; +type Result_2 = variant { Ok : Ok_2; Err : Err_2 }; type SetDappControllersCallResult = record { possibility : opt Possibility }; type SetDappControllersResponse = record { failed_updates : vec FailedUpdate }; -type SetModeCallResult = record { possibility : opt Possibility_2 }; +type SetModeCallResult = record { possibility : opt Possibility_3 }; type SettleCommunityFundParticipationResult = record { possibility : opt Possibility_1; }; +type SettleNeuronsFundParticipationResult = record { + possibility : opt Possibility_2; +}; type SnsNeuronRecipe = record { sns : opt TransferableAmount; claimed_status : opt int32; @@ -183,15 +239,20 @@ type SnsNeuronRecipe = record { investor : opt Investor; }; type Swap = record { + auto_finalize_swap_response : opt FinalizeSwapResponse; neuron_recipes : vec SnsNeuronRecipe; next_ticket_id : opt nat64; decentralization_sale_open_timestamp_seconds : opt nat64; finalize_swap_in_progress : opt bool; cf_participants : vec CfParticipant; init : opt Init; + already_tried_to_auto_finalize : opt bool; + neurons_fund_participation_icp_e8s : opt nat64; purge_old_tickets_last_completion_timestamp_nanoseconds : opt nat64; + direct_participation_icp_e8s : opt nat64; lifecycle : int32; - purge_old_tickets_next_principal : opt vec nat8; + purge_old_tickets_next_principal : opt blob; + decentralization_swap_termination_timestamp_seconds : opt nat64; buyers : vec record { text; BuyerState }; params : opt Params; open_sns_token_swap_proposal_id : opt nat64; @@ -219,6 +280,9 @@ type TransferableAmount = record { service : (Init) -> { error_refund_icp : (ErrorRefundIcpRequest) -> (ErrorRefundIcpResponse); finalize_swap : (record {}) -> (FinalizeSwapResponse); + get_auto_finalization_status : (record {}) -> ( + GetAutoFinalizationStatusResponse, + ) query; get_buyer_state : (GetBuyerStateRequest) -> (GetBuyerStateResponse) query; get_buyers_total : (record {}) -> (GetBuyersTotalResponse); get_canister_status : (record {}) -> (CanisterStatusResultV2); @@ -229,7 +293,7 @@ service : (Init) -> { get_sale_parameters : (record {}) -> (GetSaleParametersResponse) query; get_state : (record {}) -> (GetStateResponse) query; list_community_fund_participants : (ListCommunityFundParticipantsRequest) -> ( - ListCommunityFundParticipantsResponse, + NeuronsFundParticipants, ) query; list_direct_participants : (ListDirectParticipantsRequest) -> ( ListDirectParticipantsResponse, @@ -238,10 +302,10 @@ service : (Init) -> { ListSnsNeuronRecipesResponse, ) query; new_sale_ticket : (NewSaleTicketRequest) -> (NewSaleTicketResponse); - notify_payment_failure : (record {}) -> (Ok_1); + notify_payment_failure : (record {}) -> (Ok_2); open : (OpenRequest) -> (record {}); refresh_buyer_tokens : (RefreshBuyerTokensRequest) -> ( RefreshBuyerTokensResponse, ); restore_dapp_controllers : (record {}) -> (SetDappControllersCallResult); -} +} \ No newline at end of file diff --git a/candid/snsw.did b/candid/snsw.did index f79431c8..4843b610 100644 --- a/candid/snsw.did +++ b/candid/snsw.did @@ -1,9 +1,26 @@ -type AddWasmRequest = record { hash : vec nat8; wasm : opt SnsWasm }; +type AddWasmRequest = record { hash : blob; wasm : opt SnsWasm }; type AddWasmResponse = record { result : opt Result }; type AirdropDistribution = record { airdrop_neurons : vec NeuronDistribution }; +type Canister = record { id : opt principal }; +type CfNeuron = record { + has_created_neuron_recipes : opt bool; + nns_neuron_id : nat64; + amount_icp_e8s : nat64; +}; +type CfParticipant = record { + hotkey_principal : text; + cf_neurons : vec CfNeuron; +}; type Countries = record { iso_codes : vec text }; +type DappCanisters = record { canisters : vec Canister }; +type DappCanistersTransferResult = record { + restored_dapp_canisters : vec Canister; + nns_controlled_dapp_canisters : vec Canister; + sns_controlled_dapp_canisters : vec Canister; +}; type DeployNewSnsRequest = record { sns_init_payload : opt SnsInitPayload }; type DeployNewSnsResponse = record { + dapp_canisters_transfer_result : opt DappCanistersTransferResult; subnet_id : opt principal; error : opt SnsWasmError; canisters : opt SnsCanisterIds; @@ -27,14 +44,25 @@ type FractionalDeveloperVotingPower = record { type GetAllowedPrincipalsResponse = record { allowed_principals : vec principal; }; +type GetDeployedSnsByProposalIdRequest = record { proposal_id : nat64 }; +type GetDeployedSnsByProposalIdResponse = record { + get_deployed_sns_by_proposal_id_result : opt GetDeployedSnsByProposalIdResult; +}; +type GetDeployedSnsByProposalIdResult = variant { + Error : SnsWasmError; + DeployedSns : DeployedSns; +}; type GetNextSnsVersionRequest = record { governance_canister_id : opt principal; current_version : opt SnsVersion; }; type GetNextSnsVersionResponse = record { next_version : opt SnsVersion }; type GetSnsSubnetIdsResponse = record { sns_subnet_ids : vec principal }; -type GetWasmRequest = record { hash : vec nat8 }; +type GetWasmRequest = record { hash : blob }; type GetWasmResponse = record { wasm : opt SnsWasm }; +type IdealMatchedParticipationFunction = record { + serialized_representation : opt text; +}; type InitialTokenDistribution = variant { FractionalDeveloperVotingPower : FractionalDeveloperVotingPower; }; @@ -43,6 +71,13 @@ type InsertUpgradePathEntriesRequest = record { sns_governance_canister_id : opt principal; }; type InsertUpgradePathEntriesResponse = record { error : opt SnsWasmError }; +type LinearScalingCoefficient = record { + slope_numerator : opt nat64; + intercept_icp_e8s : opt nat64; + from_direct_participation_icp_e8s : opt nat64; + slope_denominator : opt nat64; + to_direct_participation_icp_e8s : opt nat64; +}; type ListDeployedSnsesResponse = record { instances : vec DeployedSns }; type ListUpgradeStep = record { pretty_version : opt PrettySnsVersion; @@ -54,6 +89,10 @@ type ListUpgradeStepsRequest = record { sns_governance_canister_id : opt principal; }; type ListUpgradeStepsResponse = record { steps : vec ListUpgradeStep }; +type NeuronBasketConstructionParameters = record { + dissolve_delay_interval_seconds : nat64; + count : nat64; +}; type NeuronDistribution = record { controller : opt principal; dissolve_delay_seconds : nat64; @@ -61,6 +100,13 @@ type NeuronDistribution = record { stake_e8s : nat64; vesting_period_seconds : opt nat64; }; +type NeuronsFundParticipants = record { participants : vec CfParticipant }; +type NeuronsFundParticipationConstraints = record { + coefficient_intervals : vec LinearScalingCoefficient; + max_neurons_fund_participation_icp_e8s : opt nat64; + min_direct_participation_threshold_icp_e8s : opt nat64; + ideal_matched_participation_function : opt IdealMatchedParticipationFunction; +}; type PrettySnsVersion = record { archive_wasm_hash : text; root_wasm_hash : text; @@ -69,7 +115,7 @@ type PrettySnsVersion = record { governance_wasm_hash : text; index_wasm_hash : text; }; -type Result = variant { Error : SnsWasmError; Hash : vec nat8 }; +type Result = variant { Error : SnsWasmError; Hash : blob }; type SnsCanisterIds = record { root : opt principal; swap : opt principal; @@ -81,40 +127,56 @@ type SnsInitPayload = record { url : opt text; max_dissolve_delay_seconds : opt nat64; max_dissolve_delay_bonus_percentage : opt nat64; + nns_proposal_id : opt nat64; + neurons_fund_participation : opt bool; + min_participant_icp_e8s : opt nat64; + neuron_basket_construction_parameters : opt NeuronBasketConstructionParameters; fallback_controller_principal_ids : vec text; token_symbol : opt text; final_reward_rate_basis_points : opt nat64; + max_icp_e8s : opt nat64; neuron_minimum_stake_e8s : opt nat64; confirmation_text : opt text; logo : opt text; name : opt text; + swap_start_timestamp_seconds : opt nat64; + swap_due_timestamp_seconds : opt nat64; initial_voting_period_seconds : opt nat64; neuron_minimum_dissolve_delay_to_vote_seconds : opt nat64; description : opt text; max_neuron_age_seconds_for_age_bonus : opt nat64; + min_participants : opt nat64; initial_reward_rate_basis_points : opt nat64; wait_for_quiet_deadline_increase_seconds : opt nat64; transaction_fee_e8s : opt nat64; + dapp_canisters : opt DappCanisters; + neurons_fund_participation_constraints : opt NeuronsFundParticipationConstraints; + neurons_fund_participants : opt NeuronsFundParticipants; max_age_bonus_percentage : opt nat64; initial_token_distribution : opt InitialTokenDistribution; reward_rate_transition_duration_seconds : opt nat64; + token_logo : opt text; token_name : opt text; + max_participant_icp_e8s : opt nat64; + min_direct_participation_icp_e8s : opt nat64; proposal_reject_cost_e8s : opt nat64; restricted_countries : opt Countries; + min_icp_e8s : opt nat64; + max_direct_participation_icp_e8s : opt nat64; }; type SnsUpgrade = record { next_version : opt SnsVersion; current_version : opt SnsVersion; }; type SnsVersion = record { - archive_wasm_hash : vec nat8; - root_wasm_hash : vec nat8; - swap_wasm_hash : vec nat8; - ledger_wasm_hash : vec nat8; - governance_wasm_hash : vec nat8; - index_wasm_hash : vec nat8; -}; -type SnsWasm = record { wasm : vec nat8; canister_type : int32 }; + archive_wasm_hash : blob; + root_wasm_hash : blob; + swap_wasm_hash : blob; + ledger_wasm_hash : blob; + governance_wasm_hash : blob; + index_wasm_hash : blob; +}; +type SnsWasm = record { wasm : blob; canister_type : int32 }; type SnsWasmCanisterInitPayload = record { allowed_principals : vec principal; access_controls_enabled : bool; @@ -146,6 +208,9 @@ service : (SnsWasmCanisterInitPayload) -> { add_wasm : (AddWasmRequest) -> (AddWasmResponse); deploy_new_sns : (DeployNewSnsRequest) -> (DeployNewSnsResponse); get_allowed_principals : (record {}) -> (GetAllowedPrincipalsResponse) query; + get_deployed_sns_by_proposal_id : (GetDeployedSnsByProposalIdRequest) -> ( + GetDeployedSnsByProposalIdResponse, + ) query; get_latest_sns_version_pretty : (null) -> (vec record { text; text }) query; get_next_sns_version : (GetNextSnsVersionRequest) -> ( GetNextSnsVersionResponse, @@ -165,4 +230,4 @@ service : (SnsWasmCanisterInitPayload) -> { update_sns_subnet_list : (UpdateSnsSubnetListRequest) -> ( UpdateSnsSubnetListResponse, ); -} +} \ No newline at end of file diff --git a/e2e/tests-quill/create_neuron.bash b/e2e/tests-quill/create_neuron.bash index f369abe8..c8fa9e7c 100644 --- a/e2e/tests-quill/create_neuron.bash +++ b/e2e/tests-quill/create_neuron.bash @@ -11,7 +11,7 @@ teardown() { @test "basic create neuron" { #account is initialized with 10_000 tokens assert_command quill account-balance 345f723e9e619934daac6ae0f4be13a7b0ba57d6a608e511a00fd0ded5866752 --yes --insecure-local-dev-mode - assert_string_match '(record { e8s = 100_000_000_000_000_000 : nat64 })' + assert_string_match 'Balance: 1000000000.00000000 ICP' # stake 3 tokens assert_command bash -c "quill neuron-stake --amount 3 --name myneur --pem-file \"$PEM_LOCATION/identity.pem\" > stake.call" @@ -20,24 +20,23 @@ teardown() { assert_command echo "$SEND_OUTPUT" # replay the output so string matches work echo "$SEND_OUTPUT" assert_string_match "Method name: claim_or_refresh_neuron_from_account" - NEURON_ID="$(echo "$SEND_OUTPUT" | grep -E 'NeuronId' | sed 's/[^0-9]//g' | sed 's/64$//g')" + NEURON_ID="$(echo "$SEND_OUTPUT" | grep -E ' neuron ' | sed 's/[^0-9]//g')" echo "NEURON: $NEURON_ID" assert_string_match " - record { - result = opt variant { - NeuronId = record { id =" #fragment of a correct response +Successfully staked ICP in neuron " #fragment of a correct response # check that staking worked using get-neuron-info assert_command bash -c "quill get-neuron-info \"$NEURON_ID\" --yes --insecure-local-dev-mode" - assert_string_match 'stake_e8s = 300_000_000' + assert_string_match 'Total stake: 3.00000000 ICP' # increase dissolve delay by 6 months assert_command bash -c "quill neuron-manage --additional-dissolve-delay-seconds 15778800 --pem-file \"$PEM_LOCATION/identity.pem\" \"$NEURON_ID\" > more-delay.call" assert_file_not_empty more-delay.call - assert_command quill send more-delay.call --yes --insecure-local-dev-mode #provides no interesting output on succes. Command not failing is good enough here + assert_command quill send more-delay.call --yes --insecure-local-dev-mode + assert_string_match 'Neuron successfully configured' # check that increasing dissolve delay worked, this time using list-neurons assert_command bash -c "quill list-neurons --pem-file \"$PEM_LOCATION/identity.pem\" > neuron.call" assert_command quill send neuron.call --yes --insecure-local-dev-mode - assert_string_match "dissolve_delay_seconds = 15_778_800" + assert_string_match "Dissolve delay: 6 months" } diff --git a/src/commands/account_balance.rs b/src/commands/account_balance.rs index 53d58f38..a17dbbe3 100644 --- a/src/commands/account_balance.rs +++ b/src/commands/account_balance.rs @@ -1,5 +1,5 @@ use crate::{ - commands::send::submit_unsigned_ingress, + commands::{send::submit_unsigned_ingress, SendingOpts}, lib::{ get_account_id, ledger_canister_id, AnyhowResult, AuthInfo, ParsedNnsAccount, ROLE_ICRC1_LEDGER, ROLE_NNS_LEDGER, @@ -22,13 +22,8 @@ pub struct AccountBalanceOpts { #[clap(required_unless_present = "auth")] account_id: Option, - /// Skips confirmation and sends the message directly. - #[clap(long, short)] - yes: bool, - - /// Will display the query, but not send it. - #[clap(long)] - dry_run: bool, + #[clap(flatten)] + sending_opts: SendingOpts, } // We currently only support a subset of the functionality. @@ -50,8 +45,7 @@ pub async fn exec(auth: &AuthInfo, opts: AccountBalanceOpts, fetch_root_key: boo ROLE_NNS_LEDGER, "account_balance_dfx", args, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await @@ -63,8 +57,7 @@ pub async fn exec(auth: &AuthInfo, opts: AccountBalanceOpts, fetch_root_key: boo ROLE_ICRC1_LEDGER, "icrc1_balance_of", args, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await diff --git a/src/commands/ckbtc.rs b/src/commands/ckbtc.rs index 68587131..ba6852c5 100644 --- a/src/commands/ckbtc.rs +++ b/src/commands/ckbtc.rs @@ -1,10 +1,11 @@ use std::str::FromStr; use anyhow::bail; +use bigdecimal::{BigDecimal, Signed}; use candid::{Nat, Principal}; use clap::Subcommand; use icrc_ledger_types::icrc1::account::Account; -use rust_decimal::Decimal; +use num_bigint::Sign; use sha2::{Digest, Sha256}; use crate::lib::{ckbtc_minter_canister_id, AnyhowResult, AuthInfo}; @@ -66,15 +67,19 @@ pub struct Btc(pub Nat); impl FromStr for Btc { type Err = anyhow::Error; fn from_str(s: &str) -> Result { - let mut dec = Decimal::from_str(s)?; - if dec.scale() > 8 { + let dec = BigDecimal::from_str(s)?; + if dec.fractional_digit_count() > 8 { bail!("Bitcoin can only be specified to the 8th decimal."); } - if !dec.is_sign_positive() { + if !dec.is_positive() { bail!("Must specify a positive number"); } - dec.rescale(8); - Ok(Self((dec.mantissa() as u128).into())) + let dec = dec.with_scale(8); + let (mantissa, scale) = dec.into_bigint_and_exponent(); + let (sign, mantissa) = mantissa.into_parts(); + assert_eq!(scale, 8); + assert_eq!(sign, Sign::Plus); + Ok(Self(mantissa.into())) } } diff --git a/src/commands/ckbtc/balance.rs b/src/commands/ckbtc/balance.rs index 0cc7052b..030d12d1 100644 --- a/src/commands/ckbtc/balance.rs +++ b/src/commands/ckbtc/balance.rs @@ -2,7 +2,7 @@ use candid::Encode; use clap::Parser; use crate::{ - commands::{get_account, send::submit_unsigned_ingress}, + commands::{get_account, send::submit_unsigned_ingress, SendingOpts}, lib::{ ckbtc_canister_id, AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount, ROLE_ICRC1_LEDGER, @@ -22,13 +22,8 @@ pub struct BalanceOpts { #[clap(long)] of_subaccount: Option, - /// Skips confirmation and sends the message immediately. - #[clap(long, short)] - yes: bool, - - /// Will display the signed message, but not send it. - #[clap(long)] - dry_run: bool, + #[clap(flatten)] + sending_opts: SendingOpts, /// Uses ckTESTBTC instead of ckBTC. #[clap(long)] @@ -43,8 +38,7 @@ pub async fn exec(auth: &AuthInfo, opts: BalanceOpts, fetch_root_key: bool) -> A ROLE_ICRC1_LEDGER, "icrc1_balance_of", Encode!(&account)?, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await?; diff --git a/src/commands/ckbtc/retrieve_btc_status.rs b/src/commands/ckbtc/retrieve_btc_status.rs index fdcc068c..f98107b1 100644 --- a/src/commands/ckbtc/retrieve_btc_status.rs +++ b/src/commands/ckbtc/retrieve_btc_status.rs @@ -3,7 +3,7 @@ use clap::Parser; use ic_ckbtc_minter::queries::RetrieveBtcStatusRequest; use crate::{ - commands::send::submit_unsigned_ingress, + commands::{send::submit_unsigned_ingress, SendingOpts}, lib::{ckbtc_minter_canister_id, AnyhowResult, ROLE_CKBTC_MINTER}, }; @@ -14,12 +14,8 @@ use crate::{ pub struct RetrieveBtcStatusOpts { /// The block index to check. block_index: u64, - /// Will display the signed message, but not send it. - #[clap(long)] - dry_run: bool, - /// Skips confirmation and sends the message immediately. - #[clap(long, short)] - yes: bool, + #[clap(flatten)] + sending_opts: SendingOpts, /// Uses ckTESTBTC instead of ckBTC. #[clap(long)] testnet: bool, @@ -35,8 +31,7 @@ pub async fn exec(opts: RetrieveBtcStatusOpts, fetch_root_key: bool) -> AnyhowRe ROLE_CKBTC_MINTER, "retrieve_btc_status", Encode!(&args)?, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await?; diff --git a/src/commands/get_neuron_info.rs b/src/commands/get_neuron_info.rs index 37f9cd6d..cba85461 100644 --- a/src/commands/get_neuron_info.rs +++ b/src/commands/get_neuron_info.rs @@ -1,5 +1,5 @@ use crate::{ - commands::send::submit_unsigned_ingress, + commands::{send::submit_unsigned_ingress, SendingOpts}, lib::{governance_canister_id, AnyhowResult, ROLE_NNS_GOVERNANCE}, }; use candid::Encode; @@ -11,13 +11,8 @@ pub struct GetNeuronInfoOpts { /// The neuron identifier. pub ident: u64, - /// Skips confirmation and sends the message directly. - #[clap(long, short)] - yes: bool, - - /// Will display the query, but not send it. - #[clap(long)] - dry_run: bool, + #[clap(flatten)] + pub sending_opts: SendingOpts, } // We currently only support a subset of the functionality. @@ -29,8 +24,7 @@ pub async fn exec(opts: GetNeuronInfoOpts, fetch_root_key: bool) -> AnyhowResult ROLE_NNS_GOVERNANCE, "get_neuron_info", args, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await diff --git a/src/commands/get_proposal_info.rs b/src/commands/get_proposal_info.rs index b5a1596d..796a1fe3 100644 --- a/src/commands/get_proposal_info.rs +++ b/src/commands/get_proposal_info.rs @@ -1,5 +1,5 @@ use crate::{ - commands::send::submit_unsigned_ingress, + commands::{send::submit_unsigned_ingress, SendingOpts}, lib::{governance_canister_id, AnyhowResult, ROLE_NNS_GOVERNANCE}, }; use candid::Encode; @@ -10,13 +10,8 @@ pub struct GetProposalInfoOpts { /// The proposal identifier. pub ident: u64, - /// Skips confirmation and sends the message directly. - #[clap(long, short)] - yes: bool, - - /// Will display the query, but not send it. - #[clap(long)] - dry_run: bool, + #[clap(flatten)] + sending_opts: SendingOpts, } // We currently only support a subset of the functionality. @@ -28,8 +23,7 @@ pub async fn exec(opts: GetProposalInfoOpts, fetch_root_key: bool) -> AnyhowResu ROLE_NNS_GOVERNANCE, "get_proposal_info", args, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await diff --git a/src/commands/list_proposals.rs b/src/commands/list_proposals.rs index ab0ae2ff..67e728b7 100644 --- a/src/commands/list_proposals.rs +++ b/src/commands/list_proposals.rs @@ -1,5 +1,5 @@ use crate::{ - commands::send::submit_unsigned_ingress, + commands::{send::submit_unsigned_ingress, SendingOpts}, lib::{governance_canister_id, AnyhowResult, ROLE_NNS_GOVERNANCE}, }; use candid::Encode; @@ -13,13 +13,8 @@ pub struct ListProposalsOpts { #[clap(long)] pub limit: Option, - /// Skips confirmation and sends the message directly. - #[clap(long, short)] - yes: bool, - - /// Will display the query, but not send it. - #[clap(long)] - dry_run: bool, + #[clap(flatten)] + pub sending_opts: SendingOpts, } // We currently only support a subset of the functionality. @@ -39,8 +34,7 @@ pub async fn exec(opts: ListProposalsOpts, fetch_root_key: bool) -> AnyhowResult ROLE_NNS_GOVERNANCE, "list_proposals", args, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 9f38f933..b99b89e9 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -2,7 +2,7 @@ use crate::lib::{get_principal, AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount}; use anyhow::{bail, Context}; -use clap::Parser; +use clap::{Args, Parser}; use icrc_ledger_types::icrc1::account::Account; use std::io::{self, Write}; @@ -199,3 +199,18 @@ fn get_account( } Ok(account) } + +#[derive(Args)] +pub struct SendingOpts { + /// Skips confirmation and sends the message directly. + #[clap(long, short)] + yes: bool, + + /// Will display the query, but not send it. + #[clap(long)] + dry_run: bool, + + /// Always displays the response in IDL format. + #[clap(long)] + raw: bool, +} diff --git a/src/commands/request_status.rs b/src/commands/request_status.rs index 50034eb6..1c2cdfd4 100644 --- a/src/commands/request_status.rs +++ b/src/commands/request_status.rs @@ -1,7 +1,10 @@ use crate::lib::get_ic_url; -use crate::lib::{get_agent, get_idl_string, signing::RequestStatus, AnyhowResult, AuthInfo}; +use crate::lib::{ + display_response, get_agent, get_idl_string, signing::RequestStatus, AnyhowResult, AuthInfo, +}; use anyhow::{anyhow, Context}; use candid::Principal; +use ic_agent::agent::http_transport::ReqwestTransport; use ic_agent::agent::{ReplyResponse, RequestStatusResponse, Transport}; use ic_agent::AgentError::MessageError; use ic_agent::{AgentError, RequestId}; @@ -14,6 +17,7 @@ pub async fn submit( req: &RequestStatus, method_name: Option, role: &str, + raw: bool, fetch_root_key: bool, ) -> AnyhowResult { let canister_id = @@ -28,8 +32,7 @@ pub async fn submit( agent.set_transport(ProxySignTransport { req: req.clone(), http_transport: Arc::new( - ic_agent::agent::http_transport::reqwest_transport::ReqwestHttpReplicaV2Transport::create(get_ic_url()) - .context("Failed to create an agent")?, + ReqwestTransport::create(get_ic_url()).context("Failed to create an agent")?, ), }); let ReplyResponse { arg: blob } = async { @@ -37,7 +40,7 @@ pub async fn submit( match agent.request_status_raw(&request_id, canister_id).await? { RequestStatusResponse::Replied(reply) => return Ok(reply), RequestStatusResponse::Rejected(response) => { - return Err(anyhow!(AgentError::ReplicaError(response))) + return Err(anyhow!(AgentError::CertifiedReject(response))) } RequestStatusResponse::Unknown | RequestStatusResponse::Received @@ -55,13 +58,16 @@ pub async fn submit( } } .await?; - get_idl_string( - &blob, - canister_id, - role, - &method_name.unwrap_or_default(), - "rets", - ) + let method_str = method_name.unwrap_or_default(); + if raw { + get_idl_string(&blob, canister_id, role, &method_str, "rets") + } else { + display_response(&blob, canister_id, role, &method_str, "rets").or_else(|e| { + get_idl_string(&blob, canister_id, role, &method_str, "rets").map(|m| { + format!("Error pretty-printing response: {e}. Falling back to IDL display\n{m}",) + }) + }) + } .context("Invalid IDL blob.") } diff --git a/src/commands/send.rs b/src/commands/send.rs index 90e9b178..cfa94d68 100644 --- a/src/commands/send.rs +++ b/src/commands/send.rs @@ -8,15 +8,15 @@ use anyhow::{anyhow, bail, Context}; use candid::{CandidType, Principal}; use clap::Parser; use ic_agent::agent::Transport; -use ic_agent::{ - agent::http_transport::reqwest_transport::ReqwestHttpReplicaV2Transport, RequestId, -}; +use ic_agent::{agent::http_transport::ReqwestTransport, RequestId}; use icp_ledger::{Subaccount, Tokens}; use serde::{Deserialize, Serialize}; use std::io::IsTerminal; use std::path::PathBuf; use std::str::FromStr; +use super::SendingOpts; + #[derive( Serialize, Deserialize, @@ -54,13 +54,8 @@ pub struct SendOpts { /// Path to the signed message (`-` for stdin) file_name: Option, - /// Will display the signed message, but not send it. - #[clap(long)] - dry_run: bool, - - /// Skips confirmation and sends the message directly. - #[clap(long, short)] - yes: bool, + #[clap(flatten)] + sending_opts: SendingOpts, } #[tokio::main] @@ -94,8 +89,7 @@ pub async fn submit_unsigned_ingress( role: &str, method_name: &str, args: Vec, - yes: bool, - dry_run: bool, + sending_opts: SendingOpts, fetch_root_key: bool, ) -> AnyhowResult { let msg = crate::lib::signing::sign_ingress_with_request_status_query( @@ -109,8 +103,7 @@ pub async fn submit_unsigned_ingress( &msg, &SendOpts { file_name: None, - yes, - dry_run, + sending_opts, }, fetch_root_key, ) @@ -123,7 +116,7 @@ async fn submit_ingress_and_check_status( fetch_root_key: bool, ) -> AnyhowResult { send(&message.ingress, opts).await?; - if opts.dry_run { + if opts.sending_opts.dry_run { return Ok(()); } let (_, _, method_name, _, role) = &message.ingress.parse()?; @@ -131,12 +124,13 @@ async fn submit_ingress_and_check_status( &message.request_status, Some(method_name.to_string()), role, + opts.sending_opts.raw, fetch_root_key, ) .await { - Ok(result) => println!("{result}\n"), - Err(err) => println!("{err}\n"), + Ok(result) => println!("{}", result.trim()), + Err(err) => println!("{err}"), }; Ok(()) } @@ -152,11 +146,11 @@ async fn send(message: &Ingress, opts: &SendOpts) -> AnyhowResult { println!(" Method name: {method_name}"); println!(" Arguments: {args}"); - if opts.dry_run { + if opts.sending_opts.dry_run { return Ok(()); } - if message.call_type == "update" && !opts.yes { + if message.call_type == "update" && !opts.sending_opts.yes { if !std::io::stdin().is_terminal() { eprintln!("Cannot confirm y/n if the input is being piped."); eprintln!("To confirm sending this message, rerun `quill send` with the `-y` flag."); @@ -170,7 +164,7 @@ async fn send(message: &Ingress, opts: &SendOpts) -> AnyhowResult { } } - let transport = ReqwestHttpReplicaV2Transport::create(get_ic_url())?; + let transport = ReqwestTransport::create(get_ic_url())?; let content = hex::decode(&message.content)?; match message.call_type.as_str() { diff --git a/src/commands/sns/balance.rs b/src/commands/sns/balance.rs index 660b8d76..7055f17d 100644 --- a/src/commands/sns/balance.rs +++ b/src/commands/sns/balance.rs @@ -1,5 +1,5 @@ use crate::{ - commands::{get_account, send::submit_unsigned_ingress}, + commands::{get_account, send::submit_unsigned_ingress, SendingOpts}, lib::{AuthInfo, ParsedAccount, ParsedSubaccount, ROLE_ICRC1_LEDGER}, AnyhowResult, }; @@ -21,13 +21,8 @@ pub struct BalanceOpts { #[clap(long)] subaccount: Option, - /// Will display the query, but not send it. - #[clap(long)] - dry_run: bool, - - /// Skips confirmation and sends the message immediately. - #[clap(long, short)] - yes: bool, + #[clap(flatten)] + sending_opts: SendingOpts, } #[tokio::main] @@ -45,8 +40,7 @@ pub async fn exec( ROLE_ICRC1_LEDGER, "icrc1_balance_of", Encode!(&account)?, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await?; diff --git a/src/commands/sns/get_sale_participation.rs b/src/commands/sns/get_sale_participation.rs index c8672d3e..10c62eb7 100644 --- a/src/commands/sns/get_sale_participation.rs +++ b/src/commands/sns/get_sale_participation.rs @@ -3,7 +3,7 @@ use clap::Parser; use ic_sns_swap::pb::v1::GetBuyerStateRequest; use crate::{ - commands::{get_principal, send::submit_unsigned_ingress}, + commands::{get_principal, send::submit_unsigned_ingress, SendingOpts}, lib::{AnyhowResult, AuthInfo, ROLE_SNS_SWAP}, }; @@ -16,13 +16,8 @@ pub struct GetSaleParticipationOpts { #[clap(long, required_unless_present = "auth")] principal: Option, - /// Skips confirmation and sends the message immediately. - #[clap(long, short)] - yes: bool, - - /// Will display the message, but not send it. - #[clap(long)] - dry_run: bool, + #[clap(flatten)] + sending_opts: SendingOpts, } #[tokio::main] @@ -45,8 +40,7 @@ pub async fn exec( ROLE_SNS_SWAP, "get_buyer_state", Encode!(&message)?, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await?; diff --git a/src/commands/sns/list_deployed_snses.rs b/src/commands/sns/list_deployed_snses.rs index 4bd20827..21980f38 100644 --- a/src/commands/sns/list_deployed_snses.rs +++ b/src/commands/sns/list_deployed_snses.rs @@ -3,20 +3,15 @@ use clap::Parser; use ic_sns_wasm::pb::v1::ListDeployedSnsesRequest; use crate::{ - commands::send::submit_unsigned_ingress, + commands::{send::submit_unsigned_ingress, SendingOpts}, lib::{sns_wasm_canister_id, AnyhowResult, ROLE_SNS_WASM}, }; /// Lists all SNSes that have been deployed by the NNS. #[derive(Parser)] pub struct ListDeployedSnsesOpts { - /// Will display the query, but not send it. - #[clap(long)] - dry_run: bool, - - /// Skips confirmation and sends the message immediately. - #[clap(long, short)] - yes: bool, + #[clap(flatten)] + sending_opts: SendingOpts, } #[tokio::main] @@ -27,8 +22,7 @@ pub async fn exec(opts: ListDeployedSnsesOpts, fetch_root_key: bool) -> AnyhowRe ROLE_SNS_WASM, "list_deployed_snses", arg, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await?; diff --git a/src/commands/sns/status.rs b/src/commands/sns/status.rs index 48e1d211..5058946e 100644 --- a/src/commands/sns/status.rs +++ b/src/commands/sns/status.rs @@ -3,7 +3,7 @@ use clap::Parser; use ic_sns_root::GetSnsCanistersSummaryRequest; use crate::{ - commands::send::submit_unsigned_ingress, + commands::{send::submit_unsigned_ingress, SendingOpts}, lib::{AnyhowResult, ROLE_SNS_ROOT}, }; @@ -13,13 +13,8 @@ use super::SnsCanisterIds; /// cycle balance, memory size, daily cycle burn rate, and module hash, along with their principals. #[derive(Parser)] pub struct StatusOpts { - /// Will display the query, but not send it. - #[clap(long)] - dry_run: bool, - - /// Skips confirmation and sends the message immediately. - #[clap(long, short)] - yes: bool, + #[clap(flatten)] + sending_opts: SendingOpts, } #[tokio::main] @@ -33,8 +28,7 @@ pub async fn exec(ids: &SnsCanisterIds, opts: StatusOpts, fetch_root_key: bool) ROLE_SNS_ROOT, "get_sns_canisters_summary", arg, - opts.yes, - opts.dry_run, + opts.sending_opts, fetch_root_key, ) .await?; diff --git a/src/lib/format/ckbtc.rs b/src/lib/format/ckbtc.rs new file mode 100644 index 00000000..23b88c87 --- /dev/null +++ b/src/lib/format/ckbtc.rs @@ -0,0 +1,120 @@ +use candid::Decode; +use ic_ckbtc_minter::{ + state::{ReimbursementReason, RetrieveBtcStatus, RetrieveBtcStatusV2}, + updates::{ + retrieve_btc::{RetrieveBtcError, RetrieveBtcOk}, + update_balance::{UpdateBalanceError, UtxoStatus}, + }, +}; +use std::fmt::Write; + +use crate::lib::{e8s_to_tokens, AnyhowResult}; + +pub fn display_update_balance(blob: &[u8]) -> AnyhowResult { + let result = Decode!(blob, Result, UpdateBalanceError>)?; + let fmt = match result { + Ok(statuses) => { + let mut fmt = String::new(); + for status in statuses { + match status { + UtxoStatus::Minted { block_index, minted_amount, utxo } => writeln!(fmt, "{txid}({btc} BTC): Minted {ckbtc} ckBTC at block index {block_index}", txid = utxo.outpoint.txid, btc = e8s_to_tokens(utxo.value.into()), ckbtc = e8s_to_tokens(minted_amount.into()))?, + UtxoStatus::ValueTooSmall(utxo) => writeln!(fmt,"{txid}({btc} BTC): UTXO rejected: too small to cover KYT cost", txid = utxo.outpoint.txid, btc = e8s_to_tokens(utxo.value.into()))?, + UtxoStatus::Tainted(utxo) => writeln!(fmt, "{txid}({btc} BTC): UTXO rejected: the KYT process determined the BTC is tainted", txid = utxo.outpoint.txid, btc = e8s_to_tokens(utxo.value.into()))?, + UtxoStatus::Checked(utxo) => writeln!(fmt, "{txid}({btc} BTC): The deposted BTC cleared the KYT check, but minting ckBTC failed. Retry this command.", txid = utxo.outpoint.txid, btc = e8s_to_tokens(utxo.value.into()))?, + } + } + fmt + } + Err(e) => match e { + UpdateBalanceError::GenericError { error_message, .. } => { + format!("ckBTC error: {error_message}") + } + UpdateBalanceError::AlreadyProcessing => { + "ckBTC error: already processing another update_balance call for the same account" + .to_string() + } + UpdateBalanceError::NoNewUtxos { + current_confirmations, + required_confirmations, + pending_utxos, + } => { + let mut fmt = "ckBTC error: no new confirmed UTXOs to process".to_string(); + if let Some(pending_utxos) = pending_utxos { + write!( + fmt, + " ({} unconfirmed, needing {} confirmations but having {})", + pending_utxos.len(), + required_confirmations, + current_confirmations.unwrap_or_default() + )?; + } + fmt + } + UpdateBalanceError::TemporarilyUnavailable(e) => { + format!("ckBTC error: temporarily unavailable: {e}. Try again later.") + } + }, + }; + Ok(fmt) +} + +pub fn display_retrieve_btc(blob: &[u8]) -> AnyhowResult { + let result = Decode!(blob, Result)?; + let fmt = match result { + Ok(ok) => format!("Begun retrieval process at block index {}", ok.block_index), + Err(e) => match e { + RetrieveBtcError::GenericError { error_message, .. } => { + format!("ckBTC error: {error_message}") + } + RetrieveBtcError::AmountTooLow(min) => format!( + "ckBTC error: amount too low to withdraw (min: {})", + e8s_to_tokens(min.into()) + ), + RetrieveBtcError::InsufficientFunds { balance } => format!( + "ckBTC error: the withdrawal account does not have enough ckBTC (balance: {})", + e8s_to_tokens(balance.into()) + ), + RetrieveBtcError::MalformedAddress(msg) => { + format!("ckBTC error: malformed address: {msg}") + } + RetrieveBtcError::AlreadyProcessing => { + "ckBTC error: already processing another retrieve_btc call for the same account" + .to_string() + } + RetrieveBtcError::TemporarilyUnavailable(msg) => { + format!("ckBTC error: temporarily unavailable: {msg}") + } + }, + }; + Ok(fmt) +} + +pub fn display_retrieve_btc_status(blob: &[u8]) -> AnyhowResult { + let status = Decode!(blob, RetrieveBtcStatus)?; + Ok(display_retrieve_btc_status_internal(status.into())) +} + +pub fn display_retrieve_btc_status_v2(blob: &[u8]) -> AnyhowResult { + let status = Decode!(blob, RetrieveBtcStatusV2)?; + Ok(display_retrieve_btc_status_internal(status)) +} + +fn display_retrieve_btc_status_internal(status: RetrieveBtcStatusV2) -> String { + match status { + RetrieveBtcStatusV2::AmountTooLow => "ckBTC error: amount too low to withdraw".to_string(), + RetrieveBtcStatusV2::Unknown => "ckBTC error: request ID invalid or too old".to_string(), + RetrieveBtcStatusV2::Pending => "The BTC transaction is pending in the queue".to_string(), + RetrieveBtcStatusV2::Signing => "The BTC transaction is being signed".to_string(), + RetrieveBtcStatusV2::Sending { txid } => format!("The BTC transaction is being sent (id {txid})"), + RetrieveBtcStatusV2::Submitted { txid } => format!("The BTC transaction has been sent, awaiting confirmations (id {txid})"), + RetrieveBtcStatusV2::Confirmed { txid } => format!("The BTC transaction has been completed (id {txid})"), + RetrieveBtcStatusV2::WillReimburse(task) => match task.reason { + ReimbursementReason::CallFailed => format!("The BTC transaction failed. {amount} ckBTC is being reimbursed to {account}", amount = e8s_to_tokens(task.amount.into()), account = task.account), + ReimbursementReason::TaintedDestination { kyt_provider, kyt_fee } => format!("The KYT process determined that the BTC destination is tainted. {amount} ckBTC is being reimbursed to {account}\nKYT fee: {fee}, provider: {kyt_provider}", amount = e8s_to_tokens(task.amount.into()), fee = e8s_to_tokens(kyt_fee.into()), account = task.account) + } + RetrieveBtcStatusV2::Reimbursed(reimbursed) => match reimbursed.reason { + ReimbursementReason::CallFailed => format!("The BTC transaction failed. {amount} ckBTC has been reimbursed to {account} at block index {index}", amount = reimbursed.amount, account = reimbursed.account, index = reimbursed.mint_block_index), + ReimbursementReason::TaintedDestination { kyt_provider, kyt_fee } => format!("The KYT process determined that the BTC destination is tainted. {amount} ckBTC has been reimbursed to {account} at block index {index}\nKYT fee: {fee}, provider: {kyt_provider}", amount = e8s_to_tokens(reimbursed.amount.into()), account = reimbursed.account, index = reimbursed.mint_block_index, fee = e8s_to_tokens(kyt_fee.into())) + } + } +} diff --git a/src/lib/format/gtc.rs b/src/lib/format/gtc.rs new file mode 100644 index 00000000..c5352599 --- /dev/null +++ b/src/lib/format/gtc.rs @@ -0,0 +1,17 @@ +use candid::Decode; +use ic_nns_common::pb::v1::NeuronId; +use itertools::Itertools; + +use crate::lib::AnyhowResult; + +pub fn format_claim_neurons(blob: &[u8]) -> AnyhowResult { + let result = Decode!(blob, Result, String>)?; + let fmt = match result { + Ok(ids) => format!( + "Claimed neurons {}", + ids.iter().map(|id| id.id).format(", ") + ), + Err(e) => format!("NNS error: {e}"), + }; + Ok(fmt) +} diff --git a/src/lib/format/icp_ledger.rs b/src/lib/format/icp_ledger.rs new file mode 100644 index 00000000..57e0a5ed --- /dev/null +++ b/src/lib/format/icp_ledger.rs @@ -0,0 +1,25 @@ +use candid::Decode; +use icp_ledger::{Tokens, TransferError}; + +use crate::lib::{e8s_to_tokens, AnyhowResult}; + +pub fn display_transfer(blob: &[u8]) -> AnyhowResult { + let result = Decode!(blob, Result)?; + match result { + Ok(index) => Ok(format!("Transfer sent at block index {index}")), + Err(e) => Ok(format!("Transfer error: {e}")), + } +} + +pub fn display_send_dfx(blob: &[u8]) -> AnyhowResult { + let index = Decode!(blob, u64)?; + Ok(format!("Transfer sent at block index {index}")) +} + +pub fn display_account_balance_or_dfx(blob: &[u8]) -> AnyhowResult { + let tokens = Decode!(blob, Tokens)?; + Ok(format!( + "Balance: {} ICP", + e8s_to_tokens(tokens.get_e8s().into()) + )) +} diff --git a/src/lib/format/icrc1.rs b/src/lib/format/icrc1.rs new file mode 100644 index 00000000..18e912c0 --- /dev/null +++ b/src/lib/format/icrc1.rs @@ -0,0 +1,17 @@ +use candid::{Decode, Nat}; +use icrc_ledger_types::icrc1::transfer::TransferError; + +use crate::lib::{e8s_to_tokens, AnyhowResult}; + +pub fn display_transfer(blob: &[u8]) -> AnyhowResult { + let result = Decode!(blob, Result)?; + match result { + Ok(index) => Ok(format!("Transfer sent at block index {index}")), + Err(e) => Ok(format!("Transfer error: {e}")), + } +} + +pub fn display_balance(blob: &[u8]) -> AnyhowResult { + let balance = Decode!(blob, Nat)?; + Ok(format!("Balance: {}", e8s_to_tokens(balance))) // we do not use any ICRC1 calls to ledgers with digits other than 8 +} diff --git a/src/lib/format/mod.rs b/src/lib/format/mod.rs new file mode 100644 index 00000000..33029630 --- /dev/null +++ b/src/lib/format/mod.rs @@ -0,0 +1,59 @@ +use chrono::{DateTime, TimeZone, Utc}; +use itertools::Itertools; + +pub mod ckbtc; +pub mod gtc; +pub mod icp_ledger; +pub mod icrc1; +pub mod nns_governance; +pub mod registry; + +pub fn format_datetime(datetime: DateTime) -> String { + format!("{} UTC", datetime.format("%b %d %Y %X")) +} + +pub fn format_timestamp_seconds(seconds: u64) -> String { + format_datetime(Utc.timestamp_opt(seconds.try_into().unwrap(), 0).unwrap()) +} + +pub fn format_duration_seconds(mut seconds: u64) -> String { + // Required for magic numbers like '8 years' to show up as such instead of '8 years 2 days'. + const SECONDS_PER_YEAR: u64 = 31557600; // 365.25 * 24 * 60 * 60 + const SECONDS_PER_MONTH: u64 = SECONDS_PER_YEAR / 12; + const SECONDS_PER_MINUTE: u64 = 60; + const SECONDS_PER_HOUR: u64 = SECONDS_PER_MINUTE * 60; + const SECONDS_PER_DAY: u64 = SECONDS_PER_HOUR * 24; + let years = seconds / SECONDS_PER_YEAR; + seconds %= SECONDS_PER_YEAR; + let months = seconds / SECONDS_PER_MONTH; + seconds %= SECONDS_PER_MONTH; + let days = seconds / SECONDS_PER_DAY; + seconds %= SECONDS_PER_DAY; + let hours = seconds / SECONDS_PER_HOUR; + seconds %= SECONDS_PER_HOUR; + let minutes = seconds / SECONDS_PER_MINUTE; + seconds %= SECONDS_PER_MINUTE; + [ + (years, "year"), + (months, "month"), + (days, "day"), + (hours, "hour"), + (minutes, "minute"), + (seconds, "second"), + ] + .iter() + .filter(|&&(n, _)| n != 0) + .format_with(", ", |&(n, t), f| { + f(&format_args!( + "{n} {t}{s}", + s = if n == 1 { "" } else { "s" } + )) + }) + .to_string() +} + +#[test] +fn magic_durations() { + assert_eq!(format_duration_seconds(15_778_800), "6 months"); + assert_eq!(format_duration_seconds(252_460_800), "8 years"); +} diff --git a/src/lib/format/nns_governance.rs b/src/lib/format/nns_governance.rs new file mode 100644 index 00000000..1e5fbfda --- /dev/null +++ b/src/lib/format/nns_governance.rs @@ -0,0 +1,840 @@ +use std::fmt::Write; + +use anyhow::{anyhow, bail, Context}; +use bigdecimal::BigDecimal; +use candid::Decode; +use chrono::Utc; +use ic_nns_governance::pb::v1::{ + add_or_remove_node_provider::Change, + claim_or_refresh_neuron_from_account_response::Result as ClaimResult, + manage_neuron::{configure::Operation, Command as ProposalCommand, NeuronIdOrSubaccount}, + manage_neuron_response::Command, + neuron::DissolveState, + proposal::Action, + reward_node_provider::{RewardMode, RewardToAccount}, + ClaimOrRefreshNeuronFromAccountResponse, GovernanceError, ListNeuronsResponse, + ListProposalInfoResponse, ManageNeuronResponse, NeuronInfo, ProposalInfo, Topic, +}; +use itertools::Itertools; + +use crate::lib::{ + e8s_to_tokens, + format::{format_duration_seconds, format_timestamp_seconds}, + get_default_role, get_idl_string, AnyhowResult, +}; + +pub fn display_get_neuron_info(blob: &[u8]) -> AnyhowResult { + let info = Decode!(blob, Result)?; + let fmt = match info { + Ok(info) => { + let mut fmt = format!( + "\ +Age: {age} +Total stake: {icp} ICP +Voting power: {power} +State: {state:?} +Dissolve delay: {delay} +Created {creation} +", + age = format_duration_seconds(info.age_seconds), + icp = e8s_to_tokens(info.stake_e8s.into()), + power = e8s_to_tokens(info.voting_power.into()), + state = info.state(), + delay = format_duration_seconds(info.dissolve_delay_seconds), + creation = format_timestamp_seconds(info.created_timestamp_seconds) + ); + if let Some(cf) = info.joined_community_fund_timestamp_seconds { + writeln!( + fmt, + "Member of the community fund since {}", + format_timestamp_seconds(cf) + )?; + } + if let Some(known) = info.known_neuron_data { + writeln!(fmt, "Known neuron: \"{}\"", known.name)?; + if let Some(desc) = known.description { + writeln!(fmt, "Description: \"{desc}\"")?; + } + } + write!( + fmt, + "Accurate as of {}", + format_timestamp_seconds(info.retrieved_at_timestamp_seconds) + )?; + fmt + } + Err(e) => display_governance_error(e), + }; + Ok(fmt) +} + +pub fn display_list_neurons(blob: &[u8]) -> AnyhowResult { + let now_seconds = u64::try_from(Utc::now().timestamp()).unwrap(); + let neurons = Decode!(blob, ListNeuronsResponse)?; + let mut fmt = String::new(); + for neuron in neurons.full_neurons { + let neuron_type = neuron.neuron_type(); + if let Some(id) = neuron.id { + writeln!(fmt, "Neuron {}", id.id)?; + } else { + writeln!(fmt, "Neuron (unknown id)")?; + } + if neuron.aging_since_timestamp_seconds != u64::MAX { + writeln!( + fmt, + "Aging since: {}", + format_duration_seconds(neuron.aging_since_timestamp_seconds) + )?; + } + + writeln!( + fmt, + "Staked ICP: {} ICP", + e8s_to_tokens(neuron.cached_neuron_stake_e8s.into()) + )?; + if let Some(staked_maturity) = neuron.staked_maturity_e8s_equivalent { + writeln!( + fmt, + "Staked maturity: {}", + e8s_to_tokens(staked_maturity.into()) + )?; + } + if neuron.auto_stake_maturity() { + writeln!(fmt, "Auto staking maturity: Yes")?; + } + if let Some(timestamp) = neuron.spawn_at_timestamp_seconds { + writeln!( + fmt, + "Spawning maturity as ICP at: {}", + format_timestamp_seconds(timestamp) + )?; + } + writeln!(fmt, "State: {:?}", neuron.state(now_seconds))?; + if let Some(state) = neuron.dissolve_state { + match state { + DissolveState::DissolveDelaySeconds(s) => { + writeln!(fmt, "Dissolve delay: {}", format_duration_seconds(s))? + } + DissolveState::WhenDissolvedTimestampSeconds(s) => { + writeln!(fmt, "Dissolve timestamp: {}", format_timestamp_seconds(s))? + } + } + } + writeln!( + fmt, + "Created {}", + format_timestamp_seconds(neuron.created_timestamp_seconds) + )?; + if let Some(cf) = neuron.joined_community_fund_timestamp_seconds { + writeln!( + fmt, + "Member of the community fund since {}", + format_timestamp_seconds(cf) + )?; + } + if let Some(known) = neuron.known_neuron_data { + writeln!(fmt, "Known neuron: \"{}\"", known.name)?; + if let Some(desc) = known.description { + writeln!(fmt, "Description: \"{desc}\"")?; + } + } + if let Some(controller) = neuron.controller { + writeln!(fmt, "Controller: {controller}")?; + } + if !neuron.hot_keys.is_empty() { + writeln!( + fmt, + "Hot keys: {}", + neuron.hot_keys.into_iter().format(", ") + )?; + } + if neuron.neuron_type.is_some() { + writeln!(fmt, "Neuron type: {:?}", neuron_type)?; + } + if neuron.kyc_verified { + writeln!(fmt, "KYC verified: Yes")?; + } + if neuron.not_for_profit { + writeln!(fmt, "Not-for-profit: Yes")?; + } + if !neuron.recent_ballots.is_empty() { + writeln!(fmt, "Recent votes: {}", neuron.recent_ballots.len())?; + } + if !neuron.followees.is_empty() { + if neuron.followees.len() < 4 { + writeln!( + fmt, + "Followees: {}", + neuron + .followees + .into_iter() + .format_with(", ", |(topic, followees), f| { + let topic = Topic::try_from(topic).unwrap_or(Topic::Unspecified); + if followees.followees.len() < 4 { + f(&format_args!( + "neurons {} ({topic:?})", + followees.followees.into_iter().map(|id| id.id).format(", ") + )) + } else { + f(&format_args!( + "{} followees ({topic:?})", + followees.followees.len(), + )) + } + }) + )?; + } else { + writeln!( + fmt, + "Followees: {}", + neuron + .followees + .into_iter() + .map(|followees| followees.1.followees.len()) + .sum::() + )?; + } + fmt.push('\n'); + } + } + Ok(fmt) +} + +pub fn display_manage_neuron(blob: &[u8]) -> AnyhowResult { + let response = Decode!(blob, ManageNeuronResponse)?; + let cmd = response.command.context("command was null")?; + let fmt = match cmd { + Command::Error(e) => display_governance_error(e), + Command::Configure(_) => "Neuron successfully configured".to_string(), + Command::RegisterVote(_) => "Successfully voted".to_string(), + Command::Follow(_) => "Successfully set following relationship".to_string(), + Command::Spawn(c) => { + if let Some(id) = c.created_neuron_id { + format!("Maturity successfully spawned to new neuron {}", id.id) + } else { + "Maturity successfully spawned to unknown new neuron".to_string() + } + } + Command::Split(c) => { + if let Some(id) = c.created_neuron_id { + format!("Neuron successfully split off to new neuron {}", id.id) + } else { + "Neuron successfully split off to unknown new neuron".to_string() + } + } + Command::ClaimOrRefresh(c) => { + if let Some(id) = c.refreshed_neuron_id { + format!("Successfully updated the stake of neuron {}", id.id) + } else { + "Successfully updated the stake of unknown neuron".to_string() + } + } + Command::Merge(c) => { + let mut fmt = "Successfully merged ".to_string(); + if let Some(source) = c.source_neuron { + if let Some(id) = source.id { + write!(fmt, "neuron {}", id.id)?; + } else { + write!(fmt, "neuron with account {}", hex::encode(source.account))?; + } + } else { + write!(fmt, "unknown neuron")?; + } + write!(fmt, " into ")?; + if let Some(target) = c.target_neuron { + if let Some(id) = target.id { + write!(fmt, "neuron {}", id.id)?; + } else { + write!(fmt, "neuron with account {}", hex::encode(target.account))?; + } + } else { + write!(fmt, "unknown neuron")?; + } + fmt + } + Command::DisburseToNeuron(c) => { + if let Some(id) = c.created_neuron_id { + format!("Successfully disbursed into new neuron {}", id.id) + } else { + "Successfully disbursed into unknown new neuron".to_string() + } + } + Command::MakeProposal(c) => { + if let Some(id) = c.proposal_id { + format!("Successfully created new proposal with ID {id}\nhttps://dashboard.internetcomputer.org/proposal/{id}", id = id.id) + } else { + "Successfully created new proposal (unknown ID)".to_string() + } + } + Command::StakeMaturity(c) => format!( + "Successfully staked maturity ({staked} staked maturity total, {remaining} unstaked)", + staked = e8s_to_tokens(c.staked_maturity_e8s.into()), + remaining = e8s_to_tokens(c.maturity_e8s.into()), + ), + Command::MergeMaturity(c) => format!( + "Successfully merged {merged} maturity (total stake now {total})", + merged = e8s_to_tokens(c.merged_maturity_e8s.into()), + total = e8s_to_tokens(c.new_stake_e8s.into()) + ), + Command::Disburse(c) => format!( + "Successfully disbursed ICP at block index {}", + c.transfer_block_height + ), + }; + Ok(fmt) +} + +pub fn display_update_node_provider(blob: &[u8]) -> AnyhowResult { + let res = Decode!(blob, Result<(), GovernanceError>)?; + let fmt = match res { + Ok(()) => "Successfully updated node provider".to_string(), + Err(e) => display_governance_error(e), + }; + Ok(fmt) +} + +pub fn display_list_proposals(blob: &[u8]) -> AnyhowResult { + let response = Decode!(blob, ListProposalInfoResponse)?; + let mut fmt = String::new(); + for proposal_info in response.proposal_info { + write!(fmt, "{}\n\n", display_proposal_info(proposal_info)?)?; + } + Ok(fmt) +} + +pub fn display_get_proposal(blob: &[u8]) -> AnyhowResult { + let opt = Decode!(blob, Option)?; + let fmt = match opt { + Some(proposal) => display_proposal_info(proposal)?, + None => "No proposal with that ID was found.".to_string(), + }; + Ok(fmt) +} + +fn display_proposal_info(proposal_info: ProposalInfo) -> AnyhowResult { + let mut fmt = String::new(); + let topic = proposal_info.topic(); + let status = proposal_info.status(); + let reward_status = proposal_info.reward_status(); + if let Some(proposal) = proposal_info.proposal { + if let Some(title) = proposal.title { + writeln!(fmt, "\"{}\" ({:?})", title, topic)?; + } else { + writeln!(fmt, "Untitled proposal ({:?})", topic)?; + } + if !proposal.summary.is_empty() { + writeln!(fmt, "Summary: \"{}\"", proposal.summary)?; + } + if !proposal.url.is_empty() { + writeln!(fmt, "URL: {}", proposal.url)?; + } + if let Some(action) = proposal.action { + fmt.push_str("Proposed action: "); + match action { + Action::RegisterKnownNeuron(a) => { + fmt.push_str("Register known neuron"); + if let Some(id) = a.id { + write!(fmt, " {}", id.id)?; + } + if let Some(data) = a.known_neuron_data { + write!(fmt, " as {}.", data.name)?; + if let Some(desc) = data.description { + write!(fmt, " \"{desc}\"")?; + } + } + fmt.push('\n'); + } + Action::ApproveGenesisKyc(a) => writeln!( + fmt, + "Approve principals {} for Genesis KYC", + a.principals.iter().format(", ") + )?, + Action::AddOrRemoveNodeProvider(a) => { + let (change, provider) = + match a.change.context("node provider change was null")? { + Change::ToAdd(provider) => ("Add", provider), + Change::ToRemove(provider) => ("Remove", provider), + }; + write!(fmt, "{change} node provider")?; + if let Some(id) = provider.id { + write!(fmt, " {id}")?; + } + if let Some(reward) = provider.reward_account { + write!(fmt, " with reward account {}", hex::encode(reward.hash))?; + } + fmt.push('\n'); + } + Action::CreateServiceNervousSystem(_) + | Action::OpenSnsTokenSwap(_) + | Action::SetSnsTokenSwapOpenTimeWindow(_) => { + bail!("SNS proposals currently unsupported") //todo + } + Action::ExecuteNnsFunction(a) => { + let function = a.nns_function(); + writeln!(fmt, "Execute NNS function {:?}", function)?; + if a.payload.starts_with(b"DIDL") { + let (canister_id, method) = function + .canister_and_function() + .map_err(|e| anyhow!(e.error_message))?; + if let Ok(idl) = get_idl_string( + &a.payload, + canister_id.into(), + get_default_role(canister_id.into()).unwrap_or_default(), + method, + "args", + ) { + writeln!(fmt, "Payload: {idl}")?; + } else { + writeln!(fmt, "Payload: {}", hex::encode(a.payload))?; + } + } else { + writeln!(fmt, "Payload: {}", hex::encode(a.payload))?; + } + } + Action::Motion(a) => writeln!(fmt, "\"{}\" (motion)", a.motion_text)?, + Action::ManageNetworkEconomics(a) => { + writeln!(fmt, "Update network economics")?; + if a.max_proposals_to_keep_per_topic != 0 { + writeln!( + fmt, + "New maximum proposals to keep, per topic: {}", + a.max_proposals_to_keep_per_topic + )?; + } + if a.maximum_node_provider_rewards_e8s != 0 { + writeln!( + fmt, + "New maximum node provider reward: {} ICP", + e8s_to_tokens(a.maximum_node_provider_rewards_e8s.into()) + )?; + } + if a.minimum_icp_xdr_rate != 0 { + writeln!( + fmt, + "New minimum ICP/SDR conversion rate: 1 ICP <> {} XDR", + BigDecimal::new(a.minimum_icp_xdr_rate.into(), 2) + )?; + } + if a.neuron_management_fee_per_proposal_e8s != 0 { + writeln!( + fmt, + "New cost for making \"manage neuron\" proposals: {} ICP", + e8s_to_tokens(a.neuron_management_fee_per_proposal_e8s.into()) + )?; + } + if a.neuron_minimum_stake_e8s != 0 { + writeln!( + fmt, + "New minimum stake for neurons: {} ICP", + e8s_to_tokens(a.neuron_minimum_stake_e8s.into()) + )?; + } + if a.neuron_spawn_dissolve_delay_seconds != 0 { + writeln!( + fmt, + "New dissolve delay for spawned-maturity neurons: {}", + format_duration_seconds(a.neuron_spawn_dissolve_delay_seconds) + )?; + } + if a.transaction_fee_e8s != 0 { + writeln!( + fmt, + "New ICP transaction fee: {} ICP", + e8s_to_tokens(a.transaction_fee_e8s.into()) + )?; + } + if a.reject_cost_e8s != 0 { + writeln!( + fmt, + "New proposal rejection cost: {} ICP", + e8s_to_tokens(a.reject_cost_e8s.into()) + )?; + } + if let Some(extra) = a.neurons_fund_economics { + if let Some(max) = extra.maximum_icp_xdr_rate { + writeln!( + fmt, + "New maximum ICP/SDR conversion rate for the community fund: {}%", + BigDecimal::new(max.basis_points().into(), 2) + )?; + } + if let Some(min) = extra.minimum_icp_xdr_rate { + writeln!( + fmt, + "New minimum ICP/SDR conversion rate for the community fund: {}%", + BigDecimal::new(min.basis_points().into(), 2) + )?; + } + if let Some(max) = + extra.max_theoretical_neurons_fund_participation_amount_xdr + { + writeln!(fmt, "New maximum theoretical community fund participation amount: {} XDR", max.human_readable())?; + } + if let Some(extra) = extra.neurons_fund_matched_funding_curve_coefficients { + if let Some(threshold) = extra.contribution_threshold_xdr { + writeln!(fmt, "New SNS participation threshold to receive any community fund contributions: {} XDR", threshold.human_readable())?; + } + if let Some(milestone) = extra.one_third_participation_milestone_xdr { + writeln!(fmt, "New SNS participation milestone to receive 1/3 community fund contribution: {} XDR", milestone.human_readable())?; + } + if let Some(milestone) = extra.full_participation_milestone_xdr { + writeln!(fmt, "New SNS participation milestone to receive full community fund contribution: {} XDR", milestone.human_readable())?; + } + } + } + } + Action::RewardNodeProvider(a) => { + fmt.push_str("Reward node provider"); + if let Some(provider) = a.node_provider { + if let Some(id) = provider.id { + write!(fmt, " {id}")?; + } + if let Some(account) = provider.reward_account { + write!(fmt, " (reward account {})", hex::encode(account.hash))?; + } + } + write!(fmt, " with {} ICP", e8s_to_tokens(a.amount_e8s.into()))?; + match a.reward_mode { + Some(RewardMode::RewardToAccount(RewardToAccount { + to_account: Some(to), + })) => write!(fmt, " to account {}", hex::encode(to.hash))?, + Some(RewardMode::RewardToNeuron(n)) => write!( + fmt, + " to neuron with {} dissolve delay", + format_duration_seconds(n.dissolve_delay_seconds) + )?, + _ => {} + } + fmt.push('\n'); + } + Action::RewardNodeProviders(a) => { + if a.use_registry_derived_rewards() { + writeln!( + fmt, + "Reward node providers {}", + a.rewards + .into_iter() + .filter_map(|r| r.node_provider.and_then(|p| p.id)) + .format(", ") + )?; + } else { + fmt.push_str("Reward node providers\n"); + for reward in a.rewards { + if let Some(provider) = reward.node_provider { + if let Some(id) = provider.id { + write!(fmt, "{id}")?; + if let Some(account) = provider.reward_account { + write!( + fmt, + " (reward account {})", + hex::encode(account.hash) + )?; + } + write!( + fmt, + " with {} ICP", + e8s_to_tokens(reward.amount_e8s.into()) + )?; + match reward.reward_mode { + Some(RewardMode::RewardToAccount(RewardToAccount { + to_account: Some(to), + })) => write!(fmt, " to account {}", hex::encode(to.hash))?, + Some(RewardMode::RewardToNeuron(n)) => write!( + fmt, + " to neuron with {} dissolve delay", + format_duration_seconds(n.dissolve_delay_seconds) + )?, + _ => {} + } + fmt.push('\n'); + } + } + } + } + } + Action::SetDefaultFollowees(a) => { + if a.default_followees.len() == 1 { + let (topic, followees) = a.default_followees.into_iter().next().unwrap(); + writeln!( + fmt, + "Set default followees for {topic:?} to {followees}", + topic = Topic::try_from(topic).unwrap_or_default(), + followees = followees.followees.iter().map(|id| id.id).format(", ") + )?; + } else { + writeln!(fmt, "Set default followees")?; + for (topic, followees) in a.default_followees { + writeln!( + fmt, + "For {topic:?}: {followees}", + topic = Topic::try_from(topic).unwrap_or_default(), + followees = followees.followees.iter().map(|id| id.id).format(", ") + )?; + } + } + } + Action::ManageNeuron(a) => { + let neuron = a + .get_neuron_id_or_subaccount() + .map_err(|e| anyhow!(e.error_message))? + .context("neuron ID was null")?; + let neuron = display_neuron_id(neuron); + match a.command.context("command was null")? { + ProposalCommand::ClaimOrRefresh(_) => { + writeln!(fmt, "Refresh the stake of neuron {neuron}")?; + } + ProposalCommand::Disburse(c) => { + if let Some(amount) = c.amount { + write!( + fmt, + "Disburse {icp} ICP from neuron {neuron}", + icp = e8s_to_tokens(amount.e8s.into()) + )?; + } else { + write!(fmt, "Disburse neuron {neuron}")?; + } + if let Some(to) = c.to_account { + write!(fmt, " to account {}", hex::encode(to.hash))?; + } + fmt.push('\n'); + } + ProposalCommand::DisburseToNeuron(c) => { + write!( + fmt, + "Disburse {icp} ICP from neuron {neuron} to a new{verified} neuron", + icp = e8s_to_tokens(c.amount_e8s.into()), + verified = if c.kyc_verified { " KYC verified" } else { "" }, + )?; + if let Some(controller) = c.new_controller { + write!(fmt, " owned by {controller}")?; + } + writeln!( + fmt, + " with dissolve delay {}", + format_timestamp_seconds(c.dissolve_delay_seconds) + )?; + } + ProposalCommand::Follow(c) => { + writeln!(fmt, "Configure neuron {neuron} to follow {ids} for proposals of type {topic:?}", topic = c.topic(), ids = c.followees.iter().map(|id| id.id).format(", "))?; + } + ProposalCommand::MakeProposal(_) => { + bail!("nested proposals not supported") + } + ProposalCommand::Merge(c) => { + if let Some(source) = c.source_neuron_id { + writeln!( + fmt, + "Merge neuron {source} into neuron {neuron}", + source = source.id + )?; + } else { + writeln!(fmt, "Merge neuron {neuron}")?; + } + } + ProposalCommand::MergeMaturity(c) => writeln!( + fmt, + "Merge {percentage}% of maturity into the stake of neuron {neuron}", + percentage = c.percentage_to_merge + )?, + ProposalCommand::RegisterVote(c) => { + if let Some(proposal) = c.proposal { + writeln!( + fmt, + "Vote {yn:?} on proposal {proposal} from neuron {neuron}", + proposal = proposal.id, + yn = c.vote() + )? + } else { + writeln!(fmt, "Vote {yn:?} from neuron {neuron}", yn = c.vote())?; + } + } + ProposalCommand::Spawn(c) => { + if let Some(controller) = c.new_controller { + writeln!(fmt, "Spawn {percentage}% of the maturity of neuron {neuron} to {controller}", percentage = c.percentage_to_spawn())?; + } else { + writeln!(fmt, "Spawn {percentage}% of the maturity of neuron {neuron} to its owner", percentage = c.percentage_to_spawn())?; + } + } + ProposalCommand::Split(c) => writeln!( + fmt, + "Split off {icp} ICP from neuron {neuron} as a new neuron", + icp = e8s_to_tokens(c.amount_e8s.into()) + )?, + ProposalCommand::StakeMaturity(c) => writeln!( + fmt, + "Stake {percentage}% of the maturity of neuron {neuron}", + percentage = c.percentage_to_stake() + )?, + ProposalCommand::Configure(c) => { + match c.operation.context("operation was null")? { + Operation::AddHotKey(o) => { + if let Some(key) = o.new_hot_key { + writeln!(fmt, "Add hot key {key} to neuron {neuron}")? + } else { + writeln!(fmt, "Add hot key to neuron {neuron}")? + } + } + Operation::RemoveHotKey(o) => { + if let Some(key) = o.hot_key_to_remove { + writeln!(fmt, "Remove hot key {key} from neuron {neuron}")? + } else { + writeln!(fmt, "Remove hot key from neuron {neuron}")? + } + } + Operation::ChangeAutoStakeMaturity(o) => writeln!( + fmt, + "{op} auto-staking maturity for neuron {neuron}", + op = if o.requested_setting_for_auto_stake_maturity { + "Enable" + } else { + "Disable" + } + )?, + Operation::IncreaseDissolveDelay(o) => writeln!( + fmt, + "Increase dissolve delay for neuron {neuron} by {dur}", + dur = format_duration_seconds( + o.additional_dissolve_delay_seconds.into() + ) + )?, + Operation::SetDissolveTimestamp(o) => writeln!( + fmt, + "Set dissolve timestamp for neuron {neuron} to {time}", + time = format_timestamp_seconds(o.dissolve_timestamp_seconds) + )?, + Operation::JoinCommunityFund(_) => { + writeln!(fmt, "Add neuron {neuron} to the community fund")? + } + Operation::LeaveCommunityFund(_) => { + writeln!(fmt, "Remove neuron {neuron} from the community fund")? + } + Operation::StartDissolving(_) => { + writeln!(fmt, "Start dissolving neuron {neuron}")? + } + Operation::StopDissolving(_) => { + writeln!(fmt, "Stop dissolving neuron {neuron}")? + } + } + } + } + } + } + } + } else { + writeln!(fmt, "Unknown proposal ({:?})", proposal_info.topic())?; + } + if let Some(id) = proposal_info.id { + writeln!(fmt, "Proposal ID: {}", id.id)?; + } + if let Some(proposer) = proposal_info.proposer { + writeln!( + fmt, + "Created at {} by neuron {}", + format_timestamp_seconds(proposal_info.proposal_timestamp_seconds), + proposer.id, + )?; + } else { + writeln!( + fmt, + "Created at {}", + format_timestamp_seconds(proposal_info.proposal_timestamp_seconds) + )?; + } + writeln!(fmt, "Status: {status:?}, reward status: {reward_status:?}")?; + if let Some(reason) = proposal_info.failure_reason { + writeln!(fmt, "Failure reason: {}", reason.error_message)?; + } + if proposal_info.decided_timestamp_seconds != 0 { + writeln!( + fmt, + "Decided at {}", + format_timestamp_seconds(proposal_info.decided_timestamp_seconds) + )?; + } + if proposal_info.failed_timestamp_seconds != 0 { + writeln!( + fmt, + "Failed at {}", + format_timestamp_seconds(proposal_info.failed_timestamp_seconds) + )?; + } + if proposal_info.executed_timestamp_seconds != 0 { + writeln!( + fmt, + "Executed at {}", + format_timestamp_seconds(proposal_info.executed_timestamp_seconds) + )?; + } + if let Some(deadline) = proposal_info.deadline_timestamp_seconds { + writeln!(fmt, "Deadline: {}", format_timestamp_seconds(deadline))?; + } + if proposal_info.reject_cost_e8s != 0 { + writeln!( + fmt, + "Rejection cost: {} ICP", + e8s_to_tokens(proposal_info.reject_cost_e8s.into()) + )?; + } + if let Some(tally) = proposal_info.latest_tally { + let y = e8s_to_tokens(tally.yes.into()); + let n = e8s_to_tokens(tally.no.into()); + let total = e8s_to_tokens(tally.total.into()); + writeln!( + fmt, + "Current tally: Y {y} ({y_percent}%), N {n} ({n_percent}%) as of {timestamp}", + y_percent = (y.clone() / total.clone() * 100_u8).round(2), + n_percent = (n.clone() / total * 100_u8).round(2), + timestamp = format_timestamp_seconds(tally.timestamp_seconds), + )?; + } + if proposal_info.reward_event_round != 0 { + writeln!( + fmt, + "Reward event round: {}", + proposal_info.reward_event_round + )?; + } + fmt.truncate(fmt.trim_end().len()); + Ok(fmt) +} + +pub fn display_neuron_ids(blob: &[u8]) -> AnyhowResult { + let ids = Decode!(blob, Vec)?; + let fmt = ids.into_iter().format(", "); + Ok(format!("Neurons: {fmt}")) +} + +pub fn display_claim_gtc_neurons(blob: &[u8]) -> AnyhowResult { + let res = Decode!(blob, Result<(), GovernanceError>)?; + let fmt = match res { + Ok(()) => "Successfully claimed Genesis neurons".to_string(), + Err(e) => display_governance_error(e), + }; + Ok(fmt) +} + +pub fn display_claim_or_refresh_neuron_from_account(blob: &[u8]) -> AnyhowResult { + let res = Decode!(blob, ClaimOrRefreshNeuronFromAccountResponse)?; + let fmt = if let Some(res) = res.result { + match res { + ClaimResult::NeuronId(id) => format!("Successfully staked ICP in neuron {}", id.id), + ClaimResult::Error(e) => display_governance_error(e), + } + } else { + "Unknown result of call".to_string() + }; + Ok(fmt) +} + +fn display_neuron_id(id: NeuronIdOrSubaccount) -> String { + match id { + NeuronIdOrSubaccount::NeuronId(i) => format!("{}", i.id), + NeuronIdOrSubaccount::Subaccount(s) => { + format!("with subaccount {}", hex::encode(s)) + } + } +} + +pub fn display_governance_error(err: GovernanceError) -> String { + format!("NNS error: {}", err.error_message) +} diff --git a/src/lib/format/registry.rs b/src/lib/format/registry.rs new file mode 100644 index 00000000..d89e4cf1 --- /dev/null +++ b/src/lib/format/registry.rs @@ -0,0 +1,8 @@ +use candid::Decode; + +use crate::lib::AnyhowResult; + +pub fn display_update_node_operator_config_directly(blob: &[u8]) -> AnyhowResult { + Decode!(blob, ())?; + Ok("Successfully updated node operator config".to_string()) +} diff --git a/src/lib/mod.rs b/src/lib/mod.rs index d9acb3f2..bab854bd 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -1,9 +1,10 @@ //! All the common functionality. use anyhow::{anyhow, bail, ensure, Context}; +use bigdecimal::BigDecimal; use bip32::DerivationPath; use bip39::{Mnemonic, Seed}; -use candid::{types::Function, Principal, TypeEnv}; +use candid::{types::Function, Nat, Principal, TypeEnv}; use candid_parser::{typing::check_prog, IDLProg}; use crc32fast::Hasher; use data_encoding::BASE32_NOPAD; @@ -46,6 +47,7 @@ pub fn get_ic_url() -> String { env::var("IC_URL").unwrap_or_else(|_| IC_URL.to_string()) } +pub mod format; #[cfg(feature = "ledger")] pub mod ledger; pub mod signing; @@ -210,7 +212,6 @@ Should be one of: }) } -/// Returns pretty-printed encoding of a candid value. pub fn get_idl_string( blob: &[u8], canister_id: Principal, @@ -235,6 +236,63 @@ pub fn get_idl_string( Ok(format!("{}", result?)) } +/// Returns pretty-printed encoding of a candid value. +pub fn display_response( + blob: &[u8], + canister_id: Principal, + role: &str, + method_name: &str, + part: &str, +) -> AnyhowResult { + match role { + ROLE_NNS_GOVERNANCE => match method_name { + "get_neuron_info" => format::nns_governance::display_get_neuron_info(blob), + "manage_neuron" => format::nns_governance::display_manage_neuron(blob), + "get_neuron_ids" => format::nns_governance::display_neuron_ids(blob), + "update_node_provider" => format::nns_governance::display_update_node_provider(blob), + "list_proposals" => format::nns_governance::display_list_proposals(blob), + "list_neurons" => format::nns_governance::display_list_neurons(blob), + "get_proposal_info" => format::nns_governance::display_get_proposal(blob), + "claim_gtc_neurons" => format::nns_governance::display_claim_gtc_neurons(blob), + "claim_or_refresh_neuron_from_account" => { + format::nns_governance::display_claim_or_refresh_neuron_from_account(blob) + } + _ => get_idl_string(blob, canister_id, role, method_name, part), + }, + ROLE_NNS_LEDGER => match method_name { + "transfer" => format::icp_ledger::display_transfer(blob), + "send_dfx" => format::icp_ledger::display_send_dfx(blob), + "account_balance" | "account_balance_dfx" => { + format::icp_ledger::display_account_balance_or_dfx(blob) + } + _ => get_idl_string(blob, canister_id, role, method_name, part), + }, + ROLE_ICRC1_LEDGER => match method_name { + "icrc1_transfer" => format::icrc1::display_transfer(blob), + "icrc1_balance_of" => format::icrc1::display_balance(blob), + _ => get_idl_string(blob, canister_id, role, method_name, part), + }, + ROLE_CKBTC_MINTER => match method_name { + "update_balance" => format::ckbtc::display_update_balance(blob), + "retrieve_btc" => format::ckbtc::display_retrieve_btc(blob), + "retrieve_btc_status" => format::ckbtc::display_retrieve_btc_status(blob), + "retrieve_btc_status_v2" => format::ckbtc::display_retrieve_btc_status_v2(blob), + _ => get_idl_string(blob, canister_id, role, method_name, part), + }, + ROLE_NNS_GTC => match method_name { + "claim_neurons" => format::gtc::format_claim_neurons(blob), + _ => get_idl_string(blob, canister_id, role, method_name, part), + }, + ROLE_NNS_REGISTRY => match method_name { + "update_node_operator_config_directly" => { + format::registry::display_update_node_operator_config_directly(blob) + } + _ => get_idl_string(blob, canister_id, role, method_name, part), + }, + _ => get_idl_string(blob, canister_id, role, method_name, part), + } +} + /// Returns the candid type of a specifed method and correspondig idl /// description. pub fn get_candid_type(idl: &str, method_name: &str) -> Option<(TypeEnv, Function)> { @@ -265,11 +323,7 @@ pub fn read_from_file(path: impl AsRef) -> AnyhowResult { pub fn get_agent(auth: &AuthInfo) -> AnyhowResult { let timeout = Duration::from_secs(60 * 5); let builder = Agent::builder() - .with_transport( - ic_agent::agent::http_transport::reqwest_transport::ReqwestHttpReplicaV2Transport::create({ - get_ic_url() - })?, - ) + .with_url(get_ic_url()) .with_ingress_expiry(Some(timeout)); let identity = get_identity(auth)?; @@ -586,6 +640,10 @@ pub fn now_nanos() -> u64 { } } +pub fn e8s_to_tokens(e8s: Nat) -> BigDecimal { + BigDecimal::new(e8s.0.into(), 8) +} + #[cfg(test)] mod tests { use super::{ParsedAccount, ParsedSubaccount};