From 3eef801cdd7e659840583042a95f9c0340246fbb Mon Sep 17 00:00:00 2001 From: Adam Spofford Date: Fri, 3 Feb 2023 15:25:12 -0800 Subject: [PATCH 1/3] Migrate SNS commands --- CHANGELOG.md | 1 + Cargo.lock | 242 +++++----- Cargo.toml | 23 +- candid/ckbtc_minter.did | 19 +- candid/governance.did | 21 +- candid/ledger.did | 1 + candid/sns-governance.did | 418 ++++++++++++++++++ candid/sns-root.did | 85 ++++ candid/sns-swap.did | 150 +++++++ candid/snsw.did | 166 +++++++ docs/cli-reference/ckbtc/quill-ckbtc.md | 4 +- docs/cli-reference/index.md | 14 + docs/cli-reference/quill-account-balance.md | 14 +- docs/cli-reference/sns/quill-sns-balance.md | 32 ++ .../sns/quill-sns-configure-dissolve-delay.md | 38 ++ .../sns/quill-sns-get-swap-refund.md | 27 ++ .../sns/quill-sns-list-deployed-snses.md | 19 + .../sns/quill-sns-make-proposal.md | 43 ++ ...uill-sns-make-upgrade-canister-proposal.md | 38 ++ .../sns/quill-sns-neuron-permission.md | 50 +++ .../sns/quill-sns-register-vote.md | 30 ++ .../sns/quill-sns-stake-maturity.md | 31 ++ .../sns/quill-sns-stake-neuron.md | 37 ++ docs/cli-reference/sns/quill-sns-status.md | 19 + docs/cli-reference/sns/quill-sns-swap.md | 31 ++ docs/cli-reference/sns/quill-sns-transfer.md | 39 ++ docs/cli-reference/sns/quill-sns.md | 24 + src/commands/account_balance.rs | 4 +- src/commands/ckbtc.rs | 45 +- src/commands/ckbtc/balance.rs | 6 +- src/commands/ckbtc/retrieve_btc.rs | 4 +- src/commands/ckbtc/retrieve_btc_status.rs | 3 +- src/commands/ckbtc/transfer.rs | 3 +- src/commands/ckbtc/update_balance.rs | 3 +- src/commands/claim_neurons.rs | 3 +- src/commands/get_neuron_info.rs | 4 +- src/commands/get_proposal_info.rs | 4 +- src/commands/list_neurons.rs | 3 +- src/commands/list_proposals.rs | 4 +- src/commands/mod.rs | 101 ++--- src/commands/neuron_manage.rs | 3 +- src/commands/neuron_stake.rs | 22 +- src/commands/replace_node_provide_id.rs | 3 +- src/commands/request_status.rs | 11 +- src/commands/send.rs | 9 +- src/commands/sns.rs | 146 ++++++ src/commands/sns/balance.rs | 67 +++ src/commands/sns/configure_dissolve_delay.rs | 121 +++++ src/commands/sns/get_swap_refund.rs | 47 ++ src/commands/sns/list_deployed_snses.rs | 36 ++ src/commands/sns/make_proposal.rs | 91 ++++ .../sns/make_upgrade_canister_proposal.rs | 135 ++++++ src/commands/sns/neuron_permission.rs | 81 ++++ src/commands/sns/register_vote.rs | 70 +++ src/commands/sns/stake_maturity.rs | 53 +++ src/commands/sns/stake_neuron.rs | 116 +++++ src/commands/sns/status.rs | 42 ++ src/commands/sns/swap.rs | 74 ++++ src/commands/sns/transfer.rs | 73 +++ src/commands/transfer.rs | 49 +- src/commands/update_node_provider.rs | 3 +- src/lib/mod.rs | 73 ++- src/lib/signing.rs | 18 +- src/main.rs | 50 +-- tests/commands/sns-balance.sh | 2 + ...ns-configure-dissolve-delay-add-seconds.sh | 2 + ...nfigure-dissolve-delay-start-dissolving.sh | 2 + ...onfigure-dissolve-delay-stop-dissolving.sh | 2 + tests/commands/sns-list-deployed-snses.sh | 1 + tests/commands/sns-make-proposal.sh | 4 + .../sns-make-upgrade-canister-proposal.sh | 11 + tests/commands/sns-neuron-permission-add.sh | 2 + .../commands/sns-neuron-permission-remove.sh | 2 + tests/commands/sns-neuron-stake-maturity.sh | 2 + tests/commands/sns-neuron-stake-memo.sh | 1 + tests/commands/sns-neuron-stake-no-amount.sh | 1 + tests/commands/sns-refund.sh | 1 + tests/commands/sns-register-vote-no.sh | 3 + tests/commands/sns-register-vote-yes.sh | 3 + tests/commands/sns-status.sh | 1 + tests/commands/sns-swap.sh | 1 + .../sns-transfer-with-fees-and-memo.sh | 2 + tests/commands/sns-transfer.sh | 2 + tests/outputs/sns-balance.txt | 12 + ...s-configure-dissolve-delay-add-seconds.txt | 20 + ...figure-dissolve-delay-start-dissolving.txt | 16 + ...nfigure-dissolve-delay-stop-dissolving.txt | 16 + tests/outputs/sns-list-deployed-snses.txt | 7 + tests/outputs/sns-make-proposal.txt | 23 + .../sns-make-upgrade-canister-proposal.txt | 25 ++ tests/outputs/sns-neuron-permission-add.txt | 19 + .../outputs/sns-neuron-permission-remove.txt | 19 + tests/outputs/sns-neuron-stake-maturity.txt | 14 + tests/outputs/sns-neuron-stake-memo.txt | 40 ++ tests/outputs/sns-neuron-stake-no-amount.txt | 21 + tests/outputs/sns-refund.txt | 11 + tests/outputs/sns-register-vote-no.txt | 17 + tests/outputs/sns-register-vote-yes.txt | 17 + tests/outputs/sns-status.txt | 7 + tests/outputs/sns-swap.txt | 27 ++ .../sns-transfer-with-fees-and-memo.txt | 19 + tests/outputs/sns-transfer.txt | 19 + tests/outputs/sns_canister.wasm | Bin 0 -> 8 bytes tests/sns_canister_ids.json | 6 + 104 files changed, 3265 insertions(+), 331 deletions(-) create mode 100644 candid/sns-governance.did create mode 100644 candid/sns-root.did create mode 100644 candid/sns-swap.did create mode 100644 candid/snsw.did create mode 100644 docs/cli-reference/sns/quill-sns-balance.md create mode 100644 docs/cli-reference/sns/quill-sns-configure-dissolve-delay.md create mode 100644 docs/cli-reference/sns/quill-sns-get-swap-refund.md create mode 100644 docs/cli-reference/sns/quill-sns-list-deployed-snses.md create mode 100644 docs/cli-reference/sns/quill-sns-make-proposal.md create mode 100644 docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.md create mode 100644 docs/cli-reference/sns/quill-sns-neuron-permission.md create mode 100644 docs/cli-reference/sns/quill-sns-register-vote.md create mode 100644 docs/cli-reference/sns/quill-sns-stake-maturity.md create mode 100644 docs/cli-reference/sns/quill-sns-stake-neuron.md create mode 100644 docs/cli-reference/sns/quill-sns-status.md create mode 100644 docs/cli-reference/sns/quill-sns-swap.md create mode 100644 docs/cli-reference/sns/quill-sns-transfer.md create mode 100644 docs/cli-reference/sns/quill-sns.md create mode 100644 src/commands/sns.rs create mode 100644 src/commands/sns/balance.rs create mode 100644 src/commands/sns/configure_dissolve_delay.rs create mode 100644 src/commands/sns/get_swap_refund.rs create mode 100644 src/commands/sns/list_deployed_snses.rs create mode 100644 src/commands/sns/make_proposal.rs create mode 100644 src/commands/sns/make_upgrade_canister_proposal.rs create mode 100644 src/commands/sns/neuron_permission.rs create mode 100644 src/commands/sns/register_vote.rs create mode 100644 src/commands/sns/stake_maturity.rs create mode 100644 src/commands/sns/stake_neuron.rs create mode 100644 src/commands/sns/status.rs create mode 100644 src/commands/sns/swap.rs create mode 100644 src/commands/sns/transfer.rs create mode 100755 tests/commands/sns-balance.sh create mode 100755 tests/commands/sns-configure-dissolve-delay-add-seconds.sh create mode 100755 tests/commands/sns-configure-dissolve-delay-start-dissolving.sh create mode 100755 tests/commands/sns-configure-dissolve-delay-stop-dissolving.sh create mode 100755 tests/commands/sns-list-deployed-snses.sh create mode 100755 tests/commands/sns-make-proposal.sh create mode 100755 tests/commands/sns-make-upgrade-canister-proposal.sh create mode 100755 tests/commands/sns-neuron-permission-add.sh create mode 100755 tests/commands/sns-neuron-permission-remove.sh create mode 100755 tests/commands/sns-neuron-stake-maturity.sh create mode 100755 tests/commands/sns-neuron-stake-memo.sh create mode 100755 tests/commands/sns-neuron-stake-no-amount.sh create mode 100755 tests/commands/sns-refund.sh create mode 100755 tests/commands/sns-register-vote-no.sh create mode 100755 tests/commands/sns-register-vote-yes.sh create mode 100755 tests/commands/sns-status.sh create mode 100755 tests/commands/sns-swap.sh create mode 100755 tests/commands/sns-transfer-with-fees-and-memo.sh create mode 100755 tests/commands/sns-transfer.sh create mode 100644 tests/outputs/sns-balance.txt create mode 100755 tests/outputs/sns-configure-dissolve-delay-add-seconds.txt create mode 100755 tests/outputs/sns-configure-dissolve-delay-start-dissolving.txt create mode 100755 tests/outputs/sns-configure-dissolve-delay-stop-dissolving.txt create mode 100644 tests/outputs/sns-list-deployed-snses.txt create mode 100644 tests/outputs/sns-make-proposal.txt create mode 100644 tests/outputs/sns-make-upgrade-canister-proposal.txt create mode 100644 tests/outputs/sns-neuron-permission-add.txt create mode 100644 tests/outputs/sns-neuron-permission-remove.txt create mode 100644 tests/outputs/sns-neuron-stake-maturity.txt create mode 100644 tests/outputs/sns-neuron-stake-memo.txt create mode 100644 tests/outputs/sns-neuron-stake-no-amount.txt create mode 100644 tests/outputs/sns-refund.txt create mode 100644 tests/outputs/sns-register-vote-no.txt create mode 100644 tests/outputs/sns-register-vote-yes.txt create mode 100644 tests/outputs/sns-status.txt create mode 100644 tests/outputs/sns-swap.txt create mode 100644 tests/outputs/sns-transfer-with-fees-and-memo.txt create mode 100644 tests/outputs/sns-transfer.txt create mode 100644 tests/outputs/sns_canister.wasm create mode 100644 tests/sns_canister_ids.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e5ab1b1..7f37dc58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - ckBTC commands and support. (#153) +- SNS commands and support (replaces sns-quill). (#154) ## [0.3.2] - 2023-01-13 diff --git a/Cargo.lock b/Cargo.lock index 3a197306..b2e1a29a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,16 +520,16 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.18" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", "indexmap", - "lazy_static", + "once_cell", "strsim", "termcolor", "textwrap", @@ -537,9 +537,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.1.18" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -550,9 +550,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] @@ -747,7 +747,7 @@ dependencies = [ [[package]] name = "cycles-minting-canister" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "base64 0.13.0", "build-info", @@ -907,7 +907,7 @@ dependencies = [ [[package]] name = "dfn_candid" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "dfn_core", @@ -919,7 +919,7 @@ dependencies = [ [[package]] name = "dfn_core" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ic-base-types", "on_wire", @@ -928,7 +928,7 @@ dependencies = [ [[package]] name = "dfn_http" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "dfn_candid", @@ -940,7 +940,7 @@ dependencies = [ [[package]] name = "dfn_http_metrics" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "dfn_candid", "dfn_core", @@ -952,7 +952,7 @@ dependencies = [ [[package]] name = "dfn_protobuf" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "dfn_core", "ic-base-types", @@ -1009,9 +1009,9 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.14.1" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e737f9eebb44576f3ee654141a789464071eb369d02c4397b32b6a79790112" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ "der", "elliptic-curve", @@ -1100,7 +1100,7 @@ dependencies = [ [[package]] name = "fe-derive" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "hex", "num-bigint-dig", @@ -1556,7 +1556,7 @@ dependencies = [ [[package]] name = "ic-base-types" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "base32", "byte-unit", @@ -1576,7 +1576,7 @@ dependencies = [ [[package]] name = "ic-btc-types" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "serde", @@ -1586,7 +1586,7 @@ dependencies = [ [[package]] name = "ic-btc-types-internal" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "ic-btc-types", @@ -1598,12 +1598,11 @@ dependencies = [ [[package]] name = "ic-canister-client-sender" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ed25519-consensus", "ic-base-types", - "ic-crypto-internal-basic-sig-der-utils", - "ic-crypto-internal-basic-sig-ecdsa-secp256k1", + "ic-crypto-ecdsa-secp256k1", "ic-crypto-internal-types", "ic-crypto-secrets-containers", "ic-crypto-sha", @@ -1617,12 +1616,12 @@ dependencies = [ [[package]] name = "ic-canister-log" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" [[package]] name = "ic-canisters-http-types" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "serde", @@ -1668,7 +1667,7 @@ dependencies = [ [[package]] name = "ic-ckbtc-minter" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "bech32", @@ -1690,7 +1689,7 @@ dependencies = [ "ic-icrc1-client-cdk", "ic-ledger-core", "ic-metrics-encoder", - "ic-stable-structures", + "ic-stable-structures 0.1.2", "lazy_static", "num-traits", "ripemd", @@ -1702,12 +1701,25 @@ dependencies = [ [[package]] name = "ic-constants" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" + +[[package]] +name = "ic-crypto-ecdsa-secp256k1" +version = "0.1.0" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" +dependencies = [ + "k256", + "lazy_static", + "pem", + "rand", + "simple_asn1", + "zeroize", +] [[package]] name = "ic-crypto-extended-bip32" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ic-crypto-internal-threshold-sig-ecdsa", ] @@ -1715,7 +1727,7 @@ dependencies = [ [[package]] name = "ic-crypto-getrandom-for-wasm" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "getrandom 0.2.6", ] @@ -1723,35 +1735,18 @@ dependencies = [ [[package]] name = "ic-crypto-internal-basic-sig-der-utils" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "hex", "ic-types 0.8.0", "simple_asn1", -] - -[[package]] -name = "ic-crypto-internal-basic-sig-ecdsa-secp256k1" -version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" -dependencies = [ - "base64 0.11.0", - "hex", - "ic-crypto-internal-basic-sig-der-utils", - "ic-crypto-internal-types", - "ic-crypto-secrets-containers", - "ic-types 0.8.0", - "openssl", - "serde", - "serde_bytes", - "simple_asn1", "zeroize", ] [[package]] name = "ic-crypto-internal-basic-sig-ed25519" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "base64 0.11.0", "curve25519-dalek", @@ -1773,7 +1768,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-bls12-381-type" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "hex", "ic-crypto-getrandom-for-wasm", @@ -1791,7 +1786,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-hmac" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ic-crypto-internal-sha2", ] @@ -1799,7 +1794,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-multi-sig-bls12381" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "base64 0.11.0", "hex", @@ -1817,7 +1812,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-seed" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "hex", "ic-crypto-sha", @@ -1831,7 +1826,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-sha2" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "openssl", "sha2 0.9.9", @@ -1840,7 +1835,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-threshold-sig-bls12381" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "arrayvec 0.5.2", "base64 0.11.0", @@ -1867,7 +1862,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-threshold-sig-bls12381-der" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "simple_asn1", ] @@ -1875,7 +1870,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-threshold-sig-ecdsa" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "fe-derive", "hex", @@ -1901,7 +1896,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-types" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "arrayvec 0.5.2", "base64 0.11.0", @@ -1919,7 +1914,7 @@ dependencies = [ [[package]] name = "ic-crypto-node-key-validation" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "hex", "ic-base-types", @@ -1937,7 +1932,7 @@ dependencies = [ [[package]] name = "ic-crypto-secrets-containers" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "serde", "zeroize", @@ -1946,7 +1941,7 @@ dependencies = [ [[package]] name = "ic-crypto-sha" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ic-crypto-internal-sha2", ] @@ -1954,7 +1949,7 @@ dependencies = [ [[package]] name = "ic-crypto-tls-cert-validation" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "chrono", "dfn_core", @@ -1970,7 +1965,7 @@ dependencies = [ [[package]] name = "ic-crypto-tree-hash" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ic-crypto-internal-types", "ic-crypto-sha", @@ -1982,7 +1977,7 @@ dependencies = [ [[package]] name = "ic-crypto-utils-basic-sig" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "base64 0.11.0", "ed25519-consensus", @@ -1997,7 +1992,7 @@ dependencies = [ [[package]] name = "ic-error-types" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "serde", "strum 0.23.0", @@ -2007,7 +2002,7 @@ dependencies = [ [[package]] name = "ic-ic00-types" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "float-cmp", @@ -2027,7 +2022,7 @@ dependencies = [ [[package]] name = "ic-icrc1" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "ciborium 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2044,7 +2039,7 @@ dependencies = [ [[package]] name = "ic-icrc1-client" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "candid", @@ -2058,7 +2053,7 @@ dependencies = [ [[package]] name = "ic-icrc1-client-cdk" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "ic-cdk", @@ -2068,14 +2063,13 @@ dependencies = [ [[package]] name = "ic-icrc1-index" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "candid", "ciborium 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dfn_core", - "dfn_http_metrics", "ic-base-types", + "ic-canisters-http-types", "ic-cdk", "ic-cdk-macros", "ic-icrc1", @@ -2088,7 +2082,7 @@ dependencies = [ [[package]] name = "ic-icrc1-ledger" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "candid", @@ -2096,6 +2090,8 @@ dependencies = [ "dfn_http_metrics", "hex", "ic-base-types", + "ic-canister-log", + "ic-canisters-http-types", "ic-cdk", "ic-cdk-macros", "ic-crypto-tree-hash", @@ -2127,11 +2123,12 @@ dependencies = [ [[package]] name = "ic-ledger-canister-core" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "candid", "ic-base-types", + "ic-canister-log", "ic-constants", "ic-ic00-types", "ic-ledger-core", @@ -2142,7 +2139,7 @@ dependencies = [ [[package]] name = "ic-ledger-core" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "candid", @@ -2165,7 +2162,7 @@ checksum = "8aef00d455eba8b8244a415f073a43042e57da6d09c294485a2b2ebc858c9da2" [[package]] name = "ic-nervous-system-common" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "anyhow", "async-trait", @@ -2177,10 +2174,13 @@ dependencies = [ "dfn_core", "dfn_protobuf", "ic-base-types", + "ic-canister-log", + "ic-canisters-http-types", "ic-crypto-sha", "ic-ic00-types", "ic-icrc1", "ic-ledger-core", + "ic-metrics-encoder", "icp-ledger", "rand", "rand_chacha", @@ -2191,12 +2191,12 @@ dependencies = [ [[package]] name = "ic-nervous-system-common-build-metadata" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" [[package]] name = "ic-nervous-system-common-test-keys" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ic-base-types", "ic-canister-client-sender", @@ -2210,7 +2210,7 @@ dependencies = [ [[package]] name = "ic-nervous-system-root" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "dfn_candid", @@ -2227,7 +2227,7 @@ dependencies = [ [[package]] name = "ic-nns-common" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "comparable", @@ -2250,7 +2250,7 @@ dependencies = [ [[package]] name = "ic-nns-constants" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "ic-base-types", "lazy_static", @@ -2259,7 +2259,7 @@ dependencies = [ [[package]] name = "ic-nns-governance" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "build-info", @@ -2299,7 +2299,7 @@ dependencies = [ [[package]] name = "ic-protobuf" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "bincode", "candid", @@ -2314,7 +2314,7 @@ dependencies = [ [[package]] name = "ic-registry-keys" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "ic-base-types", @@ -2326,7 +2326,7 @@ dependencies = [ [[package]] name = "ic-registry-routing-table" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "ic-base-types", @@ -2337,7 +2337,7 @@ dependencies = [ [[package]] name = "ic-registry-subnet-features" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "ic-ic00-types", @@ -2348,7 +2348,7 @@ dependencies = [ [[package]] name = "ic-registry-subnet-type" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "ic-protobuf", @@ -2360,7 +2360,7 @@ dependencies = [ [[package]] name = "ic-registry-transport" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "bytes", "candid", @@ -2372,7 +2372,7 @@ dependencies = [ [[package]] name = "ic-sns-governance" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "base64 0.13.0", @@ -2389,6 +2389,8 @@ dependencies = [ "dfn_protobuf", "hex", "ic-base-types", + "ic-canister-log", + "ic-canisters-http-types", "ic-crypto-sha", "ic-ic00-types", "ic-icrc1", @@ -2419,7 +2421,7 @@ dependencies = [ [[package]] name = "ic-sns-init" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "anyhow", "base64 0.13.0", @@ -2451,7 +2453,7 @@ dependencies = [ [[package]] name = "ic-sns-root" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "build-info", @@ -2461,8 +2463,11 @@ dependencies = [ "dfn_candid", "dfn_core", "ic-base-types", + "ic-canister-log", + "ic-canisters-http-types", "ic-ic00-types", "ic-icrc1", + "ic-metrics-encoder", "ic-nervous-system-common", "ic-nervous-system-common-build-metadata", "ic-nervous-system-root", @@ -2475,7 +2480,7 @@ dependencies = [ [[package]] name = "ic-sns-swap" version = "0.1.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "build-info", @@ -2489,6 +2494,8 @@ dependencies = [ "dfn_protobuf", "hex", "ic-base-types", + "ic-canister-log", + "ic-canisters-http-types", "ic-crypto-sha", "ic-ic00-types", "ic-icrc1", @@ -2498,7 +2505,9 @@ dependencies = [ "ic-nervous-system-root", "ic-protobuf", "ic-sns-governance", + "ic-stable-structures 0.4.1", "icp-ledger", + "itertools", "lazy_static", "on_wire", "prost", @@ -2515,7 +2524,7 @@ dependencies = [ [[package]] name = "ic-sns-wasm" version = "1.0.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "build-info", @@ -2548,10 +2557,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8ded18fe296ff693ba8d8fd9890189ea28df4fc75d8b009523e15918452d8b" +[[package]] +name = "ic-stable-structures" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77002de282a2042e50e345d17ff8a4b8a396bc6b4033aeb0dee1b7d519a80630" + [[package]] name = "ic-sys" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "hex", "ic-crypto-sha", @@ -2580,7 +2595,7 @@ dependencies = [ [[package]] name = "ic-types" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "base32", "base64 0.11.0", @@ -2620,7 +2635,7 @@ dependencies = [ [[package]] name = "ic-utils" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "bitflags", "cvt", @@ -2666,7 +2681,7 @@ dependencies = [ [[package]] name = "icp-ledger" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "comparable", @@ -2678,6 +2693,7 @@ dependencies = [ "dfn_protobuf", "hex", "ic-base-types", + "ic-canisters-http-types", "ic-crypto-sha", "ic-icrc1", "ic-ledger-canister-core", @@ -2775,9 +2791,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.11.4" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2573d3fd3e4cc741affc9b5ce1a8ce36cf29f09f80f36da4309d0ae6d7854" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if 1.0.0", "ecdsa", @@ -2842,7 +2858,7 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "ledger-canister" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "async-trait", "candid", @@ -2852,6 +2868,7 @@ dependencies = [ "dfn_http_metrics", "dfn_protobuf", "ic-base-types", + "ic-canister-log", "ic-cdk", "ic-constants", "ic-icrc1", @@ -3249,7 +3266,7 @@ dependencies = [ [[package]] name = "on_wire" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" [[package]] name = "once_cell" @@ -3391,9 +3408,9 @@ dependencies = [ [[package]] name = "pem" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ "base64 0.13.0", ] @@ -3426,7 +3443,7 @@ dependencies = [ [[package]] name = "phantom_newtype" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "candid", "serde", @@ -3667,9 +3684,14 @@ dependencies = [ "ic-ckbtc-minter", "ic-icrc1", "ic-identity-hsm", + "ic-nervous-system-common", "ic-nns-common", "ic-nns-constants", "ic-nns-governance", + "ic-sns-governance", + "ic-sns-root", + "ic-sns-swap", + "ic-sns-wasm", "ic-types 0.4.2", "icp-ledger", "itertools", @@ -3793,7 +3815,7 @@ checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "registry-canister" version = "0.8.0" -source = "git+https://github.com/dfinity/ic?rev=a6ae48d2a5273d595bc113e0d28aba19da7612eb#a6ae48d2a5273d595bc113e0d28aba19da7612eb" +source = "git+https://github.com/dfinity/ic?rev=0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77#0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" dependencies = [ "build-info", "build-info-build", @@ -3883,9 +3905,9 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c0788437d5ee113c49af91d3594ebc4fcdcc962f8b6df5aa1c3eeafd8ad95de" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ "crypto-bigint", "hmac", @@ -4266,9 +4288,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.5.0" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest 0.10.3", "rand_core 0.6.3", @@ -4497,9 +4519,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" diff --git a/Cargo.toml b/Cargo.toml index 0575f9a0..1ed21c6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,15 +18,20 @@ flate2 = "1.0.22" hex = {version = "0.4.2", features = ["serde"] } ic-agent = "0.21.0" ic-identity-hsm = "0.21.0" -ic-base-types = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } -ic-ckbtc-minter = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } -ic-icrc1 = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } -ic-nns-common = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } -ic-nns-constants = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } -ic-nns-governance = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } +ic-base-types = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-ckbtc-minter = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-icrc1 = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-nervous-system-common = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-nns-common = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-nns-constants = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-nns-governance = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-sns-governance = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-sns-root = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-sns-swap = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ic-sns-wasm = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } ic-types = "0.4.1" -icp-ledger = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } -ledger-canister = { git = "https://github.com/dfinity/ic", rev = "a6ae48d2a5273d595bc113e0d28aba19da7612eb" } +icp-ledger = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } +ledger-canister = { git = "https://github.com/dfinity/ic", rev = "0fc243cb16fbe9d45fd39b0bc6bd7a30dfc0aa77" } num-bigint = "0.4.3" openssl = "0.10.45" pem = "1.0.1" @@ -54,4 +59,4 @@ tempfile = "3.3.0" [features] static-ssl = ["openssl/vendored"] -default = ["static-ssl"] \ No newline at end of file +default = ["static-ssl"] diff --git a/candid/ckbtc_minter.did b/candid/ckbtc_minter.did index 0c48a5c0..753c535c 100644 --- a/candid/ckbtc_minter.did +++ b/candid/ckbtc_minter.did @@ -65,6 +65,15 @@ type BtcNetwork = variant { Regtest; }; +type Mode = variant { + // The minter does not allow any state modifications. + ReadOnly; + // Only specified principals can modify minter's state. + RestrictedTo : vec principal; + // Anyone can interact with the minter. + GeneralAvailability; +}; + // The initialization parameters of the minter canister. type InitArgs = record { // The minter will interact with this Bitcoin network to wrap/unwrap BTC. @@ -90,8 +99,8 @@ type InitArgs = record { /// accept a Bitcoin transaction. min_confirmations : opt nat32; - /// Flag that indicates if the minter is in read-only mode. - is_read_only : bool; + /// The minter's operation mode. + mode : Mode; }; // The upgrade parameters of the minter canister. @@ -107,8 +116,8 @@ type UpgradeArgs = record { /// accept a Bitcoin transaction. min_confirmations : opt nat32; - /// Flag that indicates if the minter is in read-only mode. - is_read_only : opt bool; + /// If set, overrides the current minter's operation mode. + mode : opt Mode; }; type RetrieveBtcStatus = variant { @@ -169,7 +178,7 @@ type Event = variant { requests : vec nat64; txid : blob; utxos : vec Utxo; - change_output : opt record { vout : nat32; value : nat32 }; + change_output : opt record { vout : nat32; value : nat64 }; submitted_at : nat64; }; confirmed_transaction : record { txid : blob }; diff --git a/candid/governance.did b/candid/governance.did index 690744b6..79d93458 100644 --- a/candid/governance.did +++ b/candid/governance.did @@ -146,6 +146,7 @@ type GovernanceCachedMetrics = record { community_fund_total_maturity_e8s_equivalent : nat64; total_staked_e8s : nat64; not_dissolving_neurons_count : nat64; + total_locked_e8s : nat64; dissolved_neurons_e8s : nat64; neurons_with_less_than_6_months_dissolve_delay_e8s : nat64; dissolving_neurons_count_buckets : vec record { nat64; nat64 }; @@ -344,10 +345,11 @@ type RemoveHotKey = record { hot_key_to_remove : opt principal }; type Result = variant { Ok; Err : GovernanceError }; type Result_1 = variant { Error : GovernanceError; NeuronId : NeuronId }; type Result_2 = variant { Ok : Neuron; Err : GovernanceError }; -type Result_3 = variant { Ok : RewardNodeProviders; Err : GovernanceError }; -type Result_4 = variant { Ok : NeuronInfo; Err : GovernanceError }; -type Result_5 = variant { Ok : NodeProvider; Err : GovernanceError }; -type Result_6 = variant { Committed : Committed; Aborted : record {} }; +type Result_3 = variant { Ok : GovernanceCachedMetrics; Err : GovernanceError }; +type Result_4 = variant { Ok : RewardNodeProviders; Err : GovernanceError }; +type Result_5 = variant { Ok : NeuronInfo; Err : GovernanceError }; +type Result_6 = variant { Ok : NodeProvider; Err : GovernanceError }; +type Result_7 = variant { Committed : Committed; Aborted : record {} }; type RewardEvent = record { day_after_genesis : nat64; actual_timestamp_seconds : nat64; @@ -379,7 +381,7 @@ type SetSnsTokenSwapOpenTimeWindow = record { swap_canister_id : opt principal; }; type SettleCommunityFundParticipation = record { - result : opt Result_6; + result : opt Result_7; open_sns_token_swap_proposal_id : opt nat64; }; type Spawn = record { @@ -426,17 +428,18 @@ service : (Governance) -> { get_full_neuron_by_id_or_subaccount : (NeuronIdOrSubaccount) -> ( Result_2, ) query; - get_monthly_node_provider_rewards : () -> (Result_3); + get_metrics : () -> (Result_3) query; + get_monthly_node_provider_rewards : () -> (Result_4); get_most_recent_monthly_node_provider_rewards : () -> ( opt MostRecentMonthlyNodeProviderRewards, ) query; get_network_economics_parameters : () -> (NetworkEconomics) query; get_neuron_ids : () -> (vec nat64) query; - get_neuron_info : (nat64) -> (Result_4) query; + get_neuron_info : (nat64) -> (Result_5) query; get_neuron_info_by_id_or_subaccount : (NeuronIdOrSubaccount) -> ( - Result_4, + Result_5, ) query; - get_node_provider_by_caller : (null) -> (Result_5) query; + get_node_provider_by_caller : (null) -> (Result_6) query; get_pending_proposals : () -> (vec ProposalInfo) query; get_proposal_info : (nat64) -> (opt ProposalInfo) query; list_known_neurons : () -> (ListKnownNeuronsResponse) query; diff --git a/candid/ledger.did b/candid/ledger.did index c6a9a633..4b04b28b 100644 --- a/candid/ledger.did +++ b/candid/ledger.did @@ -100,4 +100,5 @@ service: (LedgerCanisterInitPayload) -> { send_dfx : (SendArgs) -> (BlockIndex); notify_dfx: (NotifyCanisterArgs) -> (); account_balance_dfx : (AccountBalanceArgs) -> (Tokens) query; + notify_pb: () -> (); } diff --git a/candid/sns-governance.did b/candid/sns-governance.did new file mode 100644 index 00000000..c820117e --- /dev/null +++ b/candid/sns-governance.did @@ -0,0 +1,418 @@ +type Account = record { owner : opt principal; subaccount : opt Subaccount }; +type Action = variant { + ManageNervousSystemParameters : NervousSystemParameters; + AddGenericNervousSystemFunction : NervousSystemFunction; + RemoveGenericNervousSystemFunction : nat64; + UpgradeSnsToNextVersion : record {}; + RegisterDappCanisters : RegisterDappCanisters; + TransferSnsTreasuryFunds : TransferSnsTreasuryFunds; + UpgradeSnsControlledCanister : UpgradeSnsControlledCanister; + DeregisterDappCanisters : DeregisterDappCanisters; + Unspecified : record {}; + ManageSnsMetadata : ManageSnsMetadata; + ExecuteGenericNervousSystemFunction : ExecuteGenericNervousSystemFunction; + Motion : Motion; +}; +type AddNeuronPermissions = record { + permissions_to_add : opt NeuronPermissionList; + principal_id : opt principal; +}; +type Amount = record { e8s : nat64 }; +type Ballot = record { + vote : int32; + cast_timestamp_seconds : nat64; + voting_power : nat64; +}; +type By = variant { + MemoAndController : MemoAndController; + NeuronId : record {}; +}; +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; +}; +type CanisterStatusType = variant { stopped; stopping; running }; +type ChangeAutoStakeMaturity = record { + requested_setting_for_auto_stake_maturity : bool; +}; +type ClaimOrRefresh = record { by : opt By }; +type ClaimOrRefreshResponse = record { refreshed_neuron_id : opt NeuronId }; +type ClaimSwapNeuronsRequest = record { + neuron_parameters : vec NeuronParameters; +}; +type ClaimSwapNeuronsResponse = record { + skipped_claims : nat32; + successful_claims : nat32; + failed_claims : nat32; +}; +type Command = variant { + Split : Split; + Follow : Follow; + DisburseMaturity : DisburseMaturity; + ClaimOrRefresh : ClaimOrRefresh; + Configure : Configure; + RegisterVote : RegisterVote; + MakeProposal : Proposal; + StakeMaturity : StakeMaturity; + RemoveNeuronPermissions : RemoveNeuronPermissions; + AddNeuronPermissions : AddNeuronPermissions; + MergeMaturity : MergeMaturity; + Disburse : Disburse; +}; +type Command_1 = variant { + Error : GovernanceError; + Split : SplitResponse; + Follow : record {}; + DisburseMaturity : DisburseMaturityResponse; + ClaimOrRefresh : ClaimOrRefreshResponse; + Configure : record {}; + RegisterVote : record {}; + MakeProposal : GetProposal; + RemoveNeuronPermission : record {}; + StakeMaturity : StakeMaturityResponse; + MergeMaturity : MergeMaturityResponse; + Disburse : DisburseResponse; + AddNeuronPermission : record {}; +}; +type Command_2 = variant { + Split : Split; + Follow : Follow; + DisburseMaturity : DisburseMaturity; + Configure : Configure; + RegisterVote : RegisterVote; + SyncCommand : record {}; + MakeProposal : Proposal; + FinalizeDisburseMaturity : FinalizeDisburseMaturity; + ClaimOrRefreshNeuron : ClaimOrRefresh; + RemoveNeuronPermissions : RemoveNeuronPermissions; + AddNeuronPermissions : AddNeuronPermissions; + MergeMaturity : MergeMaturity; + Disburse : Disburse; +}; +type Configure = record { operation : opt Operation }; +type DefaultFollowees = record { followees : vec record { nat64; Followees } }; +type DefiniteCanisterSettingsArgs = record { + controller : principal; + freezing_threshold : nat; + controllers : vec principal; + memory_allocation : nat; + compute_allocation : nat; +}; +type DeregisterDappCanisters = record { + canister_ids : vec principal; + new_controllers : vec principal; +}; +type Disburse = record { to_account : opt Account; amount : opt Amount }; +type DisburseMaturity = record { + to_account : opt Account; + percentage_to_disburse : nat32; +}; +type DisburseMaturityInProgress = record { + timestamp_of_disbursement_seconds : nat64; + amount_e8s : nat64; + account_to_disburse_to : opt Account; +}; +type DisburseMaturityResponse = record { amount_disbursed_e8s : nat64 }; +type DisburseResponse = record { transfer_block_height : nat64 }; +type DissolveState = variant { + DissolveDelaySeconds : nat64; + WhenDissolvedTimestampSeconds : nat64; +}; +type ExecuteGenericNervousSystemFunction = record { + function_id : nat64; + payload : vec nat8; +}; +type FinalizeDisburseMaturity = record { + amount_to_be_disbursed_e8s : nat64; + to_account : opt Account; +}; +type Follow = record { function_id : nat64; followees : vec NeuronId }; +type Followees = record { followees : vec NeuronId }; +type FunctionType = variant { + NativeNervousSystemFunction : record {}; + GenericNervousSystemFunction : GenericNervousSystemFunction; +}; +type GenericNervousSystemFunction = record { + validator_canister_id : opt principal; + target_canister_id : opt principal; + validator_method_name : opt text; + target_method_name : opt text; +}; +type GetMetadataResponse = record { + url : opt text; + logo : opt text; + name : opt text; + description : opt text; +}; +type GetModeResponse = record { mode : opt int32 }; +type GetNeuron = record { neuron_id : opt NeuronId }; +type GetNeuronResponse = record { result : opt Result }; +type GetProposal = record { proposal_id : opt ProposalId }; +type GetProposalResponse = record { result : opt Result_1 }; +type GetRunningSnsVersionResponse = record { + deployed_version : opt Version; + pending_version : opt UpgradeInProgress; +}; +type GetSnsInitializationParametersResponse = record { + sns_initialization_parameters : text; +}; +type Governance = record { + root_canister_id : opt principal; + id_to_nervous_system_functions : vec record { nat64; NervousSystemFunction }; + metrics : opt GovernanceCachedMetrics; + mode : int32; + parameters : opt NervousSystemParameters; + is_finalizing_disburse_maturity : opt bool; + deployed_version : opt Version; + sns_initialization_parameters : text; + latest_reward_event : opt RewardEvent; + pending_version : opt UpgradeInProgress; + swap_canister_id : opt principal; + ledger_canister_id : opt principal; + proposals : vec record { nat64; ProposalData }; + in_flight_commands : vec record { text; NeuronInFlightCommand }; + sns_metadata : opt ManageSnsMetadata; + neurons : vec record { text; Neuron }; + genesis_timestamp_seconds : nat64; +}; +type GovernanceCachedMetrics = record { + not_dissolving_neurons_e8s_buckets : vec record { nat64; float64 }; + garbage_collectable_neurons_count : nat64; + neurons_with_invalid_stake_count : nat64; + not_dissolving_neurons_count_buckets : vec record { nat64; nat64 }; + neurons_with_less_than_6_months_dissolve_delay_count : nat64; + dissolved_neurons_count : nat64; + total_staked_e8s : nat64; + total_supply_governance_tokens : nat64; + not_dissolving_neurons_count : nat64; + dissolved_neurons_e8s : nat64; + neurons_with_less_than_6_months_dissolve_delay_e8s : nat64; + dissolving_neurons_count_buckets : vec record { nat64; nat64 }; + dissolving_neurons_count : nat64; + dissolving_neurons_e8s_buckets : vec record { nat64; float64 }; + timestamp_seconds : nat64; +}; +type GovernanceError = record { error_message : text; error_type : int32 }; +type IncreaseDissolveDelay = record { + additional_dissolve_delay_seconds : nat32; +}; +type ListNervousSystemFunctionsResponse = record { + reserved_ids : vec nat64; + functions : vec NervousSystemFunction; +}; +type ListNeurons = record { + of_principal : opt principal; + limit : nat32; + start_page_at : opt NeuronId; +}; +type ListNeuronsResponse = record { neurons : vec Neuron }; +type ListProposals = record { + include_reward_status : vec int32; + before_proposal : opt ProposalId; + limit : nat32; + exclude_type : vec nat64; + include_status : vec int32; +}; +type ListProposalsResponse = record { proposals : vec ProposalData }; +type ManageNeuron = record { subaccount : vec nat8; command : opt Command }; +type ManageNeuronResponse = record { command : opt Command_1 }; +type ManageSnsMetadata = record { + url : opt text; + logo : opt text; + name : opt text; + description : opt text; +}; +type MemoAndController = record { controller : opt principal; memo : nat64 }; +type MergeMaturity = record { percentage_to_merge : nat32 }; +type MergeMaturityResponse = record { + merged_maturity_e8s : nat64; + new_stake_e8s : nat64; +}; +type Motion = record { motion_text : text }; +type NervousSystemFunction = record { + id : nat64; + name : text; + description : opt text; + function_type : opt FunctionType; +}; +type NervousSystemParameters = record { + default_followees : opt DefaultFollowees; + max_dissolve_delay_seconds : opt nat64; + max_dissolve_delay_bonus_percentage : opt nat64; + max_followees_per_function : opt nat64; + neuron_claimer_permissions : opt NeuronPermissionList; + neuron_minimum_stake_e8s : opt nat64; + max_neuron_age_for_age_bonus : opt nat64; + initial_voting_period_seconds : opt nat64; + neuron_minimum_dissolve_delay_to_vote_seconds : opt nat64; + reject_cost_e8s : opt nat64; + max_proposals_to_keep_per_action : opt nat32; + wait_for_quiet_deadline_increase_seconds : opt nat64; + max_number_of_neurons : opt nat64; + transaction_fee_e8s : opt nat64; + max_number_of_proposals_with_ballots : opt nat64; + max_age_bonus_percentage : opt nat64; + neuron_grantable_permissions : opt NeuronPermissionList; + voting_rewards_parameters : opt VotingRewardsParameters; + max_number_of_principals_per_neuron : opt nat64; +}; +type Neuron = record { + id : opt NeuronId; + staked_maturity_e8s_equivalent : opt nat64; + permissions : vec NeuronPermission; + maturity_e8s_equivalent : nat64; + cached_neuron_stake_e8s : nat64; + created_timestamp_seconds : nat64; + source_nns_neuron_id : opt nat64; + auto_stake_maturity : opt bool; + aging_since_timestamp_seconds : nat64; + dissolve_state : opt DissolveState; + voting_power_percentage_multiplier : nat64; + vesting_period_seconds : opt nat64; + disburse_maturity_in_progress : vec DisburseMaturityInProgress; + followees : vec record { nat64; Followees }; + neuron_fees_e8s : nat64; +}; +type NeuronId = record { id : vec nat8 }; +type NeuronInFlightCommand = record { + command : opt Command_2; + timestamp : nat64; +}; +type NeuronParameters = record { + controller : opt principal; + dissolve_delay_seconds : opt nat64; + memo : opt nat64; + source_nns_neuron_id : opt nat64; + stake_e8s : opt nat64; + hotkey : opt principal; +}; +type NeuronPermission = record { + "principal" : opt principal; + permission_type : vec int32; +}; +type NeuronPermissionList = record { permissions : vec int32 }; +type Operation = variant { + ChangeAutoStakeMaturity : ChangeAutoStakeMaturity; + StopDissolving : record {}; + StartDissolving : record {}; + IncreaseDissolveDelay : IncreaseDissolveDelay; + SetDissolveTimestamp : SetDissolveTimestamp; +}; +type Proposal = record { + url : text; + title : text; + action : opt Action; + summary : text; +}; +type ProposalData = record { + id : opt ProposalId; + payload_text_rendering : opt text; + action : nat64; + failure_reason : opt GovernanceError; + ballots : vec record { text; Ballot }; + reward_event_round : nat64; + failed_timestamp_seconds : nat64; + proposal_creation_timestamp_seconds : nat64; + initial_voting_period_seconds : nat64; + reject_cost_e8s : nat64; + latest_tally : opt Tally; + wait_for_quiet_deadline_increase_seconds : nat64; + decided_timestamp_seconds : nat64; + proposal : opt Proposal; + proposer : opt NeuronId; + wait_for_quiet_state : opt WaitForQuietState; + is_eligible_for_rewards : bool; + executed_timestamp_seconds : nat64; +}; +type ProposalId = record { id : nat64 }; +type RegisterDappCanisters = record { canister_ids : vec principal }; +type RegisterVote = record { vote : int32; proposal : opt ProposalId }; +type RemoveNeuronPermissions = record { + permissions_to_remove : opt NeuronPermissionList; + principal_id : opt principal; +}; +type Result = variant { Error : GovernanceError; Neuron : Neuron }; +type Result_1 = variant { Error : GovernanceError; Proposal : ProposalData }; +type RewardEvent = record { + actual_timestamp_seconds : nat64; + distributed_e8s_equivalent : nat64; + round : nat64; + settled_proposals : vec ProposalId; +}; +type SetDissolveTimestamp = record { dissolve_timestamp_seconds : nat64 }; +type SetMode = record { mode : int32 }; +type Split = record { memo : nat64; amount_e8s : nat64 }; +type SplitResponse = record { created_neuron_id : opt NeuronId }; +type StakeMaturity = record { percentage_to_stake : opt nat32 }; +type StakeMaturityResponse = record { + maturity_e8s : nat64; + staked_maturity_e8s : nat64; +}; +type Subaccount = record { subaccount : vec nat8 }; +type Tally = record { + no : nat64; + yes : nat64; + total : nat64; + timestamp_seconds : nat64; +}; +type TransferSnsTreasuryFunds = record { + from_treasury : int32; + to_principal : opt principal; + to_subaccount : opt Subaccount; + memo : opt nat64; + amount_e8s : nat64; +}; +type UpgradeInProgress = record { + mark_failed_at_seconds : nat64; + checking_upgrade_lock : nat64; + proposal_id : nat64; + target_version : opt Version; +}; +type UpgradeSnsControlledCanister = record { + new_canister_wasm : vec nat8; + canister_id : opt principal; + canister_upgrade_arg : opt vec nat8; +}; +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; +}; +type VotingRewardsParameters = record { + final_reward_rate_basis_points : opt nat64; + initial_reward_rate_basis_points : opt nat64; + reward_rate_transition_duration_seconds : opt nat64; + round_duration_seconds : opt nat64; +}; +type WaitForQuietState = record { current_deadline_timestamp_seconds : nat64 }; +service : (Governance) -> { + claim_swap_neurons : (ClaimSwapNeuronsRequest) -> (ClaimSwapNeuronsResponse); + get_build_metadata : () -> (text) query; + get_metadata : (record {}) -> (GetMetadataResponse) query; + get_mode : (record {}) -> (GetModeResponse) query; + get_nervous_system_parameters : (null) -> (NervousSystemParameters) query; + get_neuron : (GetNeuron) -> (GetNeuronResponse) query; + get_proposal : (GetProposal) -> (GetProposalResponse) query; + get_root_canister_status : (null) -> (CanisterStatusResultV2); + get_running_sns_version : (record {}) -> (GetRunningSnsVersionResponse) query; + get_sns_initialization_parameters : (record {}) -> ( + GetSnsInitializationParametersResponse, + ) query; + list_nervous_system_functions : () -> ( + ListNervousSystemFunctionsResponse, + ) query; + list_neurons : (ListNeurons) -> (ListNeuronsResponse) query; + list_proposals : (ListProposals) -> (ListProposalsResponse) query; + manage_neuron : (ManageNeuron) -> (ManageNeuronResponse); + set_mode : (SetMode) -> (record {}); +} diff --git a/candid/sns-root.did b/candid/sns-root.did new file mode 100644 index 00000000..b2e0cbe2 --- /dev/null +++ b/candid/sns-root.did @@ -0,0 +1,85 @@ +type CanisterCallError = record { code : opt int32; description : text }; +type CanisterIdRecord = record { canister_id : principal }; +type CanisterStatusResult = record { + controller : principal; + status : CanisterStatusType; + memory_size : nat; + module_hash : opt vec nat8; +}; +type CanisterStatusResultV2 = record { + controller : principal; + status : CanisterStatusType_1; + 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; +}; +type CanisterStatusType = variant { stopped; stopping; running }; +type CanisterStatusType_1 = variant { stopped; stopping; running }; +type CanisterSummary = record { + status : opt CanisterStatusResultV2; + canister_id : opt principal; +}; +type DefiniteCanisterSettingsArgs = record { + controller : principal; + freezing_threshold : nat; + controllers : vec principal; + memory_allocation : nat; + compute_allocation : nat; +}; +type FailedUpdate = record { + err : opt CanisterCallError; + dapp_canister_id : opt principal; +}; +type GetSnsCanistersSummaryRequest = record { update_canister_list : opt bool }; +type GetSnsCanistersSummaryResponse = record { + root : opt CanisterSummary; + swap : opt CanisterSummary; + ledger : opt CanisterSummary; + index : opt CanisterSummary; + governance : opt CanisterSummary; + dapps : vec CanisterSummary; + archives : vec CanisterSummary; +}; +type ListSnsCanistersResponse = record { + root : opt principal; + swap : opt principal; + ledger : opt principal; + index : opt principal; + governance : opt principal; + dapps : vec principal; + archives : vec principal; +}; +type RegisterDappCanisterRequest = record { canister_id : opt principal }; +type RegisterDappCanistersRequest = record { canister_ids : vec principal }; +type SetDappControllersRequest = record { + canister_ids : opt RegisterDappCanistersRequest; + controller_principal_ids : vec principal; +}; +type SetDappControllersResponse = record { failed_updates : vec FailedUpdate }; +type SnsRootCanister = record { + dapp_canister_ids : vec principal; + testflight : bool; + latest_ledger_archive_poll_timestamp_seconds : opt nat64; + archive_canister_ids : vec principal; + governance_canister_id : opt principal; + index_canister_id : opt principal; + swap_canister_id : opt principal; + ledger_canister_id : opt principal; +}; +service : (SnsRootCanister) -> { + canister_status : (CanisterIdRecord) -> (CanisterStatusResult); + get_build_metadata : () -> (text) query; + get_sns_canisters_summary : (GetSnsCanistersSummaryRequest) -> ( + GetSnsCanistersSummaryResponse, + ); + list_sns_canisters : (record {}) -> (ListSnsCanistersResponse) query; + register_dapp_canister : (RegisterDappCanisterRequest) -> (record {}); + register_dapp_canisters : (RegisterDappCanistersRequest) -> (record {}); + set_dapp_controllers : (SetDappControllersRequest) -> ( + SetDappControllersResponse, + ); +} diff --git a/candid/sns-swap.did b/candid/sns-swap.did new file mode 100644 index 00000000..01bf35c9 --- /dev/null +++ b/candid/sns-swap.did @@ -0,0 +1,150 @@ +type BuyerState = record { icp : opt TransferableAmount }; +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; +}; +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 CfParticipant = record { + hotkey_principal : text; + cf_neurons : vec CfNeuron; +}; +type DefiniteCanisterSettingsArgs = record { + controller : principal; + freezing_threshold : nat; + controllers : vec principal; + memory_allocation : nat; + compute_allocation : nat; +}; +type DerivedState = record { + sns_tokens_per_icp : float32; + buyer_total_icp_e8s : nat64; +}; +type DirectInvestment = record { buyer_principal : text }; +type Err = record { description : opt text; error_type : opt int32 }; +type ErrorRefundIcpRequest = record { source_principal_id : opt principal }; +type ErrorRefundIcpResponse = record { result : opt Result }; +type FailedUpdate = record { + err : opt CanisterCallError; + dapp_canister_id : opt principal; +}; +type FinalizeSwapResponse = record { + settle_community_fund_participation_result : opt SettleCommunityFundParticipationResult; + error_message : opt text; + set_dapp_controllers_result : opt SetDappControllersCallResult; + sns_governance_normal_mode_enabled : opt SetModeCallResult; + sweep_icp : opt SweepResult; + sweep_sns : opt SweepResult; + create_neuron : opt SweepResult; +}; +type GetBuyerStateRequest = record { principal_id : opt principal }; +type GetBuyerStateResponse = record { buyer_state : opt BuyerState }; +type GetBuyersTotalResponse = record { buyers_total : nat64 }; +type GetDerivedStateResponse = record { + sns_tokens_per_icp : opt float64; + buyer_total_icp_e8s : opt nat64; +}; +type GetInitResponse = record { init : opt Init }; +type GetLifecycleResponse = record { lifecycle : opt int32 }; +type GetStateResponse = record { swap : opt Swap; derived : opt DerivedState }; +type GovernanceError = record { error_message : text; error_type : int32 }; +type Init = record { + sns_root_canister_id : text; + fallback_controller_principal_ids : vec text; + neuron_minimum_stake_e8s : opt nat64; + nns_governance_canister_id : text; + transaction_fee_e8s : opt nat64; + icp_ledger_canister_id : text; + sns_ledger_canister_id : text; + sns_governance_canister_id : text; +}; +type Investor = variant { + CommunityFund : CfInvestment; + Direct : DirectInvestment; +}; +type NeuronAttributes = record { dissolve_delay_seconds : nat64; memo : nat64 }; +type NeuronBasketConstructionParameters = record { + dissolve_delay_interval_seconds : nat64; + count : nat64; +}; +type Ok = record { block_height : opt nat64 }; +type OpenRequest = record { + cf_participants : vec CfParticipant; + params : opt Params; + open_sns_token_swap_proposal_id : opt nat64; +}; +type Params = record { + min_participant_icp_e8s : nat64; + neuron_basket_construction_parameters : opt NeuronBasketConstructionParameters; + max_icp_e8s : nat64; + swap_due_timestamp_seconds : nat64; + min_participants : nat32; + sns_token_e8s : nat64; + max_participant_icp_e8s : nat64; + min_icp_e8s : nat64; +}; +type Possibility = variant { Ok : Response; Err : CanisterCallError }; +type Possibility_1 = variant { + Ok : SetDappControllersResponse; + Err : CanisterCallError; +}; +type Possibility_2 = variant { Err : CanisterCallError }; +type RefreshBuyerTokensRequest = record { buyer : text }; +type RefreshBuyerTokensResponse = record { + icp_accepted_participation_e8s : nat64; + icp_ledger_account_balance_e8s : nat64; +}; +type Response = record { governance_error : opt GovernanceError }; +type Result = variant { Ok : Ok; Err : Err }; +type SetDappControllersCallResult = record { possibility : opt Possibility_1 }; +type SetDappControllersResponse = record { failed_updates : vec FailedUpdate }; +type SetModeCallResult = record { possibility : opt Possibility_2 }; +type SettleCommunityFundParticipationResult = record { + possibility : opt Possibility; +}; +type SnsNeuronRecipe = record { + sns : opt TransferableAmount; + neuron_attributes : opt NeuronAttributes; + investor : opt Investor; +}; +type Swap = record { + neuron_recipes : vec SnsNeuronRecipe; + finalize_swap_in_progress : opt bool; + cf_participants : vec CfParticipant; + init : opt Init; + lifecycle : int32; + buyers : vec record { text; BuyerState }; + params : opt Params; + open_sns_token_swap_proposal_id : opt nat64; +}; +type SweepResult = record { failure : nat32; skipped : nat32; success : nat32 }; +type TransferableAmount = record { + transfer_start_timestamp_seconds : nat64; + amount_e8s : nat64; + transfer_success_timestamp_seconds : nat64; +}; +service : (Init) -> { + error_refund_icp : (ErrorRefundIcpRequest) -> (ErrorRefundIcpResponse); + finalize_swap : (record {}) -> (FinalizeSwapResponse); + get_buyer_state : (GetBuyerStateRequest) -> (GetBuyerStateResponse) query; + get_buyers_total : (record {}) -> (GetBuyersTotalResponse); + get_canister_status : (record {}) -> (CanisterStatusResultV2); + get_derived_state : (record {}) -> (GetDerivedStateResponse) query; + get_init : (record {}) -> (GetInitResponse) query; + get_lifecycle : (record {}) -> (GetLifecycleResponse) query; + get_state : (record {}) -> (GetStateResponse) query; + open : (OpenRequest) -> (record {}); + refresh_buyer_tokens : (RefreshBuyerTokensRequest) -> ( + RefreshBuyerTokensResponse, + ); + restore_dapp_controllers : (record {}) -> (SetDappControllersCallResult); +} diff --git a/candid/snsw.did b/candid/snsw.did new file mode 100644 index 00000000..3ecd4603 --- /dev/null +++ b/candid/snsw.did @@ -0,0 +1,166 @@ +type AddWasmRequest = record { hash : vec nat8; wasm : opt SnsWasm }; +type AddWasmResponse = record { result : opt Result }; +type AirdropDistribution = record { airdrop_neurons : vec NeuronDistribution }; +type DeployNewSnsRequest = record { sns_init_payload : opt SnsInitPayload }; +type DeployNewSnsResponse = record { + subnet_id : opt principal; + error : opt SnsWasmError; + canisters : opt SnsCanisterIds; +}; +type DeployedSns = record { + root_canister_id : opt principal; + governance_canister_id : opt principal; + index_canister_id : opt principal; + swap_canister_id : opt principal; + ledger_canister_id : opt principal; +}; +type DeveloperDistribution = record { + developer_neurons : vec NeuronDistribution; +}; +type FractionalDeveloperVotingPower = record { + treasury_distribution : opt TreasuryDistribution; + developer_distribution : opt DeveloperDistribution; + airdrop_distribution : opt AirdropDistribution; + swap_distribution : opt SwapDistribution; +}; +type GetAllowedPrincipalsResponse = record { + allowed_principals : vec principal; +}; +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 GetWasmResponse = record { wasm : opt SnsWasm }; +type InitialTokenDistribution = variant { + FractionalDeveloperVotingPower : FractionalDeveloperVotingPower; +}; +type InsertUpgradePathEntriesRequest = record { + upgrade_path : vec SnsUpgrade; + sns_governance_canister_id : opt principal; +}; +type InsertUpgradePathEntriesResponse = record { error : opt SnsWasmError }; +type ListDeployedSnsesResponse = record { instances : vec DeployedSns }; +type ListUpgradeStep = record { + pretty_version : opt PrettySnsVersion; + version : opt SnsVersion; +}; +type ListUpgradeStepsRequest = record { + limit : nat32; + starting_at : opt SnsVersion; + sns_governance_canister_id : opt principal; +}; +type ListUpgradeStepsResponse = record { steps : vec ListUpgradeStep }; +type NeuronDistribution = record { + controller : opt principal; + dissolve_delay_seconds : nat64; + memo : nat64; + stake_e8s : nat64; + vesting_period_seconds : opt nat64; +}; +type PrettySnsVersion = record { + archive_wasm_hash : text; + root_wasm_hash : text; + swap_wasm_hash : text; + ledger_wasm_hash : text; + governance_wasm_hash : text; + index_wasm_hash : text; +}; +type Result = variant { Error : SnsWasmError; Hash : vec nat8 }; +type SnsCanisterIds = record { + root : opt principal; + swap : opt principal; + ledger : opt principal; + index : opt principal; + governance : opt principal; +}; +type SnsInitPayload = record { + url : opt text; + max_dissolve_delay_seconds : opt nat64; + max_dissolve_delay_bonus_percentage : opt nat64; + fallback_controller_principal_ids : vec text; + token_symbol : opt text; + final_reward_rate_basis_points : opt nat64; + neuron_minimum_stake_e8s : opt nat64; + logo : opt text; + name : opt text; + 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; + initial_reward_rate_basis_points : opt nat64; + wait_for_quiet_deadline_increase_seconds : opt nat64; + transaction_fee_e8s : opt nat64; + sns_initialization_parameters : opt text; + max_age_bonus_percentage : opt nat64; + initial_token_distribution : opt InitialTokenDistribution; + reward_rate_transition_duration_seconds : opt nat64; + token_name : opt text; + proposal_reject_cost_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 }; +type SnsWasmCanisterInitPayload = record { + allowed_principals : vec principal; + access_controls_enabled : bool; + sns_subnet_ids : vec principal; +}; +type SnsWasmError = record { message : text }; +type SwapDistribution = record { + total_e8s : nat64; + initial_swap_amount_e8s : nat64; +}; +type TreasuryDistribution = record { total_e8s : nat64 }; +type UpdateAllowedPrincipalsRequest = record { + added_principals : vec principal; + removed_principals : vec principal; +}; +type UpdateAllowedPrincipalsResponse = record { + update_allowed_principals_result : opt UpdateAllowedPrincipalsResult; +}; +type UpdateAllowedPrincipalsResult = variant { + Error : SnsWasmError; + AllowedPrincipals : GetAllowedPrincipalsResponse; +}; +type UpdateSnsSubnetListRequest = record { + sns_subnet_ids_to_add : vec principal; + sns_subnet_ids_to_remove : vec principal; +}; +type UpdateSnsSubnetListResponse = record { error : opt SnsWasmError }; +service : (SnsWasmCanisterInitPayload) -> { + add_wasm : (AddWasmRequest) -> (AddWasmResponse); + deploy_new_sns : (DeployNewSnsRequest) -> (DeployNewSnsResponse); + get_allowed_principals : (record {}) -> (GetAllowedPrincipalsResponse) query; + get_latest_sns_version_pretty : (null) -> (vec record { text; text }) query; + get_next_sns_version : (GetNextSnsVersionRequest) -> ( + GetNextSnsVersionResponse, + ) query; + get_sns_subnet_ids : (record {}) -> (GetSnsSubnetIdsResponse) query; + get_wasm : (GetWasmRequest) -> (GetWasmResponse) query; + insert_upgrade_path_entries : (InsertUpgradePathEntriesRequest) -> ( + InsertUpgradePathEntriesResponse, + ); + list_deployed_snses : (record {}) -> (ListDeployedSnsesResponse) query; + list_upgrade_steps : (ListUpgradeStepsRequest) -> ( + ListUpgradeStepsResponse, + ) query; + update_allowed_principals : (UpdateAllowedPrincipalsRequest) -> ( + UpdateAllowedPrincipalsResponse, + ); + update_sns_subnet_list : (UpdateSnsSubnetListRequest) -> ( + UpdateSnsSubnetListResponse, + ); +} diff --git a/docs/cli-reference/ckbtc/quill-ckbtc.md b/docs/cli-reference/ckbtc/quill-ckbtc.md index f42762a5..99a03d21 100644 --- a/docs/cli-reference/ckbtc/quill-ckbtc.md +++ b/docs/cli-reference/ckbtc/quill-ckbtc.md @@ -6,10 +6,10 @@ The `quill ckbtc` family of commands is used for minting, burning, and transferr ## Basic usage -The basic syntax for running `quill` commands is: +The basic syntax for running `quill ckbtc` commands is: ``` bash -quill [subcommand] [option] [flag] +quill ckbtc [subcommand] [option] [flag] ``` To see the available subcommands, please refer to the [index page](../index.md) of the quill reference. diff --git a/docs/cli-reference/index.md b/docs/cli-reference/index.md index 6146982d..54b2bdb2 100644 --- a/docs/cli-reference/index.md +++ b/docs/cli-reference/index.md @@ -36,5 +36,19 @@ When you have quill installed, you can use the following commands to specify the - [quill replace-node-provider-id](./quill-replace-node-provider-id.md) - [quill scanner-qr-code](./quill-scanner-qr-code.md) - [quill send](./quill-send.md) +- [quill sns](./sns/quill-sns.md) + - [quill sns balance](./sns/quill-sns-balance.md) + - [quill sns configure-dissolve-delay](./sns/quill-sns-configure-dissolve-delay.md) + - [quill sns get-swap-refund](./sns/quill-sns-get-swap-refund.md) + - [quill sns list-deployed-snses](./sns/quill-sns-list-deployed-snses.md) + - [quill sns make-proposal](./sns/quill-sns-make-proposal.md) + - [quill sns make-upgrade-canister-proposal](./sns/quill-sns-make-upgrade-canister-proposal.md) + - [quill sns neuron-permission](./sns/quill-sns-neuron-permission.md) + - [quill sns register-vote](./sns/quill-sns-register-vote.md) + - [quill sns stake-maturity](./sns/quill-sns-stake-maturity.md) + - [quill sns stake-neuron](./sns/quill-sns-stake-neuron.md) + - [quill sns status](./sns/quill-sns-status.md) + - [quill sns swap](./sns/quill-sns-swap.md) + - [quill sns transfer](./sns/quill-sns-transfer.md) - [quill transfer](./quill-transfer.md) - [quill update-node-provider](./quill-update-node-provider.md) diff --git a/docs/cli-reference/quill-account-balance.md b/docs/cli-reference/quill-account-balance.md index 8ea1919d..d8df4399 100644 --- a/docs/cli-reference/quill-account-balance.md +++ b/docs/cli-reference/quill-account-balance.md @@ -12,15 +12,15 @@ quill account-balance [flag] ## Arguments -| Argument | Description | -|----------|-------------| +| Argument | Description | +|----------------|---------------------------------| | `` | The id of the account to query. | ## Flags -| Flag | Description | -|----------------------|-------------------------------------------------| -| `--dry-run` | Will display the query, but not send it. | -| `-h`, `--help` | Displays usage information. | -| `--yes` | Skips confirmation and sends the message directly. | +| Flag | Description | +|----------------|----------------------------------------------------| +| `--dry-run` | Will display the query, but not send it. | +| `-h`, `--help` | Displays usage information. | +| `--yes` | Skips confirmation and sends the message directly. | diff --git a/docs/cli-reference/sns/quill-sns-balance.md b/docs/cli-reference/sns/quill-sns-balance.md new file mode 100644 index 00000000..541787df --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-balance.md @@ -0,0 +1,32 @@ +# quill sns balance + +Sends a ledger account-balance query call. + +The `--of` parameter is required if a signing key is not provided. + +## Basic usage + +The basic syntax for running `quill sns balance` commands is: + +```bash +quill sns balance [option] +``` + +## Flags + +| Flag | Description | +|----------------|----------------------------------------------------| +| `--dry-run` | Will display the query, but not send it. | +| `-h`, `--help` | Displays usage information. | +| `--yes` | Skips confirmation and sends the message directly. | + +## Options + +| Option | Description | +|-----------------------------|----------------------------------------| +| `--of ` | The account to query | +| `--subaccount ` | The subaccount of the account to query | + +## Remarks + +The queried account can be specified as a separate principal and subaccount, or as a single ICRC-1 account. diff --git a/docs/cli-reference/sns/quill-sns-configure-dissolve-delay.md b/docs/cli-reference/sns/quill-sns-configure-dissolve-delay.md new file mode 100644 index 00000000..d53944b3 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-configure-dissolve-delay.md @@ -0,0 +1,38 @@ +# quill sns configure-dissolve-delay + +Signs a ManageNeuron message to configure the dissolve delay of a neuron. With this command neuron +holders can start dissolving, stop dissolving, or increase dissolve delay. The dissolve delay of a +neuron determines its voting power, its ability to vote, its ability to make proposals, and other +actions it can take (such as disbursing). + +## Basic usage + +The basic syntax for running `quill sns configure-dissolve-delay` commands is: + +```bash +quill sns configure-dissolve-delay [option] +``` + +## Arguments + +| Argument | Description | +|---------------|------------------------------------| +| `` | The ID of the neuron to configure. | + +## Flags + +| Flag | Description | +|----------------------|-----------------------------------------------| +| `-h`, `--help` | Displays usage information. | +| `--start-dissolving` | The neuron will go into the dissolving state. | +| `--stop-dissolving` | The neuron will exit the dissolving state. | + +## Options + +| Option | Description | +|-------------------------------------------------------|--------------------------------------------------------------------------| +| `-a`, `--additional-dissolve-delay-seconds ` | Additional number of seconds to add to the dissolve delay of the neuron. | + +## Remarks + +When the neuron starts dissolving, a countdown timer will begin. When the timer is exhausted (i.e. dissolve_delay_seconds amount of time has elapsed), the neuron can be disbursed. When the neuron stops dissolving, whatever amount of dissolve delay seconds is left in the countdown timer is stored. A neuron's dissolve delay can be extended (for instance to increase voting power) by using the `--additional_dissolve_delay_seconds` flag. If the neuron is already dissolving and this argument is specified, the neuron will stop dissolving and begin aging. diff --git a/docs/cli-reference/sns/quill-sns-get-swap-refund.md b/docs/cli-reference/sns/quill-sns-get-swap-refund.md new file mode 100644 index 00000000..b760c3b5 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-get-swap-refund.md @@ -0,0 +1,27 @@ +# quill sns get-swap-refund + +Signs a message to request a refund from the SNS swap canister. If the swap was aborted or failed, or some of your contributed ICP never made it into a neuron, this command can retrieve your unused ICP, minus transaction fees. + +## Basic usage + +The basic syntax for running `quill sns get-swap-refund` commands is: + +```bash +quill sns get-swap-refund [option] +``` + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | + +## Options + +| Option | Description | +|---------------------------|----------------------------------------------------------------------| +| `--principal ` | The principal that made the ICP contribution and should be refunded. | + +## Remarks + +If no principal is provided, the sender's principal will be used. diff --git a/docs/cli-reference/sns/quill-sns-list-deployed-snses.md b/docs/cli-reference/sns/quill-sns-list-deployed-snses.md new file mode 100644 index 00000000..41da925d --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-list-deployed-snses.md @@ -0,0 +1,19 @@ +# quill sns list-deployed-snses + +Lists all SNSes that have been deployed by the NNS. + +## Basic usage + +The basic syntax for running `quill sns list-deploy-snses` commands is: + +```bash +quill sns list-deployed-snses [option] +``` + +## Flags + +| Flag | Description | +|----------------|----------------------------------------------------| +| `--dry-run` | Will display the query, but not send it. | +| `-h`, `--help` | Displays usage information. | +| `--yes` | Skips confirmation and sends the message directly. | diff --git a/docs/cli-reference/sns/quill-sns-make-proposal.md b/docs/cli-reference/sns/quill-sns-make-proposal.md new file mode 100644 index 00000000..1c75da56 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-make-proposal.md @@ -0,0 +1,43 @@ +# quill sns make-proposal + +Signs a ManageNeuron message to submit a proposal. With this command, neuron holders can submit +proposals (such as a Motion Proposal) to be voted on by other neuron holders. + +## Basic usage + +The basic syntax for running `quill sns make-proposal` commands is: + +```bash +quill sns make-proposal --proposal [option] +``` + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | + +## Options + +| Option | Description | +|-------------------------|-------------------------------| +| `--proposal ` | The proposal to be submitted. | + +## Remarks + +Proposals must be formatted as candid records. For example: + +```candid +( + record { + title = "SNS Launch"; + url = "https://dfinity.org"; + summary = "A motion to start the SNS"; + action = opt variant { + Motion = record { + motion_text = "I hereby raise the motion that the use of the SNS shall commence"; + } + }; + } +) +``` diff --git a/docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.md b/docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.md new file mode 100644 index 00000000..cc530f73 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.md @@ -0,0 +1,38 @@ +# quill sns make-upgrade-canister-proposal + +Signs a ManageNeuron message to submit a UpgradeSnsControlledCanister proposal. + +## Basic usage + +The basic syntax for running `quill sns make-upgrade-canister-proposal` commands is: + +```bash +quill sns make-upgrade-canister-proposal --target-canister-id --wasm-path [option] +``` + +## Arguments + +| Argument | Description | +|------------------------|------------------------------------------| +| `` | The ID of the neuron making the proposal | + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | + +## Options + +| Option | Description | +|---------------------------------------------|---------------------------------------------------------------------------------------| +| `--canister-upgrade-arg-path ` | Path to the file containing argument to post-upgrade method of the new canister WASM. | +| `--summary ` | Summary of the proposal. | +| `--target-canister-id ` | Canister to be upgraded. | +| `--title ` | Title of the proposal. | +| `--url <URL>` | URL of the proposal. | +| `--wasm-path <WASM_PATH>` | Path to the WASM file to be installed into the target canister. | + +## Remarks + +If an empty summary is provided, a somewhat generic summary will be constructed. The default title is "Upgrade Canister". diff --git a/docs/cli-reference/sns/quill-sns-neuron-permission.md b/docs/cli-reference/sns/quill-sns-neuron-permission.md new file mode 100644 index 00000000..26be57d7 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-neuron-permission.md @@ -0,0 +1,50 @@ +# quill sns neuron-permission + +Signs a ManageNeuron message to add or remove permissions for a principal to/from a neuron. + +This will selectively enable/disable that principal to do a variety of management tasks for the +neuron, including voting and disbursing. + +## Basic usage + +The basic syntax for running `quill sns neuron-permission` commands is: + +```bash +quill sns neuron-permission <NEURON_ID> <SUBCOMMAND> --principal <PRINCIPAL> --permissions <PERMISSIONS>... +``` + +## Arguments + +| Argument | Description | +|----------------|--------------------------------------------------------| +| `<SUBCOMMAND>` | Whether to add or remove permissions. (`add`/`remove`) | +| `<NEURON_ID>` | The ID of the neuron to configure. | + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | + +## Options + +| Option | Description | +|-------------------------------|------------------------------------------------------| +| `--permissions <PERMISSIONS>` | The permissions to add to/remove from the principal. | +| `--principal <PRINCIPAL>` | The principal to change the permissions of. | + +## Remarks + +Multiple permissions can be specified in one command. The possible permissions are: + +* `unspecified` +* `configure-dissolve-state` +* `manage-principals` +* `submit-proposal` +* `vote` +* `disburse` +* `split` +* `merge-maturity` +* `disburse-maturity` +* `stake-maturity` +* `manage-voting-permission` diff --git a/docs/cli-reference/sns/quill-sns-register-vote.md b/docs/cli-reference/sns/quill-sns-register-vote.md new file mode 100644 index 00000000..f71f58ed --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-register-vote.md @@ -0,0 +1,30 @@ +# quill sns register-vote + +Signs a ManageNeuron message to register a vote for a proposal. Registering a vote will update the ballot of the given proposal and could trigger followees to vote. When enough votes are cast or enough time passes, the proposal will either be rejected or adopted and executed. + +## Basic usage + +The basic syntax for running `quill sns register-vote` commands is: + +```bash +quill sns register-vote <NEURON_ID> --proposal-id <PROPOSAL_ID> --vote <VOTE> [option] +``` + +## Arguments + +| Argument | Description | +|---------------|------------------------------------| +| `<NEURON_ID>` | The ID of the neuron to configure. | + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | + +## Options + +| Option | Description | +|-------------------------------|--------------------------------------------| +| `--proposal-id <PROPOSAL_ID>` | The ID of the proposal to be voted on. | +| `--vote <VOTE>` | The vote to be cast on the proposal (y/n). | diff --git a/docs/cli-reference/sns/quill-sns-stake-maturity.md b/docs/cli-reference/sns/quill-sns-stake-maturity.md new file mode 100644 index 00000000..4e7fb9dd --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-stake-maturity.md @@ -0,0 +1,31 @@ +# quill sns stake-maturity + +Signs a ManageNeuron message to stake a percentage of a neuron's maturity. + +A neuron's total stake is the combination of its staked governance tokens and staked maturity. + +## Basic usage + +The basic syntax for running `quill sns stake-maturity` commands is: + +```bash +quill sns stake-maturity <NEURON_ID> --percentage <PERCENTAGE> [option] +``` + +## Arguments + +| Argument | Description | +|---------------|------------------------------------| +| `<NEURON_ID>` | The ID of the neuron to configure. | + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | + +## Options + +| Option | Description | +|-----------------------------|---------------------------------------------------------| +| `--percentage <PERCENTAGE>` | The percentage of the current maturity to stake (1-100) | diff --git a/docs/cli-reference/sns/quill-sns-stake-neuron.md b/docs/cli-reference/sns/quill-sns-stake-neuron.md new file mode 100644 index 00000000..b16a5e2c --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-stake-neuron.md @@ -0,0 +1,37 @@ +# quill sns stake-neuron + +Signs messages needed to stake governance tokens for a neuron. First, stake-neuron will sign a ledger transfer to a subaccount of the Governance canister calculated from the provided private key and memo. Second, stake-neuron will sign a ManageNeuron message for Governance to claim the neuron for the principal derived from the provided private key. + +## Basic usage + +The basic syntax for running `quill sns stake-neuron` commands is: + +```bash +quill sns stake-neuron --memo <MEMO> [option] +``` + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | +| `--claim-only` | No transfer will be made. | + +## Options + +| Option | Descriptio | +|---------------------------------------|---------------------------------------------------------------------------| +| `--amount <AMOUNT>` | The amount of tokens in e8s to be transferred to the Governance canister. | +| `--fee <FEE>` | The amount that the caller pays for the transaction. | +| `--from-subaccount <FROM_SUBACCOUNT>` | The subaccount to make the transfer from. | +| `--memo <MEMO> ` | An arbitrary number used in calculating the neuron's subaccount. | + +## Remarks + +The amount of specified tokens will be transferred to the governance canister's ledger subaccount (the neuron's account ID) from the account ID derived from the provided private key. This is known as a staking transfer. These funds will be returned when disbursing the neuron. If an amount is _not_ specified, no transfer will be made, and only a neuron claim command will be signed. This is useful for situations where the transfer was initially made with some other command or tool. + +The memo must be unique among the neurons claimed for a single principal. More information on ledger accounts and subaccounts can be found here: [Ledger Canister Overview](https://smartcontracts.org/docs/integration/ledger-quick-start.html#_ledger_canister_overview) + +The default fee is 0.0001 tokens. Use the `--fee` flag when using an SNS that sets its own transaction fee. + +If `--claim-only` is specified, then only the neuron claim message will be generated. This is useful if there was an error previously submitting the notification which you have since rectified, or if you have made the transfer with another tool. diff --git a/docs/cli-reference/sns/quill-sns-status.md b/docs/cli-reference/sns/quill-sns-status.md new file mode 100644 index 00000000..bf08963f --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-status.md @@ -0,0 +1,19 @@ +# quill sns status + +Fetches the status of the canisters in the SNS. This includes their controller, running status, canister settings, cycle balance, memory size, daily cycle burn rate, and module hash, along with their principals. + +## Basic usage + +The basic syntax for running `quill sns status` commands is: + +```bash +quill sns status [option] +``` + +## Flags + +| Flag | Description | +|----------------|----------------------------------------------------| +| `--dry-run` | Will display the query, but not send it. | +| `-h`, `--help` | Displays usage information. | +| `--yes` | Skips confirmation and sends the message directly. | diff --git a/docs/cli-reference/sns/quill-sns-swap.md b/docs/cli-reference/sns/quill-sns-swap.md new file mode 100644 index 00000000..3f4215b4 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-swap.md @@ -0,0 +1,31 @@ +# quill sns swap + +Signs messages needed to participate in the initial token swap. This operation consists of two messages: First, `amount` ICP is transferred to the swap canister on the NNS ledger, under the subaccount for your principal. Second, the swap canister is notified that the transfer has been made. + +## Basic usage + +The basic syntax for running `quill sns swap` commands is: + +```bash +quill sns swap [option] +``` + +## Flags + +| Flag | Description | +|-----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | +| `--notify-only` | No transfer will be made. | + +## Options + +| Option | Description | +|---------------------|-------------------------------------------------------------------------------| +| `--amount <AMOUNT>` | The amount of ICP to transfer. | +| `--memo <MEMO>` | An arbitrary number used to identify the NNS block this transfer was made in. | + +## Remarks + +Once the swap has been finalized, if it was successful, you will receive your neurons automatically. Your neuron's share of the governance tokens at sale finalization will be proportional to your share of the contributed ICP. + +If `--notify-only` is specified, only the notification message will be generated. This is useful if there was an error previously submitting the notification which you have since rectified, or if you have made the transfer with another tool. diff --git a/docs/cli-reference/sns/quill-sns-transfer.md b/docs/cli-reference/sns/quill-sns-transfer.md new file mode 100644 index 00000000..952cba57 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns-transfer.md @@ -0,0 +1,39 @@ +# quill sns transfer + +Signs a ledger transfer update call. + +## Basic usage + +The basic syntax for running `quill sns transfer` commands is: + +```bash +quill sns transfer <TO> --amount <AMOUNT> [option] +``` + +## Arguments + +| Argument | Description | +|----------|--------------------------| +| `<TO>` | The destination account. | + +## Flags + +| Flag | Description | +|----------------|-----------------------------| +| `-h`, `--help` | Displays usage information. | + +## Options + +| Option | Description | +|---------------------------------------|------------------------------------------------------| +| `--amount <AMOUNT>` | Amount of governance tokens to transfer. | +| `--fee <FEE>` | The amount that the caller pays for the transaction. | +| `--from-subaccount <FROM_SUBACCOUNT>` | The subaccount to transfer from. | +| `--memo <MEMO>` | An arbitrary number associated with a transaction. | +| `--to-subaccount <TO_SUBACCOUNT>` | The subaccount of the destination account. | + +## Remarks + +The default fee is 0.0001 tokens. Use the `--fee` flag when using an SNS that sets its own transaction fee. + +The destination account can be specified as a separate principal and subaccount, or as a single ICRC-1 account. diff --git a/docs/cli-reference/sns/quill-sns.md b/docs/cli-reference/sns/quill-sns.md new file mode 100644 index 00000000..3ebde295 --- /dev/null +++ b/docs/cli-reference/sns/quill-sns.md @@ -0,0 +1,24 @@ +# quill sns + +The `quill sns` family of commands is used to interact with a Service Nervous System (SNS) canister array. For more information about SNS, see [the wiki page](https://internetcomputer.org/docs/current/tokenomics/sns/sns-intro-tokens). + +`quill sns` commands use the same authentication flags as other `quill` commands, but require another `--canister-ids-file <FILE>` flag. This should contain the path to a file containing a JSON document describing the layout of an SNS. An example of such a file would be: + +```json +{ + "governance_canister_id": "rrkah-fqaaa-aaaaa-aaaaq-cai", + "ledger_canister_id": "ryjl3-tyaaa-aaaaa-aaaba-cai", + "root_canister_id": "r7inp-6aaaa-aaaaa-aaabq-cai", + "dapp_canister_id_list": [ "qoctq-giaaa-aaaaa-aaaea-cai" ] +} +``` + +## Basic usage + +The basic syntax for running `quill sns` commands is: + +```bash +quill sns [subcommand] [option] [flag] +``` + +To see the available subcommands, please refer to the [index page](../index.md) of the quill reference. diff --git a/src/commands/account_balance.rs b/src/commands/account_balance.rs index 612217e1..3b714e55 100644 --- a/src/commands/account_balance.rs +++ b/src/commands/account_balance.rs @@ -1,6 +1,6 @@ use crate::{ commands::send::submit_unsigned_ingress, - lib::{ledger_canister_id, AnyhowResult}, + lib::{ledger_canister_id, AnyhowResult, ROLE_NNS_LEDGER}, }; use candid::{CandidType, Encode}; use clap::Parser; @@ -26,12 +26,14 @@ pub struct AccountBalanceOpts { } // We currently only support a subset of the functionality. +#[tokio::main] pub async fn exec(opts: AccountBalanceOpts, fetch_root_key: bool) -> AnyhowResult { let args = Encode!(&AccountBalanceArgs { account: opts.account_id, })?; submit_unsigned_ingress( ledger_canister_id(), + ROLE_NNS_LEDGER, "account_balance_dfx", args, opts.yes, diff --git a/src/commands/ckbtc.rs b/src/commands/ckbtc.rs index 0c3ce8f1..034de34b 100644 --- a/src/commands/ckbtc.rs +++ b/src/commands/ckbtc.rs @@ -7,11 +7,7 @@ use ic_icrc1::Account; use openssl::sha::Sha256; use rust_decimal::Decimal; -use crate::{ - get_auth, - lib::{ckbtc_minter_canister_id, AnyhowResult}, - BaseOpts, -}; +use crate::lib::{ckbtc_minter_canister_id, AnyhowResult, AuthInfo}; use super::print_vec; @@ -25,44 +21,41 @@ mod withdrawal_address; /// Commands for chain-key bitcoin (ckBTC) #[derive(Subcommand)] pub enum CkbtcCommand { - Balance(BaseOpts<balance::BalanceOpts>), - UpdateBalance(BaseOpts<update_balance::UpdateBalanceOpts>), - Transfer(BaseOpts<transfer::TransferOpts>), - RetrieveBtc(BaseOpts<retrieve_btc::RetrieveBtcOpts>), - RetrieveBtcStatus(BaseOpts<retrieve_btc_status::RetrieveBtcStatusOpts>), - WithdrawalAddress(BaseOpts<withdrawal_address::GetWithdrawalAddressOpts>), + Balance(balance::BalanceOpts), + UpdateBalance(update_balance::UpdateBalanceOpts), + Transfer(transfer::TransferOpts), + RetrieveBtc(retrieve_btc::RetrieveBtcOpts), + RetrieveBtcStatus(retrieve_btc_status::RetrieveBtcStatusOpts), + WithdrawalAddress(withdrawal_address::GetWithdrawalAddressOpts), } -pub fn dispatch(command: CkbtcCommand) -> AnyhowResult { +pub fn dispatch( + auth: &AuthInfo, + command: CkbtcCommand, + qr: bool, + fetch_root_key: bool, +) -> AnyhowResult { match command { CkbtcCommand::UpdateBalance(opts) => { - let qr = opts.global_opts.qr; - let out = update_balance::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = update_balance::exec(auth, opts)?; print_vec(qr, &out)?; } CkbtcCommand::Transfer(opts) => { - let qr = opts.global_opts.qr; - let out = transfer::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = transfer::exec(auth, opts)?; print_vec(qr, &out)?; } CkbtcCommand::RetrieveBtc(opts) => { - let qr = opts.global_opts.qr; - let out = retrieve_btc::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = retrieve_btc::exec(auth, opts)?; print_vec(qr, &out)?; } CkbtcCommand::RetrieveBtcStatus(opts) => { - retrieve_btc_status::exec(opts.command_opts, opts.global_opts.fetch_root_key)?; + retrieve_btc_status::exec(opts, fetch_root_key)?; } CkbtcCommand::Balance(opts) => { - let fetch_root_key = opts.global_opts.fetch_root_key; - balance::exec( - &get_auth(opts.global_opts)?, - opts.command_opts, - fetch_root_key, - )?; + balance::exec(auth, opts, fetch_root_key)?; } CkbtcCommand::WithdrawalAddress(opts) => { - withdrawal_address::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + withdrawal_address::exec(auth, opts)?; } } Ok(()) diff --git a/src/commands/ckbtc/balance.rs b/src/commands/ckbtc/balance.rs index ac1af29d..2030775f 100644 --- a/src/commands/ckbtc/balance.rs +++ b/src/commands/ckbtc/balance.rs @@ -4,7 +4,10 @@ use ic_icrc1::Account; use crate::{ commands::{get_ids, send::submit_unsigned_ingress}, - lib::{ckbtc_canister_id, AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount}, + lib::{ + ckbtc_canister_id, AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount, + ROLE_ICRC1_LEDGER, + }, }; /// Sends a message to check the provided user's ckBTC balance. @@ -49,6 +52,7 @@ pub async fn exec(auth: &AuthInfo, opts: BalanceOpts, fetch_root_key: bool) -> A } submit_unsigned_ingress( ckbtc_canister_id(opts.testnet), + ROLE_ICRC1_LEDGER, "icrc1_balance_of", Encode!(&account)?, opts.yes, diff --git a/src/commands/ckbtc/retrieve_btc.rs b/src/commands/ckbtc/retrieve_btc.rs index e9b78189..338be8e8 100644 --- a/src/commands/ckbtc/retrieve_btc.rs +++ b/src/commands/ckbtc/retrieve_btc.rs @@ -11,7 +11,7 @@ use crate::{ lib::{ ckbtc_canister_id, ckbtc_minter_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - AnyhowResult, AuthInfo, ParsedSubaccount, + AnyhowResult, AuthInfo, ParsedSubaccount, ROLE_CKBTC_MINTER, ROLE_ICRC1_LEDGER, }, }; @@ -76,6 +76,7 @@ pub fn exec(auth: &AuthInfo, opts: RetrieveBtcOpts) -> AnyhowResult<Vec<IngressW messages.push(sign_ingress_with_request_status_query( auth, ckbtc_canister_id(opts.testnet), + ROLE_ICRC1_LEDGER, "icrc1_transfer", Encode!(&transfer_args)?, )?); @@ -87,6 +88,7 @@ pub fn exec(auth: &AuthInfo, opts: RetrieveBtcOpts) -> AnyhowResult<Vec<IngressW messages.push(sign_ingress_with_request_status_query( auth, ckbtc_minter_canister_id(opts.testnet), + ROLE_CKBTC_MINTER, "retrieve_btc", Encode!(&retrieve_args)?, )?); diff --git a/src/commands/ckbtc/retrieve_btc_status.rs b/src/commands/ckbtc/retrieve_btc_status.rs index 46758a82..fdcc068c 100644 --- a/src/commands/ckbtc/retrieve_btc_status.rs +++ b/src/commands/ckbtc/retrieve_btc_status.rs @@ -4,7 +4,7 @@ use ic_ckbtc_minter::queries::RetrieveBtcStatusRequest; use crate::{ commands::send::submit_unsigned_ingress, - lib::{ckbtc_minter_canister_id, AnyhowResult}, + lib::{ckbtc_minter_canister_id, AnyhowResult, ROLE_CKBTC_MINTER}, }; /// Sends a message to check the status of a ckBTC-to-BTC conversion. @@ -32,6 +32,7 @@ pub async fn exec(opts: RetrieveBtcStatusOpts, fetch_root_key: bool) -> AnyhowRe }; submit_unsigned_ingress( ckbtc_minter_canister_id(opts.testnet), + ROLE_CKBTC_MINTER, "retrieve_btc_status", Encode!(&args)?, opts.yes, diff --git a/src/commands/ckbtc/transfer.rs b/src/commands/ckbtc/transfer.rs index 4648be68..339378c9 100644 --- a/src/commands/ckbtc/transfer.rs +++ b/src/commands/ckbtc/transfer.rs @@ -7,7 +7,7 @@ use crate::{ lib::{ ckbtc_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount, + AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount, ROLE_ICRC1_LEDGER, }, }; @@ -63,6 +63,7 @@ pub fn exec(auth: &AuthInfo, opts: TransferOpts) -> AnyhowResult<Vec<IngressWith let message = sign_ingress_with_request_status_query( auth, ckbtc_canister_id(opts.testnet), + ROLE_ICRC1_LEDGER, "icrc1_transfer", Encode!(&args)?, )?; diff --git a/src/commands/ckbtc/update_balance.rs b/src/commands/ckbtc/update_balance.rs index b4512443..068ad8cb 100644 --- a/src/commands/ckbtc/update_balance.rs +++ b/src/commands/ckbtc/update_balance.rs @@ -5,7 +5,7 @@ use ic_ckbtc_minter::updates::update_balance::UpdateBalanceArgs; use crate::lib::{ ckbtc_minter_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount, + AnyhowResult, AuthInfo, ParsedAccount, ParsedSubaccount, ROLE_CKBTC_MINTER, }; /// Signs a message to mint ckBTC from previously deposited BTC. @@ -33,6 +33,7 @@ pub fn exec(auth: &AuthInfo, opts: UpdateBalanceOpts) -> AnyhowResult<Vec<Ingres let message = sign_ingress_with_request_status_query( auth, ckbtc_minter_canister_id(opts.testnet), + ROLE_CKBTC_MINTER, "update_balance", Encode!(&args)?, )?; diff --git a/src/commands/claim_neurons.rs b/src/commands/claim_neurons.rs index e8fc17b7..d1532c03 100644 --- a/src/commands/claim_neurons.rs +++ b/src/commands/claim_neurons.rs @@ -1,7 +1,7 @@ use crate::lib::{ genesis_token_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - AnyhowResult, AuthInfo, + AnyhowResult, AuthInfo, ROLE_NNS_GTC, }; use anyhow::anyhow; use candid::Encode; @@ -24,6 +24,7 @@ pub fn exec(auth: &AuthInfo) -> AnyhowResult<Vec<IngressWithRequestId>> { Ok(vec![sign_ingress_with_request_status_query( auth, genesis_token_canister_id(), + ROLE_NNS_GTC, "claim_neurons", sig, )?]) diff --git a/src/commands/get_neuron_info.rs b/src/commands/get_neuron_info.rs index ed19dbc9..488b1734 100644 --- a/src/commands/get_neuron_info.rs +++ b/src/commands/get_neuron_info.rs @@ -1,6 +1,6 @@ use crate::{ commands::send::submit_unsigned_ingress, - lib::{governance_canister_id, AnyhowResult}, + lib::{governance_canister_id, AnyhowResult, ROLE_NNS_GOVERNANCE}, }; use candid::Encode; use clap::Parser; @@ -19,10 +19,12 @@ pub struct GetNeuronInfoOpts { } // We currently only support a subset of the functionality. +#[tokio::main] pub async fn exec(opts: GetNeuronInfoOpts, fetch_root_key: bool) -> AnyhowResult { let args = Encode!(&opts.ident)?; submit_unsigned_ingress( governance_canister_id(), + ROLE_NNS_GOVERNANCE, "get_neuron_info", args, opts.yes, diff --git a/src/commands/get_proposal_info.rs b/src/commands/get_proposal_info.rs index 112e22da..dd38e12c 100644 --- a/src/commands/get_proposal_info.rs +++ b/src/commands/get_proposal_info.rs @@ -1,6 +1,6 @@ use crate::{ commands::send::submit_unsigned_ingress, - lib::{governance_canister_id, AnyhowResult}, + lib::{governance_canister_id, AnyhowResult, ROLE_NNS_GOVERNANCE}, }; use candid::Encode; use clap::Parser; @@ -19,10 +19,12 @@ pub struct GetProposalInfoOpts { } // We currently only support a subset of the functionality. +#[tokio::main] pub async fn exec(opts: GetProposalInfoOpts, fetch_root_key: bool) -> AnyhowResult { let args = Encode!(&opts.ident)?; submit_unsigned_ingress( governance_canister_id(), + ROLE_NNS_GOVERNANCE, "get_proposal_info", args, opts.yes, diff --git a/src/commands/list_neurons.rs b/src/commands/list_neurons.rs index 6e65a2bf..b2178f5a 100644 --- a/src/commands/list_neurons.rs +++ b/src/commands/list_neurons.rs @@ -1,7 +1,7 @@ use crate::lib::{ governance_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - AnyhowResult, AuthInfo, + AnyhowResult, AuthInfo, ROLE_NNS_GOVERNANCE, }; use candid::{CandidType, Encode}; use clap::Parser; @@ -32,6 +32,7 @@ pub fn exec(auth: &AuthInfo, opts: ListNeuronsOpts) -> AnyhowResult<Vec<IngressW Ok(vec![sign_ingress_with_request_status_query( auth, governance_canister_id(), + ROLE_NNS_GOVERNANCE, "list_neurons", args, )?]) diff --git a/src/commands/list_proposals.rs b/src/commands/list_proposals.rs index ed238f84..6ac57a91 100644 --- a/src/commands/list_proposals.rs +++ b/src/commands/list_proposals.rs @@ -1,6 +1,6 @@ use crate::{ commands::send::submit_unsigned_ingress, - lib::{governance_canister_id, AnyhowResult}, + lib::{governance_canister_id, AnyhowResult, ROLE_NNS_GOVERNANCE}, }; use candid::Encode; use clap::Parser; @@ -21,6 +21,7 @@ pub struct ListProposalsOpts { } // We currently only support a subset of the functionality. +#[tokio::main] pub async fn exec(opts: ListProposalsOpts, fetch_root_key: bool) -> AnyhowResult { let args = Encode!(&ListProposalInfo { limit: opts.limit.unwrap_or(100), @@ -31,6 +32,7 @@ pub async fn exec(opts: ListProposalsOpts, fetch_root_key: bool) -> AnyhowResult })?; submit_unsigned_ingress( governance_canister_id(), + ROLE_NNS_GOVERNANCE, "list_proposals", args, opts.yes, diff --git a/src/commands/mod.rs b/src/commands/mod.rs index cb8e877d..9078dd2b 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,10 +1,9 @@ //! This module implements the command-line API. -use crate::{get_auth, lib::AnyhowResult, BaseOpts}; +use crate::lib::{AnyhowResult, AuthInfo}; use anyhow::Context; -use clap::{Args, Parser}; +use clap::Parser; use std::io::{self, Write}; -use tokio::runtime::Runtime; mod account_balance; mod ckbtc; @@ -21,6 +20,7 @@ mod qrcode; mod replace_node_provide_id; mod request_status; mod send; +mod sns; mod transfer; mod update_node_provider; @@ -29,91 +29,82 @@ pub use public::get_ids; #[derive(Parser)] pub enum Command { /// Prints the principal id and the account id. - PublicIds(BaseOpts<public::PublicOpts>), - Send(BaseOpts<send::SendOpts>), - Transfer(BaseOpts<transfer::TransferOpts>), + PublicIds(public::PublicOpts), + Send(send::SendOpts), + Transfer(transfer::TransferOpts), /// Claim seed neurons from the Genesis Token Canister. - ClaimNeurons(BaseOpts<Empty>), - NeuronStake(BaseOpts<neuron_stake::StakeOpts>), - NeuronManage(BaseOpts<neuron_manage::ManageOpts>), + ClaimNeurons, + NeuronStake(neuron_stake::StakeOpts), + NeuronManage(neuron_manage::ManageOpts), /// Signs the query for all neurons belonging to the signing principal. - ListNeurons(BaseOpts<list_neurons::ListNeuronsOpts>), - ListProposals(BaseOpts<list_proposals::ListProposalsOpts>), - GetProposalInfo(BaseOpts<get_proposal_info::GetProposalInfoOpts>), - GetNeuronInfo(BaseOpts<get_neuron_info::GetNeuronInfoOpts>), + ListNeurons(list_neurons::ListNeuronsOpts), + ListProposals(list_proposals::ListProposalsOpts), + GetProposalInfo(get_proposal_info::GetProposalInfoOpts), + GetNeuronInfo(get_neuron_info::GetNeuronInfoOpts), /// Queries a ledger account balance. - AccountBalance(BaseOpts<account_balance::AccountBalanceOpts>), + AccountBalance(account_balance::AccountBalanceOpts), /// Update node provider details - UpdateNodeProvider(BaseOpts<update_node_provider::UpdateNodeProviderOpts>), - ReplaceNodeProviderId(BaseOpts<replace_node_provide_id::ReplaceNodeProviderIdOpts>), + UpdateNodeProvider(update_node_provider::UpdateNodeProviderOpts), + ReplaceNodeProviderId(replace_node_provide_id::ReplaceNodeProviderIdOpts), #[clap(subcommand)] Ckbtc(ckbtc::CkbtcCommand), + Sns(sns::SnsOpts), /// Generate a mnemonic seed phrase and generate or recover PEM. Generate(generate::GenerateOpts), /// Print QR Scanner dapp QR code: scan to start dapp to submit QR results. ScannerQRCode, /// Print QR code for data e.g. principal id. - QRCode(BaseOpts<qrcode::QRCodeOpts>), + QRCode(qrcode::QRCodeOpts), } -#[derive(Args)] -pub struct Empty; - -pub fn dispatch(cmd: Command) -> AnyhowResult { - let runtime = Runtime::new().expect("Unable to create a runtime"); +pub fn dispatch(auth: &AuthInfo, cmd: Command, fetch_root_key: bool, qr: bool) -> AnyhowResult { match cmd { - Command::PublicIds(opts) => public::exec(&get_auth(opts.global_opts)?, opts.command_opts)?, + Command::PublicIds(opts) => public::exec(auth, opts)?, Command::Transfer(opts) => { - let qr = opts.global_opts.qr; - let out = transfer::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = transfer::exec(auth, opts)?; print_vec(qr, &out)?; } Command::NeuronStake(opts) => { - let qr = opts.global_opts.qr; - let out = neuron_stake::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = neuron_stake::exec(auth, opts)?; print_vec(qr, &out)?; } Command::NeuronManage(opts) => { - let qr = opts.global_opts.qr; - let out = neuron_manage::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = neuron_manage::exec(auth, opts)?; print_vec(qr, &out)?; } Command::ListNeurons(opts) => { - let qr = opts.global_opts.qr; - let out = list_neurons::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = list_neurons::exec(auth, opts)?; print_vec(qr, &out)?; } - Command::ClaimNeurons(opts) => { - let qr = opts.global_opts.qr; - claim_neurons::exec(&get_auth(opts.global_opts)?) - .and_then(|out| print_vec(qr, &out))?; + Command::ClaimNeurons => { + claim_neurons::exec(auth).and_then(|out| print_vec(qr, &out))?; + } + Command::ListProposals(opts) => { + list_proposals::exec(opts, fetch_root_key)?; + } + Command::GetProposalInfo(opts) => { + get_proposal_info::exec(opts, fetch_root_key)?; + } + Command::GetNeuronInfo(opts) => { + get_neuron_info::exec(opts, fetch_root_key)?; + } + Command::AccountBalance(opts) => { + account_balance::exec(opts, fetch_root_key)?; } - Command::ListProposals(opts) => runtime.block_on(async { - list_proposals::exec(opts.command_opts, opts.global_opts.fetch_root_key).await - })?, - Command::GetProposalInfo(opts) => runtime.block_on(async { - get_proposal_info::exec(opts.command_opts, opts.global_opts.fetch_root_key).await - })?, - Command::GetNeuronInfo(opts) => runtime.block_on(async { - get_neuron_info::exec(opts.command_opts, opts.global_opts.fetch_root_key).await - })?, - Command::AccountBalance(opts) => runtime.block_on(async { - account_balance::exec(opts.command_opts, opts.global_opts.fetch_root_key).await - })?, Command::UpdateNodeProvider(opts) => { - let out = update_node_provider::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = update_node_provider::exec(auth, opts)?; print(&out)?; } Command::ReplaceNodeProviderId(opts) => { - let out = - replace_node_provide_id::exec(&get_auth(opts.global_opts)?, opts.command_opts)?; + let out = replace_node_provide_id::exec(auth, opts)?; print(&out)?; } - Command::Send(opts) => runtime.block_on(async { - send::exec(opts.command_opts, opts.global_opts.fetch_root_key).await - })?, + Command::Send(opts) => { + send::exec(opts, fetch_root_key)?; + } Command::Generate(opts) => generate::exec(opts)?, - Command::Ckbtc(subcmd) => ckbtc::dispatch(subcmd)?, + Command::Ckbtc(subcmd) => ckbtc::dispatch(auth, subcmd, qr, fetch_root_key)?, + Command::Sns(opts) => sns::dispatch(auth, opts, qr, fetch_root_key)?, // QR code for URL: https://p5deo-6aaaa-aaaab-aaaxq-cai.raw.ic0.app/ // Source code: https://github.com/ninegua/ic-qr-scanner Command::ScannerQRCode => { @@ -140,7 +131,7 @@ pub fn dispatch(cmd: Command) -> AnyhowResult { █████████████████████████████████████" ); } - Command::QRCode(opts) => qrcode::exec(opts.command_opts)?, + Command::QRCode(opts) => qrcode::exec(opts)?, } Ok(()) } diff --git a/src/commands/neuron_manage.rs b/src/commands/neuron_manage.rs index 4f8586f4..0b293437 100644 --- a/src/commands/neuron_manage.rs +++ b/src/commands/neuron_manage.rs @@ -1,7 +1,7 @@ use crate::lib::{ governance_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - AnyhowResult, AuthInfo, + AnyhowResult, AuthInfo, ROLE_NNS_GOVERNANCE, }; use anyhow::{anyhow, bail, Context}; use candid::{CandidType, Encode, Principal}; @@ -370,6 +370,7 @@ pub fn exec(auth: &AuthInfo, opts: ManageOpts) -> AnyhowResult<Vec<IngressWithRe generated.push(sign_ingress_with_request_status_query( auth, governance_canister_id(), + ROLE_NNS_GOVERNANCE, "manage_neuron", args, )?); diff --git a/src/commands/neuron_stake.rs b/src/commands/neuron_stake.rs index 683ee59c..58c72169 100644 --- a/src/commands/neuron_stake.rs +++ b/src/commands/neuron_stake.rs @@ -1,16 +1,19 @@ use crate::{ - commands::{send::Memo, transfer}, + commands::{ + send::Memo, + transfer::{self, parse_tokens}, + }, lib::{ governance_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - AnyhowResult, AuthInfo, + AnyhowResult, AuthInfo, ROLE_NNS_GOVERNANCE, }, }; use anyhow::anyhow; use candid::{CandidType, Encode, Principal}; use clap::Parser; use ic_nns_constants::GOVERNANCE_CANISTER_ID; -use icp_ledger::{AccountIdentifier, Subaccount}; +use icp_ledger::{AccountIdentifier, Subaccount, Tokens}; #[derive(CandidType)] pub struct ClaimOrRefreshNeuronFromAccount { @@ -22,8 +25,8 @@ pub struct ClaimOrRefreshNeuronFromAccount { #[derive(Parser)] pub struct StakeOpts { /// ICPs to be staked on the newly created neuron. - #[clap(long)] - amount: Option<String>, + #[clap(long, value_parser = parse_tokens)] + amount: Option<Tokens>, /// The name of the neuron (up to 8 ASCII characters). #[clap(long, validator(neuron_name_validator))] @@ -33,9 +36,9 @@ pub struct StakeOpts { #[clap(long, validator(neuron_name_validator), conflicts_with("name"))] nonce: Option<u64>, - /// Transaction fee, default is 10000 e8s. - #[clap(long)] - fee: Option<String>, + /// Transaction fee, default is 0.0001 ICP. + #[clap(long, value_parser = parse_tokens)] + fee: Option<Tokens>, } pub fn exec(auth: &AuthInfo, opts: StakeOpts) -> AnyhowResult<Vec<IngressWithRequestId>> { @@ -54,7 +57,7 @@ pub fn exec(auth: &AuthInfo, opts: StakeOpts) -> AnyhowResult<Vec<IngressWithReq to: account.to_hex(), amount, fee: opts.fee, - memo: Some(nonce.to_string()), + memo: Some(nonce), }, )?, _ => Vec::new(), @@ -67,6 +70,7 @@ pub fn exec(auth: &AuthInfo, opts: StakeOpts) -> AnyhowResult<Vec<IngressWithReq messages.push(sign_ingress_with_request_status_query( auth, governance_canister_id(), + ROLE_NNS_GOVERNANCE, "claim_or_refresh_neuron_from_account", args, )?); diff --git a/src/commands/replace_node_provide_id.rs b/src/commands/replace_node_provide_id.rs index 9be595a1..6f3118e1 100644 --- a/src/commands/replace_node_provide_id.rs +++ b/src/commands/replace_node_provide_id.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use crate::{ lib::signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - lib::{registry_canister_id, AnyhowResult, AuthInfo}, + lib::{registry_canister_id, AnyhowResult, AuthInfo, ROLE_NNS_REGISTRY}, }; use anyhow::{anyhow, Context}; use candid::{CandidType, Encode}; @@ -56,6 +56,7 @@ pub fn exec( Ok(vec![sign_ingress_with_request_status_query( auth, registry_canister_id(), + ROLE_NNS_REGISTRY, "update_node_operator_config_directly", args, )?]) diff --git a/src/commands/request_status.rs b/src/commands/request_status.rs index 000e3a40..d4cac81b 100644 --- a/src/commands/request_status.rs +++ b/src/commands/request_status.rs @@ -13,6 +13,7 @@ use std::sync::Arc; pub async fn submit( req: &RequestStatus, method_name: Option<String>, + role: &str, fetch_root_key: bool, ) -> AnyhowResult<String> { let canister_id = Principal::from_text(&req.canister_id).expect("Couldn't parse canister id"); @@ -62,8 +63,14 @@ pub async fn submit( } } .await?; - get_idl_string(&blob, canister_id, &method_name.unwrap_or_default(), "rets") - .context("Invalid IDL blob.") + get_idl_string( + &blob, + canister_id, + role, + &method_name.unwrap_or_default(), + "rets", + ) + .context("Invalid IDL blob.") } pub(crate) struct ProxySignReplicaV2Transport { diff --git a/src/commands/send.rs b/src/commands/send.rs index 476698b8..04909f81 100644 --- a/src/commands/send.rs +++ b/src/commands/send.rs @@ -60,6 +60,7 @@ pub struct SendOpts { yes: bool, } +#[tokio::main] pub async fn exec(opts: SendOpts, fetch_root_key: bool) -> AnyhowResult { let json = read_from_file(&opts.file_name)?; if let Ok(val) = serde_json::from_str::<Ingress>(&json) { @@ -80,6 +81,7 @@ pub async fn exec(opts: SendOpts, fetch_root_key: bool) -> AnyhowResult { pub async fn submit_unsigned_ingress( canister_id: Principal, + role: &str, method_name: &str, args: Vec<u8>, yes: bool, @@ -89,6 +91,7 @@ pub async fn submit_unsigned_ingress( let msg = crate::lib::signing::sign_ingress_with_request_status_query( &AuthInfo::NoAuth, canister_id, + role, method_name, args, )?; @@ -113,10 +116,11 @@ async fn submit_ingress_and_check_status( if opts.dry_run { return Ok(()); } - let (_, _, method_name, _) = &message.ingress.parse()?; + let (_, _, method_name, _, role) = &message.ingress.parse()?; match request_status::submit( &message.request_status, Some(method_name.to_string()), + role, fetch_root_key, ) .await @@ -128,7 +132,7 @@ async fn submit_ingress_and_check_status( } async fn send(message: &Ingress, opts: &SendOpts) -> AnyhowResult { - let (sender, canister_id, method_name, args) = message.parse()?; + let (sender, canister_id, method_name, args, role) = message.parse()?; println!("Sending message with\n"); println!(" Call type: {}", message.call_type); @@ -159,6 +163,7 @@ async fn send(message: &Ingress, opts: &SendOpts) -> AnyhowResult { ic_agent::agent::ReplicaV2Transport::query(&transport, canister_id, content) .await?, canister_id, + &role, &method_name, )?; println!("Response: {}", response); diff --git a/src/commands/sns.rs b/src/commands/sns.rs new file mode 100644 index 00000000..33e69553 --- /dev/null +++ b/src/commands/sns.rs @@ -0,0 +1,146 @@ +use std::{ + fmt::{self, Display, Formatter}, + fs, + path::PathBuf, + str::FromStr, +}; + +use anyhow::Context; +use candid::{Deserialize, Principal}; +use clap::{Parser, Subcommand}; +use ic_sns_governance::pb::v1::NeuronId; +use serde::Serialize; + +use crate::lib::{AnyhowResult, AuthInfo}; + +use super::print_vec; + +mod balance; +mod configure_dissolve_delay; +mod get_swap_refund; +mod list_deployed_snses; +mod make_proposal; +mod make_upgrade_canister_proposal; +mod neuron_permission; +mod register_vote; +mod stake_maturity; +mod stake_neuron; +mod status; +mod swap; +mod transfer; + +/// Commands for interacting with a Service Nervous System's Ledger & Governance canisters. +/// +/// Most commands require a JSON file containing a JSON map of canister names to canister IDs. +/// +/// For example, +/// { +/// "governance_canister_id": "rrkah-fqaaa-aaaaa-aaaaq-cai", +/// "ledger_canister_id": "ryjl3-tyaaa-aaaaa-aaaba-cai", +/// "root_canister_id": "r7inp-6aaaa-aaaaa-aaabq-cai", +/// "swap_canister_id": "rkp4c-7iaaa-aaaaa-aaaca-cai" +/// } +#[derive(Parser)] +pub struct SnsOpts { + /// Path to a SNS canister JSON file (see `quill sns help`) + #[clap(long, global = true, help_heading = "COMMON")] + canister_ids_file: Option<PathBuf>, + #[clap(subcommand)] + subcommand: SnsCommand, +} + +#[derive(Subcommand)] +pub enum SnsCommand { + Balance(balance::BalanceOpts), + ConfigureDissolveDelay(configure_dissolve_delay::ConfigureDissolveDelayOpts), + GetSwapRefund(get_swap_refund::GetSwapRefundOpts), + ListDeployedSnses(list_deployed_snses::ListDeployedSnsesOpts), + MakeProposal(make_proposal::MakeProposalOpts), + MakeUpgradeCanisterProposal(make_upgrade_canister_proposal::MakeUpgradeCanisterProposalOpts), + NeuronPermission(neuron_permission::NeuronPermissionOpts), + RegisterVote(register_vote::RegisterVoteOpts), + StakeMaturity(stake_maturity::StakeMaturityOpts), + StakeNeuron(stake_neuron::StakeNeuronOpts), + Status(status::StatusOpts), + Swap(swap::SwapOpts), + Transfer(transfer::TransferOpts), +} + +pub fn dispatch(auth: &AuthInfo, opts: SnsOpts, qr: bool, fetch_root_key: bool) -> AnyhowResult { + let canister_ids = opts.canister_ids_file + .context("Cannot sign message without knowing the SNS canister ids, did you forget `--canister-ids-file <json-file>`?") + .and_then(|file| Ok(serde_json::from_slice::<SnsCanisterIds>(&fs::read(file)?)?)); + match opts.subcommand { + SnsCommand::Balance(opts) => { + balance::exec(auth, &canister_ids?, opts, fetch_root_key)?; + } + SnsCommand::ConfigureDissolveDelay(opts) => { + let out = configure_dissolve_delay::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::GetSwapRefund(opts) => { + let out = get_swap_refund::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::ListDeployedSnses(opts) => list_deployed_snses::exec(opts, fetch_root_key)?, + SnsCommand::MakeProposal(opts) => { + let out = make_proposal::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::MakeUpgradeCanisterProposal(opts) => { + let out = make_upgrade_canister_proposal::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::NeuronPermission(opts) => { + let out = neuron_permission::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::RegisterVote(opts) => { + let out = register_vote::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::StakeMaturity(opts) => { + let out = stake_maturity::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::StakeNeuron(opts) => { + let out = stake_neuron::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::Status(opts) => status::exec(&canister_ids?, opts, fetch_root_key)?, + SnsCommand::Swap(opts) => { + let out = swap::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + SnsCommand::Transfer(opts) => { + let out = transfer::exec(auth, &canister_ids?, opts)?; + print_vec(qr, &out)?; + } + } + Ok(()) +} + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct SnsCanisterIds { + pub governance_canister_id: Principal, + pub ledger_canister_id: Principal, + pub root_canister_id: Principal, + pub swap_canister_id: Principal, +} + +pub struct ParsedSnsNeuron(pub NeuronId); + +impl Display for ParsedSnsNeuron { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(&hex::encode(&self.0.id)) + } +} + +impl FromStr for ParsedSnsNeuron { + type Err = hex::FromHexError; + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Self(NeuronId { + id: hex::decode(s)?, + })) + } +} diff --git a/src/commands/sns/balance.rs b/src/commands/sns/balance.rs new file mode 100644 index 00000000..5eabec3a --- /dev/null +++ b/src/commands/sns/balance.rs @@ -0,0 +1,67 @@ +use crate::{ + commands::{get_ids, send::submit_unsigned_ingress}, + lib::{AuthInfo, ParsedAccount, ParsedSubaccount, ROLE_ICRC1_LEDGER}, + AnyhowResult, +}; +use candid::Encode; +use clap::Parser; +use ic_icrc1::Account; + +use super::SnsCanisterIds; + +/// Sends a ledger account-balance query call. +/// +/// The `--of` parameter is required if a signing key is not provided. +#[derive(Parser)] +pub struct BalanceOpts { + /// The account to query. + #[clap(long)] + of: Option<ParsedAccount>, + + /// The subaccount of the account to query. + #[clap(long)] + subaccount: Option<ParsedSubaccount>, + + /// 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, +} + +#[tokio::main] +pub async fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: BalanceOpts, + fetch_root_key: bool, +) -> AnyhowResult { + let ledger_canister_id = sns_canister_ids.ledger_canister_id; + let mut account = if let Some(acct) = opts.of { + acct.0 + } else { + let (principal, _) = get_ids(auth)?; + Account { + owner: principal.into(), + subaccount: None, + } + }; + if let Some(subaccount) = opts.subaccount { + account.subaccount = Some(subaccount.0 .0); + } + + submit_unsigned_ingress( + ledger_canister_id, + ROLE_ICRC1_LEDGER, + "icrc1_balance_of", + Encode!(&account)?, + opts.yes, + opts.dry_run, + fetch_root_key, + ) + .await?; + + Ok(()) +} diff --git a/src/commands/sns/configure_dissolve_delay.rs b/src/commands/sns/configure_dissolve_delay.rs new file mode 100644 index 00000000..5ccc0944 --- /dev/null +++ b/src/commands/sns/configure_dissolve_delay.rs @@ -0,0 +1,121 @@ +use crate::{ + lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AuthInfo, ROLE_SNS_GOVERNANCE, + }, + AnyhowResult, +}; +use anyhow::{anyhow, Error}; +use candid::Encode; +use clap::Parser; + +use ic_sns_governance::pb::v1::{ + manage_neuron, + manage_neuron::{ + configure::Operation, Configure, IncreaseDissolveDelay, StartDissolving, StopDissolving, + }, + ManageNeuron, +}; + +use super::{ParsedSnsNeuron, SnsCanisterIds}; + +/// Signs a ManageNeuron message to configure the dissolve delay of a neuron. With this command +/// neuron holders can start dissolving, stop dissolving, or increase dissolve delay. The +/// dissolve delay of a neuron determines its voting power, its ability to vote, its ability +/// to make proposals, and other actions it can take (such as disbursing). +#[derive(Parser)] +pub struct ConfigureDissolveDelayOpts { + /// The id of the neuron to configure as a hex encoded string. + neuron_id: ParsedSnsNeuron, + + /// Additional number of seconds to add to the dissolve delay of a neuron. If the neuron is + /// already dissolving and this argument is specified, the neuron will stop dissolving + /// and begin aging + #[clap(short, long)] + additional_dissolve_delay_seconds: Option<String>, + + /// When this argument is specified, the neuron will go into the dissolving state and a + /// countdown timer will begin. When the timer is exhausted (i.e. dissolve_delay_seconds + /// amount of time has elapsed), the neuron can be disbursed + #[clap(long)] + start_dissolving: bool, + + /// When this argument is specified, the neuron will exit the dissolving state and whatever + /// amount of dissolve delay seconds is left in the countdown timer is stored. A neuron's + /// dissolve delay can be extended (for instance to increase voting power) by using the + /// additional_dissolve_delay_seconds flag + #[clap(long, conflicts_with = "start-dissolving")] + stop_dissolving: bool, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: ConfigureDissolveDelayOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + require_mutually_exclusive( + opts.start_dissolving, + opts.stop_dissolving, + &opts.additional_dissolve_delay_seconds, + )?; + + let neuron_subaccount = opts.neuron_id.0.subaccount().map_err(Error::msg)?; + let governance_canister_id = sns_canister_ids.governance_canister_id; + + let mut args = Vec::new(); + + if opts.stop_dissolving { + args = Encode!(&ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(manage_neuron::Command::Configure(Configure { + operation: Some(Operation::StopDissolving(StopDissolving {})) + })), + })?; + } + + if opts.start_dissolving { + args = Encode!(&ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(manage_neuron::Command::Configure(Configure { + operation: Some(Operation::StartDissolving(StartDissolving {})) + })), + })?; + } + + if let Some(additional_dissolve_delay_seconds) = opts.additional_dissolve_delay_seconds { + let parsed_additional_dissolve_delay_seconds = additional_dissolve_delay_seconds + .parse::<u32>() + .expect("Failed to parse the dissolve delay"); + + args = Encode!(&ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(manage_neuron::Command::Configure(Configure { + operation: Some(Operation::IncreaseDissolveDelay(IncreaseDissolveDelay { + additional_dissolve_delay_seconds: parsed_additional_dissolve_delay_seconds + })) + })), + })?; + }; + + let msg = sign_ingress_with_request_status_query( + auth, + governance_canister_id, + ROLE_SNS_GOVERNANCE, + "manage_neuron", + args, + )?; + Ok(vec![msg]) +} + +fn require_mutually_exclusive( + stop_dissolving: bool, + start_dissolving: bool, + additional_dissolve_delay_seconds: &Option<String>, +) -> AnyhowResult { + match (stop_dissolving, start_dissolving, additional_dissolve_delay_seconds) { + (true, false, None) => Ok(()), + (false, true, None) => Ok(()), + (false, false, Some(_)) => Ok(()), + _ => Err(anyhow!("--stop-dissolving, --start-dissolving, --additional-dissolve-delay-seconds are mutually exclusive arguments")) + } +} diff --git a/src/commands/sns/get_swap_refund.rs b/src/commands/sns/get_swap_refund.rs new file mode 100644 index 00000000..51e29c62 --- /dev/null +++ b/src/commands/sns/get_swap_refund.rs @@ -0,0 +1,47 @@ +use candid::{Encode, Principal}; +use clap::Parser; +use ic_sns_swap::pb::v1::ErrorRefundIcpRequest; + +use crate::{ + commands::get_ids, + lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AnyhowResult, AuthInfo, ROLE_SNS_SWAP, + }, +}; + +use super::SnsCanisterIds; + +/// Signs a message to request a refund from the SNS swap canister. +/// If the swap was aborted or failed, or some of your contributed ICP never made it into a neuron, +/// this command can retrieve your unused ICP, minus transaction fees. +#[derive(Parser)] +pub struct GetSwapRefundOpts { + /// The principal that made the ICP contribution and should be refunded. The ICP will be + /// refunded to the main account of this Principal irrespective of the caller. + #[clap(long)] + principal: Option<Principal>, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: GetSwapRefundOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let principal = if let Some(principal) = opts.principal { + principal + } else { + get_ids(auth)?.0 + }; + let message = ErrorRefundIcpRequest { + source_principal_id: Some(principal.into()), + }; + let req = sign_ingress_with_request_status_query( + auth, + sns_canister_ids.swap_canister_id, + ROLE_SNS_SWAP, + "error_refund_icp", + Encode!(&message)?, + )?; + Ok(vec![req]) +} diff --git a/src/commands/sns/list_deployed_snses.rs b/src/commands/sns/list_deployed_snses.rs new file mode 100644 index 00000000..4bd20827 --- /dev/null +++ b/src/commands/sns/list_deployed_snses.rs @@ -0,0 +1,36 @@ +use candid::Encode; +use clap::Parser; +use ic_sns_wasm::pb::v1::ListDeployedSnsesRequest; + +use crate::{ + commands::send::submit_unsigned_ingress, + 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, +} + +#[tokio::main] +pub async fn exec(opts: ListDeployedSnsesOpts, fetch_root_key: bool) -> AnyhowResult { + let arg = Encode!(&ListDeployedSnsesRequest {})?; + submit_unsigned_ingress( + sns_wasm_canister_id(), + ROLE_SNS_WASM, + "list_deployed_snses", + arg, + opts.yes, + opts.dry_run, + fetch_root_key, + ) + .await?; + Ok(()) +} diff --git a/src/commands/sns/make_proposal.rs b/src/commands/sns/make_proposal.rs new file mode 100644 index 00000000..615d05f3 --- /dev/null +++ b/src/commands/sns/make_proposal.rs @@ -0,0 +1,91 @@ +use std::{fs, path::PathBuf}; + +use crate::{ + lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AuthInfo, ROLE_SNS_GOVERNANCE, + }, + AnyhowResult, +}; +use anyhow::Error; +use candid::{Decode, Encode, IDLArgs}; +use clap::Parser; +use ic_sns_governance::pb::v1::{manage_neuron, ManageNeuron, Proposal}; + +use super::{ParsedSnsNeuron, SnsCanisterIds}; + +/// Signs a ManageNeuron message to submit a proposal. With this command, neuron holders +/// can submit proposals (such as a Motion Proposal) to be voted on by other neuron +/// holders. +#[derive(Parser)] +pub struct MakeProposalOpts { + /// The id of the neuron making the proposal as a hex encoded string. + proposer_neuron_id: ParsedSnsNeuron, + + /// The proposal to be submitted. The proposal must be formatted as a string + /// wrapped candid record. + /// + /// For example: + /// '( + /// record { + /// title="SNS Launch"; + /// url="https://dfinity.org"; + /// summary="A motion to start the SNS"; + /// action=opt variant { + /// Motion=record { + /// motion_text="I hereby raise the motion that the use of the SNS shall commence"; + /// } + /// }; + /// } + /// )' + #[clap(long)] + proposal: Option<String>, + + /// Path to a file containing the proposal. The proposal must be formatted as a string + /// wrapped candid record. + #[clap( + long, + conflicts_with = "proposal", + required_unless_present = "proposal" + )] + proposal_path: Option<PathBuf>, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: MakeProposalOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let neuron_id = opts.proposer_neuron_id.0; + let neuron_subaccount = neuron_id.subaccount().map_err(Error::msg)?; + let governance_canister_id = sns_canister_ids.governance_canister_id; + + let proposal_string = if let Some(proposal) = opts.proposal { + proposal + } else { + fs::read_to_string(opts.proposal_path.unwrap())? + }; + + let proposal = parse_proposal_from_candid_string(proposal_string)?; + + let args = Encode!(&ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(manage_neuron::Command::MakeProposal(proposal)) + })?; + + let msg = sign_ingress_with_request_status_query( + auth, + governance_canister_id, + ROLE_SNS_GOVERNANCE, + "manage_neuron", + args, + )?; + + Ok(vec![msg]) +} + +fn parse_proposal_from_candid_string(proposal_candid: String) -> AnyhowResult<Proposal> { + let args: IDLArgs = proposal_candid.parse()?; + let args: Vec<u8> = args.to_bytes()?; + Decode!(args.as_slice(), Proposal).map_err(Error::msg) +} diff --git a/src/commands/sns/make_upgrade_canister_proposal.rs b/src/commands/sns/make_upgrade_canister_proposal.rs new file mode 100644 index 00000000..dff9ee7a --- /dev/null +++ b/src/commands/sns/make_upgrade_canister_proposal.rs @@ -0,0 +1,135 @@ +use std::path::PathBuf; + +use crate::{ + lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AuthInfo, ROLE_SNS_GOVERNANCE, + }, + AnyhowResult, +}; +use anyhow::{Context, Error}; +use candid::Encode; +use candid::Principal; +use clap::Parser; +use ic_sns_governance::pb::v1::{ + manage_neuron, proposal, ManageNeuron, Proposal, UpgradeSnsControlledCanister, +}; +use k256::sha2::{Digest, Sha256}; + +use super::{ParsedSnsNeuron, SnsCanisterIds}; + +/// Signs a ManageNeuron message to submit a UpgradeSnsControlledCanister +/// proposal. +#[derive(Parser)] +pub struct MakeUpgradeCanisterProposalOpts { + /// The id of the neuron making the proposal. A hex encoded string. + proposer_neuron_id: ParsedSnsNeuron, + + /// Title of the proposal. + #[clap(long, default_value_t = String::from("Upgrade Canister"))] + title: String, + + /// URL of the proposal. + #[clap(long, default_value_t = String::new())] + url: String, + + /// Summary of the proposal. If empty, a somewhat generic summary will be + /// constructed dynamically. + #[clap(long, default_value_t = String::new())] + summary: String, + + /// Canister to be upgraded. + #[clap(long)] + target_canister_id: Principal, + + /// Path to the WASM file to be installed onto the target canister. + #[clap(long)] + wasm_path: PathBuf, + + /// Path to the file containing argument to post-upgrade method of the new canister WASM. + #[clap(long)] + canister_upgrade_arg_path: Option<PathBuf>, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: MakeUpgradeCanisterProposalOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let MakeUpgradeCanisterProposalOpts { + proposer_neuron_id, + title, + url, + summary, + target_canister_id, + wasm_path, + canister_upgrade_arg_path, + } = opts; + + let wasm = std::fs::read(wasm_path).context("Unable to read --wasm-path.")?; + let canister_upgrade_arg = match canister_upgrade_arg_path { + Some(path) => { + Some(std::fs::read(path).context("Unable to read --canister-upgrade-arg-path.")?) + } + None => None, + }; + + // (Dynamically) come up with a summary if one wasn't provided. + let summary = if !summary.is_empty() { + summary + } else { + summarize(target_canister_id, &wasm) + }; + + let proposal = Proposal { + title, + url, + summary, + action: Some(proposal::Action::UpgradeSnsControlledCanister( + UpgradeSnsControlledCanister { + canister_id: Some(target_canister_id.into()), + new_canister_wasm: wasm, + canister_upgrade_arg, + }, + )), + }; + + let neuron_id = proposer_neuron_id.0; + let neuron_subaccount = neuron_id.subaccount().map_err(Error::msg)?; + let governance_canister_id = sns_canister_ids.governance_canister_id; + + let args = Encode!(&ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(manage_neuron::Command::MakeProposal(proposal)) + })?; + + let msg = sign_ingress_with_request_status_query( + auth, + governance_canister_id, + ROLE_SNS_GOVERNANCE, + "manage_neuron", + args, + )?; + + Ok(vec![msg]) +} + +fn summarize(target_canister_id: Principal, wasm: &Vec<u8>) -> String { + // Fingerprint wasm. + let mut hasher = Sha256::new(); + hasher.update(wasm); + let wasm_fingerprint = hex::encode(hasher.finalize()); + + format!( + "Upgrade canister: + + ID: {} + + WASM: + length: {} + fingerprint: {}", + target_canister_id, + wasm.len(), + wasm_fingerprint + ) +} diff --git a/src/commands/sns/neuron_permission.rs b/src/commands/sns/neuron_permission.rs new file mode 100644 index 00000000..bdf7b9a8 --- /dev/null +++ b/src/commands/sns/neuron_permission.rs @@ -0,0 +1,81 @@ +use anyhow::anyhow; +use candid::{Encode, Principal}; +use clap::{ArgEnum, Parser}; +use ic_sns_governance::pb::v1::{ + manage_neuron::{AddNeuronPermissions, Command, RemoveNeuronPermissions}, + ManageNeuron, NeuronPermissionList, NeuronPermissionType, +}; + +use crate::lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AnyhowResult, AuthInfo, ROLE_SNS_GOVERNANCE, +}; + +use super::{ParsedSnsNeuron, SnsCanisterIds}; + +/// Signs a ManageNeuron message to add or remove permissions for a principal to/from a neuron. +/// +/// This will selectively enable/disable that principal to do a variety of management tasks for the neuron, including voting and disbursing. +#[derive(Parser)] +pub struct NeuronPermissionOpts { + /// Whether to add or remove permissions. + #[clap(arg_enum)] + subcommand: Subcmd, + + /// The id of the neuron to configure as a hex encoded string. + neuron_id: ParsedSnsNeuron, + + /// The principal to change the permissions of. + #[clap(long)] + principal: Principal, + + /// The permissions to add to/remove from the principal. You can specify multiple in one command. + #[clap( + long, + multiple_values(true), + use_value_delimiter(true), + arg_enum, + min_values(1), + required(true) + )] + permissions: Vec<NeuronPermissionType>, +} + +#[derive(ArgEnum, Clone)] +enum Subcmd { + Add, + Remove, +} + +pub fn exec( + auth: &AuthInfo, + canister_ids: &SnsCanisterIds, + opts: NeuronPermissionOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let neuron_subaccount = opts.neuron_id.0.subaccount().map_err(|e| anyhow!(e))?; + let permission_list = NeuronPermissionList { + permissions: opts.permissions.into_iter().map(|x| x as i32).collect(), + }; + let req = ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(if let Subcmd::Add = opts.subcommand { + Command::AddNeuronPermissions(AddNeuronPermissions { + principal_id: Some(opts.principal.into()), + permissions_to_add: Some(permission_list), + }) + } else { + Command::RemoveNeuronPermissions(RemoveNeuronPermissions { + principal_id: Some(opts.principal.into()), + permissions_to_remove: Some(permission_list), + }) + }), + }; + let msg = sign_ingress_with_request_status_query( + auth, + canister_ids.governance_canister_id, + ROLE_SNS_GOVERNANCE, + "manage_neuron", + Encode!(&req)?, + )?; + Ok(vec![msg]) +} diff --git a/src/commands/sns/register_vote.rs b/src/commands/sns/register_vote.rs new file mode 100644 index 00000000..d190c19f --- /dev/null +++ b/src/commands/sns/register_vote.rs @@ -0,0 +1,70 @@ +use crate::{ + lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AuthInfo, ROLE_SNS_GOVERNANCE, + }, + AnyhowResult, +}; +use anyhow::{anyhow, Error}; +use candid::Encode; +use clap::Parser; +use ic_sns_governance::pb::v1::{ + manage_neuron, manage_neuron::RegisterVote, ManageNeuron, ProposalId, Vote, +}; + +use super::{ParsedSnsNeuron, SnsCanisterIds}; + +/// Signs a ManageNeuron message to register a vote for a proposal. Registering a vote will +/// update the ballot of the given proposal and could trigger followees to vote. When +/// enough votes are cast or enough time passes, the proposal will either be rejected or +/// adopted and executed. +#[derive(Parser)] +pub struct RegisterVoteOpts { + /// The id of the neuron to configure as a hex encoded string. + neuron_id: ParsedSnsNeuron, + + /// The id of the proposal to voted on. + #[clap(long)] + proposal_id: u64, + + /// The vote to be cast on the proposal [y/n] + #[clap(long)] + vote: String, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: RegisterVoteOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let neuron_subaccount = opts.neuron_id.0.subaccount().map_err(Error::msg)?; + let governance_canister_id = sns_canister_ids.governance_canister_id; + + let vote = match opts.vote.as_str() { + "y" => Ok(Vote::Yes), + "n" => Ok(Vote::No), + _ => Err(anyhow!( + "Unsupported vote supplied to --vote. Supported values: ['y', 'n']" + )), + }?; + + let args = Encode!(&ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(manage_neuron::Command::RegisterVote(RegisterVote { + proposal: Some(ProposalId { + id: opts.proposal_id + }), + vote: vote as i32 + })) + })?; + + let msg = sign_ingress_with_request_status_query( + auth, + governance_canister_id, + ROLE_SNS_GOVERNANCE, + "manage_neuron", + args, + )?; + + Ok(vec![msg]) +} diff --git a/src/commands/sns/stake_maturity.rs b/src/commands/sns/stake_maturity.rs new file mode 100644 index 00000000..c9363c77 --- /dev/null +++ b/src/commands/sns/stake_maturity.rs @@ -0,0 +1,53 @@ +use anyhow::Error; +use candid::Encode; +use clap::Parser; +use ic_sns_governance::pb::v1::{ + manage_neuron::{Command, StakeMaturity}, + ManageNeuron, +}; + +use crate::lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AnyhowResult, AuthInfo, ROLE_SNS_GOVERNANCE, +}; + +use super::{ParsedSnsNeuron, SnsCanisterIds}; + +/// Signs a ManageNeuron message to stake a percentage of a neuron's maturity. +/// +/// A neuron's total stake is the combination of its staked governance tokens and staked maturity. +#[derive(Parser)] +pub struct StakeMaturityOpts { + /// The percentage of the current maturity to stake (1-100). + #[clap(long, value_parser = 1..=100)] + percentage: i64, + + /// The id of the neuron to configure as a hex encoded string. + neuron_id: ParsedSnsNeuron, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: StakeMaturityOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let neuron_subaccount = opts.neuron_id.0.subaccount().map_err(Error::msg)?; + + let governance_canister_id = sns_canister_ids.governance_canister_id; + + let command = ManageNeuron { + command: Some(Command::StakeMaturity(StakeMaturity { + percentage_to_stake: Some(opts.percentage as u32), + })), + subaccount: neuron_subaccount.to_vec(), + }; + + let message = sign_ingress_with_request_status_query( + auth, + governance_canister_id, + ROLE_SNS_GOVERNANCE, + "manage_neuron", + Encode!(&command)?, + )?; + Ok(vec![message]) +} diff --git a/src/commands/sns/stake_neuron.rs b/src/commands/sns/stake_neuron.rs new file mode 100644 index 00000000..1a7fd822 --- /dev/null +++ b/src/commands/sns/stake_neuron.rs @@ -0,0 +1,116 @@ +use crate::commands::transfer::parse_tokens; +use crate::{ + lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AuthInfo, ParsedSubaccount, ROLE_ICRC1_LEDGER, ROLE_SNS_GOVERNANCE, + }, + AnyhowResult, +}; +use candid::Encode; +use clap::Parser; +use ic_icrc1::{endpoints::TransferArg, Account, Memo}; +use ic_nervous_system_common::ledger; +use ic_sns_governance::pb::v1::{ + manage_neuron, + manage_neuron::{ + claim_or_refresh::{By, MemoAndController}, + ClaimOrRefresh, + }, + ManageNeuron, +}; +use icp_ledger::Tokens; + +use super::SnsCanisterIds; + +/// Signs messages needed to stake governance tokens for a neuron. First, stake-neuron will sign +/// a ledger transfer to a subaccount of the Governance canister calculated from the +/// provided private key and memo. Second, stake-neuron will sign a ManageNeuron message for +/// Governance to claim the neuron for the principal derived from the provided private key. +#[derive(Parser)] +pub struct StakeNeuronOpts { + /// The amount of tokens to be transferred to the Governance canister's ledger subaccount + /// (the neuron's AccountId) from the AccountId derived from the provided private key. This is + /// known as a staking transfer. These funds will be returned when disbursing the neuron. + #[clap(long, value_parser = parse_tokens, required_unless_present = "claim-only")] + amount: Option<Tokens>, + + /// The subaccount to make the transfer from. Only necessary if `--amount` is specified. + #[clap(long, requires = "amount")] + from_subaccount: Option<ParsedSubaccount>, + + /// An arbitrary number used in calculating the neuron's subaccount. The memo must be unique among + /// the neurons claimed for a single PrincipalId. More information on ledger accounts and + /// subaccounts can be found here: https://smartcontracts.org/docs/integration/ledger-quick-start.html#_ledger_canister_overview + #[clap(long)] + memo: u64, + + /// The amount that the caller pays for the transaction, default is 0.0001 tokens. Specify this amount + /// when using an SNS that sets its own transaction fee + #[clap(long, value_parser = parse_tokens)] + fee: Option<Tokens>, + + /// If this flag is set, then no transfer will be made, and only the neuron claim message will be generated. + /// This is useful if there was an error previously submitting the notification which you have since rectified, + /// or if you have made the transfer with another tool. + #[clap(long, conflicts_with = "amount", conflicts_with = "from-subaccount")] + claim_only: bool, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: StakeNeuronOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let (controller, _) = crate::commands::public::get_ids(auth)?; + let neuron_subaccount = ledger::compute_neuron_staking_subaccount(controller.into(), opts.memo); + + let governance_canister_id = sns_canister_ids.governance_canister_id; + + let mut messages = Vec::new(); + + // If amount is provided, sign a transfer message that will transfer tokens from the principal's + // account on the ledger to a subaccount of the governance canister. + if let Some(amount) = opts.amount { + let args = TransferArg { + memo: Some(Memo::from(opts.memo)), + amount: amount.get_e8s().into(), + fee: opts.fee.map(|fee| fee.get_e8s().into()), + from_subaccount: opts.from_subaccount.map(|x| x.0 .0), + created_at_time: None, + to: Account { + owner: governance_canister_id.into(), + subaccount: Some(neuron_subaccount.0), + }, + }; + + let msg = sign_ingress_with_request_status_query( + auth, + sns_canister_ids.ledger_canister_id, + ROLE_ICRC1_LEDGER, + "icrc1_transfer", + Encode!(&args)?, + )?; + messages.push(msg); + } + + // Sign a message claiming the neuron with funds staked to the previously calculated subaccount. + let args = Encode!(&ManageNeuron { + subaccount: neuron_subaccount.to_vec(), + command: Some(manage_neuron::Command::ClaimOrRefresh(ClaimOrRefresh { + by: Some(By::MemoAndController(MemoAndController { + memo: opts.memo, + controller: Some(controller.into()), + })) + })) + })?; + + messages.push(sign_ingress_with_request_status_query( + auth, + governance_canister_id, + ROLE_SNS_GOVERNANCE, + "manage_neuron", + args, + )?); + + Ok(messages) +} diff --git a/src/commands/sns/status.rs b/src/commands/sns/status.rs new file mode 100644 index 00000000..48e1d211 --- /dev/null +++ b/src/commands/sns/status.rs @@ -0,0 +1,42 @@ +use candid::Encode; +use clap::Parser; +use ic_sns_root::GetSnsCanistersSummaryRequest; + +use crate::{ + commands::send::submit_unsigned_ingress, + lib::{AnyhowResult, ROLE_SNS_ROOT}, +}; + +use super::SnsCanisterIds; + +/// Fetches the status of the canisters in the SNS. This includes their controller, running status, canister settings, +/// 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, +} + +#[tokio::main] +pub async fn exec(ids: &SnsCanisterIds, opts: StatusOpts, fetch_root_key: bool) -> AnyhowResult { + let root_canister_id = ids.root_canister_id; + let arg = Encode!(&GetSnsCanistersSummaryRequest { + update_canister_list: None, + })?; + submit_unsigned_ingress( + root_canister_id, + ROLE_SNS_ROOT, + "get_sns_canisters_summary", + arg, + opts.yes, + opts.dry_run, + fetch_root_key, + ) + .await?; + Ok(()) +} diff --git a/src/commands/sns/swap.rs b/src/commands/sns/swap.rs new file mode 100644 index 00000000..2274a104 --- /dev/null +++ b/src/commands/sns/swap.rs @@ -0,0 +1,74 @@ +use candid::Encode; +use clap::Parser; +use ic_base_types::PrincipalId; +use ic_sns_swap::pb::v1::RefreshBuyerTokensRequest; +use icp_ledger::{AccountIdentifier, Memo, SendArgs, Subaccount, Tokens}; + +use crate::commands::transfer::parse_tokens; +use crate::lib::{ + ledger_canister_id, + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AnyhowResult, AuthInfo, ROLE_NNS_LEDGER, ROLE_SNS_SWAP, +}; + +use super::SnsCanisterIds; + +/// Signs messages needed to participate in the initial token swap. This operation consists of two messages: +/// First, `amount` ICP is transferred to the swap canister on the NNS ledger, under the subaccount for your principal. +/// Second, the swap canister is notified that the transfer has been made. +/// Once the swap has been finalized, if it was successful, you will receive your neurons automatically. +#[derive(Parser)] +pub struct SwapOpts { + /// The amount of ICP to transfer. Your neuron's share of the governance tokens at sale finalization will be proportional to your share of the contributed ICP. + #[clap(long, requires("memo"), required_unless_present("notify-only"), value_parser = parse_tokens)] + amount: Option<Tokens>, + + /// An arbitrary number used to identify the NNS block this transfer was made in. + #[clap(long)] + memo: Option<u64>, + + /// If this flag is specified, then no transfer will be made, and only the notification message will be generated. + /// This is useful if there was an error previously submitting the notification which you have since rectified, or if you have made the transfer with another tool. + #[clap(long)] + notify_only: bool, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: SwapOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let (controller, _) = crate::commands::public::get_ids(auth)?; + let mut messages = vec![]; + if !opts.notify_only { + let subaccount = Subaccount::from(&PrincipalId(controller)); + let account_id = + AccountIdentifier::new(sns_canister_ids.swap_canister_id.into(), Some(subaccount)); + let request = SendArgs { + amount: opts.amount.unwrap(), + created_at_time: None, + from_subaccount: None, + fee: Tokens::from_e8s(10_000), + memo: Memo(opts.memo.unwrap()), + to: account_id, + }; + messages.push(sign_ingress_with_request_status_query( + auth, + ledger_canister_id(), + ROLE_NNS_LEDGER, + "send_dfx", + Encode!(&request)?, + )?) + } + let refresh = RefreshBuyerTokensRequest { + buyer: controller.to_text(), + }; + messages.push(sign_ingress_with_request_status_query( + auth, + sns_canister_ids.swap_canister_id, + ROLE_SNS_SWAP, + "refresh_buyer_tokens", + Encode!(&refresh)?, + )?); + Ok(messages) +} diff --git a/src/commands/sns/transfer.rs b/src/commands/sns/transfer.rs new file mode 100644 index 00000000..e60b2472 --- /dev/null +++ b/src/commands/sns/transfer.rs @@ -0,0 +1,73 @@ +use crate::commands::transfer::parse_tokens; +use crate::lib::{ + signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, + AnyhowResult, AuthInfo, ParsedSubaccount, +}; +use crate::lib::{ParsedAccount, ROLE_ICRC1_LEDGER}; +use candid::Encode; +use clap::Parser; +use ic_icrc1::{endpoints::TransferArg, Memo}; +use icp_ledger::Tokens; + +use super::SnsCanisterIds; + +/// Signs a ledger transfer update call. +#[derive(Parser)] +pub struct TransferOpts { + /// The destination account. + pub to: ParsedAccount, + + /// The subaccount of the destination account. + #[clap(long)] + pub to_subaccount: Option<ParsedSubaccount>, + + #[clap(long)] + /// The subaccount to transfer from. + pub from_subaccount: Option<ParsedSubaccount>, + + /// Amount of governance tokens to transfer (with up to 8 decimal digits after decimal point) + #[clap(long, value_parser = parse_tokens)] + pub amount: Tokens, + + /// An arbitrary number associated with a transaction. The default is 0 + #[clap(long)] + pub memo: Option<u64>, + + /// The amount that the caller pays for the transaction, default is 0.0001 tokens. Specify this amount + /// when using an SNS that sets its own transaction fee + #[clap(long, value_parser = parse_tokens)] + pub fee: Option<Tokens>, +} + +pub fn exec( + auth: &AuthInfo, + sns_canister_ids: &SnsCanisterIds, + opts: TransferOpts, +) -> AnyhowResult<Vec<IngressWithRequestId>> { + let amount = opts.amount.get_e8s().into(); + let fee = opts.fee.map(|fee| fee.get_e8s().into()); + let memo = opts.memo.map(Memo::from); + let ledger_canister_id = sns_canister_ids.ledger_canister_id; + let mut to = opts.to.0; + if let Some(to_subaccount) = opts.to_subaccount { + to.subaccount = Some(to_subaccount.0 .0); + } + let args = TransferArg { + memo, + amount, + fee, + from_subaccount: opts.from_subaccount.map(|x| x.0 .0), + created_at_time: None, + to, + }; + + let msg = sign_ingress_with_request_status_query( + auth, + ledger_canister_id, + ROLE_ICRC1_LEDGER, + "icrc1_transfer", + Encode!(&args)?, + )?; + + Ok(vec![msg]) +} diff --git a/src/commands/transfer.rs b/src/commands/transfer.rs index 5dd27aba..12fc1914 100644 --- a/src/commands/transfer.rs +++ b/src/commands/transfer.rs @@ -1,4 +1,5 @@ use crate::commands::send::{Memo, SendArgs}; +use crate::lib::ROLE_NNS_LEDGER; use crate::lib::{ ledger_canister_id, signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, @@ -16,29 +17,22 @@ pub struct TransferOpts { pub to: String, /// Amount of ICPs to transfer (with up to 8 decimal digits after comma). - #[clap(long, validator(token_amount_validator))] - pub amount: String, + #[clap(long, value_parser = parse_tokens)] + pub amount: Tokens, /// Reference number, default is 0. - #[clap(long, validator(memo_validator))] - pub memo: Option<String>, + #[clap(long)] + pub memo: Option<u64>, - /// Transaction fee, default is 10000 e8s. - #[clap(long, validator(token_amount_validator))] - pub fee: Option<String>, + /// Transaction fee, default is 0.0001 ICP. + #[clap(long, value_parser = parse_tokens)] + pub fee: Option<Tokens>, } pub fn exec(auth: &AuthInfo, opts: TransferOpts) -> AnyhowResult<Vec<IngressWithRequestId>> { - let amount = parse_tokens(&opts.amount).context("Cannot parse amount")?; - let fee = opts.fee.map_or(Ok(DEFAULT_TRANSFER_FEE), |v| { - parse_tokens(&v).context("Cannot parse fee") - })?; - let memo = Memo( - opts.memo - .unwrap_or_else(|| "0".to_string()) - .parse::<u64>() - .context("Failed to parse memo as unsigned integer")?, - ); + let amount = opts.amount; + let fee = opts.fee.unwrap_or(DEFAULT_TRANSFER_FEE); + let memo = Memo(opts.memo.unwrap_or(0)); let to = opts.to; let args = Encode!(&SendArgs { @@ -50,7 +44,13 @@ pub fn exec(auth: &AuthInfo, opts: TransferOpts) -> AnyhowResult<Vec<IngressWith created_at_time: None, })?; - let msg = sign_ingress_with_request_status_query(auth, ledger_canister_id(), "send_dfx", args)?; + let msg = sign_ingress_with_request_status_query( + auth, + ledger_canister_id(), + ROLE_NNS_LEDGER, + "send_dfx", + args, + )?; Ok(vec![msg]) } @@ -60,7 +60,7 @@ fn new_tokens(tokens: u64, e8s: u64) -> AnyhowResult<Tokens> { .context("Cannot create new tokens structure") } -fn parse_tokens(amount: &str) -> AnyhowResult<Tokens> { +pub fn parse_tokens(amount: &str) -> AnyhowResult<Tokens> { let parse = |s: &str| { s.parse::<u64>() .context("Failed to parse tokens as unsigned integer") @@ -78,14 +78,3 @@ fn parse_tokens(amount: &str) -> AnyhowResult<Tokens> { _ => bail!("Cannot parse amount {}", amount), } } - -fn token_amount_validator(tokens: &str) -> AnyhowResult<()> { - parse_tokens(tokens).map(|_| ()) -} - -fn memo_validator(memo: &str) -> Result<(), String> { - if memo.parse::<u64>().is_ok() { - return Ok(()); - } - Err("Memo must be an unsigned integer".to_string()) -} diff --git a/src/commands/update_node_provider.rs b/src/commands/update_node_provider.rs index e4a6237d..4dcebd49 100644 --- a/src/commands/update_node_provider.rs +++ b/src/commands/update_node_provider.rs @@ -1,6 +1,6 @@ use crate::{ lib::signing::{sign_ingress_with_request_status_query, IngressWithRequestId}, - lib::{governance_canister_id, AnyhowResult, AuthInfo}, + lib::{governance_canister_id, AnyhowResult, AuthInfo, ROLE_NNS_GOVERNANCE}, }; use anyhow::{anyhow, Context}; use candid::{CandidType, Encode}; @@ -38,6 +38,7 @@ pub fn exec( Ok(vec![sign_ingress_with_request_status_query( auth, governance_canister_id(), + ROLE_NNS_GOVERNANCE, "update_node_provider", args, )?]) diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 855f52ae..38686604 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -17,6 +17,7 @@ use ic_icrc1::Account; use ic_identity_hsm::HardwareIdentity; use ic_nns_constants::{ GENESIS_TOKEN_CANISTER_ID, GOVERNANCE_CANISTER_ID, LEDGER_CANISTER_ID, REGISTRY_CANISTER_ID, + SNS_WASM_CANISTER_ID, }; use icp_ledger::{AccountIdentifier, Subaccount}; use itertools::Itertools; @@ -96,6 +97,10 @@ pub fn registry_canister_id() -> Principal { Principal::from_slice(REGISTRY_CANISTER_ID.as_ref()) } +pub fn sns_wasm_canister_id() -> Principal { + Principal::from_slice(SNS_WASM_CANISTER_ID.as_ref()) +} + pub fn ckbtc_canister_id(testnet: bool) -> Principal { if testnet { Principal::from_text("mc6ru-gyaaa-aaaar-qaaaq-cai").unwrap() @@ -112,52 +117,85 @@ pub fn ckbtc_minter_canister_id(testnet: bool) -> Principal { } } -// Returns the candid for the specified canister id, if there is one. -pub fn get_local_candid(canister_id: Principal) -> AnyhowResult<&'static str> { +pub const ROLE_NNS_GOVERNANCE: &str = "nns:governance"; +pub const ROLE_NNS_LEDGER: &str = "nns:ledger"; +pub const ROLE_NNS_GTC: &str = "nns:gtc"; +pub const ROLE_NNS_REGISTRY: &str = "nns:registry"; +pub const ROLE_SNS_WASM: &str = "nns:sns-wasm"; +pub const ROLE_ICRC1_LEDGER: &str = "icrc1:ledger"; +pub const ROLE_CKBTC_MINTER: &str = "ckbtc:minter"; +pub const ROLE_SNS_GOVERNANCE: &str = "sns:governance"; +pub const ROLE_SNS_ROOT: &str = "sns:root"; +pub const ROLE_SNS_SWAP: &str = "sns:swap"; + +pub fn get_default_role(canister_id: Principal) -> Option<&'static str> { if canister_id == governance_canister_id() { - Ok(include_str!("../../candid/governance.did")) + Some(ROLE_NNS_GOVERNANCE) } else if canister_id == ledger_canister_id() { - Ok(include_str!("../../candid/ledger.did")) + Some(ROLE_NNS_LEDGER) } else if canister_id == genesis_token_canister_id() { - Ok(include_str!("../../candid/gtc.did")) + Some(ROLE_NNS_GTC) } else if canister_id == registry_canister_id() { - Ok(include_str!("../../candid/registry.did")) + Some(ROLE_NNS_REGISTRY) } else if canister_id == ckbtc_canister_id(false) || canister_id == ckbtc_canister_id(true) { - Ok(include_str!("../../candid/icrc1.did")) + Some(ROLE_ICRC1_LEDGER) } else if canister_id == ckbtc_minter_canister_id(false) || canister_id == ckbtc_minter_canister_id(true) { - Ok(include_str!("../../candid/ckbtc_minter.did")) + Some(ROLE_CKBTC_MINTER) } else { - bail!( + None + } +} + +pub fn get_local_candid(canister_id: Principal, role: &str) -> AnyhowResult<&'static str> { + Ok(match role { + ROLE_NNS_GOVERNANCE => include_str!("../../candid/governance.did"), + ROLE_NNS_LEDGER => include_str!("../../candid/ledger.did"), + ROLE_NNS_GTC => include_str!("../../candid/gtc.did"), + ROLE_NNS_REGISTRY => include_str!("../../candid/registry.did"), + ROLE_ICRC1_LEDGER => include_str!("../../candid/icrc1.did"), + ROLE_CKBTC_MINTER => include_str!("../../candid/ckbtc_minter.did"), + ROLE_SNS_WASM => include_str!("../../candid/snsw.did"), + ROLE_SNS_GOVERNANCE => include_str!("../../candid/sns-governance.did"), + ROLE_SNS_ROOT => include_str!("../../candid/sns-root.did"), + ROLE_SNS_SWAP => include_str!("../../candid/sns-swap.did"), + _ => bail!( "\ -Unknown recipient in message! +Unknown recipient '{role}' in message! Recipient: {canister_id} -Should be one of: -- Ledger: {ledger} +Should be one of: +- NNS Ledger: {ledger} - Governance: {governance} - Genesis: {genesis} - Registry: {registry} - ckBTC minter: {ckbtc_minter} -- ckBTC ledger: {ckbtc}", +- ckBTC ledger: {ckbtc} +- SNS-WASM: {sns_wasm} +- SNS Governance +- SNS Ledger +- SNS Root +- SNS Swap", ledger = ledger_canister_id(), governance = governance_canister_id(), genesis = genesis_token_canister_id(), registry = registry_canister_id(), ckbtc_minter = ckbtc_minter_canister_id(false), ckbtc = ckbtc_canister_id(false), - ); - } + sns_wasm = sns_wasm_canister_id(), + ), + }) } /// Returns pretty-printed encoding of a candid value. pub fn get_idl_string( blob: &[u8], canister_id: Principal, + role: &str, method_name: &str, part: &str, ) -> AnyhowResult<String> { - let spec = get_local_candid(canister_id)?; + let spec = get_local_candid(canister_id, role)?; let method_type = get_candid_type(spec, method_name); let result = match method_type { None => candid::IDLArgs::from_bytes(blob), @@ -270,6 +308,7 @@ pub fn get_identity(auth: &AuthInfo) -> AnyhowResult<Box<dyn Identity>> { pub fn parse_query_response( response: Vec<u8>, canister_id: Principal, + role: &str, method_name: &str, ) -> AnyhowResult<String> { let cbor: Value = serde_cbor::from_slice(&response) @@ -293,7 +332,7 @@ pub fn parse_query_response( m.get(&Value::Text("reply".to_string())), ) { if let Some(Value::Bytes(reply)) = m.get(&Value::Text("arg".to_string())) { - return get_idl_string(reply, canister_id, method_name, "rets"); + return get_idl_string(reply, canister_id, role, method_name, "rets"); } } } diff --git a/src/lib/signing.rs b/src/lib/signing.rs index 7fa19919..1ebdd247 100644 --- a/src/lib/signing.rs +++ b/src/lib/signing.rs @@ -9,7 +9,7 @@ use serde_cbor::Value; use std::convert::TryFrom; use std::time::Duration; -use super::get_agent; +use super::{get_agent, get_default_role}; #[derive(Debug)] pub struct MessageError(String); @@ -40,6 +40,7 @@ pub struct Ingress { pub call_type: String, pub request_id: Option<String>, pub content: String, + pub role: Option<String>, } #[derive(Debug, Default, Clone, Deserialize, Serialize)] @@ -49,7 +50,7 @@ pub struct IngressWithRequestId { } impl Ingress { - pub fn parse(&self) -> AnyhowResult<(Principal, Principal, String, String)> { + pub fn parse(&self) -> AnyhowResult<(Principal, Principal, String, String, String)> { let cbor: Value = serde_cbor::from_slice(&hex::decode(&self.content)?) .context("Invalid cbor data in the content of the message.")?; if let Value::Map(m) = cbor { @@ -70,11 +71,17 @@ impl Ingress { ) { let sender = Principal::try_from(sender)?; let canister_id = Principal::try_from(canister_id)?; + let role = if let Some(role) = &self.role { + role + } else { + get_default_role(sender).unwrap_or("<none>") + }; return Ok(( sender, canister_id, method_name.to_string(), - get_idl_string(arg, canister_id, method_name, "args")?, + get_idl_string(arg, canister_id, role, method_name, "args")?, + role.to_owned(), )); } } @@ -102,6 +109,7 @@ pub fn sign( canister_id: Principal, method_name: &str, args: Vec<u8>, + role: &str, ) -> AnyhowResult<SignedMessageWithRequestId> { let ingress_expiry = Duration::from_secs(5 * 60); @@ -118,6 +126,7 @@ pub fn sign( call_type: "update".to_string(), request_id: Some(request_id.into()), content, + role: Some(role.to_owned()), }, request_id: Some(request_id), }) @@ -127,10 +136,11 @@ pub fn sign( pub fn sign_ingress_with_request_status_query( auth: &AuthInfo, canister_id: Principal, + role: &str, method_name: &str, args: Vec<u8>, ) -> AnyhowResult<IngressWithRequestId> { - let msg_with_req_id = sign(auth, canister_id, method_name, args)?; + let msg_with_req_id = sign(auth, canister_id, method_name, args, role)?; let request_id = msg_with_req_id .request_id .context("No request id for transfer call found")?; diff --git a/src/main.rs b/src/main.rs index 1f1f289b..4c51a006 100755 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,8 @@ mod lib; #[derive(Parser)] #[clap(name("quill"), version = crate_version!())] pub struct CliOpts { + #[clap(flatten, next_help_heading = "COMMON")] + global_opts: GlobalOpts, #[clap(subcommand)] command: commands::Command, } @@ -22,58 +24,46 @@ pub struct CliOpts { #[derive(Args)] struct GlobalOpts { /// Path to your PEM file (use "-" for STDIN) - #[clap(long, group = "auth")] + #[clap(long, group = "auth", global = true)] pem_file: Option<PathBuf>, - #[clap(long, group = "auth")] + #[clap(long, group = "auth", global = true)] hsm: bool, - #[clap(long)] + #[clap(long, global = true)] hsm_libpath: Option<PathBuf>, - #[clap(long)] + #[clap(long, global = true)] hsm_slot: Option<usize>, - #[clap(long)] + #[clap(long, global = true)] hsm_id: Option<String>, /// Path to your seed file (use "-" for STDIN) - #[clap(long)] + #[clap(long, global = true)] seed_file: Option<PathBuf>, /// Output the result(s) as UTF-8 QR codes. - #[clap(long)] + #[clap(long, global = true)] qr: bool, /// Fetches the root key before making requests so that interfacing with local instances is possible. /// DO NOT USE WITH ANY REAL INFORMATION - #[clap(long = "insecure-local-dev-mode", name = "insecure-local-dev-mode")] + #[clap( + long = "insecure-local-dev-mode", + name = "insecure-local-dev-mode", + global = true + )] fetch_root_key: bool, } -#[derive(Args)] -pub struct BaseOpts<T: Args> { - #[clap(flatten)] - command_opts: T, - #[clap(flatten, next_help_heading = "COMMON")] - global_opts: GlobalOpts, -} - -fn main() { +fn main() -> AnyhowResult { let opts = CliOpts::parse(); - if let Err(err) = commands::dispatch(opts.command) { - for (level, cause) in err.chain().enumerate() { - if level == 0 { - eprintln!("Error: {}", err); - continue; - } - if level == 1 { - eprintln!("Caused by:"); - } - eprintln!("{:width$}{}", "", cause, width = level * 2); - } - std::process::exit(1); - } + let qr = opts.global_opts.qr; + let fetch_root_key = opts.global_opts.fetch_root_key; + let auth = get_auth(opts.global_opts)?; + commands::dispatch(&auth, opts.command, fetch_root_key, qr)?; + Ok(()) } fn get_auth(opts: GlobalOpts) -> AnyhowResult<AuthInfo> { diff --git a/tests/commands/sns-balance.sh b/tests/commands/sns-balance.sh new file mode 100755 index 00000000..ac3f4840 --- /dev/null +++ b/tests/commands/sns-balance.sh @@ -0,0 +1,2 @@ +PRINCIPAL=fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae +"$QUILL" sns balance --of $PRINCIPAL --dry-run --canister-ids-file ./sns_canister_ids.json diff --git a/tests/commands/sns-configure-dissolve-delay-add-seconds.sh b/tests/commands/sns-configure-dissolve-delay-add-seconds.sh new file mode 100755 index 00000000..8980aa03 --- /dev/null +++ b/tests/commands/sns-configure-dissolve-delay-add-seconds.sh @@ -0,0 +1,2 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns configure-dissolve-delay $NEURON_ID --additional-dissolve-delay-seconds 1000 --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-configure-dissolve-delay-start-dissolving.sh b/tests/commands/sns-configure-dissolve-delay-start-dissolving.sh new file mode 100755 index 00000000..aaf6abbf --- /dev/null +++ b/tests/commands/sns-configure-dissolve-delay-start-dissolving.sh @@ -0,0 +1,2 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns configure-dissolve-delay $NEURON_ID --start-dissolving --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-configure-dissolve-delay-stop-dissolving.sh b/tests/commands/sns-configure-dissolve-delay-stop-dissolving.sh new file mode 100755 index 00000000..77274505 --- /dev/null +++ b/tests/commands/sns-configure-dissolve-delay-stop-dissolving.sh @@ -0,0 +1,2 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns configure-dissolve-delay $NEURON_ID --stop-dissolving --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-list-deployed-snses.sh b/tests/commands/sns-list-deployed-snses.sh new file mode 100755 index 00000000..19f9ae89 --- /dev/null +++ b/tests/commands/sns-list-deployed-snses.sh @@ -0,0 +1 @@ +"$QUILL" sns list-deployed-snses --canister-ids-file ./sns_canister_ids.json --dry-run diff --git a/tests/commands/sns-make-proposal.sh b/tests/commands/sns-make-proposal.sh new file mode 100755 index 00000000..d790c2d3 --- /dev/null +++ b/tests/commands/sns-make-proposal.sh @@ -0,0 +1,4 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +PROPOSAL='( record { title="SNS Launch"; url="https://dfinity.org"; summary="A motion to start the SNS"; action=opt variant { Motion=record { motion_text="I hereby raise the motion that the use of the SNS shall commence"; } }; } )' +"$QUILL" sns make-proposal $NEURON_ID --proposal "$PROPOSAL" --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - + diff --git a/tests/commands/sns-make-upgrade-canister-proposal.sh b/tests/commands/sns-make-upgrade-canister-proposal.sh new file mode 100755 index 00000000..187adff8 --- /dev/null +++ b/tests/commands/sns-make-upgrade-canister-proposal.sh @@ -0,0 +1,11 @@ +PROPOSER_NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 + +"$QUILL" sns \ + make-upgrade-canister-proposal \ + --wasm-path=outputs/sns_canister.wasm \ + --target-canister-id=pycv5-3jbbb-ccccc-ddddd-cai \ + --canister-ids-file=./sns_canister_ids.json \ + --pem-file=- \ + $PROPOSER_NEURON_ID \ + | "$QUILL" send --dry-run - + diff --git a/tests/commands/sns-neuron-permission-add.sh b/tests/commands/sns-neuron-permission-add.sh new file mode 100755 index 00000000..febffe06 --- /dev/null +++ b/tests/commands/sns-neuron-permission-add.sh @@ -0,0 +1,2 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns neuron-permission add $NEURON_ID --principal fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae --permissions submit-proposal,vote --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-neuron-permission-remove.sh b/tests/commands/sns-neuron-permission-remove.sh new file mode 100755 index 00000000..45a21dab --- /dev/null +++ b/tests/commands/sns-neuron-permission-remove.sh @@ -0,0 +1,2 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns neuron-permission remove $NEURON_ID --principal fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae --permissions merge-maturity disburse-maturity --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-neuron-stake-maturity.sh b/tests/commands/sns-neuron-stake-maturity.sh new file mode 100755 index 00000000..cd988f17 --- /dev/null +++ b/tests/commands/sns-neuron-stake-maturity.sh @@ -0,0 +1,2 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns stake-maturity $NEURON_ID --percentage 70 --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-neuron-stake-memo.sh b/tests/commands/sns-neuron-stake-memo.sh new file mode 100755 index 00000000..1d69340a --- /dev/null +++ b/tests/commands/sns-neuron-stake-memo.sh @@ -0,0 +1 @@ +"$QUILL" sns stake-neuron --amount 12 --memo 777 --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-neuron-stake-no-amount.sh b/tests/commands/sns-neuron-stake-no-amount.sh new file mode 100755 index 00000000..e569aefc --- /dev/null +++ b/tests/commands/sns-neuron-stake-no-amount.sh @@ -0,0 +1 @@ +"$QUILL" sns stake-neuron --memo 777 --claim-only --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-refund.sh b/tests/commands/sns-refund.sh new file mode 100755 index 00000000..5fc69506 --- /dev/null +++ b/tests/commands/sns-refund.sh @@ -0,0 +1 @@ +"$QUILL" sns get-swap-refund --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - \ No newline at end of file diff --git a/tests/commands/sns-register-vote-no.sh b/tests/commands/sns-register-vote-no.sh new file mode 100755 index 00000000..aa6de291 --- /dev/null +++ b/tests/commands/sns-register-vote-no.sh @@ -0,0 +1,3 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns register-vote $NEURON_ID --proposal-id 1 --vote n --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - + diff --git a/tests/commands/sns-register-vote-yes.sh b/tests/commands/sns-register-vote-yes.sh new file mode 100755 index 00000000..89d50d88 --- /dev/null +++ b/tests/commands/sns-register-vote-yes.sh @@ -0,0 +1,3 @@ +NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 +"$QUILL" sns register-vote $NEURON_ID --proposal-id 1 --vote y --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - + diff --git a/tests/commands/sns-status.sh b/tests/commands/sns-status.sh new file mode 100755 index 00000000..719e89bf --- /dev/null +++ b/tests/commands/sns-status.sh @@ -0,0 +1 @@ +"$QUILL" sns status --dry-run --canister-ids-file ./sns_canister_ids.json diff --git a/tests/commands/sns-swap.sh b/tests/commands/sns-swap.sh new file mode 100755 index 00000000..0da87e13 --- /dev/null +++ b/tests/commands/sns-swap.sh @@ -0,0 +1 @@ +"$QUILL" sns swap --amount 500 --memo 4 --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-transfer-with-fees-and-memo.sh b/tests/commands/sns-transfer-with-fees-and-memo.sh new file mode 100755 index 00000000..bfed7ad5 --- /dev/null +++ b/tests/commands/sns-transfer-with-fees-and-memo.sh @@ -0,0 +1,2 @@ +PRINCIPAL=fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae +"$QUILL" sns transfer $PRINCIPAL --amount 123.0456 --fee 0.0023 --memo 777 --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/commands/sns-transfer.sh b/tests/commands/sns-transfer.sh new file mode 100755 index 00000000..51c5c66f --- /dev/null +++ b/tests/commands/sns-transfer.sh @@ -0,0 +1,2 @@ +PRINCIPAL=fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae +"$QUILL" sns transfer $PRINCIPAL --amount 0.000123 --canister-ids-file ./sns_canister_ids.json --pem-file - | "$QUILL" send --dry-run - diff --git a/tests/outputs/sns-balance.txt b/tests/outputs/sns-balance.txt new file mode 100644 index 00000000..11dab9a4 --- /dev/null +++ b/tests/outputs/sns-balance.txt @@ -0,0 +1,12 @@ +Sending message with + + Call type: update + Sender: 2vxsx-fae + Canister id: ryjl3-tyaaa-aaaaa-aaaba-cai + Method name: icrc1_balance_of + Arguments: ( + record { + owner = principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + subaccount = null; + }, +) diff --git a/tests/outputs/sns-configure-dissolve-delay-add-seconds.txt b/tests/outputs/sns-configure-dissolve-delay-add-seconds.txt new file mode 100755 index 00000000..d332b966 --- /dev/null +++ b/tests/outputs/sns-configure-dissolve-delay-add-seconds.txt @@ -0,0 +1,20 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + Configure = record { + operation = opt variant { + IncreaseDissolveDelay = record { + additional_dissolve_delay_seconds = 1_000 : nat32; + } + }; + } + }; + }, +) diff --git a/tests/outputs/sns-configure-dissolve-delay-start-dissolving.txt b/tests/outputs/sns-configure-dissolve-delay-start-dissolving.txt new file mode 100755 index 00000000..b91ff0ba --- /dev/null +++ b/tests/outputs/sns-configure-dissolve-delay-start-dissolving.txt @@ -0,0 +1,16 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + Configure = record { + operation = opt variant { StartDissolving = record {} }; + } + }; + }, +) diff --git a/tests/outputs/sns-configure-dissolve-delay-stop-dissolving.txt b/tests/outputs/sns-configure-dissolve-delay-stop-dissolving.txt new file mode 100755 index 00000000..5d4bddf1 --- /dev/null +++ b/tests/outputs/sns-configure-dissolve-delay-stop-dissolving.txt @@ -0,0 +1,16 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + Configure = record { + operation = opt variant { StopDissolving = record {} }; + } + }; + }, +) diff --git a/tests/outputs/sns-list-deployed-snses.txt b/tests/outputs/sns-list-deployed-snses.txt new file mode 100644 index 00000000..75e8bce2 --- /dev/null +++ b/tests/outputs/sns-list-deployed-snses.txt @@ -0,0 +1,7 @@ +Sending message with + + Call type: update + Sender: 2vxsx-fae + Canister id: qaa6y-5yaaa-aaaaa-aaafa-cai + Method name: list_deployed_snses + Arguments: (record {}) diff --git a/tests/outputs/sns-make-proposal.txt b/tests/outputs/sns-make-proposal.txt new file mode 100644 index 00000000..6469c146 --- /dev/null +++ b/tests/outputs/sns-make-proposal.txt @@ -0,0 +1,23 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + MakeProposal = record { + url = "https://dfinity.org"; + title = "SNS Launch"; + action = opt variant { + Motion = record { + motion_text = "I hereby raise the motion that the use of the SNS shall commence"; + } + }; + summary = "A motion to start the SNS"; + } + }; + }, +) diff --git a/tests/outputs/sns-make-upgrade-canister-proposal.txt b/tests/outputs/sns-make-upgrade-canister-proposal.txt new file mode 100644 index 00000000..b3e6658a --- /dev/null +++ b/tests/outputs/sns-make-upgrade-canister-proposal.txt @@ -0,0 +1,25 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + MakeProposal = record { + url = ""; + title = "Upgrade Canister"; + action = opt variant { + UpgradeSnsControlledCanister = record { + new_canister_wasm = blob "\00asm\01\00\00\00"; + canister_id = opt principal "pycv5-3jbbb-ccccc-ddddd-cai"; + canister_upgrade_arg = null; + } + }; + summary = "Upgrade canister:\n\n ID: pycv5-3jbbb-ccccc-ddddd-cai\n\n WASM:\n length: 8\n fingerprint: 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"; + } + }; + }, +) diff --git a/tests/outputs/sns-neuron-permission-add.txt b/tests/outputs/sns-neuron-permission-add.txt new file mode 100644 index 00000000..062eb6fd --- /dev/null +++ b/tests/outputs/sns-neuron-permission-add.txt @@ -0,0 +1,19 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + AddNeuronPermissions = record { + permissions_to_add = opt record { + permissions = vec { 3 : int32; 4 : int32 }; + }; + principal_id = opt principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + } + }; + }, +) diff --git a/tests/outputs/sns-neuron-permission-remove.txt b/tests/outputs/sns-neuron-permission-remove.txt new file mode 100644 index 00000000..77da0091 --- /dev/null +++ b/tests/outputs/sns-neuron-permission-remove.txt @@ -0,0 +1,19 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + RemoveNeuronPermissions = record { + permissions_to_remove = opt record { + permissions = vec { 7 : int32; 8 : int32 }; + }; + principal_id = opt principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + } + }; + }, +) diff --git a/tests/outputs/sns-neuron-stake-maturity.txt b/tests/outputs/sns-neuron-stake-maturity.txt new file mode 100644 index 00000000..90dadf32 --- /dev/null +++ b/tests/outputs/sns-neuron-stake-maturity.txt @@ -0,0 +1,14 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + StakeMaturity = record { percentage_to_stake = opt (70 : nat32) } + }; + }, +) diff --git a/tests/outputs/sns-neuron-stake-memo.txt b/tests/outputs/sns-neuron-stake-memo.txt new file mode 100644 index 00000000..29cd3f49 --- /dev/null +++ b/tests/outputs/sns-neuron-stake-memo.txt @@ -0,0 +1,40 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: ryjl3-tyaaa-aaaaa-aaaba-cai + Method name: icrc1_transfer + Arguments: ( + record { + to = record { + owner = principal "rrkah-fqaaa-aaaaa-aaaaq-cai"; + subaccount = opt blob "r\8a\c1;\10I\a3\ac\af\fe\13\f1;\c7\1e\fd\9b4\97e\80\d4\0d\f2y\b2s n\f14$"; + }; + fee = null; + memo = opt blob "\00\00\00\00\00\00\03\09"; + from_subaccount = null; + created_at_time = null; + amount = 1_200_000_000 : nat; + }, +) +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "r\8a\c1;\10I\a3\ac\af\fe\13\f1;\c7\1e\fd\9b4\97e\80\d4\0d\f2y\b2s n\f14$"; + command = opt variant { + ClaimOrRefresh = record { + by = opt variant { + MemoAndController = record { + controller = opt principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + memo = 777 : nat64; + } + }; + } + }; + }, +) diff --git a/tests/outputs/sns-neuron-stake-no-amount.txt b/tests/outputs/sns-neuron-stake-no-amount.txt new file mode 100644 index 00000000..09ee2fe6 --- /dev/null +++ b/tests/outputs/sns-neuron-stake-no-amount.txt @@ -0,0 +1,21 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "r\8a\c1;\10I\a3\ac\af\fe\13\f1;\c7\1e\fd\9b4\97e\80\d4\0d\f2y\b2s n\f14$"; + command = opt variant { + ClaimOrRefresh = record { + by = opt variant { + MemoAndController = record { + controller = opt principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + memo = 777 : nat64; + } + }; + } + }; + }, +) diff --git a/tests/outputs/sns-refund.txt b/tests/outputs/sns-refund.txt new file mode 100644 index 00000000..eb7d64d2 --- /dev/null +++ b/tests/outputs/sns-refund.txt @@ -0,0 +1,11 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rkp4c-7iaaa-aaaaa-aaaca-cai + Method name: error_refund_icp + Arguments: ( + record { + source_principal_id = opt principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + }, +) diff --git a/tests/outputs/sns-register-vote-no.txt b/tests/outputs/sns-register-vote-no.txt new file mode 100644 index 00000000..92e53ebb --- /dev/null +++ b/tests/outputs/sns-register-vote-no.txt @@ -0,0 +1,17 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + RegisterVote = record { + vote = 2 : int32; + proposal = opt record { id = 1 : nat64 }; + } + }; + }, +) diff --git a/tests/outputs/sns-register-vote-yes.txt b/tests/outputs/sns-register-vote-yes.txt new file mode 100644 index 00000000..497b4e0a --- /dev/null +++ b/tests/outputs/sns-register-vote-yes.txt @@ -0,0 +1,17 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + RegisterVote = record { + vote = 1 : int32; + proposal = opt record { id = 1 : nat64 }; + } + }; + }, +) diff --git a/tests/outputs/sns-status.txt b/tests/outputs/sns-status.txt new file mode 100644 index 00000000..b784c38e --- /dev/null +++ b/tests/outputs/sns-status.txt @@ -0,0 +1,7 @@ +Sending message with + + Call type: update + Sender: 2vxsx-fae + Canister id: r7inp-6aaaa-aaaaa-aaabq-cai + Method name: get_sns_canisters_summary + Arguments: (record { update_canister_list = null }) \ No newline at end of file diff --git a/tests/outputs/sns-swap.txt b/tests/outputs/sns-swap.txt new file mode 100644 index 00000000..69cb862a --- /dev/null +++ b/tests/outputs/sns-swap.txt @@ -0,0 +1,27 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: ryjl3-tyaaa-aaaaa-aaaba-cai + Method name: send_dfx + Arguments: ( + record { + to = "bff3218e708b09187a586a1f397edf081964e560a5a0f6435fac044c7f4a25e9"; + fee = record { e8s = 10_000 : nat64 }; + memo = 4 : nat64; + from_subaccount = null; + created_at_time = null; + amount = record { e8s = 50_000_000_000 : nat64 }; + }, +) +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rkp4c-7iaaa-aaaaa-aaaca-cai + Method name: refresh_buyer_tokens + Arguments: ( + record { + buyer = "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + }, +) diff --git a/tests/outputs/sns-transfer-with-fees-and-memo.txt b/tests/outputs/sns-transfer-with-fees-and-memo.txt new file mode 100644 index 00000000..51002406 --- /dev/null +++ b/tests/outputs/sns-transfer-with-fees-and-memo.txt @@ -0,0 +1,19 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: ryjl3-tyaaa-aaaaa-aaaba-cai + Method name: icrc1_transfer + Arguments: ( + record { + to = record { + owner = principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + subaccount = null; + }; + fee = opt (230_000 : nat); + memo = opt blob "\00\00\00\00\00\00\03\09"; + from_subaccount = null; + created_at_time = null; + amount = 12_304_560_000 : nat; + }, +) diff --git a/tests/outputs/sns-transfer.txt b/tests/outputs/sns-transfer.txt new file mode 100644 index 00000000..9cc126b1 --- /dev/null +++ b/tests/outputs/sns-transfer.txt @@ -0,0 +1,19 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: ryjl3-tyaaa-aaaaa-aaaba-cai + Method name: icrc1_transfer + Arguments: ( + record { + to = record { + owner = principal "fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae"; + subaccount = null; + }; + fee = null; + memo = null; + from_subaccount = null; + created_at_time = null; + amount = 12_300 : nat; + }, +) diff --git a/tests/outputs/sns_canister.wasm b/tests/outputs/sns_canister.wasm new file mode 100644 index 0000000000000000000000000000000000000000..d8fc92d022fbf4d1072da17bc8e0840054b51ddc GIT binary patch literal 8 PcmZQbEY4+QU|;|M2ZjMd literal 0 HcmV?d00001 diff --git a/tests/sns_canister_ids.json b/tests/sns_canister_ids.json new file mode 100644 index 00000000..71ec5d56 --- /dev/null +++ b/tests/sns_canister_ids.json @@ -0,0 +1,6 @@ +{ + "governance_canister_id": "rrkah-fqaaa-aaaaa-aaaaq-cai", + "ledger_canister_id": "ryjl3-tyaaa-aaaaa-aaaba-cai", + "root_canister_id": "r7inp-6aaaa-aaaaa-aaabq-cai", + "swap_canister_id": "rkp4c-7iaaa-aaaaa-aaaca-cai" +} From 58315b5250638b926ad4baa0ccf83187c0006226 Mon Sep 17 00:00:00 2001 From: Adam Spofford <adam.spofford@dfinity.org> Date: Fri, 3 Feb 2023 15:49:17 -0800 Subject: [PATCH 2/3] whoops --- docs/cli-reference/quill-account-balance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli-reference/quill-account-balance.md b/docs/cli-reference/quill-account-balance.md index d8df4399..659fe99e 100644 --- a/docs/cli-reference/quill-account-balance.md +++ b/docs/cli-reference/quill-account-balance.md @@ -12,7 +12,7 @@ quill account-balance [flag] <account id> ## Arguments -| Argument | Description | +| Argument | Description | |----------------|---------------------------------| | `<account id>` | The id of the account to query. | From f790c68b28264e726cbf485eb4a6cffa9e044bf2 Mon Sep 17 00:00:00 2001 From: Adam Spofford <adam.spofford@dfinity.org> Date: Tue, 7 Feb 2023 09:44:42 -0800 Subject: [PATCH 3/3] Incorporate changes from dfinity/sns-quill#36 --- .../sns/make_upgrade_canister_proposal.rs | 22 +++++++++++----- ...make-upgrade-canister-proposal-with-arg.sh | 17 +++++++++++++ ...ake-upgrade-canister-proposal-with-arg.txt | 25 +++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 tests/commands/sns-make-upgrade-canister-proposal-with-arg.sh create mode 100644 tests/outputs/sns-make-upgrade-canister-proposal-with-arg.txt diff --git a/src/commands/sns/make_upgrade_canister_proposal.rs b/src/commands/sns/make_upgrade_canister_proposal.rs index dff9ee7a..9c6b9f4b 100644 --- a/src/commands/sns/make_upgrade_canister_proposal.rs +++ b/src/commands/sns/make_upgrade_canister_proposal.rs @@ -8,8 +8,8 @@ use crate::{ AnyhowResult, }; use anyhow::{Context, Error}; -use candid::Encode; use candid::Principal; +use candid::{Encode, IDLArgs}; use clap::Parser; use ic_sns_governance::pb::v1::{ manage_neuron, proposal, ManageNeuron, Proposal, UpgradeSnsControlledCanister, @@ -46,9 +46,14 @@ pub struct MakeUpgradeCanisterProposalOpts { #[clap(long)] wasm_path: PathBuf, - /// Path to the file containing argument to post-upgrade method of the new canister WASM. + /// Argument to post-upgrade method of the new canister WASM. The argument must be formatted as a string + /// wrapped candid record. #[clap(long)] - canister_upgrade_arg_path: Option<PathBuf>, + canister_upgrade_arg: Option<String>, + + /// Path to the binary file containing argument to post-upgrade method of the new canister WASM. + #[clap(long, conflicts_with("canister-upgrade-arg"))] + canister_upgrade_arg_path: Option<String>, } pub fn exec( @@ -63,15 +68,20 @@ pub fn exec( summary, target_canister_id, wasm_path, + canister_upgrade_arg, canister_upgrade_arg_path, } = opts; let wasm = std::fs::read(wasm_path).context("Unable to read --wasm-path.")?; - let canister_upgrade_arg = match canister_upgrade_arg_path { - Some(path) => { + let canister_upgrade_arg = match (canister_upgrade_arg, canister_upgrade_arg_path) { + (Some(arg), _) => { + let parsed_arg: IDLArgs = arg.parse()?; + Some(parsed_arg.to_bytes()?) + } + (_, Some(path)) => { Some(std::fs::read(path).context("Unable to read --canister-upgrade-arg-path.")?) } - None => None, + (None, None) => None, }; // (Dynamically) come up with a summary if one wasn't provided. diff --git a/tests/commands/sns-make-upgrade-canister-proposal-with-arg.sh b/tests/commands/sns-make-upgrade-canister-proposal-with-arg.sh new file mode 100644 index 00000000..21539e54 --- /dev/null +++ b/tests/commands/sns-make-upgrade-canister-proposal-with-arg.sh @@ -0,0 +1,17 @@ +PROPOSER_NEURON_ID=83a7d2b12f654ff58335e5a2512ccae0d7839c744b1807a47c96f5b9f3969069 + +#$ didc encode '(record {major=2:nat32; minor=3:nat32;})' --format blob +#blob "DIDL\01l\02\b9\fa\ee\18y\b5\f6\a1Cy\01\00\02\00\00\00\03\00\00\00" + +"$QUILL" sns \ + make-upgrade-canister-proposal \ + --wasm-path outputs/sns_canister.wasm \ + --canister-upgrade-arg "(record {major=2:nat32; minor=3:nat32;})" \ + --target-canister-id pycv5-3jbbb-ccccc-ddddd-cai \ + $PROPOSER_NEURON_ID \ + --canister-ids-file ./sns_canister_ids.json \ + --pem-file - \ + | "$QUILL" \ + send \ + --dry-run \ + - diff --git a/tests/outputs/sns-make-upgrade-canister-proposal-with-arg.txt b/tests/outputs/sns-make-upgrade-canister-proposal-with-arg.txt new file mode 100644 index 00000000..d3eda666 --- /dev/null +++ b/tests/outputs/sns-make-upgrade-canister-proposal-with-arg.txt @@ -0,0 +1,25 @@ +Sending message with + + Call type: update + Sender: fdsgv-62ihb-nbiqv-xgic5-iefsv-3cscz-tmbzv-63qd5-vh43v-dqfrt-pae + Canister id: rrkah-fqaaa-aaaaa-aaaaq-cai + Method name: manage_neuron + Arguments: ( + record { + subaccount = blob "\83\a7\d2\b1/eO\f5\835\e5\a2Q,\ca\e0\d7\83\9ctK\18\07\a4|\96\f5\b9\f3\96\90i"; + command = opt variant { + MakeProposal = record { + url = ""; + title = "Upgrade Canister"; + action = opt variant { + UpgradeSnsControlledCanister = record { + new_canister_wasm = blob "\00asm\01\00\00\00"; + canister_id = opt principal "pycv5-3jbbb-ccccc-ddddd-cai"; + canister_upgrade_arg = opt blob "DIDL\01l\02\b9\fa\ee\18y\b5\f6\a1Cy\01\00\02\00\00\00\03\00\00\00"; + } + }; + summary = "Upgrade canister:\n\n ID: pycv5-3jbbb-ccccc-ddddd-cai\n\n WASM:\n length: 8\n fingerprint: 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"; + } + }; + }, +)