├── .gitattributes ├── .github └── workflows │ ├── add-to-devtools.yml │ ├── code_style.yml │ ├── release-plz.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CODEOWNERS ├── Cargo.lock ├── Cargo.toml ├── Cross.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── cross └── x86_64-unknown-linux-gnu │ └── Dockerfile ├── docs ├── GUIDE.en.md ├── GUIDE.ru.md ├── NEW_NEAR_CLI_INTERFACE.md ├── README.en.md ├── README.ru.md ├── SHELL_HISTORY_INTEGRATION.md └── media │ ├── block_hash.png │ ├── blocks.png │ ├── create-account.svg │ ├── install-powershell-script-small.mp4 │ ├── install-windows-msvc-msi-small.mp4 │ ├── install-windows-msvc-tar-gz-small.mp4 │ ├── linkdrop_account_id.png │ └── view-account.svg ├── extensions └── README.md ├── release-plz.toml ├── rust-toolchain ├── src ├── commands │ ├── account │ │ ├── add_key │ │ │ ├── access_key_type │ │ │ │ └── mod.rs │ │ │ ├── autogenerate_new_keypair │ │ │ │ ├── mod.rs │ │ │ │ ├── print_keypair_to_terminal │ │ │ │ │ └── mod.rs │ │ │ │ ├── save_keypair_to_keychain │ │ │ │ │ └── mod.rs │ │ │ │ └── save_keypair_to_legacy_keychain │ │ │ │ │ └── mod.rs │ │ │ ├── mod.rs │ │ │ ├── use_ledger │ │ │ │ └── mod.rs │ │ │ ├── use_manually_provided_seed_phrase │ │ │ │ └── mod.rs │ │ │ └── use_public_key │ │ │ │ └── mod.rs │ │ ├── create_account │ │ │ ├── create_implicit_account │ │ │ │ ├── mod.rs │ │ │ │ ├── use_auto_generation.rs │ │ │ │ ├── use_ledger.rs │ │ │ │ └── use_seed_phrase.rs │ │ │ ├── fund_myself_create_account │ │ │ │ ├── add_key │ │ │ │ │ ├── autogenerate_new_keypair │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── use_ledger │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── use_manually_provided_seed_phrase │ │ │ │ │ │ └── mod.rs │ │ │ │ │ └── use_public_key │ │ │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ └── sign_as │ │ │ │ │ └── mod.rs │ │ │ ├── mod.rs │ │ │ └── sponsor_by_faucet_service │ │ │ │ ├── add_key │ │ │ │ ├── autogenerate_new_keypair │ │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── use_ledger │ │ │ │ │ └── mod.rs │ │ │ │ ├── use_manually_provided_seed_phrase │ │ │ │ │ └── mod.rs │ │ │ │ └── use_public_key │ │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ └── network │ │ │ │ └── mod.rs │ │ ├── delete_account │ │ │ └── mod.rs │ │ ├── delete_key │ │ │ ├── mod.rs │ │ │ └── public_keys_to_delete.rs │ │ ├── export_account │ │ │ ├── mod.rs │ │ │ ├── using_private_key │ │ │ │ └── mod.rs │ │ │ ├── using_seed_phrase │ │ │ │ └── mod.rs │ │ │ └── using_web_wallet │ │ │ │ └── mod.rs │ │ ├── get_public_key │ │ │ ├── from_keychain │ │ │ │ └── mod.rs │ │ │ ├── from_ledger │ │ │ │ └── mod.rs │ │ │ ├── from_legacy_keychain │ │ │ │ └── mod.rs │ │ │ ├── from_plaintext_private_key │ │ │ │ └── mod.rs │ │ │ ├── from_seed_phrase │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ ├── import_account │ │ │ ├── mod.rs │ │ │ ├── using_private_key │ │ │ │ └── mod.rs │ │ │ ├── using_seed_phrase │ │ │ │ └── mod.rs │ │ │ └── using_web_wallet │ │ │ │ └── mod.rs │ │ ├── list_keys │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── storage_management │ │ │ ├── mod.rs │ │ │ ├── storage_deposit.rs │ │ │ ├── storage_withdraw.rs │ │ │ └── view_storage_balance.rs │ │ ├── update_social_profile │ │ │ ├── mod.rs │ │ │ ├── profile_args_type │ │ │ │ ├── base64_args.rs │ │ │ │ ├── file_args.rs │ │ │ │ ├── json_args.rs │ │ │ │ ├── manually.rs │ │ │ │ └── mod.rs │ │ │ └── sign_as.rs │ │ └── view_account_summary │ │ │ └── mod.rs │ ├── config │ │ ├── add_connection │ │ │ └── mod.rs │ │ ├── delete_connection │ │ │ └── mod.rs │ │ ├── edit_connection │ │ │ └── mod.rs │ │ └── mod.rs │ ├── contract │ │ ├── call_function │ │ │ ├── as_read_only │ │ │ │ └── mod.rs │ │ │ ├── as_transaction │ │ │ │ └── mod.rs │ │ │ ├── call_function_args_type │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ ├── deploy │ │ │ ├── initialize_mode │ │ │ │ ├── call_function_type │ │ │ │ │ └── mod.rs │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ ├── deploy_global │ │ │ └── mod.rs │ │ ├── download_abi │ │ │ └── mod.rs │ │ ├── download_wasm │ │ │ └── mod.rs │ │ ├── inspect │ │ │ ├── contract_metadata.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── view_storage │ │ │ ├── keys_to_view │ │ │ ├── all_keys.rs │ │ │ ├── keys_start_with_bytes_as_base64.rs │ │ │ ├── keys_start_with_string.rs │ │ │ └── mod.rs │ │ │ ├── mod.rs │ │ │ └── output_format │ │ │ ├── as_json.rs │ │ │ ├── as_text.rs │ │ │ └── mod.rs │ ├── extensions │ │ ├── mod.rs │ │ └── self_update │ │ │ └── mod.rs │ ├── mod.rs │ ├── staking │ │ ├── delegate │ │ │ ├── deposit_and_stake.rs │ │ │ ├── mod.rs │ │ │ ├── stake.rs │ │ │ ├── stake_all.rs │ │ │ ├── unstake.rs │ │ │ ├── unstake_all.rs │ │ │ ├── view_balance.rs │ │ │ ├── withdraw.rs │ │ │ └── withdraw_all.rs │ │ ├── mod.rs │ │ └── validator_list │ │ │ └── mod.rs │ ├── tokens │ │ ├── mod.rs │ │ ├── send_ft │ │ │ ├── amount_ft.rs │ │ │ └── mod.rs │ │ ├── send_near │ │ │ └── mod.rs │ │ ├── send_nft │ │ │ └── mod.rs │ │ ├── view_ft_balance │ │ │ └── mod.rs │ │ ├── view_near_balance │ │ │ └── mod.rs │ │ └── view_nft_assets │ │ │ └── mod.rs │ └── transaction │ │ ├── construct_transaction │ │ ├── add_action_1 │ │ │ ├── add_action │ │ │ │ ├── add_key │ │ │ │ │ ├── access_key_type │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── use_manually_provided_seed_phrase │ │ │ │ │ │ └── mod.rs │ │ │ │ │ └── use_public_key │ │ │ │ │ │ └── mod.rs │ │ │ │ ├── call_function │ │ │ │ │ └── mod.rs │ │ │ │ ├── create_account │ │ │ │ │ └── mod.rs │ │ │ │ ├── delete_account │ │ │ │ │ └── mod.rs │ │ │ │ ├── delete_key │ │ │ │ │ └── mod.rs │ │ │ │ ├── deploy_contract │ │ │ │ │ ├── initialize_mode │ │ │ │ │ │ └── mod.rs │ │ │ │ │ └── mod.rs │ │ │ │ ├── deploy_global_contract │ │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── stake │ │ │ │ │ └── mod.rs │ │ │ │ ├── transfer │ │ │ │ │ └── mod.rs │ │ │ │ └── use_global_contract │ │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ ├── add_action_2 │ │ │ ├── add_action │ │ │ │ ├── add_key │ │ │ │ │ ├── access_key_type │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── use_manually_provided_seed_phrase │ │ │ │ │ │ └── mod.rs │ │ │ │ │ └── use_public_key │ │ │ │ │ │ └── mod.rs │ │ │ │ ├── call_function │ │ │ │ │ └── mod.rs │ │ │ │ ├── create_account │ │ │ │ │ └── mod.rs │ │ │ │ ├── delete_account │ │ │ │ │ └── mod.rs │ │ │ │ ├── delete_key │ │ │ │ │ └── mod.rs │ │ │ │ ├── deploy_contract │ │ │ │ │ ├── initialize_mode │ │ │ │ │ │ └── mod.rs │ │ │ │ │ └── mod.rs │ │ │ │ ├── deploy_global_contract │ │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── stake │ │ │ │ │ └── mod.rs │ │ │ │ ├── transfer │ │ │ │ │ └── mod.rs │ │ │ │ └── use_global_contract │ │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ ├── add_action_3 │ │ │ ├── add_action │ │ │ │ ├── add_key │ │ │ │ │ ├── access_key_type │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── use_manually_provided_seed_phrase │ │ │ │ │ │ └── mod.rs │ │ │ │ │ └── use_public_key │ │ │ │ │ │ └── mod.rs │ │ │ │ ├── call_function │ │ │ │ │ └── mod.rs │ │ │ │ ├── create_account │ │ │ │ │ └── mod.rs │ │ │ │ ├── delete_account │ │ │ │ │ └── mod.rs │ │ │ │ ├── delete_key │ │ │ │ │ └── mod.rs │ │ │ │ ├── deploy_contract │ │ │ │ │ ├── initialize_mode │ │ │ │ │ │ └── mod.rs │ │ │ │ │ └── mod.rs │ │ │ │ ├── deploy_global_contract │ │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── stake │ │ │ │ │ └── mod.rs │ │ │ │ ├── transfer │ │ │ │ │ └── mod.rs │ │ │ │ └── use_global_contract │ │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ ├── add_action_last │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── skip_action │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── print_transaction │ │ ├── mod.rs │ │ ├── signed │ │ │ └── mod.rs │ │ └── unsigned │ │ │ └── mod.rs │ │ ├── reconstruct_transaction │ │ └── mod.rs │ │ ├── send_meta_transaction │ │ ├── mod.rs │ │ └── sign_as │ │ │ └── mod.rs │ │ ├── send_signed_transaction │ │ ├── mod.rs │ │ └── network │ │ │ └── mod.rs │ │ ├── sign_transaction │ │ └── mod.rs │ │ └── view_status │ │ └── mod.rs ├── common.rs ├── config │ ├── migrations.rs │ └── mod.rs ├── js_command_match │ ├── account │ │ ├── create.rs │ │ ├── delete.rs │ │ ├── login.rs │ │ ├── mod.rs │ │ └── state.rs │ ├── constants.rs │ ├── contract │ │ ├── call.rs │ │ ├── deploy.rs │ │ ├── mod.rs │ │ ├── storage.rs │ │ └── view.rs │ ├── deprecated.rs │ ├── keys │ │ ├── add.rs │ │ ├── delete.rs │ │ ├── list.rs │ │ └── mod.rs │ ├── mod.rs │ └── transactions │ │ ├── mod.rs │ │ ├── send.rs │ │ └── status.rs ├── lib.rs ├── main.rs ├── network │ └── mod.rs ├── network_for_transaction │ └── mod.rs ├── network_view_at_block │ └── mod.rs ├── transaction_signature_options │ ├── display │ │ └── mod.rs │ ├── mod.rs │ ├── save_to_file │ │ └── mod.rs │ ├── send │ │ └── mod.rs │ ├── sign_later │ │ ├── display.rs │ │ ├── mod.rs │ │ └── save_to_file.rs │ ├── sign_with_access_key_file │ │ └── mod.rs │ ├── sign_with_keychain │ │ └── mod.rs │ ├── sign_with_ledger │ │ └── mod.rs │ ├── sign_with_legacy_keychain │ │ └── mod.rs │ ├── sign_with_private_key │ │ └── mod.rs │ └── sign_with_seed_phrase │ │ └── mod.rs ├── types │ ├── account_id.rs │ ├── api_key.rs │ ├── base64_bytes.rs │ ├── crypto_hash.rs │ ├── file_bytes.rs │ ├── ft_properties.rs │ ├── json.rs │ ├── mod.rs │ ├── near_allowance.rs │ ├── near_token.rs │ ├── path_buf.rs │ ├── public_key.rs │ ├── public_key_list.rs │ ├── secret_key.rs │ ├── signature.rs │ ├── signed_delegate_action.rs │ ├── signed_transaction.rs │ ├── slip10.rs │ ├── transaction.rs │ ├── url.rs │ └── vec_string.rs └── utils_command │ ├── generate_keypair_subcommand │ └── mod.rs │ └── mod.rs └── wix └── main.wxs /.gitattributes: -------------------------------------------------------------------------------- 1 | Cargo.lock linguist-generated=true -diff 2 | -------------------------------------------------------------------------------- /.github/workflows/add-to-devtools.yml: -------------------------------------------------------------------------------- 1 | name: 'Add to DevTools Project' 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - reopened 8 | pull_request_target: 9 | types: 10 | - opened 11 | - reopened 12 | 13 | jobs: 14 | add-to-project: 15 | name: Add issue/PR to project 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/add-to-project@v1.0.0 19 | with: 20 | # add to DevTools Project #156 21 | project-url: https://github.com/orgs/near/projects/156 22 | github-token: ${{ secrets.PROJECT_GH_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/code_style.yml: -------------------------------------------------------------------------------- 1 | name: Code Style 2 | on: 3 | pull_request: 4 | 5 | jobs: 6 | codestyle: 7 | name: Code Style (fmt + clippy) 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v2 12 | - name: Install Rust 13 | uses: actions-rs/toolchain@v1 14 | with: 15 | toolchain: stable 16 | override: true 17 | profile: minimal 18 | components: rustfmt 19 | - name: Check formatting 20 | run: | 21 | cargo fmt --all -- --check 22 | - name: Install libudev-dev 23 | run: | 24 | sudo apt-get update 25 | sudo apt-get install --assume-yes libudev-dev 26 | - name: Check lints (cargo clippy) 27 | run: cargo clippy -- -D warnings 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/release-plz.yml: -------------------------------------------------------------------------------- 1 | name: Release-plz 2 | 3 | permissions: 4 | pull-requests: write 5 | contents: write 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | release-plz: 14 | name: Release-plz 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v3 19 | with: 20 | fetch-depth: 0 21 | token: ${{ secrets.CUSTOM_GITHUB_TOKEN }} 22 | - name: Install Rust toolchain 23 | uses: dtolnay/rust-toolchain@stable 24 | - name: Install packages (Linux) 25 | if: runner.os == 'Linux' 26 | run: sudo apt-get update && sudo apt-get install --assume-yes libudev-dev 27 | - name: Run release-plz 28 | uses: MarcoIeni/release-plz-action@v0.5 29 | env: 30 | # https://marcoieni.github.io/release-plz/github-action.html#triggering-further-workflow-runs 31 | GITHUB_TOKEN: ${{ secrets.CUSTOM_GITHUB_TOKEN }} 32 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /test* 3 | .DS_Store 4 | *.wasm 5 | *.json 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @FroVolod @akorchyn @dj8yfo @PolyProgrammist 2 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-gnu] 2 | # Run the following command to get the build environment: 3 | # ``` 4 | # docker build --tag cross:x86_64-unknown-linux-gnu ./cross/x86_64-unknown-linux-gnu/ 5 | # ``` 6 | image = "cross:x86_64-unknown-linux-gnu" 7 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2025 Near Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cross/x86_64-unknown-linux-gnu/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rustembedded/cross:x86_64-unknown-linux-gnu-0.2.1 2 | 3 | RUN apt-get update && \ 4 | apt-get install --assume-yes libudev-dev 5 | -------------------------------------------------------------------------------- /docs/media/block_hash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/near/near-cli-rs/3962a7be036d3062b73b07e6ef470ef86d4541e2/docs/media/block_hash.png -------------------------------------------------------------------------------- /docs/media/blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/near/near-cli-rs/3962a7be036d3062b73b07e6ef470ef86d4541e2/docs/media/blocks.png -------------------------------------------------------------------------------- /docs/media/install-powershell-script-small.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/near/near-cli-rs/3962a7be036d3062b73b07e6ef470ef86d4541e2/docs/media/install-powershell-script-small.mp4 -------------------------------------------------------------------------------- /docs/media/install-windows-msvc-msi-small.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/near/near-cli-rs/3962a7be036d3062b73b07e6ef470ef86d4541e2/docs/media/install-windows-msvc-msi-small.mp4 -------------------------------------------------------------------------------- /docs/media/install-windows-msvc-tar-gz-small.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/near/near-cli-rs/3962a7be036d3062b73b07e6ef470ef86d4541e2/docs/media/install-windows-msvc-tar-gz-small.mp4 -------------------------------------------------------------------------------- /docs/media/linkdrop_account_id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/near/near-cli-rs/3962a7be036d3062b73b07e6ef470ef86d4541e2/docs/media/linkdrop_account_id.png -------------------------------------------------------------------------------- /extensions/README.md: -------------------------------------------------------------------------------- 1 | # NEAR CLI extensions system 2 | `NEAR CLI` is built to scale. The number of possible features is endless. Instead of choosing only some of them, we are creating an `Extensions System` that will empower our users to choose, build and share `NEAR CLI` functionality. 3 | 4 | ## How it works 5 | Extensibility is achieved by translating a `NEAR CLI` invocation of the form `near (?[^ ]+)` into an invocation of an external tool `near-cli-${command}` that then needs to be present in one of the user's `$PATH` directories. 6 | It means that you can write it in any language and with the use of any framework, it just needs to be called `near-cli-{extension-name}` and be installed on your system. This approach is inspired by [Cargo](https://github.com/rust-lang/cargo). 7 | 8 | ## How to build an extension 9 | As mentioned above, any binary can become an extension, but we are encouraging developers to use [Rust](https://www.rust-lang.org/), [Clap](https://docs.rs/clap/2.33.0/clap/), and a set of libraries developed by NEAR. Here is some of them: 10 | - `near-cli-builder` - CLI specific helpers to make your life easier and follow the standards of `NEAR CLI` at the same time (NOTE: Under development) 11 | - `near-api-rs` - Rust library to interact with accounts and smart contracts on NEAR. (NOTE: Under development) 12 | - [near-jsonrpc-client-rs](https://github.com/near/near-jsonrpc-client-rs) - Lower-level JSON RPC API for interfacing with the NEAR Protocol. 13 | 14 | ## Example 15 | Core `NEAR CLI` does not have validator specific functionality, but we can add it as a simple bash script: 16 | 17 | `near-cli-staking-pool-info` 18 | ```bash 19 | #!/bin/sh 20 | POOL_ID=$1 21 | near execute view-method network mainnet contract "name.near" call "get_fields_by_pool" '{"pool_id": "'"$POOL_ID"'"}' at-final-block 22 | ``` 23 | 24 | Make sure that this script is in your `$PATH` and has proper permissions to be executed. Then call it like this: 25 | 26 | ```bash 27 | $ near staking-pool-info aurora.near 28 | { 29 | "country": "Gibraltar", 30 | "country_code": "gi", 31 | "github": "auroraisnear", 32 | "twitter": "auroraisnear", 33 | "telegram": "auroraisnear", 34 | "url": "https://aurora.dev/", 35 | "city": "Gibraltar", 36 | "description": "Aurora validator fees are spent on supporting the Rainbow Bridge infrastructure, keeping the bridge free and accessible to everyone (except for the gas fees).", 37 | "logo": "https://aurora.dev/static/favicon-32x32.png", 38 | "name": "Aurora" 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /release-plz.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | git_release_enable = false 3 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | stable 2 | -------------------------------------------------------------------------------- /src/commands/account/add_key/autogenerate_new_keypair/mod.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | mod print_keypair_to_terminal; 5 | mod save_keypair_to_keychain; 6 | mod save_keypair_to_legacy_keychain; 7 | 8 | #[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)] 9 | #[interactive_clap(input_context = super::access_key_type::AccessTypeContext)] 10 | #[interactive_clap(output_context = GenerateKeypairContext)] 11 | pub struct GenerateKeypair { 12 | #[interactive_clap(subcommand)] 13 | save_mode: SaveMode, 14 | } 15 | 16 | #[derive(Debug, Clone)] 17 | pub struct GenerateKeypairContext { 18 | global_context: crate::GlobalContext, 19 | signer_account_id: near_primitives::types::AccountId, 20 | permission: near_primitives::account::AccessKeyPermission, 21 | key_pair_properties: crate::common::KeyPairProperties, 22 | public_key: near_crypto::PublicKey, 23 | } 24 | 25 | impl GenerateKeypairContext { 26 | pub fn from_previous_context( 27 | previous_context: super::access_key_type::AccessTypeContext, 28 | _scope: &::InteractiveClapContextScope, 29 | ) -> color_eyre::eyre::Result { 30 | let key_pair_properties: crate::common::KeyPairProperties = 31 | crate::common::generate_keypair()?; 32 | let public_key = near_crypto::PublicKey::from_str(&key_pair_properties.public_key_str)?; 33 | Ok(Self { 34 | global_context: previous_context.global_context, 35 | signer_account_id: previous_context.signer_account_id, 36 | permission: previous_context.permission, 37 | key_pair_properties, 38 | public_key, 39 | }) 40 | } 41 | } 42 | 43 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 44 | #[interactive_clap(context = GenerateKeypairContext)] 45 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 46 | /// Save an access key for this account: 47 | pub enum SaveMode { 48 | #[strum_discriminants(strum( 49 | message = "save-to-keychain - Save automatically generated key pair to keychain" 50 | ))] 51 | /// Save automatically generated key pair to keychain 52 | SaveToKeychain(self::save_keypair_to_keychain::SaveKeypairToKeychain), 53 | #[strum_discriminants(strum( 54 | message = "save-to-legacy-keychain - Save automatically generated key pair to the legacy keychain (compatible with JS CLI)" 55 | ))] 56 | /// Save automatically generated key pair to the legacy keychain (compatible with JS CLI) 57 | SaveToLegacyKeychain(self::save_keypair_to_legacy_keychain::SaveKeypairToLegacyKeychain), 58 | #[strum_discriminants(strum( 59 | message = "print-to-terminal - Print automatically generated key pair in terminal" 60 | ))] 61 | /// Print automatically generated key pair in terminal 62 | PrintToTerminal(self::print_keypair_to_terminal::PrintKeypairToTerminal), 63 | } 64 | -------------------------------------------------------------------------------- /src/commands/account/create_account/create_implicit_account/use_auto_generation.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | use color_eyre::eyre::Context; 4 | 5 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 6 | #[interactive_clap(input_context = crate::GlobalContext)] 7 | #[interactive_clap(output_context = SaveWithUseAutoGenerationContext)] 8 | pub struct SaveWithUseAutoGeneration { 9 | #[interactive_clap(named_arg)] 10 | /// Specify a folder to save the implicit account file 11 | save_to_folder: super::SaveToFolder, 12 | } 13 | 14 | #[derive(Clone)] 15 | struct SaveWithUseAutoGenerationContext(super::SaveImplicitAccountContext); 16 | 17 | impl SaveWithUseAutoGenerationContext { 18 | pub fn from_previous_context( 19 | previous_context: crate::GlobalContext, 20 | _scope: &::InteractiveClapContextScope, 21 | ) -> color_eyre::eyre::Result { 22 | let on_after_getting_folder_path_callback: super::OnAfterGettingFolderPathCallback = 23 | std::sync::Arc::new({ 24 | move |folder_path| { 25 | let key_pair_properties = crate::common::generate_keypair()?; 26 | let buf = serde_json::json!({ 27 | "master_seed_phrase": key_pair_properties.master_seed_phrase, 28 | "seed_phrase_hd_path": key_pair_properties.seed_phrase_hd_path, 29 | "implicit_account_id": key_pair_properties.implicit_account_id, 30 | "public_key": key_pair_properties.public_key_str, 31 | "private_key": key_pair_properties.secret_keypair_str, 32 | }) 33 | .to_string(); 34 | let mut file_path = std::path::PathBuf::new(); 35 | let mut file_name = std::path::PathBuf::new(); 36 | file_name.push(format!("{}.json", key_pair_properties.implicit_account_id)); 37 | file_path.push(folder_path); 38 | 39 | std::fs::create_dir_all(&file_path)?; 40 | file_path.push(file_name); 41 | std::fs::File::create(&file_path) 42 | .wrap_err_with(|| format!("Failed to create file: {:?}", file_path))? 43 | .write(buf.as_bytes()) 44 | .wrap_err_with(|| format!("Failed to write to file: {:?}", folder_path))?; 45 | 46 | tracing::info!( 47 | parent: &tracing::Span::none(), 48 | "The file {:?} was saved successfully", 49 | &file_path 50 | ); 51 | 52 | Ok(()) 53 | } 54 | }); 55 | Ok(Self(super::SaveImplicitAccountContext { 56 | config: previous_context.config, 57 | on_after_getting_folder_path_callback, 58 | })) 59 | } 60 | } 61 | 62 | impl From for super::SaveImplicitAccountContext { 63 | fn from(item: SaveWithUseAutoGenerationContext) -> Self { 64 | item.0 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/commands/account/create_account/fund_myself_create_account/add_key/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | pub mod autogenerate_new_keypair; 4 | #[cfg(feature = "ledger")] 5 | mod use_ledger; 6 | mod use_manually_provided_seed_phrase; 7 | mod use_public_key; 8 | 9 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 10 | #[interactive_clap(context = super::NewAccountContext)] 11 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 12 | /// Add an access key for this account: 13 | pub enum AccessKeyMode { 14 | #[strum_discriminants(strum( 15 | message = "autogenerate-new-keypair - Automatically generate a key pair" 16 | ))] 17 | /// Automatically generate a key pair 18 | AutogenerateNewKeypair(self::autogenerate_new_keypair::GenerateKeypair), 19 | #[strum_discriminants(strum( 20 | message = "use-manually-provided-seed-prase - Use the provided seed phrase manually" 21 | ))] 22 | /// Use the provided seed phrase manually 23 | UseManuallyProvidedSeedPhrase( 24 | self::use_manually_provided_seed_phrase::AddAccessWithSeedPhraseAction, 25 | ), 26 | #[strum_discriminants(strum( 27 | message = "use-manually-provided-public-key - Use the provided public key manually" 28 | ))] 29 | /// Use the provided public key manually 30 | UseManuallyProvidedPublicKey(self::use_public_key::AddPublicKeyAction), 31 | #[cfg(feature = "ledger")] 32 | #[strum_discriminants(strum(message = "use-ledger - Use a ledger"))] 33 | /// Use a ledger 34 | UseLedger(self::use_ledger::AddAccessWithLedger), 35 | } 36 | -------------------------------------------------------------------------------- /src/commands/account/create_account/fund_myself_create_account/add_key/use_manually_provided_seed_phrase/mod.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = super::super::NewAccountContext)] 5 | #[interactive_clap(output_context = AddAccessWithSeedPhraseActionContext)] 6 | pub struct AddAccessWithSeedPhraseAction { 7 | /// Enter the seed-phrase for this sub-account: 8 | master_seed_phrase: String, 9 | #[interactive_clap(named_arg)] 10 | /// What is the signer account ID? 11 | sign_as: super::super::sign_as::SignerAccountId, 12 | } 13 | 14 | #[derive(Clone)] 15 | struct AddAccessWithSeedPhraseActionContext(super::super::AccountPropertiesContext); 16 | 17 | impl AddAccessWithSeedPhraseActionContext { 18 | pub fn from_previous_context( 19 | previous_context: super::super::NewAccountContext, 20 | scope: &::InteractiveClapContextScope, 21 | ) -> color_eyre::eyre::Result { 22 | // This is the HD path that is used in NEAR Wallet for plaintext seed phrase generation and, subsequently, for account recovery by a seed phrase. 23 | let near_wallet_seed_phrase_hd_path_default = 24 | slipped10::BIP32Path::from_str("m/44'/397'/0'").unwrap(); 25 | let public_key = crate::common::get_public_key_from_seed_phrase( 26 | near_wallet_seed_phrase_hd_path_default, 27 | &scope.master_seed_phrase, 28 | )?; 29 | let account_properties = super::super::AccountProperties { 30 | new_account_id: previous_context.new_account_id, 31 | initial_balance: previous_context.initial_balance, 32 | public_key, 33 | }; 34 | 35 | Ok(Self(super::super::AccountPropertiesContext { 36 | global_context: previous_context.global_context, 37 | account_properties, 38 | on_before_sending_transaction_callback: std::sync::Arc::new( 39 | |_signed_transaction, _network_config| Ok(String::new()), 40 | ), 41 | })) 42 | } 43 | } 44 | 45 | impl From for super::super::AccountPropertiesContext { 46 | fn from(item: AddAccessWithSeedPhraseActionContext) -> Self { 47 | item.0 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/commands/account/create_account/fund_myself_create_account/add_key/use_public_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::NewAccountContext)] 3 | #[interactive_clap(output_context = AddPublicKeyActionContext)] 4 | pub struct AddPublicKeyAction { 5 | /// Enter the public key for this account: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(named_arg)] 8 | /// What is the signer account ID? 9 | sign_as: super::super::sign_as::SignerAccountId, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct AddPublicKeyActionContext(super::super::AccountPropertiesContext); 14 | 15 | impl AddPublicKeyActionContext { 16 | pub fn from_previous_context( 17 | previous_context: super::super::NewAccountContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | let account_properties = super::super::AccountProperties { 21 | new_account_id: previous_context.new_account_id, 22 | initial_balance: previous_context.initial_balance, 23 | public_key: scope.public_key.clone().into(), 24 | }; 25 | 26 | Ok(Self(super::super::AccountPropertiesContext { 27 | global_context: previous_context.global_context, 28 | account_properties, 29 | on_before_sending_transaction_callback: std::sync::Arc::new( 30 | |_signed_transaction, _network_config| Ok(String::new()), 31 | ), 32 | })) 33 | } 34 | } 35 | 36 | impl From for super::super::AccountPropertiesContext { 37 | fn from(item: AddPublicKeyActionContext) -> Self { 38 | item.0 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/commands/account/create_account/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::enum_variant_names, clippy::large_enum_variant)] 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | mod create_implicit_account; 5 | mod fund_myself_create_account; 6 | pub mod sponsor_by_faucet_service; 7 | 8 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 9 | #[interactive_clap(context = crate::GlobalContext)] 10 | pub struct CreateAccount { 11 | #[interactive_clap(subcommand)] 12 | account_actions: CoverCostsCreateAccount, 13 | } 14 | 15 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 16 | #[interactive_clap(input_context = crate::GlobalContext)] 17 | #[interactive_clap(output_context = CoverCostsCreateAccountContext)] 18 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 19 | /// How do you cover the costs of account creation? 20 | pub enum CoverCostsCreateAccount { 21 | #[strum_discriminants(strum( 22 | message = "sponsor-by-faucet-service - I would like the faucet service sponsor to cover the cost of creating an account (testnet only for now)" 23 | ))] 24 | /// I would like the faucet service sponsor to cover the cost of creating an account (testnet only for now) 25 | SponsorByFaucetService(self::sponsor_by_faucet_service::NewAccount), 26 | #[strum_discriminants(strum( 27 | message = "fund-myself - I would like fund myself to cover the cost of creating an account" 28 | ))] 29 | /// I would like fund myself to cover the cost of creating an account 30 | FundMyself(self::fund_myself_create_account::NewAccount), 31 | #[strum_discriminants(strum( 32 | message = "fund-later - Create an implicit-account" 33 | ))] 34 | /// Create an implicit-account 35 | FundLater(self::create_implicit_account::ImplicitAccount), 36 | } 37 | 38 | #[derive(Debug, Clone)] 39 | pub struct CoverCostsCreateAccountContext(crate::GlobalContext); 40 | 41 | impl CoverCostsCreateAccountContext { 42 | pub fn from_previous_context( 43 | previous_context: crate::GlobalContext, 44 | scope: &::InteractiveClapContextScope, 45 | ) -> color_eyre::eyre::Result { 46 | match scope { 47 | CoverCostsCreateAccountDiscriminants::SponsorByFaucetService => { 48 | if previous_context.offline { 49 | Err(color_eyre::Report::msg( 50 | "Error: Creating an account with a faucet sponsor is not possible offline.", 51 | )) 52 | } else { 53 | Ok(Self(previous_context)) 54 | } 55 | } 56 | _ => Ok(Self(previous_context)), 57 | } 58 | } 59 | } 60 | 61 | impl From for crate::GlobalContext { 62 | fn from(item: CoverCostsCreateAccountContext) -> Self { 63 | item.0 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/commands/account/create_account/sponsor_by_faucet_service/add_key/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | pub mod autogenerate_new_keypair; 4 | #[cfg(feature = "ledger")] 5 | mod use_ledger; 6 | mod use_manually_provided_seed_phrase; 7 | mod use_public_key; 8 | 9 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 10 | #[interactive_clap(context = super::NewAccountContext)] 11 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 12 | /// Add an access key for this account: 13 | pub enum AccessKeyMode { 14 | #[strum_discriminants(strum( 15 | message = "autogenerate-new-keypair - Automatically generate a key pair" 16 | ))] 17 | /// Automatically generate a key pair 18 | AutogenerateNewKeypair(self::autogenerate_new_keypair::GenerateKeypair), 19 | #[strum_discriminants(strum( 20 | message = "use-manually-provided-seed-prase - Use the provided seed phrase manually" 21 | ))] 22 | /// Use the provided seed phrase manually 23 | UseManuallyProvidedSeedPhrase( 24 | self::use_manually_provided_seed_phrase::AddAccessWithSeedPhraseAction, 25 | ), 26 | #[strum_discriminants(strum( 27 | message = "use-manually-provided-public-key - Use the provided public key manually" 28 | ))] 29 | /// Use the provided public key manually 30 | UseManuallyProvidedPublicKey(self::use_public_key::AddPublicKeyAction), 31 | #[cfg(feature = "ledger")] 32 | #[strum_discriminants(strum(message = "use-ledger - Use a ledger"))] 33 | /// Use a ledger 34 | UseLedger(self::use_ledger::AddAccessWithLedger), 35 | } 36 | -------------------------------------------------------------------------------- /src/commands/account/create_account/sponsor_by_faucet_service/add_key/use_manually_provided_seed_phrase/mod.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = super::super::NewAccountContext)] 5 | #[interactive_clap(output_context = AddAccessWithSeedPhraseActionContext)] 6 | pub struct AddAccessWithSeedPhraseAction { 7 | /// Enter the seed-phrase for this account: 8 | master_seed_phrase: String, 9 | #[interactive_clap(named_arg)] 10 | /// Select network 11 | network_config: super::super::network::Network, 12 | } 13 | 14 | #[derive(Clone)] 15 | struct AddAccessWithSeedPhraseActionContext(super::super::SponsorServiceContext); 16 | 17 | impl AddAccessWithSeedPhraseActionContext { 18 | pub fn from_previous_context( 19 | previous_context: super::super::NewAccountContext, 20 | scope: &::InteractiveClapContextScope, 21 | ) -> color_eyre::eyre::Result { 22 | // This is the HD path that is used in NEAR Wallet for plaintext seed phrase generation and, subsequently, for account recovery by a seed phrase. 23 | let near_wallet_seed_phrase_hd_path_default = 24 | slipped10::BIP32Path::from_str("m/44'/397'/0'").unwrap(); 25 | let public_key = crate::common::get_public_key_from_seed_phrase( 26 | near_wallet_seed_phrase_hd_path_default, 27 | &scope.master_seed_phrase, 28 | )?; 29 | 30 | Ok(Self(super::super::SponsorServiceContext { 31 | config: previous_context.config, 32 | new_account_id: previous_context.new_account_id, 33 | public_key, 34 | on_after_getting_network_callback: std::sync::Arc::new(|_network_config| { 35 | Ok(String::new()) 36 | }), 37 | on_before_creating_account_callback: previous_context 38 | .on_before_creating_account_callback, 39 | })) 40 | } 41 | } 42 | 43 | impl From for super::super::SponsorServiceContext { 44 | fn from(item: AddAccessWithSeedPhraseActionContext) -> Self { 45 | item.0 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/commands/account/create_account/sponsor_by_faucet_service/add_key/use_public_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::NewAccountContext)] 3 | #[interactive_clap(output_context = AddPublicKeyActionContext)] 4 | pub struct AddPublicKeyAction { 5 | /// Enter the public key for this account: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(named_arg)] 8 | /// Select network 9 | network_config: super::super::network::Network, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct AddPublicKeyActionContext(super::super::SponsorServiceContext); 14 | 15 | impl AddPublicKeyActionContext { 16 | pub fn from_previous_context( 17 | previous_context: super::super::NewAccountContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | Ok(Self(super::super::SponsorServiceContext { 21 | config: previous_context.config, 22 | new_account_id: previous_context.new_account_id, 23 | public_key: scope.public_key.clone().into(), 24 | on_after_getting_network_callback: std::sync::Arc::new(|_network_config| { 25 | Ok(String::new()) 26 | }), 27 | on_before_creating_account_callback: previous_context 28 | .on_before_creating_account_callback, 29 | })) 30 | } 31 | } 32 | 33 | impl From for super::super::SponsorServiceContext { 34 | fn from(item: AddPublicKeyActionContext) -> Self { 35 | item.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/commands/account/delete_key/mod.rs: -------------------------------------------------------------------------------- 1 | mod public_keys_to_delete; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = crate::GlobalContext)] 5 | #[interactive_clap(output_context = DeleteKeysCommandContext)] 6 | pub struct DeleteKeysCommand { 7 | #[interactive_clap(skip_default_input_arg)] 8 | /// Which account should you delete the access key for? 9 | owner_account_id: crate::types::account_id::AccountId, 10 | #[interactive_clap(named_arg)] 11 | /// Specify public keys you wish to delete 12 | public_keys: self::public_keys_to_delete::PublicKeyList, 13 | } 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct DeleteKeysCommandContext { 17 | global_context: crate::GlobalContext, 18 | owner_account_id: near_primitives::types::AccountId, 19 | } 20 | 21 | impl DeleteKeysCommandContext { 22 | pub fn from_previous_context( 23 | previous_context: crate::GlobalContext, 24 | scope: &::InteractiveClapContextScope, 25 | ) -> color_eyre::eyre::Result { 26 | Ok(Self { 27 | global_context: previous_context, 28 | owner_account_id: scope.owner_account_id.clone().into(), 29 | }) 30 | } 31 | } 32 | 33 | impl DeleteKeysCommand { 34 | pub fn input_owner_account_id( 35 | context: &crate::GlobalContext, 36 | ) -> color_eyre::eyre::Result> { 37 | crate::common::input_signer_account_id_from_used_account_list( 38 | &context.config.credentials_home_dir, 39 | "Which account should you delete the access key for?", 40 | ) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/commands/account/export_account/using_private_key/mod.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::WrapErr; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = super::ExportAccountContext)] 5 | #[interactive_clap(output_context = ExportAccountFromPrivateKeyContext)] 6 | pub struct ExportAccountFromPrivateKey { 7 | #[interactive_clap(named_arg)] 8 | /// Select network 9 | network_config: crate::network::Network, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct ExportAccountFromPrivateKeyContext(crate::network::NetworkContext); 14 | 15 | impl ExportAccountFromPrivateKeyContext { 16 | pub fn from_previous_context( 17 | previous_context: super::ExportAccountContext, 18 | _scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | let config = previous_context.global_context.config.clone(); 21 | let account_id = previous_context.account_id.clone(); 22 | 23 | let on_after_getting_network_callback: crate::network::OnAfterGettingNetworkCallback = 24 | std::sync::Arc::new({ 25 | move |network_config| { 26 | if let Ok(account_key_pair) = 27 | super::get_account_key_pair_from_keychain(network_config, &account_id) 28 | { 29 | println!( 30 | "Here is the private key for account <{}>: {}", 31 | account_id, account_key_pair.private_key, 32 | ); 33 | return Ok(()); 34 | } 35 | 36 | let account_key_pair = super::get_account_key_pair_from_legacy_keychain( 37 | network_config, 38 | &account_id, 39 | &config.credentials_home_dir, 40 | ) 41 | .wrap_err_with(|| { 42 | format!("There are no access keys in keychain to export for account <{account_id}>.") 43 | })?; 44 | 45 | println!( 46 | "Here is the private key for account <{}>: {}", 47 | account_id, account_key_pair.private_key, 48 | ); 49 | Ok(()) 50 | } 51 | }); 52 | 53 | Ok(Self(crate::network::NetworkContext { 54 | config: previous_context.global_context.config, 55 | interacting_with_account_ids: vec![previous_context.account_id], 56 | on_after_getting_network_callback, 57 | })) 58 | } 59 | } 60 | 61 | impl From for crate::network::NetworkContext { 62 | fn from(item: ExportAccountFromPrivateKeyContext) -> Self { 63 | item.0 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/commands/account/get_public_key/from_ledger/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = PublicKeyFromLedgerContext)] 4 | pub struct PublicKeyFromLedger { 5 | #[interactive_clap(long)] 6 | #[interactive_clap(skip_default_input_arg)] 7 | seed_phrase_hd_path: crate::types::slip10::BIP32Path, 8 | } 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct PublicKeyFromLedgerContext {} 12 | 13 | impl PublicKeyFromLedgerContext { 14 | pub fn from_previous_context( 15 | previous_context: crate::GlobalContext, 16 | scope: &::InteractiveClapContextScope, 17 | ) -> color_eyre::eyre::Result { 18 | let seed_phrase_hd_path = scope.seed_phrase_hd_path.clone(); 19 | eprintln!("Opening the NEAR application... Please approve opening the application"); 20 | near_ledger::open_near_application().map_err(|ledger_error| { 21 | color_eyre::Report::msg(format!("An error happened while trying to open the NEAR application on the ledger: {ledger_error:?}")) 22 | })?; 23 | 24 | std::thread::sleep(std::time::Duration::from_secs(1)); 25 | 26 | eprintln!( 27 | "Please allow getting the PublicKey on Ledger device (HD Path: {})", 28 | seed_phrase_hd_path 29 | ); 30 | let verifying_key = near_ledger::get_public_key(seed_phrase_hd_path.into()).map_err( 31 | |near_ledger_error| { 32 | color_eyre::Report::msg(format!( 33 | "An error occurred while trying to get PublicKey from Ledger device: {:?}", 34 | near_ledger_error 35 | )) 36 | }, 37 | )?; 38 | let public_key = near_crypto::PublicKey::ED25519(near_crypto::ED25519PublicKey::from( 39 | verifying_key.to_bytes(), 40 | )); 41 | 42 | if let crate::Verbosity::Quiet = previous_context.verbosity { 43 | println!("{}", public_key); 44 | } else { 45 | eprintln!("\nPublic key (printed to stdout): "); 46 | println!("{}", public_key); 47 | } 48 | 49 | Ok(Self {}) 50 | } 51 | } 52 | 53 | impl PublicKeyFromLedger { 54 | pub fn input_seed_phrase_hd_path( 55 | _context: &crate::GlobalContext, 56 | ) -> color_eyre::eyre::Result> { 57 | crate::transaction_signature_options::sign_with_ledger::input_seed_phrase_hd_path() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/commands/account/get_public_key/from_plaintext_private_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = PublicKeyFromPlaintextPrivateKeyContext)] 4 | pub struct PublicKeyFromPlaintextPrivateKey { 5 | /// Enter your private (secret) key: 6 | private_key: crate::types::secret_key::SecretKey, 7 | } 8 | 9 | #[derive(Debug, Clone)] 10 | pub struct PublicKeyFromPlaintextPrivateKeyContext {} 11 | 12 | impl PublicKeyFromPlaintextPrivateKeyContext { 13 | pub fn from_previous_context( 14 | previous_context: crate::GlobalContext, 15 | scope: &::InteractiveClapContextScope, 16 | ) -> color_eyre::eyre::Result { 17 | let private_key: near_crypto::SecretKey = scope.private_key.clone().into(); 18 | let public_key = private_key.public_key(); 19 | 20 | if let crate::Verbosity::Quiet = previous_context.verbosity { 21 | println!("{}", public_key); 22 | } else { 23 | eprintln!("\nPublic key (printed to stdout): "); 24 | println!("{}", public_key); 25 | } 26 | 27 | Ok(Self {}) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/commands/account/get_public_key/from_seed_phrase/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = PublicKeyFromSeedPhraseContext)] 4 | pub struct PublicKeyFromSeedPhrase { 5 | /// Enter the seed-phrase: 6 | master_seed_phrase: String, 7 | #[interactive_clap(long)] 8 | #[interactive_clap(skip_default_input_arg)] 9 | seed_phrase_hd_path: crate::types::slip10::BIP32Path, 10 | } 11 | 12 | #[derive(Debug, Clone)] 13 | pub struct PublicKeyFromSeedPhraseContext; 14 | 15 | impl PublicKeyFromSeedPhraseContext { 16 | pub fn from_previous_context( 17 | previous_context: crate::GlobalContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | let public_key = crate::common::get_public_key_from_seed_phrase( 21 | scope.seed_phrase_hd_path.clone().into(), 22 | &scope.master_seed_phrase, 23 | )?; 24 | 25 | if let crate::Verbosity::Quiet = previous_context.verbosity { 26 | println!("{}", public_key); 27 | } else { 28 | eprintln!("\nPublic key (printed to stdout): "); 29 | println!("{}", public_key); 30 | } 31 | 32 | Ok(Self) 33 | } 34 | } 35 | 36 | impl PublicKeyFromSeedPhrase { 37 | pub fn input_seed_phrase_hd_path( 38 | _context: &crate::GlobalContext, 39 | ) -> color_eyre::eyre::Result> { 40 | crate::transaction_signature_options::sign_with_seed_phrase::input_seed_phrase_hd_path() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/commands/account/get_public_key/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | mod from_keychain; 4 | #[cfg(feature = "ledger")] 5 | mod from_ledger; 6 | mod from_legacy_keychain; 7 | mod from_plaintext_private_key; 8 | mod from_seed_phrase; 9 | 10 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 11 | #[interactive_clap(context = crate::GlobalContext)] 12 | pub struct GetPublicKey { 13 | #[interactive_clap(subcommand)] 14 | get_public_key_mode: GetPublicKeyMode, 15 | } 16 | 17 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 18 | #[interactive_clap(context = crate::GlobalContext)] 19 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 20 | /// Where do you want to get the public key from? 21 | pub enum GetPublicKeyMode { 22 | #[cfg(feature = "ledger")] 23 | #[strum_discriminants(strum( 24 | message = "from-ledger - Get the public key stored on your Ledger Nano device" 25 | ))] 26 | /// Get the public key stored on your Ledger Nano device 27 | FromLedger(self::from_ledger::PublicKeyFromLedger), 28 | #[strum_discriminants(strum( 29 | message = "from-seed-phrase - Get the public key with the seed phrase" 30 | ))] 31 | /// Get the public key with the seed phrase 32 | FromSeedPhrase(self::from_seed_phrase::PublicKeyFromSeedPhrase), 33 | #[strum_discriminants(strum( 34 | message = "from-plaintext-private-key - Get the public key from the plaintext private key" 35 | ))] 36 | /// Get the public key from the plaintext private key 37 | FromPlaintextPrivateKey(self::from_plaintext_private_key::PublicKeyFromPlaintextPrivateKey), 38 | #[strum_discriminants(strum( 39 | message = "from-keychain - Get the public key stored in a secure keychain" 40 | ))] 41 | /// Get the public key (full access key) stored in a secure keychain 42 | FromKeychain(self::from_keychain::PublicKeyFromKeychain), 43 | #[strum_discriminants(strum( 44 | message = "from-legacy-keychain - Get the public key stored in the legacy keychain (compatible with the old near CLI)" 45 | ))] 46 | /// Get the public key (full access key) stored in the legacy keychain (compatible with the old near CLI) 47 | FromLegacyKeychain(self::from_legacy_keychain::PublicKeyFromKeychain), 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/account/import_account/using_private_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = LoginFromPrivateKeyContext)] 4 | pub struct LoginFromPrivateKey { 5 | /// Enter your private (secret) key: 6 | private_key: crate::types::secret_key::SecretKey, 7 | #[interactive_clap(named_arg)] 8 | /// Select network 9 | network_config: crate::network::Network, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct LoginFromPrivateKeyContext(crate::network::NetworkContext); 14 | 15 | impl LoginFromPrivateKeyContext { 16 | pub fn from_previous_context( 17 | previous_context: crate::GlobalContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | let private_key: near_crypto::SecretKey = scope.private_key.clone().into(); 21 | let public_key = private_key.public_key(); 22 | let key_pair_properties = KeyPairProperties { 23 | public_key: public_key.clone(), 24 | private_key, 25 | }; 26 | let key_pair_properties_buf = serde_json::to_string(&key_pair_properties).unwrap(); 27 | 28 | let on_after_getting_network_callback: crate::network::OnAfterGettingNetworkCallback = 29 | std::sync::Arc::new({ 30 | let config = previous_context.config.clone(); 31 | 32 | move |network_config| { 33 | super::login( 34 | network_config.clone(), 35 | config.credentials_home_dir.clone(), 36 | &key_pair_properties_buf, 37 | &public_key.to_string(), 38 | &format!("\nIt is currently not possible to verify the account access key on network <{}>.\nYou may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n", 39 | network_config.network_name 40 | ) 41 | ) 42 | } 43 | }); 44 | 45 | Ok(Self(crate::network::NetworkContext { 46 | config: previous_context.config, 47 | interacting_with_account_ids: Vec::new(), 48 | on_after_getting_network_callback, 49 | })) 50 | } 51 | } 52 | 53 | impl From for crate::network::NetworkContext { 54 | fn from(item: LoginFromPrivateKeyContext) -> Self { 55 | item.0 56 | } 57 | } 58 | 59 | #[derive(Debug, serde::Serialize)] 60 | struct KeyPairProperties { 61 | public_key: near_crypto::PublicKey, 62 | private_key: near_crypto::SecretKey, 63 | } 64 | -------------------------------------------------------------------------------- /src/commands/account/import_account/using_seed_phrase/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = LoginFromSeedPhraseContext)] 4 | pub struct LoginFromSeedPhrase { 5 | /// Enter the seed-phrase for this account: 6 | master_seed_phrase: String, 7 | #[interactive_clap(long)] 8 | #[interactive_clap(skip_default_input_arg)] 9 | seed_phrase_hd_path: crate::types::slip10::BIP32Path, 10 | #[interactive_clap(named_arg)] 11 | /// Select network 12 | network_config: crate::network::Network, 13 | } 14 | 15 | #[derive(Clone)] 16 | pub struct LoginFromSeedPhraseContext(crate::network::NetworkContext); 17 | 18 | impl LoginFromSeedPhraseContext { 19 | pub fn from_previous_context( 20 | previous_context: crate::GlobalContext, 21 | scope: &::InteractiveClapContextScope, 22 | ) -> color_eyre::eyre::Result { 23 | let key_pair_properties = crate::common::get_key_pair_properties_from_seed_phrase( 24 | scope.seed_phrase_hd_path.clone(), 25 | scope.master_seed_phrase.clone(), 26 | )?; 27 | let key_pair_properties_buf = serde_json::to_string(&key_pair_properties).unwrap(); 28 | 29 | let on_after_getting_network_callback: crate::network::OnAfterGettingNetworkCallback = 30 | std::sync::Arc::new({ 31 | let config = previous_context.config.clone(); 32 | 33 | move |network_config| { 34 | super::login( 35 | network_config.clone(), 36 | config.credentials_home_dir.clone(), 37 | &key_pair_properties_buf, 38 | &key_pair_properties.public_key_str, 39 | &format!("\nIt is currently not possible to verify the account access key on network <{}>.\nYou may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n", 40 | network_config.network_name 41 | ) 42 | ) 43 | } 44 | }); 45 | 46 | Ok(Self(crate::network::NetworkContext { 47 | config: previous_context.config, 48 | interacting_with_account_ids: Vec::new(), 49 | on_after_getting_network_callback, 50 | })) 51 | } 52 | } 53 | 54 | impl From for crate::network::NetworkContext { 55 | fn from(item: LoginFromSeedPhraseContext) -> Self { 56 | item.0 57 | } 58 | } 59 | 60 | impl LoginFromSeedPhrase { 61 | pub fn input_seed_phrase_hd_path( 62 | _context: &crate::GlobalContext, 63 | ) -> color_eyre::eyre::Result> { 64 | crate::transaction_signature_options::sign_with_seed_phrase::input_seed_phrase_hd_path() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/commands/account/import_account/using_web_wallet/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = LoginFromWebWalletContext)] 4 | pub struct LoginFromWebWallet { 5 | #[interactive_clap(named_arg)] 6 | /// Select network 7 | network_config: crate::network::Network, 8 | } 9 | 10 | #[derive(Clone)] 11 | pub struct LoginFromWebWalletContext(crate::network::NetworkContext); 12 | 13 | impl LoginFromWebWalletContext { 14 | pub fn from_previous_context( 15 | previous_context: crate::GlobalContext, 16 | _scope: &::InteractiveClapContextScope, 17 | ) -> color_eyre::eyre::Result { 18 | let on_after_getting_network_callback: crate::network::OnAfterGettingNetworkCallback = 19 | std::sync::Arc::new({ 20 | let config = previous_context.config.clone(); 21 | 22 | move |network_config| { 23 | let key_pair_properties: crate::common::KeyPairProperties = 24 | crate::common::generate_keypair()?; 25 | let mut url: url::Url = network_config.wallet_url.join("login/")?; 26 | url.query_pairs_mut() 27 | .append_pair("title", "NEAR CLI") 28 | .append_pair("public_key", &key_pair_properties.public_key_str); 29 | // Use `success_url` once capture mode is implemented 30 | //.append_pair("success_url", "http://127.0.0.1:8080"); 31 | eprintln!( 32 | "If your browser doesn't automatically open, please visit this URL:\n {}\n", 33 | &url.as_str() 34 | ); 35 | // url.open(); 36 | open::that(url.as_ref()).ok(); 37 | 38 | let key_pair_properties_buf = serde_json::to_string(&key_pair_properties)?; 39 | let error_message = format!("\nIt is currently not possible to verify the account access key.\nYou may not be logged in to {} or you may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n", &url.as_str()); 40 | super::login( 41 | network_config.clone(), 42 | config.credentials_home_dir.clone(), 43 | &key_pair_properties_buf, 44 | &key_pair_properties.public_key_str, 45 | &error_message, 46 | ) 47 | } 48 | }); 49 | 50 | Ok(Self(crate::network::NetworkContext { 51 | config: previous_context.config, 52 | interacting_with_account_ids: Vec::new(), 53 | on_after_getting_network_callback, 54 | })) 55 | } 56 | } 57 | 58 | impl From for crate::network::NetworkContext { 59 | fn from(item: LoginFromWebWalletContext) -> Self { 60 | item.0 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/commands/account/list_keys/mod.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::Context; 2 | 3 | use crate::common::JsonRpcClientExt; 4 | use crate::common::RpcQueryResponseExt; 5 | 6 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 7 | #[interactive_clap(input_context = crate::GlobalContext)] 8 | #[interactive_clap(output_context = ViewListKeysContext)] 9 | pub struct ViewListKeys { 10 | #[interactive_clap(skip_default_input_arg)] 11 | /// What Account ID do you need to view? 12 | account_id: crate::types::account_id::AccountId, 13 | #[interactive_clap(named_arg)] 14 | /// Select network 15 | network_config: crate::network_view_at_block::NetworkViewAtBlockArgs, 16 | } 17 | 18 | #[derive(Clone)] 19 | pub struct ViewListKeysContext(crate::network_view_at_block::ArgsForViewContext); 20 | 21 | impl ViewListKeysContext { 22 | pub fn from_previous_context( 23 | previous_context: crate::GlobalContext, 24 | scope: &::InteractiveClapContextScope, 25 | ) -> color_eyre::eyre::Result { 26 | let on_after_getting_block_reference_callback: crate::network_view_at_block::OnAfterGettingBlockReferenceCallback = std::sync::Arc::new({ 27 | let account_id: near_primitives::types::AccountId = scope.account_id.clone().into(); 28 | 29 | move |network_config, block_reference| { 30 | let access_key_list = network_config 31 | .json_rpc_client() 32 | .blocking_call_view_access_key_list( 33 | &account_id, 34 | block_reference.clone(), 35 | ) 36 | .wrap_err_with(|| { 37 | format!( 38 | "Failed to fetch query AccessKeyList for {}", 39 | &account_id 40 | ) 41 | })? 42 | .access_key_list_view()?; 43 | 44 | crate::common::display_access_key_list(&access_key_list.keys); 45 | Ok(()) 46 | } 47 | }); 48 | 49 | Ok(Self(crate::network_view_at_block::ArgsForViewContext { 50 | config: previous_context.config, 51 | interacting_with_account_ids: vec![scope.account_id.clone().into()], 52 | on_after_getting_block_reference_callback, 53 | })) 54 | } 55 | } 56 | 57 | impl From for crate::network_view_at_block::ArgsForViewContext { 58 | fn from(item: ViewListKeysContext) -> Self { 59 | item.0 60 | } 61 | } 62 | 63 | impl ViewListKeys { 64 | pub fn input_account_id( 65 | context: &crate::GlobalContext, 66 | ) -> color_eyre::eyre::Result> { 67 | crate::common::input_non_signer_account_id_from_used_account_list( 68 | &context.config.credentials_home_dir, 69 | "What Account ID do you need to view?", 70 | ) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/commands/account/storage_management/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | mod storage_deposit; 4 | mod storage_withdraw; 5 | mod view_storage_balance; 6 | 7 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(input_context = crate::GlobalContext)] 9 | #[interactive_clap(output_context = ContractContext)] 10 | pub struct Contract { 11 | #[interactive_clap(skip_default_input_arg)] 12 | /// Which contract account ID do you want to manage the storage deposit for? 13 | contract_account_id: crate::types::account_id::AccountId, 14 | #[interactive_clap(subcommand)] 15 | storage_actions: StorageActions, 16 | } 17 | 18 | #[derive(Clone)] 19 | pub struct ContractContext { 20 | pub global_context: crate::GlobalContext, 21 | pub get_contract_account_id: GetContractAccountId, 22 | } 23 | 24 | impl ContractContext { 25 | pub fn from_previous_context( 26 | previous_context: crate::GlobalContext, 27 | scope: &::InteractiveClapContextScope, 28 | ) -> color_eyre::eyre::Result { 29 | let contract_account_id = scope.contract_account_id.clone(); 30 | let get_contract_account_id: GetContractAccountId = 31 | std::sync::Arc::new(move |_network_config| Ok(contract_account_id.clone().into())); 32 | Ok(Self { 33 | global_context: previous_context, 34 | get_contract_account_id, 35 | }) 36 | } 37 | } 38 | 39 | pub type GetContractAccountId = std::sync::Arc< 40 | dyn Fn( 41 | &crate::config::NetworkConfig, 42 | ) -> color_eyre::eyre::Result, 43 | >; 44 | 45 | impl Contract { 46 | pub fn input_contract_account_id( 47 | context: &crate::GlobalContext, 48 | ) -> color_eyre::eyre::Result> { 49 | crate::common::input_non_signer_account_id_from_used_account_list( 50 | &context.config.credentials_home_dir, 51 | "Which contract account ID do you want to manage the storage deposit for?", 52 | ) 53 | } 54 | } 55 | 56 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 57 | #[interactive_clap(context = ContractContext)] 58 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 59 | /// What do you want to do with the storage? 60 | pub enum StorageActions { 61 | #[strum_discriminants(strum( 62 | message = "view-balance - View storage balance for an account" 63 | ))] 64 | /// View storage balance for an account 65 | ViewBalance(self::view_storage_balance::Account), 66 | #[strum_discriminants(strum( 67 | message = "deposit - Make a storage deposit for the account" 68 | ))] 69 | /// Make a storage deposit for the account 70 | Deposit(self::storage_deposit::DepositArgs), 71 | #[strum_discriminants(strum( 72 | message = "withdraw - Withdraw a deposit from storage for an account ID" 73 | ))] 74 | /// Withdraw a deposit from storage for an account ID 75 | Withdraw(self::storage_withdraw::WithdrawArgs), 76 | } 77 | -------------------------------------------------------------------------------- /src/commands/account/update_social_profile/mod.rs: -------------------------------------------------------------------------------- 1 | mod profile_args_type; 2 | mod sign_as; 3 | 4 | #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] 5 | pub struct TransactionFunctionArgs { 6 | pub data: near_socialdb_client::types::socialdb_types::SocialDb, 7 | } 8 | 9 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 10 | #[interactive_clap(input_context = crate::GlobalContext)] 11 | #[interactive_clap(output_context = UpdateSocialProfileContext)] 12 | pub struct UpdateSocialProfile { 13 | #[interactive_clap(skip_default_input_arg)] 14 | account_id: crate::types::account_id::AccountId, 15 | #[interactive_clap(subcommand)] 16 | profile_args_type: self::profile_args_type::ProfileArgsType, 17 | } 18 | 19 | #[derive(Clone)] 20 | pub struct UpdateSocialProfileContext { 21 | pub global_context: crate::GlobalContext, 22 | pub account_id: near_primitives::types::AccountId, 23 | } 24 | 25 | impl UpdateSocialProfileContext { 26 | pub fn from_previous_context( 27 | previous_context: crate::GlobalContext, 28 | scope: &::InteractiveClapContextScope, 29 | ) -> color_eyre::eyre::Result { 30 | Ok(Self { 31 | global_context: previous_context, 32 | account_id: scope.account_id.clone().into(), 33 | }) 34 | } 35 | } 36 | 37 | impl UpdateSocialProfile { 38 | pub fn input_account_id( 39 | context: &crate::GlobalContext, 40 | ) -> color_eyre::eyre::Result> { 41 | crate::common::input_non_signer_account_id_from_used_account_list( 42 | &context.config.credentials_home_dir, 43 | "Which account do you want to update the profile for?", 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/account/update_social_profile/profile_args_type/base64_args.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::UpdateSocialProfileContext)] 3 | #[interactive_clap(output_context = Base64ArgsContext)] 4 | pub struct Base64Args { 5 | /// Enter valid Base64-encoded string (e.g. e30=): 6 | data: crate::types::base64_bytes::Base64Bytes, 7 | #[interactive_clap(named_arg)] 8 | /// Specify signer account ID 9 | sign_as: super::super::sign_as::Signer, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct Base64ArgsContext(super::ArgsContext); 14 | 15 | impl Base64ArgsContext { 16 | pub fn from_previous_context( 17 | previous_context: super::super::UpdateSocialProfileContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | Ok(Self(super::ArgsContext { 21 | global_context: previous_context.global_context, 22 | account_id: previous_context.account_id, 23 | data: scope.data.clone().into_bytes(), 24 | })) 25 | } 26 | } 27 | 28 | impl From for super::ArgsContext { 29 | fn from(item: Base64ArgsContext) -> Self { 30 | item.0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/commands/account/update_social_profile/profile_args_type/file_args.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::UpdateSocialProfileContext)] 3 | #[interactive_clap(output_context = FileArgsContext)] 4 | pub struct FileArgs { 5 | /// Enter the path to the input data file: 6 | data_path: crate::types::file_bytes::FileBytes, 7 | #[interactive_clap(named_arg)] 8 | /// Specify signer account ID 9 | sign_as: super::super::sign_as::Signer, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct FileArgsContext(super::ArgsContext); 14 | 15 | impl FileArgsContext { 16 | pub fn from_previous_context( 17 | previous_context: super::super::UpdateSocialProfileContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | Ok(Self(super::ArgsContext { 21 | global_context: previous_context.global_context, 22 | account_id: previous_context.account_id, 23 | data: scope.data_path.read_bytes()?, 24 | })) 25 | } 26 | } 27 | 28 | impl From for super::ArgsContext { 29 | fn from(item: FileArgsContext) -> Self { 30 | item.0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/commands/account/update_social_profile/profile_args_type/json_args.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::UpdateSocialProfileContext)] 3 | #[interactive_clap(output_context = JsonArgsContext)] 4 | pub struct JsonArgs { 5 | /// Enter valid JSON arguments (e.g. {"name": "NEAR", "description": "NEAR is fun"}): 6 | data: crate::types::json::Json, 7 | #[interactive_clap(named_arg)] 8 | /// Specify signer account ID 9 | sign_as: super::super::sign_as::Signer, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct JsonArgsContext(super::ArgsContext); 14 | 15 | impl JsonArgsContext { 16 | pub fn from_previous_context( 17 | previous_context: super::super::UpdateSocialProfileContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | Ok(Self(super::ArgsContext { 21 | global_context: previous_context.global_context, 22 | account_id: previous_context.account_id, 23 | data: scope.data.try_into_bytes()?, 24 | })) 25 | } 26 | } 27 | 28 | impl From for super::ArgsContext { 29 | fn from(item: JsonArgsContext) -> Self { 30 | item.0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/commands/account/update_social_profile/profile_args_type/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | mod base64_args; 4 | mod file_args; 5 | mod json_args; 6 | mod manually; 7 | 8 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 9 | #[interactive_clap(context = super::UpdateSocialProfileContext)] 10 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 11 | /// How do you want to pass profile arguments? 12 | pub enum ProfileArgsType { 13 | #[strum_discriminants(strum(message = "manually - Interactive input of arguments"))] 14 | /// Interactive input of arguments 15 | Manually(self::manually::Manually), 16 | #[strum_discriminants(strum( 17 | message = "json-args - Valid JSON arguments (e.g. {\"name\": \"NEAR\", \"description\": \"NEAR is fun\"})" 18 | ))] 19 | /// Valid JSON arguments (e.g. {"token_id": "42"}) 20 | JsonArgs(self::json_args::JsonArgs), 21 | #[strum_discriminants(strum(message = "base64-args - Base64-encoded string (e.g. e30=)"))] 22 | /// Base64-encoded string (e.g. e30=) 23 | Base64Args(self::base64_args::Base64Args), 24 | #[strum_discriminants(strum(message = "file-args - Read from JSON file"))] 25 | /// Read from JSON file 26 | FileArgs(self::file_args::FileArgs), 27 | } 28 | 29 | #[derive(Clone)] 30 | pub struct ArgsContext { 31 | pub global_context: crate::GlobalContext, 32 | pub account_id: near_primitives::types::AccountId, 33 | pub data: Vec, 34 | } 35 | -------------------------------------------------------------------------------- /src/commands/config/delete_connection/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = DeleteNetworkConnectionContext)] 4 | pub struct DeleteNetworkConnection { 5 | /// What is the network connection name? 6 | #[interactive_clap(skip_default_input_arg)] 7 | connection_name: String, 8 | } 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct DeleteNetworkConnectionContext; 12 | 13 | impl DeleteNetworkConnectionContext { 14 | pub fn from_previous_context( 15 | previous_context: crate::GlobalContext, 16 | scope: &::InteractiveClapContextScope, 17 | ) -> color_eyre::eyre::Result { 18 | let mut config = previous_context.config; 19 | config.network_connection.remove(&scope.connection_name); 20 | eprintln!(); 21 | config.write_config_toml()?; 22 | eprintln!( 23 | "Network connection \"{}\" was successfully removed from config.toml", 24 | &scope.connection_name 25 | ); 26 | Ok(Self) 27 | } 28 | } 29 | 30 | impl DeleteNetworkConnection { 31 | fn input_connection_name( 32 | context: &crate::GlobalContext, 33 | ) -> color_eyre::eyre::Result> { 34 | crate::common::input_network_name(&context.config, &[]) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/commands/config/mod.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::ContextCompat; 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | mod add_connection; 5 | mod delete_connection; 6 | mod edit_connection; 7 | 8 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 9 | #[interactive_clap(context = crate::GlobalContext)] 10 | pub struct ConfigCommands { 11 | #[interactive_clap(subcommand)] 12 | config_actions: ConfigActions, 13 | } 14 | 15 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 16 | #[interactive_clap(context = crate::GlobalContext)] 17 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 18 | #[non_exhaustive] 19 | /// What do you want to do with a near CLI config? 20 | pub enum ConfigActions { 21 | #[strum_discriminants(strum( 22 | message = "show-connections - Show a list of network connections" 23 | ))] 24 | /// Show a list of network connections 25 | ShowConnections(ShowConnections), 26 | #[strum_discriminants(strum(message = "add-connection - Add a network connection"))] 27 | /// Add a network connection 28 | AddConnection(self::add_connection::AddNetworkConnection), 29 | #[strum_discriminants(strum(message = "edit-connection - Edit a network connection"))] 30 | /// Edit a network connection 31 | EditConnection(self::edit_connection::EditConnection), 32 | #[strum_discriminants(strum( 33 | message = "delete-connection - Delete a network connection" 34 | ))] 35 | /// Delete a network connection 36 | DeleteConnection(self::delete_connection::DeleteNetworkConnection), 37 | } 38 | 39 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 40 | #[interactive_clap(input_context = crate::GlobalContext)] 41 | #[interactive_clap(output_context = ShowConnectionsContext)] 42 | pub struct ShowConnections; 43 | 44 | #[derive(Debug, Clone)] 45 | pub struct ShowConnectionsContext; 46 | 47 | impl ShowConnectionsContext { 48 | pub fn from_previous_context( 49 | previous_context: crate::GlobalContext, 50 | _scope: &::InteractiveClapContextScope, 51 | ) -> color_eyre::eyre::Result { 52 | let mut path_config_toml = 53 | dirs::config_dir().wrap_err("Impossible to get your config dir!")?; 54 | path_config_toml.push("near-cli/config.toml"); 55 | eprintln!( 56 | "\nConfiguration data is stored in a file {:?}", 57 | &path_config_toml 58 | ); 59 | let config_toml = toml::to_string(&previous_context.config)?; 60 | eprintln!("{}", &config_toml); 61 | Ok(Self) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/commands/contract/inspect/contract_metadata.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// The contract source metadata is a standard interface that allows auditing and viewing source code for a deployed smart contract. 4 | /// (https://github.com/near/near-sdk-rs/blob/master/near-contract-standards/src/contract_metadata.rs) 5 | #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] 6 | pub struct ContractSourceMetadata { 7 | pub version: Option, 8 | pub link: Option, 9 | pub standards: Vec, 10 | } 11 | 12 | #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] 13 | pub struct Standard { 14 | pub standard: String, 15 | pub version: String, 16 | } 17 | -------------------------------------------------------------------------------- /src/commands/contract/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | pub mod call_function; 4 | pub mod deploy; 5 | pub mod deploy_global; 6 | mod download_abi; 7 | pub mod download_wasm; 8 | mod inspect; 9 | mod view_storage; 10 | 11 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 12 | #[interactive_clap(context = crate::GlobalContext)] 13 | pub struct ContractCommands { 14 | #[interactive_clap(subcommand)] 15 | contract_actions: ContractActions, 16 | } 17 | 18 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 19 | #[interactive_clap(context = crate::GlobalContext)] 20 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 21 | #[non_exhaustive] 22 | /// Choose a contract action: 23 | pub enum ContractActions { 24 | #[strum_discriminants(strum( 25 | message = "call-function - Execute function (contract method)" 26 | ))] 27 | /// Execute function (contract method) 28 | CallFunction(self::call_function::CallFunctionCommands), 29 | #[strum_discriminants(strum( 30 | message = "deploy - Deploy own WASM code or re-use an existing global code from the chain" 31 | ))] 32 | /// Add a contract code 33 | Deploy(self::deploy::Contract), 34 | #[strum_discriminants(strum( 35 | message = "deploy-as-global - Deploy a WASM contract code to the global contract code on-chain registry" 36 | ))] 37 | /// Add a global contract code 38 | DeployAsGlobal(self::deploy_global::Contract), 39 | #[strum_discriminants(strum( 40 | message = "inspect - Get a list of available function names" 41 | ))] 42 | /// Get a list of available function names 43 | Inspect(self::inspect::Contract), 44 | #[strum_discriminants(strum(message = "download-abi - Download contract ABI"))] 45 | /// Download contract ABI 46 | DownloadAbi(self::download_abi::Contract), 47 | #[strum_discriminants(strum(message = "download-wasm - Download wasm"))] 48 | /// Download wasm 49 | DownloadWasm(self::download_wasm::Contract), 50 | #[strum_discriminants(strum(message = "view-storage - View contract storage state"))] 51 | /// View contract storage state 52 | ViewStorage(self::view_storage::ViewStorage), 53 | } 54 | -------------------------------------------------------------------------------- /src/commands/contract/view_storage/keys_to_view/all_keys.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::ViewStorageContext)] 3 | #[interactive_clap(output_context = AllKeysContext)] 4 | pub struct AllKeys { 5 | #[interactive_clap(subcommand)] 6 | output_format: super::super::output_format::OutputFormat, 7 | } 8 | 9 | #[derive(Debug, Clone)] 10 | pub struct AllKeysContext(super::KeysContext); 11 | 12 | impl AllKeysContext { 13 | pub fn from_previous_context( 14 | previous_context: super::super::ViewStorageContext, 15 | _scope: &::InteractiveClapContextScope, 16 | ) -> color_eyre::eyre::Result { 17 | Ok(Self(super::KeysContext { 18 | global_context: previous_context.global_context, 19 | contract_account_id: previous_context.contract_account_id, 20 | prefix: near_primitives::types::StoreKey::from(Vec::new()), 21 | })) 22 | } 23 | } 24 | 25 | impl From for super::KeysContext { 26 | fn from(item: AllKeysContext) -> Self { 27 | item.0 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/commands/contract/view_storage/keys_to_view/keys_start_with_bytes_as_base64.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::ViewStorageContext)] 3 | #[interactive_clap(output_context = KeysStartWithBytesAsBase64Context)] 4 | pub struct KeysStartWithBytesAsBase64 { 5 | /// Enter the string that the keys begin with Base64 bytes (for example, "Uw=="): 6 | keys_begin_with: crate::types::base64_bytes::Base64Bytes, 7 | #[interactive_clap(subcommand)] 8 | output_format: super::super::output_format::OutputFormat, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct KeysStartWithBytesAsBase64Context(super::KeysContext); 13 | 14 | impl KeysStartWithBytesAsBase64Context { 15 | pub fn from_previous_context( 16 | previous_context: super::super::ViewStorageContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | Ok(Self(super::KeysContext { 20 | global_context: previous_context.global_context, 21 | contract_account_id: previous_context.contract_account_id, 22 | prefix: near_primitives::types::StoreKey::from( 23 | scope.keys_begin_with.clone().into_bytes(), 24 | ), 25 | })) 26 | } 27 | } 28 | 29 | impl From for super::KeysContext { 30 | fn from(item: KeysStartWithBytesAsBase64Context) -> Self { 31 | item.0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/contract/view_storage/keys_to_view/keys_start_with_string.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::ViewStorageContext)] 3 | #[interactive_clap(output_context = KeysStartWithStringContext)] 4 | pub struct KeysStartWithString { 5 | /// Enter the string that the keys begin with (for example, "S"): 6 | keys_begin_with: String, 7 | #[interactive_clap(subcommand)] 8 | output_format: super::super::output_format::OutputFormat, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct KeysStartWithStringContext(super::KeysContext); 13 | 14 | impl KeysStartWithStringContext { 15 | pub fn from_previous_context( 16 | previous_context: super::super::ViewStorageContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | Ok(Self(super::KeysContext { 20 | global_context: previous_context.global_context, 21 | contract_account_id: previous_context.contract_account_id, 22 | prefix: near_primitives::types::StoreKey::from( 23 | scope.keys_begin_with.clone().into_bytes(), 24 | ), 25 | })) 26 | } 27 | } 28 | 29 | impl From for super::KeysContext { 30 | fn from(item: KeysStartWithStringContext) -> Self { 31 | item.0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/contract/view_storage/keys_to_view/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | mod all_keys; 4 | mod keys_start_with_bytes_as_base64; 5 | mod keys_start_with_string; 6 | 7 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(context = super::ViewStorageContext)] 9 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 10 | /// Select keys to view contract storage state: 11 | pub enum KeysToView { 12 | #[strum_discriminants(strum( 13 | message = "all - View contract storage state for all keys" 14 | ))] 15 | /// View contract storage state for all keys 16 | All(self::all_keys::AllKeys), 17 | #[strum_discriminants(strum( 18 | message = "keys-start-with-string - View contract storage state for keys that start with a string (for example, \"S\")" 19 | ))] 20 | /// View contract storage state for keys that start with a string (for example, "S") 21 | KeysStartWithString(self::keys_start_with_string::KeysStartWithString), 22 | #[strum_discriminants(strum( 23 | message = "keys-start-with-bytes-as-base64 - View contract storage state for keys that start with Base64 bytes (for example, \"Uw==\")" 24 | ))] 25 | /// View contract storage state for keys that start with Base64 bytes (for example, "Uw==") 26 | KeysStartWithBytesAsBase64(self::keys_start_with_bytes_as_base64::KeysStartWithBytesAsBase64), 27 | } 28 | 29 | #[derive(Debug, Clone)] 30 | pub struct KeysContext { 31 | pub global_context: crate::GlobalContext, 32 | pub contract_account_id: near_primitives::types::AccountId, 33 | pub prefix: near_primitives::types::StoreKey, 34 | } 35 | -------------------------------------------------------------------------------- /src/commands/contract/view_storage/mod.rs: -------------------------------------------------------------------------------- 1 | mod keys_to_view; 2 | mod output_format; 3 | 4 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 5 | #[interactive_clap(input_context = crate::GlobalContext)] 6 | #[interactive_clap(output_context = ViewStorageContext)] 7 | pub struct ViewStorage { 8 | #[interactive_clap(skip_default_input_arg)] 9 | /// What is the contract account ID? 10 | contract_account_id: crate::types::account_id::AccountId, 11 | #[interactive_clap(subcommand)] 12 | keys_to_view: self::keys_to_view::KeysToView, 13 | } 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct ViewStorageContext { 17 | global_context: crate::GlobalContext, 18 | contract_account_id: near_primitives::types::AccountId, 19 | } 20 | 21 | impl ViewStorageContext { 22 | pub fn from_previous_context( 23 | previous_context: crate::GlobalContext, 24 | scope: &::InteractiveClapContextScope, 25 | ) -> color_eyre::eyre::Result { 26 | Ok(Self { 27 | global_context: previous_context, 28 | contract_account_id: scope.contract_account_id.clone().into(), 29 | }) 30 | } 31 | } 32 | 33 | impl ViewStorage { 34 | pub fn input_contract_account_id( 35 | context: &crate::GlobalContext, 36 | ) -> color_eyre::eyre::Result> { 37 | crate::common::input_non_signer_account_id_from_used_account_list( 38 | &context.config.credentials_home_dir, 39 | "What is the contract account ID?", 40 | ) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/commands/contract/view_storage/output_format/as_json.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::keys_to_view::KeysContext)] 3 | #[interactive_clap(output_context = AsJsonContext)] 4 | pub struct AsJson { 5 | #[interactive_clap(named_arg)] 6 | /// Select network 7 | network_config: crate::network_view_at_block::NetworkViewAtBlockArgs, 8 | } 9 | 10 | #[derive(Clone)] 11 | pub struct AsJsonContext(crate::network_view_at_block::ArgsForViewContext); 12 | 13 | impl AsJsonContext { 14 | pub fn from_previous_context( 15 | previous_context: super::super::keys_to_view::KeysContext, 16 | _scope: &::InteractiveClapContextScope, 17 | ) -> color_eyre::eyre::Result { 18 | let on_after_getting_block_reference_callback: crate::network_view_at_block::OnAfterGettingBlockReferenceCallback = std::sync::Arc::new({ 19 | let contract_account_id = previous_context.contract_account_id.clone(); 20 | let prefix = previous_context.prefix; 21 | 22 | move |network_config, block_reference| { 23 | let query_view_method_response = 24 | super::get_contract_state(&contract_account_id, prefix.clone(), network_config, block_reference.clone())?; 25 | 26 | if let near_jsonrpc_primitives::types::query::QueryResponseKind::ViewState(result) = 27 | query_view_method_response.kind 28 | { 29 | if let crate::Verbosity::Quiet = previous_context.global_context.verbosity { 30 | println!("Contract state (values):\n{}\n", serde_json::to_string_pretty(&result.values)?); 31 | println!("Contract state (proof):\n{:#?}\n", result.proof); 32 | return Ok(()); 33 | } 34 | tracing::info!( 35 | parent: &tracing::Span::none(), 36 | "Contract state (values):\n{}\n", 37 | crate::common::indent_payload(&serde_json::to_string_pretty(&result.values)?) 38 | ); 39 | tracing::info!( 40 | parent: &tracing::Span::none(), 41 | "Contract state (proof):\n{}\n", 42 | crate::common::indent_payload(&format!("{:#?}", result.proof)) 43 | ); 44 | } else { 45 | return Err(color_eyre::Report::msg("Error call result".to_string())); 46 | }; 47 | Ok(()) 48 | } 49 | }); 50 | 51 | Ok(Self(crate::network_view_at_block::ArgsForViewContext { 52 | config: previous_context.global_context.config, 53 | interacting_with_account_ids: vec![previous_context.contract_account_id], 54 | on_after_getting_block_reference_callback, 55 | })) 56 | } 57 | } 58 | 59 | impl From for crate::network_view_at_block::ArgsForViewContext { 60 | fn from(item: AsJsonContext) -> Self { 61 | item.0 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/commands/contract/view_storage/output_format/mod.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::Context; 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | use crate::common::JsonRpcClientExt; 5 | 6 | mod as_json; 7 | mod as_text; 8 | 9 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 10 | #[interactive_clap(context = super::keys_to_view::KeysContext)] 11 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 12 | /// Choose a format to view contract storage state: 13 | pub enum OutputFormat { 14 | #[strum_discriminants(strum( 15 | message = "as-json - View contract storage state in JSON format" 16 | ))] 17 | /// View contract storage state in JSON format 18 | AsJson(self::as_json::AsJson), 19 | #[strum_discriminants(strum( 20 | message = "as-text - View contract storage state in the text" 21 | ))] 22 | /// View contract storage state in the text 23 | AsText(self::as_text::AsText), 24 | } 25 | 26 | #[tracing::instrument(name = "Obtaining the state of the contract ...", skip_all)] 27 | pub fn get_contract_state( 28 | contract_account_id: &near_primitives::types::AccountId, 29 | prefix: near_primitives::types::StoreKey, 30 | network_config: &crate::config::NetworkConfig, 31 | block_reference: near_primitives::types::BlockReference, 32 | ) -> color_eyre::eyre::Result { 33 | network_config 34 | .json_rpc_client() 35 | .blocking_call(near_jsonrpc_client::methods::query::RpcQueryRequest { 36 | block_reference, 37 | request: near_primitives::views::QueryRequest::ViewState { 38 | account_id: contract_account_id.clone(), 39 | prefix, 40 | include_proof: false, 41 | }, 42 | }) 43 | .wrap_err_with(|| { 44 | format!( 45 | "Failed to fetch query ViewState for <{contract_account_id}> on network <{}>", 46 | network_config.network_name 47 | ) 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /src/commands/extensions/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | pub mod self_update; 4 | 5 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 6 | #[interactive_clap(context = crate::GlobalContext)] 7 | pub struct ExtensionsCommands { 8 | #[interactive_clap(subcommand)] 9 | pub extensions_actions: ExtensionsActions, 10 | } 11 | 12 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 13 | #[interactive_clap(context = crate::GlobalContext)] 14 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 15 | #[non_exhaustive] 16 | /// What do you want to do with a near CLI? 17 | pub enum ExtensionsActions { 18 | #[strum_discriminants(strum(message = "self-update - Self update near CLI"))] 19 | /// Self update near CLI 20 | SelfUpdate(self::self_update::SelfUpdateCommand), 21 | } 22 | -------------------------------------------------------------------------------- /src/commands/extensions/self_update/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(windows)] 2 | const BIN_NAME: &str = "near.exe"; 3 | #[cfg(not(windows))] 4 | const BIN_NAME: &str = "near"; 5 | 6 | use color_eyre::{eyre::WrapErr, owo_colors::OwoColorize}; 7 | 8 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 9 | #[interactive_clap(input_context = crate::GlobalContext)] 10 | #[interactive_clap(output_context = SelfUpdateCommandContext)] 11 | pub struct SelfUpdateCommand; 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct SelfUpdateCommandContext; 15 | 16 | impl SelfUpdateCommandContext { 17 | pub fn from_previous_context( 18 | _previous_context: crate::GlobalContext, 19 | _scope: &::InteractiveClapContextScope, 20 | ) -> color_eyre::eyre::Result { 21 | let status = self_update::backends::github::Update::configure() 22 | .repo_owner("near") 23 | .repo_name("near-cli-rs") 24 | .bin_path_in_archive( 25 | format!("near-cli-rs-{}/{}", self_update::get_target(), BIN_NAME).as_str(), 26 | ) 27 | .bin_name(BIN_NAME) 28 | .show_download_progress(true) 29 | .current_version(self_update::cargo_crate_version!()) 30 | .build() 31 | .wrap_err("Failed to build self_update")? 32 | .update() 33 | .wrap_err("Failed to update near CLI")?; 34 | if let self_update::Status::Updated(release) = status { 35 | println!( 36 | "\n{}{}{}\n", 37 | "Welcome to `near` CLI v".green().bold(), 38 | release.green().bold(), 39 | "!".green().bold() 40 | ); 41 | println!("Report any bugs:\n"); 42 | println!("\thttps://github.com/near/near-cli-rs/issues\n"); 43 | println!("What's new:\n"); 44 | println!( 45 | "\t{}{}\n", 46 | "https://github.com/near/near-cli-rs/releases/tag/v".truecolor(0, 160, 150), 47 | release.truecolor(0, 160, 150) 48 | ); 49 | } 50 | 51 | Ok(Self) 52 | } 53 | } 54 | 55 | pub fn get_latest_version() -> color_eyre::eyre::Result { 56 | Ok(self_update::backends::github::Update::configure() 57 | .repo_owner("near") 58 | .repo_name("near-cli-rs") 59 | .bin_name("near") 60 | .current_version(self_update::cargo_crate_version!()) 61 | .build() 62 | .wrap_err("Failed to build self_update")? 63 | .get_latest_release() 64 | .wrap_err("Failed to get latest release")? 65 | .version) 66 | } 67 | -------------------------------------------------------------------------------- /src/commands/staking/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | pub mod delegate; 4 | mod validator_list; 5 | 6 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 7 | #[interactive_clap(context = crate::GlobalContext)] 8 | pub struct Staking { 9 | #[interactive_clap(subcommand)] 10 | stake: StakingType, 11 | } 12 | 13 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 14 | #[interactive_clap(context = crate::GlobalContext)] 15 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 16 | #[non_exhaustive] 17 | /// Select the type of stake: 18 | pub enum StakingType { 19 | #[strum_discriminants(strum( 20 | message = "validator-list - View the list of validators to delegate" 21 | ))] 22 | /// View the list of validators to delegate 23 | ValidatorList(self::validator_list::ValidatorList), 24 | #[strum_discriminants(strum(message = "delegation - Delegation management"))] 25 | /// Delegation management 26 | Delegation(self::delegate::StakeDelegation), 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/staking/validator_list/mod.rs: -------------------------------------------------------------------------------- 1 | use prettytable::Table; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = crate::GlobalContext)] 5 | #[interactive_clap(output_context = ValidatorListContext)] 6 | pub struct ValidatorList { 7 | #[interactive_clap(named_arg)] 8 | /// Select network 9 | network_config: crate::network::Network, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct ValidatorListContext(crate::network::NetworkContext); 14 | 15 | impl ValidatorListContext { 16 | pub fn from_previous_context( 17 | previous_context: crate::GlobalContext, 18 | _scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | let on_after_getting_network_callback: crate::network::OnAfterGettingNetworkCallback = 21 | std::sync::Arc::new(display_validators_info); 22 | Ok(Self(crate::network::NetworkContext { 23 | config: previous_context.config, 24 | interacting_with_account_ids: vec![], 25 | on_after_getting_network_callback, 26 | })) 27 | } 28 | } 29 | 30 | impl From for crate::network::NetworkContext { 31 | fn from(item: ValidatorListContext) -> Self { 32 | item.0 33 | } 34 | } 35 | 36 | #[tracing::instrument(name = "View the list of validators for delegation ...", skip_all)] 37 | fn display_validators_info(network_config: &crate::config::NetworkConfig) -> crate::CliResult { 38 | let mut table = Table::new(); 39 | table.set_titles(prettytable::row![Fg=>"#", "Validator Id", "Fee", "Delegators", "Stake"]); 40 | 41 | for (index, validator) in crate::common::get_validator_list(network_config)? 42 | .into_iter() 43 | .enumerate() 44 | { 45 | let fee = if let Some(fee) = validator.fee { 46 | format!("{:>6.2} %", fee.numerator * 100 / fee.denominator) 47 | } else { 48 | format!("{:>6}", "N/A") 49 | }; 50 | let delegators = if let Some(num) = validator.delegators { 51 | format!("{:>8}", num) 52 | } else { 53 | format!("{:>8}", "N/A") 54 | }; 55 | table.add_row(prettytable::row![ 56 | Fg->index + 1, 57 | validator.validator_id, 58 | fee, 59 | delegators, 60 | near_token::NearToken::from_yoctonear(validator.stake), 61 | ]); 62 | } 63 | table.set_format(*prettytable::format::consts::FORMAT_NO_LINESEP_WITH_TITLE); 64 | table.printstd(); 65 | let validators_url: url::Url = network_config.wallet_url.join("staking/validators")?; 66 | eprintln!( 67 | "This is not a complete list of validators. To see the full list of validators visit Explorer:\n{}\n", 68 | &validators_url.as_str() 69 | ); 70 | Ok(()) 71 | } 72 | -------------------------------------------------------------------------------- /src/commands/tokens/view_near_balance/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::TokensCommandsContext)] 3 | #[interactive_clap(output_context = ViewNearBalanceContext)] 4 | pub struct ViewNearBalance { 5 | #[interactive_clap(named_arg)] 6 | /// Select network 7 | network_config: crate::network_view_at_block::NetworkViewAtBlockArgs, 8 | } 9 | 10 | #[derive(Clone)] 11 | pub struct ViewNearBalanceContext(crate::network_view_at_block::ArgsForViewContext); 12 | 13 | impl ViewNearBalanceContext { 14 | pub fn from_previous_context( 15 | previous_context: super::TokensCommandsContext, 16 | _scope: &::InteractiveClapContextScope, 17 | ) -> color_eyre::eyre::Result { 18 | let on_after_getting_block_reference_callback: crate::network_view_at_block::OnAfterGettingBlockReferenceCallback = std::sync::Arc::new({ 19 | let owner_account_id = previous_context.owner_account_id.clone(); 20 | 21 | move |network_config, block_reference| { 22 | let account_transfer_allowance = tokio::runtime::Runtime::new() 23 | .unwrap() 24 | .block_on(crate::common::get_account_transfer_allowance( 25 | network_config, 26 | owner_account_id.clone(), 27 | block_reference.clone(), 28 | ))?; 29 | tracing::info!( 30 | parent: &tracing::Span::none(), 31 | "{}", 32 | crate::common::indent_payload(&format!("{account_transfer_allowance}")) 33 | ); 34 | if let crate::Verbosity::Quiet = previous_context.global_context.verbosity { 35 | println!("{account_transfer_allowance}"); 36 | }; 37 | Ok(()) 38 | } 39 | }); 40 | 41 | Ok(Self(crate::network_view_at_block::ArgsForViewContext { 42 | config: previous_context.global_context.config, 43 | interacting_with_account_ids: vec![previous_context.owner_account_id], 44 | on_after_getting_block_reference_callback, 45 | })) 46 | } 47 | } 48 | 49 | impl From for crate::network_view_at_block::ArgsForViewContext { 50 | fn from(item: ViewNearBalanceContext) -> Self { 51 | item.0 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/add_key/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | pub mod access_key_type; 4 | pub mod use_manually_provided_seed_phrase; 5 | pub mod use_public_key; 6 | 7 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 9 | pub struct AddKeyAction { 10 | #[interactive_clap(subcommand)] 11 | permission: AccessKeyPermission, 12 | } 13 | 14 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 15 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 16 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 17 | /// Select a permission that you want to add to the access key: 18 | pub enum AccessKeyPermission { 19 | #[strum_discriminants(strum( 20 | message = "grant-full-access - A permission with full access" 21 | ))] 22 | /// Provide data for a full access key 23 | GrantFullAccess(self::access_key_type::FullAccessType), 24 | #[strum_discriminants(strum( 25 | message = "grant-function-call-access - A permission with function call" 26 | ))] 27 | /// Provide data for a function-call access key 28 | GrantFunctionCallAccess(self::access_key_type::FunctionCallType), 29 | } 30 | 31 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 32 | #[interactive_clap(context = self::access_key_type::AccessKeyPermissionContext)] 33 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 34 | /// Add an access key for this account: 35 | pub enum AccessKeyMode { 36 | #[strum_discriminants(strum( 37 | message = "use-manually-provided-seed-prase - Use the provided seed phrase manually" 38 | ))] 39 | /// Use the provided seed phrase manually 40 | UseManuallyProvidedSeedPhrase( 41 | self::use_manually_provided_seed_phrase::AddAccessWithSeedPhraseAction, 42 | ), 43 | #[strum_discriminants(strum( 44 | message = "use-manually-provided-public-key - Use the provided public key manually" 45 | ))] 46 | /// Use the provided public key manually 47 | UseManuallyProvidedPublicKey(self::use_public_key::AddAccessKeyAction), 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/add_key/use_manually_provided_seed_phrase/mod.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = super::access_key_type::AccessKeyPermissionContext)] 5 | #[interactive_clap(output_context = AddAccessWithSeedPhraseActionContext)] 6 | pub struct AddAccessWithSeedPhraseAction { 7 | /// Enter the seed_phrase: 8 | master_seed_phrase: String, 9 | #[interactive_clap(subcommand)] 10 | next_action: super::super::super::super::add_action_2::NextAction, 11 | } 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct AddAccessWithSeedPhraseActionContext( 15 | super::super::super::super::ConstructTransactionContext, 16 | ); 17 | 18 | impl AddAccessWithSeedPhraseActionContext { 19 | pub fn from_previous_context( 20 | previous_context: super::access_key_type::AccessKeyPermissionContext, 21 | scope: &::InteractiveClapContextScope, 22 | ) -> color_eyre::eyre::Result { 23 | let seed_phrase_hd_path_default = slipped10::BIP32Path::from_str("m/44'/397'/0'").unwrap(); 24 | let public_key = crate::common::get_public_key_from_seed_phrase( 25 | seed_phrase_hd_path_default, 26 | &scope.master_seed_phrase, 27 | )?; 28 | let access_key = near_primitives::account::AccessKey { 29 | nonce: 0, 30 | permission: previous_context.access_key_permission, 31 | }; 32 | let action = near_primitives::transaction::Action::AddKey(Box::new( 33 | near_primitives::transaction::AddKeyAction { 34 | public_key, 35 | access_key, 36 | }, 37 | )); 38 | let mut actions = previous_context.actions; 39 | actions.push(action); 40 | Ok(Self( 41 | super::super::super::super::ConstructTransactionContext { 42 | global_context: previous_context.global_context, 43 | signer_account_id: previous_context.signer_account_id, 44 | receiver_account_id: previous_context.receiver_account_id, 45 | actions, 46 | }, 47 | )) 48 | } 49 | } 50 | 51 | impl From 52 | for super::super::super::super::ConstructTransactionContext 53 | { 54 | fn from(item: AddAccessWithSeedPhraseActionContext) -> Self { 55 | item.0 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/add_key/use_public_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::access_key_type::AccessKeyPermissionContext)] 3 | #[interactive_clap(output_context = AddAccessKeyActionContext)] 4 | pub struct AddAccessKeyAction { 5 | /// Enter the public key: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::super::add_action_2::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct AddAccessKeyActionContext(super::super::super::super::ConstructTransactionContext); 13 | 14 | impl AddAccessKeyActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::access_key_type::AccessKeyPermissionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let access_key = near_primitives::account::AccessKey { 20 | nonce: 0, 21 | permission: previous_context.access_key_permission, 22 | }; 23 | let action = near_primitives::transaction::Action::AddKey(Box::new( 24 | near_primitives::transaction::AddKeyAction { 25 | public_key: scope.public_key.clone().into(), 26 | access_key, 27 | }, 28 | )); 29 | let mut actions = previous_context.actions; 30 | actions.push(action); 31 | Ok(Self( 32 | super::super::super::super::ConstructTransactionContext { 33 | global_context: previous_context.global_context, 34 | signer_account_id: previous_context.signer_account_id, 35 | receiver_account_id: previous_context.receiver_account_id, 36 | actions, 37 | }, 38 | )) 39 | } 40 | } 41 | 42 | impl From for super::super::super::super::ConstructTransactionContext { 43 | fn from(item: AddAccessKeyActionContext) -> Self { 44 | item.0 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/create_account/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = CreateAccountActionContext)] 4 | pub struct CreateAccountAction { 5 | #[interactive_clap(subcommand)] 6 | next_action: super::super::super::add_action_2::NextAction, 7 | } 8 | 9 | #[derive(Debug, Clone)] 10 | pub struct CreateAccountActionContext(super::super::super::ConstructTransactionContext); 11 | 12 | impl CreateAccountActionContext { 13 | pub fn from_previous_context( 14 | previous_context: super::super::super::ConstructTransactionContext, 15 | _scope: &::InteractiveClapContextScope, 16 | ) -> color_eyre::eyre::Result { 17 | let action = near_primitives::transaction::Action::CreateAccount( 18 | near_primitives::transaction::CreateAccountAction {}, 19 | ); 20 | let mut actions = previous_context.actions; 21 | actions.push(action); 22 | Ok(Self(super::super::super::ConstructTransactionContext { 23 | global_context: previous_context.global_context, 24 | signer_account_id: previous_context.signer_account_id, 25 | receiver_account_id: previous_context.receiver_account_id, 26 | actions, 27 | })) 28 | } 29 | } 30 | 31 | impl From for super::super::super::ConstructTransactionContext { 32 | fn from(item: CreateAccountActionContext) -> Self { 33 | item.0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/delete_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = DeleteKeyActionContext)] 4 | pub struct DeleteKeyAction { 5 | /// Enter the public key You wish to delete: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::add_action_2::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct DeleteKeyActionContext(super::super::super::ConstructTransactionContext); 13 | 14 | impl DeleteKeyActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::super::super::ConstructTransactionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let action = near_primitives::transaction::Action::DeleteKey(Box::new( 20 | near_primitives::transaction::DeleteKeyAction { 21 | public_key: scope.public_key.clone().into(), 22 | }, 23 | )); 24 | let mut actions = previous_context.actions; 25 | actions.push(action); 26 | Ok(Self(super::super::super::ConstructTransactionContext { 27 | global_context: previous_context.global_context, 28 | signer_account_id: previous_context.signer_account_id, 29 | receiver_account_id: previous_context.receiver_account_id, 30 | actions, 31 | })) 32 | } 33 | } 34 | 35 | impl From for super::super::super::ConstructTransactionContext { 36 | fn from(item: DeleteKeyActionContext) -> Self { 37 | item.0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/deploy_contract/initialize_mode/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap_derive::InteractiveClap)] 4 | #[interactive_clap(context = super::super::super::super::ConstructTransactionContext)] 5 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 6 | /// Select the need for initialization: 7 | pub enum InitializeMode { 8 | /// Add an initialize 9 | #[strum_discriminants(strum(message = "with-init-call - Add an initialize"))] 10 | WithInitCall(super::super::call_function::FunctionCallAction), 11 | /// Don't add an initialize 12 | #[strum_discriminants(strum(message = "without-init-call - Don't add an initialize"))] 13 | WithoutInitCall(NoInitialize), 14 | } 15 | 16 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 17 | #[interactive_clap(context = super::super::super::super::ConstructTransactionContext)] 18 | pub struct NoInitialize { 19 | #[interactive_clap(subcommand)] 20 | next_action: super::super::super::super::add_action_2::NextAction, 21 | } 22 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/deploy_contract/mod.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::Context; 2 | 3 | pub mod initialize_mode; 4 | 5 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 6 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 7 | pub struct DeployContractAction { 8 | #[interactive_clap(named_arg)] 9 | /// Specify a path to wasm file 10 | use_file: ContractFile, 11 | } 12 | 13 | #[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)] 14 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 15 | #[interactive_clap(output_context = ContractFileContext)] 16 | pub struct ContractFile { 17 | /// What is the file location of the contract? 18 | pub file_path: crate::types::path_buf::PathBuf, 19 | #[interactive_clap(subcommand)] 20 | initialize: self::initialize_mode::InitializeMode, 21 | } 22 | 23 | #[derive(Debug, Clone)] 24 | pub struct ContractFileContext(super::super::super::ConstructTransactionContext); 25 | 26 | impl ContractFileContext { 27 | pub fn from_previous_context( 28 | previous_context: super::super::super::ConstructTransactionContext, 29 | scope: &::InteractiveClapContextScope, 30 | ) -> color_eyre::eyre::Result { 31 | let code = std::fs::read(&scope.file_path).wrap_err_with(|| { 32 | format!("Failed to open or read the file: {:?}.", &scope.file_path.0,) 33 | })?; 34 | let action = near_primitives::transaction::Action::DeployContract( 35 | near_primitives::transaction::DeployContractAction { code }, 36 | ); 37 | let mut actions = previous_context.actions; 38 | actions.push(action); 39 | Ok(Self(super::super::super::ConstructTransactionContext { 40 | global_context: previous_context.global_context, 41 | signer_account_id: previous_context.signer_account_id, 42 | receiver_account_id: previous_context.receiver_account_id, 43 | actions, 44 | })) 45 | } 46 | } 47 | 48 | impl From for super::super::super::ConstructTransactionContext { 49 | fn from(item: ContractFileContext) -> Self { 50 | item.0 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/stake/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = StakeActionContext)] 4 | pub struct StakeAction { 5 | /// Enter the amount to stake: (example: 10000NEAR) 6 | stake_amount: crate::types::near_token::NearToken, 7 | /// Enter the public key of the validator key pair used on your NEAR node (see validator_key.json): 8 | public_key: crate::types::public_key::PublicKey, 9 | #[interactive_clap(subcommand)] 10 | next_action: super::super::super::add_action_2::NextAction, 11 | } 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct StakeActionContext(super::super::super::ConstructTransactionContext); 15 | 16 | impl StakeActionContext { 17 | pub fn from_previous_context( 18 | previous_context: super::super::super::ConstructTransactionContext, 19 | scope: &::InteractiveClapContextScope, 20 | ) -> color_eyre::eyre::Result { 21 | let action = near_primitives::transaction::Action::Stake(Box::new( 22 | near_primitives::transaction::StakeAction { 23 | stake: scope.stake_amount.as_yoctonear(), 24 | public_key: scope.public_key.clone().into(), 25 | }, 26 | )); 27 | let mut actions = previous_context.actions; 28 | actions.push(action); 29 | Ok(Self(super::super::super::ConstructTransactionContext { 30 | global_context: previous_context.global_context, 31 | signer_account_id: previous_context.signer_account_id, 32 | receiver_account_id: previous_context.receiver_account_id, 33 | actions, 34 | })) 35 | } 36 | } 37 | 38 | impl From for super::super::super::ConstructTransactionContext { 39 | fn from(item: StakeActionContext) -> Self { 40 | item.0 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/add_action/transfer/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = TransferActionContext)] 4 | pub struct TransferAction { 5 | /// How many NEAR Tokens do you want to transfer? (example: 10NEAR or 0.5near or 10000yoctonear) 6 | pub amount_in_near: crate::types::near_token::NearToken, 7 | #[interactive_clap(subcommand)] 8 | pub next_action: super::super::super::add_action_2::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct TransferActionContext(super::super::super::ConstructTransactionContext); 13 | 14 | impl TransferActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::super::super::ConstructTransactionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let action = near_primitives::transaction::Action::Transfer( 20 | near_primitives::transaction::TransferAction { 21 | deposit: scope.amount_in_near.as_yoctonear(), 22 | }, 23 | ); 24 | let mut actions = previous_context.actions; 25 | actions.push(action); 26 | Ok(Self(super::super::super::ConstructTransactionContext { 27 | global_context: previous_context.global_context, 28 | signer_account_id: previous_context.signer_account_id, 29 | receiver_account_id: previous_context.receiver_account_id, 30 | actions, 31 | })) 32 | } 33 | } 34 | 35 | impl From for super::super::super::ConstructTransactionContext { 36 | fn from(item: TransferActionContext) -> Self { 37 | item.0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_1/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::enum_variant_names, clippy::large_enum_variant)] 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | pub mod add_action; 5 | 6 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 7 | #[interactive_clap(context = super::ConstructTransactionContext)] 8 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 9 | /// Select an action that you want to add to the action: 10 | pub enum NextAction { 11 | #[strum_discriminants(strum(message = "add-action - Select a new action"))] 12 | /// Choose next action 13 | AddAction(self::add_action::AddAction), 14 | #[strum_discriminants(strum(message = "skip - Skip adding a new action"))] 15 | /// Go to transaction signing 16 | Skip(super::skip_action::SkipAction), 17 | } 18 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/add_key/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | mod access_key_type; 4 | mod use_manually_provided_seed_phrase; 5 | mod use_public_key; 6 | 7 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 9 | pub struct AddKeyAction { 10 | #[interactive_clap(subcommand)] 11 | permission: AccessKeyPermission, 12 | } 13 | 14 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 15 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 16 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 17 | /// Select a permission that you want to add to the access key: 18 | pub enum AccessKeyPermission { 19 | #[strum_discriminants(strum( 20 | message = "grant-full-access - A permission with full access" 21 | ))] 22 | /// Provide data for a full access key 23 | GrantFullAccess(self::access_key_type::FullAccessType), 24 | #[strum_discriminants(strum( 25 | message = "grant-function-call-access - A permission with function call" 26 | ))] 27 | /// Provide data for a function-call access key 28 | GrantFunctionCallAccess(self::access_key_type::FunctionCallType), 29 | } 30 | 31 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 32 | #[interactive_clap(context = self::access_key_type::AccessKeyPermissionContext)] 33 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 34 | /// Add an access key for this account: 35 | pub enum AccessKeyMode { 36 | #[strum_discriminants(strum( 37 | message = "use-manually-provided-seed-prase - Use the provided seed phrase manually" 38 | ))] 39 | /// Use the provided seed phrase manually 40 | UseManuallyProvidedSeedPhrase( 41 | self::use_manually_provided_seed_phrase::AddAccessWithSeedPhraseAction, 42 | ), 43 | #[strum_discriminants(strum( 44 | message = "use-manually-provided-public-key - Use the provided public key manually" 45 | ))] 46 | /// Use the provided public key manually 47 | UseManuallyProvidedPublicKey(self::use_public_key::AddAccessKeyAction), 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/add_key/use_manually_provided_seed_phrase/mod.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = super::access_key_type::AccessKeyPermissionContext)] 5 | #[interactive_clap(output_context = AddAccessWithSeedPhraseActionContext)] 6 | pub struct AddAccessWithSeedPhraseAction { 7 | /// Enter the seed_phrase: 8 | master_seed_phrase: String, 9 | #[interactive_clap(subcommand)] 10 | next_action: super::super::super::super::add_action_3::NextAction, 11 | } 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct AddAccessWithSeedPhraseActionContext( 15 | super::super::super::super::ConstructTransactionContext, 16 | ); 17 | 18 | impl AddAccessWithSeedPhraseActionContext { 19 | pub fn from_previous_context( 20 | previous_context: super::access_key_type::AccessKeyPermissionContext, 21 | scope: &::InteractiveClapContextScope, 22 | ) -> color_eyre::eyre::Result { 23 | let seed_phrase_hd_path_default = slipped10::BIP32Path::from_str("m/44'/397'/0'").unwrap(); 24 | let public_key = crate::common::get_public_key_from_seed_phrase( 25 | seed_phrase_hd_path_default, 26 | &scope.master_seed_phrase, 27 | )?; 28 | let access_key = near_primitives::account::AccessKey { 29 | nonce: 0, 30 | permission: previous_context.access_key_permission, 31 | }; 32 | let action = near_primitives::transaction::Action::AddKey(Box::new( 33 | near_primitives::transaction::AddKeyAction { 34 | public_key, 35 | access_key, 36 | }, 37 | )); 38 | let mut actions = previous_context.actions; 39 | actions.push(action); 40 | Ok(Self( 41 | super::super::super::super::ConstructTransactionContext { 42 | global_context: previous_context.global_context, 43 | signer_account_id: previous_context.signer_account_id, 44 | receiver_account_id: previous_context.receiver_account_id, 45 | actions, 46 | }, 47 | )) 48 | } 49 | } 50 | 51 | impl From 52 | for super::super::super::super::ConstructTransactionContext 53 | { 54 | fn from(item: AddAccessWithSeedPhraseActionContext) -> Self { 55 | item.0 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/add_key/use_public_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::access_key_type::AccessKeyPermissionContext)] 3 | #[interactive_clap(output_context = AddAccessKeyActionContext)] 4 | pub struct AddAccessKeyAction { 5 | /// Enter the public key: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::super::add_action_3::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct AddAccessKeyActionContext(super::super::super::super::ConstructTransactionContext); 13 | 14 | impl AddAccessKeyActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::access_key_type::AccessKeyPermissionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let access_key = near_primitives::account::AccessKey { 20 | nonce: 0, 21 | permission: previous_context.access_key_permission, 22 | }; 23 | let action = near_primitives::transaction::Action::AddKey(Box::new( 24 | near_primitives::transaction::AddKeyAction { 25 | public_key: scope.public_key.clone().into(), 26 | access_key, 27 | }, 28 | )); 29 | let mut actions = previous_context.actions; 30 | actions.push(action); 31 | Ok(Self( 32 | super::super::super::super::ConstructTransactionContext { 33 | global_context: previous_context.global_context, 34 | signer_account_id: previous_context.signer_account_id, 35 | receiver_account_id: previous_context.receiver_account_id, 36 | actions, 37 | }, 38 | )) 39 | } 40 | } 41 | 42 | impl From for super::super::super::super::ConstructTransactionContext { 43 | fn from(item: AddAccessKeyActionContext) -> Self { 44 | item.0 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/create_account/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = CreateAccountActionContext)] 4 | pub struct CreateAccountAction { 5 | #[interactive_clap(subcommand)] 6 | next_action: super::super::super::add_action_3::NextAction, 7 | } 8 | 9 | #[derive(Debug, Clone)] 10 | pub struct CreateAccountActionContext(super::super::super::ConstructTransactionContext); 11 | 12 | impl CreateAccountActionContext { 13 | pub fn from_previous_context( 14 | previous_context: super::super::super::ConstructTransactionContext, 15 | _scope: &::InteractiveClapContextScope, 16 | ) -> color_eyre::eyre::Result { 17 | let action = near_primitives::transaction::Action::CreateAccount( 18 | near_primitives::transaction::CreateAccountAction {}, 19 | ); 20 | let mut actions = previous_context.actions; 21 | actions.push(action); 22 | Ok(Self(super::super::super::ConstructTransactionContext { 23 | global_context: previous_context.global_context, 24 | signer_account_id: previous_context.signer_account_id, 25 | receiver_account_id: previous_context.receiver_account_id, 26 | actions, 27 | })) 28 | } 29 | } 30 | 31 | impl From for super::super::super::ConstructTransactionContext { 32 | fn from(item: CreateAccountActionContext) -> Self { 33 | item.0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/delete_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = DeleteKeyActionContext)] 4 | pub struct DeleteKeyAction { 5 | /// Enter the public key You wish to delete: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::add_action_3::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct DeleteKeyActionContext(super::super::super::ConstructTransactionContext); 13 | 14 | impl DeleteKeyActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::super::super::ConstructTransactionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let action = near_primitives::transaction::Action::DeleteKey(Box::new( 20 | near_primitives::transaction::DeleteKeyAction { 21 | public_key: scope.public_key.clone().into(), 22 | }, 23 | )); 24 | let mut actions = previous_context.actions; 25 | actions.push(action); 26 | Ok(Self(super::super::super::ConstructTransactionContext { 27 | global_context: previous_context.global_context, 28 | signer_account_id: previous_context.signer_account_id, 29 | receiver_account_id: previous_context.receiver_account_id, 30 | actions, 31 | })) 32 | } 33 | } 34 | 35 | impl From for super::super::super::ConstructTransactionContext { 36 | fn from(item: DeleteKeyActionContext) -> Self { 37 | item.0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/deploy_contract/initialize_mode/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap_derive::InteractiveClap)] 4 | #[interactive_clap(context = super::super::super::super::ConstructTransactionContext)] 5 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 6 | /// Select the need for initialization: 7 | pub enum InitializeMode { 8 | /// Add an initialize 9 | #[strum_discriminants(strum(message = "with-init-call - Add an initialize"))] 10 | WithInitCall(super::super::call_function::FunctionCallAction), 11 | /// Don't add an initialize 12 | #[strum_discriminants(strum(message = "without-init-call - Don't add an initialize"))] 13 | WithoutInitCall(NoInitialize), 14 | } 15 | 16 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 17 | #[interactive_clap(context = super::super::super::super::ConstructTransactionContext)] 18 | pub struct NoInitialize { 19 | #[interactive_clap(subcommand)] 20 | next_action: super::super::super::super::add_action_3::NextAction, 21 | } 22 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/deploy_contract/mod.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::Context; 2 | 3 | pub mod initialize_mode; 4 | 5 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 6 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 7 | pub struct DeployContractAction { 8 | #[interactive_clap(named_arg)] 9 | /// Specify a path to wasm file 10 | use_file: ContractFile, 11 | } 12 | 13 | #[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)] 14 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 15 | #[interactive_clap(output_context = ContractFileContext)] 16 | pub struct ContractFile { 17 | /// What is the file location of the contract? 18 | pub file_path: crate::types::path_buf::PathBuf, 19 | #[interactive_clap(subcommand)] 20 | initialize: self::initialize_mode::InitializeMode, 21 | } 22 | 23 | #[derive(Debug, Clone)] 24 | pub struct ContractFileContext(super::super::super::ConstructTransactionContext); 25 | 26 | impl ContractFileContext { 27 | pub fn from_previous_context( 28 | previous_context: super::super::super::ConstructTransactionContext, 29 | scope: &::InteractiveClapContextScope, 30 | ) -> color_eyre::eyre::Result { 31 | let code = std::fs::read(&scope.file_path).wrap_err_with(|| { 32 | format!("Failed to open or read the file: {:?}.", &scope.file_path.0,) 33 | })?; 34 | let action = near_primitives::transaction::Action::DeployContract( 35 | near_primitives::transaction::DeployContractAction { code }, 36 | ); 37 | let mut actions = previous_context.actions; 38 | actions.push(action); 39 | Ok(Self(super::super::super::ConstructTransactionContext { 40 | global_context: previous_context.global_context, 41 | signer_account_id: previous_context.signer_account_id, 42 | receiver_account_id: previous_context.receiver_account_id, 43 | actions, 44 | })) 45 | } 46 | } 47 | 48 | impl From for super::super::super::ConstructTransactionContext { 49 | fn from(item: ContractFileContext) -> Self { 50 | item.0 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/stake/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = StakeActionContext)] 4 | pub struct StakeAction { 5 | /// Enter the amount to stake: (example: 10000NEAR) 6 | stake_amount: crate::types::near_token::NearToken, 7 | /// Enter the public key of the validator key pair used on your NEAR node (see validator_key.json): 8 | public_key: crate::types::public_key::PublicKey, 9 | #[interactive_clap(subcommand)] 10 | next_action: super::super::super::add_action_3::NextAction, 11 | } 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct StakeActionContext(super::super::super::ConstructTransactionContext); 15 | 16 | impl StakeActionContext { 17 | pub fn from_previous_context( 18 | previous_context: super::super::super::ConstructTransactionContext, 19 | scope: &::InteractiveClapContextScope, 20 | ) -> color_eyre::eyre::Result { 21 | let action = near_primitives::transaction::Action::Stake(Box::new( 22 | near_primitives::transaction::StakeAction { 23 | stake: scope.stake_amount.as_yoctonear(), 24 | public_key: scope.public_key.clone().into(), 25 | }, 26 | )); 27 | let mut actions = previous_context.actions; 28 | actions.push(action); 29 | Ok(Self(super::super::super::ConstructTransactionContext { 30 | global_context: previous_context.global_context, 31 | signer_account_id: previous_context.signer_account_id, 32 | receiver_account_id: previous_context.receiver_account_id, 33 | actions, 34 | })) 35 | } 36 | } 37 | 38 | impl From for super::super::super::ConstructTransactionContext { 39 | fn from(item: StakeActionContext) -> Self { 40 | item.0 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/add_action/transfer/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = TransferActionContext)] 4 | pub struct TransferAction { 5 | /// How many NEAR Tokens do you want to transfer? (example: 10NEAR or 0.5near or 10000yoctonear) 6 | amount_in_near: crate::types::near_token::NearToken, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::add_action_3::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct TransferActionContext(super::super::super::ConstructTransactionContext); 13 | 14 | impl TransferActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::super::super::ConstructTransactionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let action = near_primitives::transaction::Action::Transfer( 20 | near_primitives::transaction::TransferAction { 21 | deposit: scope.amount_in_near.as_yoctonear(), 22 | }, 23 | ); 24 | let mut actions = previous_context.actions; 25 | actions.push(action); 26 | Ok(Self(super::super::super::ConstructTransactionContext { 27 | global_context: previous_context.global_context, 28 | signer_account_id: previous_context.signer_account_id, 29 | receiver_account_id: previous_context.receiver_account_id, 30 | actions, 31 | })) 32 | } 33 | } 34 | 35 | impl From for super::super::super::ConstructTransactionContext { 36 | fn from(item: TransferActionContext) -> Self { 37 | item.0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_2/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::enum_variant_names, clippy::large_enum_variant)] 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | mod add_action; 5 | 6 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 7 | #[interactive_clap(context = super::ConstructTransactionContext)] 8 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 9 | /// Select an action that you want to add to the action: 10 | pub enum NextAction { 11 | #[strum_discriminants(strum(message = "add-action - Select a new action"))] 12 | /// Choose next action 13 | AddAction(self::add_action::AddAction), 14 | #[strum_discriminants(strum(message = "skip - Skip adding a new action"))] 15 | /// Go to transaction signing 16 | Skip(super::skip_action::SkipAction), 17 | } 18 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/add_key/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | mod access_key_type; 4 | mod use_manually_provided_seed_phrase; 5 | mod use_public_key; 6 | 7 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 9 | pub struct AddKeyAction { 10 | #[interactive_clap(subcommand)] 11 | permission: AccessKeyPermission, 12 | } 13 | 14 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 15 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 16 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 17 | /// Select a permission that you want to add to the access key: 18 | pub enum AccessKeyPermission { 19 | #[strum_discriminants(strum( 20 | message = "grant-full-access - A permission with full access" 21 | ))] 22 | /// Provide data for a full access key 23 | GrantFullAccess(self::access_key_type::FullAccessType), 24 | #[strum_discriminants(strum( 25 | message = "grant-function-call-access - A permission with function call" 26 | ))] 27 | /// Provide data for a function-call access key 28 | GrantFunctionCallAccess(self::access_key_type::FunctionCallType), 29 | } 30 | 31 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 32 | #[interactive_clap(context = self::access_key_type::AccessKeyPermissionContext)] 33 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 34 | /// Add an access key for this account: 35 | pub enum AccessKeyMode { 36 | #[strum_discriminants(strum( 37 | message = "use-manually-provided-seed-prase - Use the provided seed phrase manually" 38 | ))] 39 | /// Use the provided seed phrase manually 40 | UseManuallyProvidedSeedPhrase( 41 | self::use_manually_provided_seed_phrase::AddAccessWithSeedPhraseAction, 42 | ), 43 | #[strum_discriminants(strum( 44 | message = "use-manually-provided-public-key - Use the provided public key manually" 45 | ))] 46 | /// Use the provided public key manually 47 | UseManuallyProvidedPublicKey(self::use_public_key::AddAccessKeyAction), 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/add_key/use_manually_provided_seed_phrase/mod.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = super::access_key_type::AccessKeyPermissionContext)] 5 | #[interactive_clap(output_context = AddAccessWithSeedPhraseActionContext)] 6 | pub struct AddAccessWithSeedPhraseAction { 7 | /// Enter the seed_phrase: 8 | master_seed_phrase: String, 9 | #[interactive_clap(subcommand)] 10 | next_action: super::super::super::super::add_action_last::NextAction, 11 | } 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct AddAccessWithSeedPhraseActionContext( 15 | super::super::super::super::ConstructTransactionContext, 16 | ); 17 | 18 | impl AddAccessWithSeedPhraseActionContext { 19 | pub fn from_previous_context( 20 | previous_context: super::access_key_type::AccessKeyPermissionContext, 21 | scope: &::InteractiveClapContextScope, 22 | ) -> color_eyre::eyre::Result { 23 | let seed_phrase_hd_path_default = slipped10::BIP32Path::from_str("m/44'/397'/0'").unwrap(); 24 | let public_key = crate::common::get_public_key_from_seed_phrase( 25 | seed_phrase_hd_path_default, 26 | &scope.master_seed_phrase, 27 | )?; 28 | let access_key = near_primitives::account::AccessKey { 29 | nonce: 0, 30 | permission: previous_context.access_key_permission, 31 | }; 32 | let action = near_primitives::transaction::Action::AddKey(Box::new( 33 | near_primitives::transaction::AddKeyAction { 34 | public_key, 35 | access_key, 36 | }, 37 | )); 38 | let mut actions = previous_context.actions; 39 | actions.push(action); 40 | Ok(Self( 41 | super::super::super::super::ConstructTransactionContext { 42 | global_context: previous_context.global_context, 43 | signer_account_id: previous_context.signer_account_id, 44 | receiver_account_id: previous_context.receiver_account_id, 45 | actions, 46 | }, 47 | )) 48 | } 49 | } 50 | 51 | impl From 52 | for super::super::super::super::ConstructTransactionContext 53 | { 54 | fn from(item: AddAccessWithSeedPhraseActionContext) -> Self { 55 | item.0 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/add_key/use_public_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::access_key_type::AccessKeyPermissionContext)] 3 | #[interactive_clap(output_context = AddAccessKeyActionContext)] 4 | pub struct AddAccessKeyAction { 5 | /// Enter the public key: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::super::add_action_last::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct AddAccessKeyActionContext(super::super::super::super::ConstructTransactionContext); 13 | 14 | impl AddAccessKeyActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::access_key_type::AccessKeyPermissionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let access_key = near_primitives::account::AccessKey { 20 | nonce: 0, 21 | permission: previous_context.access_key_permission, 22 | }; 23 | let action = near_primitives::transaction::Action::AddKey(Box::new( 24 | near_primitives::transaction::AddKeyAction { 25 | public_key: scope.public_key.clone().into(), 26 | access_key, 27 | }, 28 | )); 29 | let mut actions = previous_context.actions; 30 | actions.push(action); 31 | Ok(Self( 32 | super::super::super::super::ConstructTransactionContext { 33 | global_context: previous_context.global_context, 34 | signer_account_id: previous_context.signer_account_id, 35 | receiver_account_id: previous_context.receiver_account_id, 36 | actions, 37 | }, 38 | )) 39 | } 40 | } 41 | 42 | impl From for super::super::super::super::ConstructTransactionContext { 43 | fn from(item: AddAccessKeyActionContext) -> Self { 44 | item.0 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/create_account/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = CreateAccountActionContext)] 4 | pub struct CreateAccountAction { 5 | #[interactive_clap(subcommand)] 6 | next_action: super::super::super::add_action_last::NextAction, 7 | } 8 | 9 | #[derive(Debug, Clone)] 10 | pub struct CreateAccountActionContext(super::super::super::ConstructTransactionContext); 11 | 12 | impl CreateAccountActionContext { 13 | pub fn from_previous_context( 14 | previous_context: super::super::super::ConstructTransactionContext, 15 | _scope: &::InteractiveClapContextScope, 16 | ) -> color_eyre::eyre::Result { 17 | let action = near_primitives::transaction::Action::CreateAccount( 18 | near_primitives::transaction::CreateAccountAction {}, 19 | ); 20 | let mut actions = previous_context.actions; 21 | actions.push(action); 22 | Ok(Self(super::super::super::ConstructTransactionContext { 23 | global_context: previous_context.global_context, 24 | signer_account_id: previous_context.signer_account_id, 25 | receiver_account_id: previous_context.receiver_account_id, 26 | actions, 27 | })) 28 | } 29 | } 30 | 31 | impl From for super::super::super::ConstructTransactionContext { 32 | fn from(item: CreateAccountActionContext) -> Self { 33 | item.0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/delete_key/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = DeleteKeyActionContext)] 4 | pub struct DeleteKeyAction { 5 | /// Enter the public key You wish to delete: 6 | public_key: crate::types::public_key::PublicKey, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::add_action_last::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct DeleteKeyActionContext(super::super::super::ConstructTransactionContext); 13 | 14 | impl DeleteKeyActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::super::super::ConstructTransactionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let action = near_primitives::transaction::Action::DeleteKey(Box::new( 20 | near_primitives::transaction::DeleteKeyAction { 21 | public_key: scope.public_key.clone().into(), 22 | }, 23 | )); 24 | let mut actions = previous_context.actions; 25 | actions.push(action); 26 | Ok(Self(super::super::super::ConstructTransactionContext { 27 | global_context: previous_context.global_context, 28 | signer_account_id: previous_context.signer_account_id, 29 | receiver_account_id: previous_context.receiver_account_id, 30 | actions, 31 | })) 32 | } 33 | } 34 | 35 | impl From for super::super::super::ConstructTransactionContext { 36 | fn from(item: DeleteKeyActionContext) -> Self { 37 | item.0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/deploy_contract/initialize_mode/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap_derive::InteractiveClap)] 4 | #[interactive_clap(context = super::super::super::super::ConstructTransactionContext)] 5 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 6 | /// Select the need for initialization: 7 | pub enum InitializeMode { 8 | /// Add an initialize 9 | #[strum_discriminants(strum(message = "with-init-call - Add an initialize"))] 10 | WithInitCall(super::super::call_function::FunctionCallAction), 11 | /// Don't add an initialize 12 | #[strum_discriminants(strum(message = "without-init-call - Don't add an initialize"))] 13 | WithoutInitCall(NoInitialize), 14 | } 15 | 16 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 17 | #[interactive_clap(context = super::super::super::super::ConstructTransactionContext)] 18 | pub struct NoInitialize { 19 | #[interactive_clap(subcommand)] 20 | next_action: super::super::super::super::add_action_last::NextAction, 21 | } 22 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/deploy_contract/mod.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::Context; 2 | 3 | pub mod initialize_mode; 4 | 5 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 6 | #[interactive_clap(context = super::super::super::ConstructTransactionContext)] 7 | pub struct DeployContractAction { 8 | #[interactive_clap(named_arg)] 9 | /// Specify a path to wasm file 10 | use_file: ContractFile, 11 | } 12 | 13 | #[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)] 14 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 15 | #[interactive_clap(output_context = ContractFileContext)] 16 | pub struct ContractFile { 17 | /// What is the file location of the contract? 18 | pub file_path: crate::types::path_buf::PathBuf, 19 | #[interactive_clap(subcommand)] 20 | initialize: self::initialize_mode::InitializeMode, 21 | } 22 | 23 | #[derive(Debug, Clone)] 24 | pub struct ContractFileContext(super::super::super::ConstructTransactionContext); 25 | 26 | impl ContractFileContext { 27 | pub fn from_previous_context( 28 | previous_context: super::super::super::ConstructTransactionContext, 29 | scope: &::InteractiveClapContextScope, 30 | ) -> color_eyre::eyre::Result { 31 | let code = std::fs::read(&scope.file_path).wrap_err_with(|| { 32 | format!("Failed to open or read the file: {:?}.", &scope.file_path.0,) 33 | })?; 34 | let action = near_primitives::transaction::Action::DeployContract( 35 | near_primitives::transaction::DeployContractAction { code }, 36 | ); 37 | let mut actions = previous_context.actions; 38 | actions.push(action); 39 | Ok(Self(super::super::super::ConstructTransactionContext { 40 | global_context: previous_context.global_context, 41 | signer_account_id: previous_context.signer_account_id, 42 | receiver_account_id: previous_context.receiver_account_id, 43 | actions, 44 | })) 45 | } 46 | } 47 | 48 | impl From for super::super::super::ConstructTransactionContext { 49 | fn from(item: ContractFileContext) -> Self { 50 | item.0 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/stake/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = StakeActionContext)] 4 | pub struct StakeAction { 5 | /// Enter the amount to stake: (example: 10000NEAR) 6 | stake_amount: crate::types::near_token::NearToken, 7 | /// Enter the public key of the validator key pair used on your NEAR node (see validator_key.json): 8 | public_key: crate::types::public_key::PublicKey, 9 | #[interactive_clap(subcommand)] 10 | next_action: super::super::super::add_action_last::NextAction, 11 | } 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct StakeActionContext(super::super::super::ConstructTransactionContext); 15 | 16 | impl StakeActionContext { 17 | pub fn from_previous_context( 18 | previous_context: super::super::super::ConstructTransactionContext, 19 | scope: &::InteractiveClapContextScope, 20 | ) -> color_eyre::eyre::Result { 21 | let action = near_primitives::transaction::Action::Stake(Box::new( 22 | near_primitives::transaction::StakeAction { 23 | stake: scope.stake_amount.as_yoctonear(), 24 | public_key: scope.public_key.clone().into(), 25 | }, 26 | )); 27 | let mut actions = previous_context.actions; 28 | actions.push(action); 29 | Ok(Self(super::super::super::ConstructTransactionContext { 30 | global_context: previous_context.global_context, 31 | signer_account_id: previous_context.signer_account_id, 32 | receiver_account_id: previous_context.receiver_account_id, 33 | actions, 34 | })) 35 | } 36 | } 37 | 38 | impl From for super::super::super::ConstructTransactionContext { 39 | fn from(item: StakeActionContext) -> Self { 40 | item.0 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/add_action/transfer/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::super::super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = TransferActionContext)] 4 | pub struct TransferAction { 5 | /// How many NEAR Tokens do you want to transfer? (example: 10NEAR or 0.5near or 10000yoctonear) 6 | amount_in_near: crate::types::near_token::NearToken, 7 | #[interactive_clap(subcommand)] 8 | next_action: super::super::super::add_action_last::NextAction, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct TransferActionContext(super::super::super::ConstructTransactionContext); 13 | 14 | impl TransferActionContext { 15 | pub fn from_previous_context( 16 | previous_context: super::super::super::ConstructTransactionContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let action = near_primitives::transaction::Action::Transfer( 20 | near_primitives::transaction::TransferAction { 21 | deposit: scope.amount_in_near.as_yoctonear(), 22 | }, 23 | ); 24 | let mut actions = previous_context.actions; 25 | actions.push(action); 26 | Ok(Self(super::super::super::ConstructTransactionContext { 27 | global_context: previous_context.global_context, 28 | signer_account_id: previous_context.signer_account_id, 29 | receiver_account_id: previous_context.receiver_account_id, 30 | actions, 31 | })) 32 | } 33 | } 34 | 35 | impl From for super::super::super::ConstructTransactionContext { 36 | fn from(item: TransferActionContext) -> Self { 37 | item.0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_3/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | mod add_action; 4 | 5 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 6 | #[interactive_clap(context = super::ConstructTransactionContext)] 7 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 8 | /// Select an action that you want to add to the action: 9 | pub enum NextAction { 10 | #[strum_discriminants(strum(message = "add-action - Select a new action"))] 11 | /// Choose next action 12 | AddAction(self::add_action::AddAction), 13 | #[strum_discriminants(strum(message = "skip - Skip adding a new action"))] 14 | /// Go to transaction signing 15 | Skip(super::skip_action::SkipAction), 16 | } 17 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/add_action_last/mod.rs: -------------------------------------------------------------------------------- 1 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 2 | 3 | #[derive(Debug, Clone, EnumDiscriminants, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(context = super::ConstructTransactionContext)] 5 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 6 | /// Select an action that you want to add to the action: 7 | pub enum NextAction { 8 | #[strum_discriminants(strum(message = "skip - Skip adding a new action"))] 9 | /// Go to transaction signing 10 | Skip(super::skip_action::SkipAction), 11 | } 12 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod add_action_1; 2 | pub mod add_action_2; 3 | pub mod add_action_3; 4 | pub mod add_action_last; 5 | pub mod skip_action; 6 | 7 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(input_context = crate::GlobalContext)] 9 | #[interactive_clap(output_context = ConstructTransactionContext)] 10 | pub struct ConstructTransaction { 11 | #[interactive_clap(skip_default_input_arg)] 12 | /// What is the sender account ID? 13 | pub sender_account_id: crate::types::account_id::AccountId, 14 | #[interactive_clap(skip_default_input_arg)] 15 | /// What is the receiver account ID? 16 | pub receiver_account_id: crate::types::account_id::AccountId, 17 | #[interactive_clap(subcommand)] 18 | pub next_actions: self::add_action_1::NextAction, 19 | } 20 | 21 | #[derive(Debug, Clone)] 22 | pub struct ConstructTransactionContext { 23 | pub global_context: crate::GlobalContext, 24 | pub signer_account_id: near_primitives::types::AccountId, 25 | pub receiver_account_id: near_primitives::types::AccountId, 26 | pub actions: Vec, 27 | } 28 | 29 | impl ConstructTransactionContext { 30 | pub fn from_previous_context( 31 | previous_context: crate::GlobalContext, 32 | scope: &::InteractiveClapContextScope, 33 | ) -> color_eyre::eyre::Result { 34 | Ok(Self { 35 | global_context: previous_context, 36 | signer_account_id: scope.sender_account_id.clone().into(), 37 | receiver_account_id: scope.receiver_account_id.clone().into(), 38 | actions: vec![], 39 | }) 40 | } 41 | } 42 | 43 | impl ConstructTransaction { 44 | pub fn input_sender_account_id( 45 | context: &crate::GlobalContext, 46 | ) -> color_eyre::eyre::Result> { 47 | crate::common::input_signer_account_id_from_used_account_list( 48 | &context.config.credentials_home_dir, 49 | "What is the sender account ID?", 50 | ) 51 | } 52 | 53 | pub fn input_receiver_account_id( 54 | context: &crate::GlobalContext, 55 | ) -> color_eyre::eyre::Result> { 56 | crate::common::input_non_signer_account_id_from_used_account_list( 57 | &context.config.credentials_home_dir, 58 | "What is the receiver account ID?", 59 | ) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/commands/transaction/construct_transaction/skip_action/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = super::ConstructTransactionContext)] 3 | #[interactive_clap(output_context = SkipActionContext)] 4 | pub struct SkipAction { 5 | #[interactive_clap(named_arg)] 6 | /// Select network 7 | pub network_config: crate::network_for_transaction::NetworkForTransactionArgs, 8 | } 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct SkipActionContext(super::ConstructTransactionContext); 12 | 13 | impl SkipActionContext { 14 | pub fn from_previous_context( 15 | previous_context: super::ConstructTransactionContext, 16 | _scope: &::InteractiveClapContextScope, 17 | ) -> color_eyre::eyre::Result { 18 | Ok(Self(previous_context)) 19 | } 20 | } 21 | 22 | impl From for crate::commands::ActionContext { 23 | fn from(item: SkipActionContext) -> Self { 24 | let get_prepopulated_transaction_after_getting_network_callback: crate::commands::GetPrepopulatedTransactionAfterGettingNetworkCallback = 25 | std::sync::Arc::new({ 26 | let signer_account_id = item.0.signer_account_id.clone(); 27 | let receiver_account_id = item.0.receiver_account_id.clone(); 28 | 29 | move |_network_config| { 30 | Ok(crate::commands::PrepopulatedTransaction { 31 | signer_id: signer_account_id.clone(), 32 | receiver_id: receiver_account_id.clone(), 33 | actions: item.0.actions.clone(), 34 | }) 35 | } 36 | }); 37 | 38 | Self { 39 | global_context: item.0.global_context, 40 | interacting_with_account_ids: vec![ 41 | item.0.signer_account_id, 42 | item.0.receiver_account_id, 43 | ], 44 | get_prepopulated_transaction_after_getting_network_callback, 45 | on_before_signing_callback: std::sync::Arc::new( 46 | |_prepolulated_unsinged_transaction, _network_config| Ok(()), 47 | ), 48 | on_before_sending_transaction_callback: std::sync::Arc::new( 49 | |_signed_transaction, _network_config| Ok(String::new()), 50 | ), 51 | on_after_sending_transaction_callback: std::sync::Arc::new( 52 | |_outcome_view, _network_config| Ok(()), 53 | ), 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/commands/transaction/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::enum_variant_names, clippy::large_enum_variant)] 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | pub mod construct_transaction; 5 | mod print_transaction; 6 | mod reconstruct_transaction; 7 | pub mod send_meta_transaction; 8 | pub mod send_signed_transaction; 9 | pub mod sign_transaction; 10 | mod view_status; 11 | 12 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 13 | #[interactive_clap(context = crate::GlobalContext)] 14 | pub struct TransactionCommands { 15 | #[interactive_clap(subcommand)] 16 | transaction_actions: TransactionActions, 17 | } 18 | 19 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 20 | #[interactive_clap(context = crate::GlobalContext)] 21 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 22 | #[non_exhaustive] 23 | /// Сhoose action for transaction: 24 | pub enum TransactionActions { 25 | #[strum_discriminants(strum( 26 | message = "view-status - View a transaction status" 27 | ))] 28 | /// Execute function (contract method) 29 | ViewStatus(self::view_status::TransactionInfo), 30 | #[strum_discriminants(strum( 31 | message = "reconstruct-transaction - Use any existing transaction from the chain to construct NEAR CLI command (helpful tool for re-submitting similar transactions)" 32 | ))] 33 | /// Use any existing transaction from the chain to construct NEAR CLI command (helpful tool for re-submitting similar transactions) 34 | ReconstructTransaction(self::reconstruct_transaction::TransactionInfo), 35 | #[strum_discriminants(strum( 36 | message = "construct-transaction - Construct a new transaction" 37 | ))] 38 | /// Construct a new transaction 39 | ConstructTransaction(self::construct_transaction::ConstructTransaction), 40 | #[strum_discriminants(strum( 41 | message = "sign-transaction - Sign previously prepared unsigned transaction" 42 | ))] 43 | /// Sign previously prepared unsigned transaction 44 | SignTransaction(self::sign_transaction::SignTransaction), 45 | #[strum_discriminants(strum( 46 | message = "print-transaction - Print all fields of previously prepared transaction without modification" 47 | ))] 48 | /// Print previously prepared unsigned transaction without modification 49 | PrintTransaction(self::print_transaction::PrintTransactionCommands), 50 | #[strum_discriminants(strum( 51 | message = "send-signed-transaction - Send a signed transaction" 52 | ))] 53 | /// Send a signed transaction 54 | SendSignedTransaction(self::send_signed_transaction::SignedTransaction), 55 | #[strum_discriminants(strum( 56 | message = "send-meta-transaction - Act as a relayer to send a signed delegate action (meta-transaction)" 57 | ))] 58 | /// Act as a relayer to send a signed delegate action (meta-transaction) 59 | SendMetaTransaction(self::send_meta_transaction::SignedMetaTransaction), 60 | } 61 | -------------------------------------------------------------------------------- /src/commands/transaction/print_transaction/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::enum_variant_names, clippy::large_enum_variant)] 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | mod signed; 5 | mod unsigned; 6 | 7 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(context = crate::GlobalContext)] 9 | pub struct PrintTransactionCommands { 10 | #[interactive_clap(subcommand)] 11 | show_transaction_actions: PrintTransactionActions, 12 | } 13 | 14 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 15 | #[interactive_clap(context = crate::GlobalContext)] 16 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 17 | /// Select signed or unsigned transaction to print: 18 | pub enum PrintTransactionActions { 19 | #[strum_discriminants(strum( 20 | message = "unsigned - Print all fields of previously prepared unsigned transaction without modification" 21 | ))] 22 | /// Print previously prepared unsigned transaction without modification 23 | Unsigned(self::unsigned::PrintTransaction), 24 | #[strum_discriminants(strum( 25 | message = "signed - Print all fields of previously prepared signed transaction without modification" 26 | ))] 27 | /// Send a signed transaction 28 | Signed(self::signed::PrintTransaction), 29 | } 30 | -------------------------------------------------------------------------------- /src/commands/transaction/print_transaction/signed/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = PrintContext)] 4 | pub struct PrintTransaction { 5 | /// Enter the signed transaction encoded in base64: 6 | signed_transaction: crate::types::signed_transaction::SignedTransactionAsBase64, 7 | } 8 | 9 | #[derive(Debug, Clone)] 10 | pub struct PrintContext; 11 | 12 | impl PrintContext { 13 | pub fn from_previous_context( 14 | previous_context: crate::GlobalContext, 15 | scope: &::InteractiveClapContextScope, 16 | ) -> color_eyre::eyre::Result { 17 | let signed_transaction: near_primitives::transaction::SignedTransaction = 18 | scope.signed_transaction.clone().into(); 19 | let info_str = crate::common::print_full_signed_transaction(signed_transaction); 20 | if let crate::Verbosity::Quiet = previous_context.verbosity { 21 | println!("Signed transaction (full):{}", info_str) 22 | }; 23 | tracing::info!( 24 | parent: &tracing::Span::none(), 25 | "Signed transaction (full):{}", 26 | crate::common::indent_payload(&info_str) 27 | ); 28 | Ok(Self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/commands/transaction/print_transaction/unsigned/mod.rs: -------------------------------------------------------------------------------- 1 | use near_primitives::transaction::Transaction; 2 | 3 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 4 | #[interactive_clap(input_context = crate::GlobalContext)] 5 | #[interactive_clap(output_context = PrintContext)] 6 | pub struct PrintTransaction { 7 | /// Enter the unsigned transaction encoded in base64: 8 | unsigned_transaction: crate::types::transaction::TransactionAsBase64, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct PrintContext; 13 | 14 | impl PrintContext { 15 | pub fn from_previous_context( 16 | previous_context: crate::GlobalContext, 17 | scope: &::InteractiveClapContextScope, 18 | ) -> color_eyre::eyre::Result { 19 | let unsigned_transaction: near_primitives::transaction::TransactionV0 = 20 | scope.unsigned_transaction.clone().into(); 21 | let info_str = 22 | crate::common::print_full_unsigned_transaction(Transaction::V0(unsigned_transaction)); 23 | 24 | if let crate::Verbosity::Quiet = previous_context.verbosity { 25 | println!("Unsigned transaction (full):{}", info_str); 26 | } 27 | tracing::info!( 28 | parent: &tracing::Span::none(), 29 | "Unsigned transaction (full):{}", 30 | crate::common::indent_payload(&info_str) 31 | ); 32 | 33 | Ok(Self) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/commands/transaction/sign_transaction/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = crate::GlobalContext)] 3 | #[interactive_clap(output_context = SignTransactionContext)] 4 | pub struct SignTransaction { 5 | /// Enter the transaction encoded in base64: 6 | unsigned_transaction: crate::types::transaction::TransactionAsBase64, 7 | #[interactive_clap(named_arg)] 8 | /// Select network 9 | network_config: crate::network_for_transaction::NetworkForTransactionArgs, 10 | } 11 | 12 | #[derive(Clone)] 13 | pub struct SignTransactionContext(crate::commands::ActionContext); 14 | 15 | impl SignTransactionContext { 16 | pub fn from_previous_context( 17 | previous_context: crate::GlobalContext, 18 | scope: &::InteractiveClapContextScope, 19 | ) -> color_eyre::eyre::Result { 20 | let get_prepopulated_transaction_after_getting_network_callback: crate::commands::GetPrepopulatedTransactionAfterGettingNetworkCallback = 21 | std::sync::Arc::new({ 22 | let unsigned_transaction: near_primitives::transaction::TransactionV0 = 23 | scope.unsigned_transaction.clone().into(); 24 | 25 | move |_network_config| { 26 | Ok(crate::commands::PrepopulatedTransaction::from( 27 | unsigned_transaction.clone(), 28 | )) 29 | } 30 | }); 31 | 32 | Ok(Self(crate::commands::ActionContext { 33 | global_context: previous_context, 34 | interacting_with_account_ids: vec![ 35 | scope.unsigned_transaction.inner.signer_id.clone(), 36 | scope.unsigned_transaction.inner.receiver_id.clone(), 37 | ], 38 | get_prepopulated_transaction_after_getting_network_callback, 39 | on_before_signing_callback: std::sync::Arc::new( 40 | |_prepolulated_unsinged_transaction, _network_config| Ok(()), 41 | ), 42 | on_before_sending_transaction_callback: std::sync::Arc::new( 43 | |_signed_transaction, _network_config| Ok(String::new()), 44 | ), 45 | on_after_sending_transaction_callback: std::sync::Arc::new( 46 | |_outcome_view, _network_config| Ok(()), 47 | ), 48 | })) 49 | } 50 | } 51 | 52 | impl From for crate::commands::ActionContext { 53 | fn from(item: SignTransactionContext) -> Self { 54 | item.0 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/js_command_match/account/login.rs: -------------------------------------------------------------------------------- 1 | use crate::js_command_match::constants::NETWORK_ID_ALIASES; 2 | 3 | #[derive(Debug, Clone, clap::Parser)] 4 | /// This is a legacy `legacy` command. Once you run it with the specified arguments, new syntax command will be suggested. 5 | pub struct LoginArgs { 6 | #[clap(long, aliases = NETWORK_ID_ALIASES)] 7 | network_id: Option, 8 | } 9 | 10 | impl LoginArgs { 11 | pub fn to_cli_args(&self, network_config: String) -> Vec { 12 | let network_id = self.network_id.clone().unwrap_or(network_config); 13 | 14 | let command = vec![ 15 | "account".to_string(), 16 | "import-account".to_string(), 17 | "using-web-wallet".to_string(), 18 | "network-config".to_string(), 19 | network_id, 20 | ]; 21 | 22 | command 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use super::super::super::JsCmd; 29 | use super::*; 30 | use clap::Parser; 31 | 32 | #[test] 33 | fn login() { 34 | for (input, expected_output) in [ 35 | ( 36 | "near import-account".to_string(), 37 | "account import-account using-web-wallet network-config testnet".to_string(), 38 | ), 39 | ( 40 | "near login".to_string(), 41 | "account import-account using-web-wallet network-config testnet".to_string(), 42 | ), 43 | ( 44 | format!("near login --{} testnet", NETWORK_ID_ALIASES[0]), 45 | "account import-account using-web-wallet network-config testnet".to_string(), 46 | ), 47 | ( 48 | format!("near login --{} mainnet", NETWORK_ID_ALIASES[1]), 49 | "account import-account using-web-wallet network-config mainnet".to_string(), 50 | ), 51 | ] { 52 | let input_cmd = 53 | shell_words::split(&input).expect("Input command must be a valid shell command"); 54 | let JsCmd::Login(login_args) = JsCmd::parse_from(&input_cmd) else { 55 | panic!( 56 | "Login command was expected, but something else was parsed out from {input}" 57 | ); 58 | }; 59 | assert_eq!( 60 | shell_words::join(LoginArgs::to_cli_args(&login_args, "testnet".to_string())), 61 | expected_output 62 | ); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/js_command_match/account/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod create; 2 | pub mod delete; 3 | pub mod login; 4 | pub mod state; 5 | -------------------------------------------------------------------------------- /src/js_command_match/account/state.rs: -------------------------------------------------------------------------------- 1 | use crate::js_command_match::constants::NETWORK_ID_ALIASES; 2 | 3 | #[derive(Debug, Clone, clap::Parser)] 4 | pub struct StateArgs { 5 | account_id: String, 6 | #[clap(long, aliases = NETWORK_ID_ALIASES)] 7 | network_id: Option, 8 | } 9 | 10 | impl StateArgs { 11 | pub fn to_cli_args(&self, network_config: String) -> Vec { 12 | let network_id = self.network_id.clone().unwrap_or(network_config); 13 | 14 | let command = vec![ 15 | "account".to_string(), 16 | "view-account-summary".to_string(), 17 | self.account_id.to_owned(), 18 | "network-config".to_string(), 19 | network_id, 20 | "now".to_string(), 21 | ]; 22 | 23 | command 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::super::super::JsCmd; 30 | use super::*; 31 | use clap::Parser; 32 | 33 | #[test] 34 | fn state() { 35 | for (input, expected_output) in [ 36 | ( 37 | "near state contract.testnet".to_string(), 38 | "account view-account-summary contract.testnet network-config testnet now" 39 | .to_string(), 40 | ), 41 | ( 42 | format!( 43 | "near state contract.testnet --{} testnet", 44 | NETWORK_ID_ALIASES[0] 45 | ), 46 | "account view-account-summary contract.testnet network-config testnet now" 47 | .to_string(), 48 | ), 49 | ( 50 | format!( 51 | "near state contract.testnet --{} mainnet", 52 | NETWORK_ID_ALIASES[1] 53 | ), 54 | "account view-account-summary contract.testnet network-config mainnet now" 55 | .to_string(), 56 | ), 57 | ] { 58 | let input_cmd = 59 | shell_words::split(&input).expect("Input command must be a valid shell command"); 60 | let JsCmd::State(state_args) = JsCmd::parse_from(&input_cmd) else { 61 | panic!( 62 | "State command was expected, but something else was parsed out from {input}" 63 | ); 64 | }; 65 | assert_eq!( 66 | shell_words::join(StateArgs::to_cli_args(&state_args, "testnet".to_string())), 67 | expected_output 68 | ); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/js_command_match/constants.rs: -------------------------------------------------------------------------------- 1 | // Accounts 2 | pub const USE_ACCOUNT_ALIASES: [&str; 6] = [ 3 | "masterAccount", 4 | "master-account", 5 | "useAccount", 6 | "use-account", 7 | "accountId", 8 | "account-id", 9 | ]; 10 | 11 | // Contracts 12 | pub const CONTRACT_ID_ALIASES: [&str; 2] = ["contractId", "contract-id"]; 13 | pub const METHOD_NAMES_ALIASES: [&str; 2] = ["methodNames", "method-names"]; 14 | 15 | // Keys 16 | pub const PUBLIC_KEY_ALIASES: [&str; 2] = ["publicKey", "public-key"]; 17 | pub const SEED_PHRASE_ALIASES: [&str; 2] = ["seedPhrase", "seed-phrase"]; 18 | 19 | // Ledger 20 | pub const LEDGER_PATH_ALIASES: [&str; 2] = ["ledgerPath", "ledger-path"]; 21 | pub const DEFAULT_SEED_PHRASE_PATH: &str = "44'/397'/0'/0'/1'"; 22 | pub const SIGN_WITH_LEDGER_ALIASES: [&str; 4] = [ 23 | "signWithLedger", 24 | "sign-with-ledger", 25 | "useLedgerKey", 26 | "use-ledger-key", 27 | ]; 28 | pub const USE_LEDGER_PK_ALIASES: [&str; 4] = [ 29 | "useLedgerPK", 30 | "use-ledger-pk", 31 | "newLedgerKey", 32 | "new-ledger-key", 33 | ]; 34 | pub const PK_LEDGER_PATH_ALIASES: [&str; 2] = ["pkLedgerPath", "pk-ledger-path"]; 35 | 36 | // Balance and faucet 37 | pub const INITIAL_BALANCE_ALIASES: [&str; 2] = ["initialBalance", "initial-balance"]; 38 | pub const USE_FAUCET_ALIASES: [&str; 2] = ["useFaucet", "use-faucet"]; 39 | 40 | // SETTINGS 41 | pub const NETWORK_ID_ALIASES: [&str; 2] = ["networkId", "network-id"]; 42 | pub const BLOCK_ID_ALIASES: [&str; 2] = ["blockId", "block-id"]; 43 | 44 | // Deploy 45 | pub const WASM_FILE_ALIASES: [&str; 2] = ["wasmFile", "wasm-file"]; 46 | pub const INIT_FUNCTION_ALIASES: [&str; 2] = ["initFunction", "init-function"]; 47 | pub const INIT_ARGS_ALIASES: [&str; 2] = ["initArgs", "init-args"]; 48 | pub const INIT_GAS_ALIASES: [&str; 2] = ["initGas", "init-gas"]; 49 | pub const INIT_DEPOSIT_ALIASES: [&str; 2] = ["initDeposit", "init-deposit"]; 50 | -------------------------------------------------------------------------------- /src/js_command_match/contract/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod call; 2 | pub mod deploy; 3 | pub mod storage; 4 | pub mod view; 5 | -------------------------------------------------------------------------------- /src/js_command_match/contract/view.rs: -------------------------------------------------------------------------------- 1 | use crate::js_command_match::constants::NETWORK_ID_ALIASES; 2 | 3 | #[derive(Debug, Clone, clap::Parser)] 4 | /// This is a legacy `view` command. Once you run it with the specified arguments, new syntax command will be suggested. 5 | pub struct ViewArgs { 6 | contract_name: String, 7 | method_name: String, 8 | #[clap(default_value = "{}")] 9 | args: String, 10 | #[clap(long, aliases = NETWORK_ID_ALIASES)] 11 | network_id: Option, 12 | } 13 | 14 | impl ViewArgs { 15 | pub fn to_cli_args(&self, network_config: String) -> Vec { 16 | let network_id = self.network_id.clone().unwrap_or(network_config); 17 | 18 | let command = vec![ 19 | "contract".to_string(), 20 | "call-function".to_string(), 21 | "as-read-only".to_string(), 22 | self.contract_name.to_owned(), 23 | self.method_name.to_owned(), 24 | "json-args".to_string(), 25 | self.args.to_owned(), 26 | "network-config".to_string(), 27 | network_id, 28 | "now".to_string(), 29 | ]; 30 | 31 | command 32 | } 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::super::super::JsCmd; 38 | use super::*; 39 | use clap::Parser; 40 | 41 | #[test] 42 | fn view() { 43 | let args = "{\"account_id\": \"bob.testnet\"}"; 44 | 45 | for (input, expected_output) in [ 46 | ( 47 | format!("near view counter.near-examples.testnet get '{args}'"), 48 | format!("contract call-function as-read-only counter.near-examples.testnet get json-args '{args}' network-config testnet now") 49 | ), 50 | ( 51 | format!("near view counter.near-examples.testnet get '{args}' --{} testnet", NETWORK_ID_ALIASES[0]), 52 | format!("contract call-function as-read-only counter.near-examples.testnet get json-args '{args}' network-config testnet now") 53 | ), 54 | ( 55 | format!("near view counter.near-examples.testnet get '{args}' --{} mainnet", NETWORK_ID_ALIASES[1]), 56 | format!("contract call-function as-read-only counter.near-examples.testnet get json-args '{args}' network-config mainnet now") 57 | ), 58 | ] { 59 | let input_cmd = shell_words::split(&input).expect("Input command must be a valid shell command"); 60 | let JsCmd::View(view_args) = JsCmd::parse_from(&input_cmd) else { 61 | panic!("View command was expected, but something else was parsed out from {input}"); 62 | }; 63 | assert_eq!( 64 | shell_words::join(ViewArgs::to_cli_args(&view_args, "testnet".to_string())), 65 | expected_output 66 | ); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/js_command_match/deprecated.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::owo_colors::OwoColorize; 2 | 3 | #[derive(Debug, Clone, clap::Parser)] 4 | /// This is a legacy `validators` command. Once you run it with the specified arguments, new syntax command will be suggested. 5 | pub struct ValidatorsArgs { 6 | #[clap(allow_hyphen_values = true, num_args = 0..)] 7 | _unknown_args: Vec, 8 | } 9 | 10 | #[derive(Debug, Clone, clap::Parser)] 11 | pub struct StakeArgs { 12 | #[clap(allow_hyphen_values = true, num_args = 0..)] 13 | _unknown_args: Vec, 14 | } 15 | 16 | const DEPRECATED: &str = "The command you tried to run has been moved into its own CLI extension called near-validator.\nPlease, follow the installation instructions here: https://github.com/near-cli-rs/near-validator-cli-rs/blob/master/README.md"; 17 | 18 | impl ValidatorsArgs { 19 | pub fn to_cli_args(&self, _network_config: String) -> Vec { 20 | eprintln!("\n{}\n", DEPRECATED.to_string().yellow()); 21 | vec!["near-validator".to_string()] 22 | } 23 | } 24 | 25 | impl StakeArgs { 26 | pub fn to_cli_args(&self, _network_config: String) -> Vec { 27 | eprintln!("\n{}\n", DEPRECATED.to_string().yellow()); 28 | vec!["near-validator".to_string()] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/js_command_match/keys/list.rs: -------------------------------------------------------------------------------- 1 | use crate::js_command_match::constants::NETWORK_ID_ALIASES; 2 | 3 | #[derive(Debug, Clone, clap::Parser)] 4 | /// This is a legacy `keys` command. Once you run it with the specified arguments, new syntax command will be suggested. 5 | pub struct KeysArgs { 6 | account_id: String, 7 | #[clap(long, aliases = NETWORK_ID_ALIASES)] 8 | network_id: Option, 9 | } 10 | 11 | impl KeysArgs { 12 | pub fn to_cli_args(&self, network_config: String) -> Vec { 13 | let network_id = self.network_id.clone().unwrap_or(network_config); 14 | 15 | let command = vec![ 16 | "account".to_string(), 17 | "list-keys".to_string(), 18 | self.account_id.to_owned(), 19 | "network-config".to_string(), 20 | network_id, 21 | "now".to_string(), 22 | ]; 23 | 24 | command 25 | } 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::super::super::JsCmd; 31 | use super::*; 32 | use clap::Parser; 33 | 34 | #[test] 35 | fn list_keys() { 36 | for (input, expected_output) in [ 37 | ( 38 | "near keys bob.testnet".to_string(), 39 | "account list-keys bob.testnet network-config testnet now".to_string(), 40 | ), 41 | ( 42 | "near list-keys bob.testnet".to_string(), 43 | "account list-keys bob.testnet network-config testnet now".to_string(), 44 | ), 45 | ( 46 | format!( 47 | "near list-keys bob.testnet --{} testnet", 48 | NETWORK_ID_ALIASES[0] 49 | ), 50 | "account list-keys bob.testnet network-config testnet now".to_string(), 51 | ), 52 | ( 53 | format!( 54 | "near list-keys bob.testnet --{} mainnet", 55 | NETWORK_ID_ALIASES[1] 56 | ), 57 | "account list-keys bob.testnet network-config mainnet now".to_string(), 58 | ), 59 | ] { 60 | let input_cmd = 61 | shell_words::split(&input).expect("Input command must be a valid shell command"); 62 | let JsCmd::ListKeys(keys_args) = JsCmd::parse_from(&input_cmd) else { 63 | panic!( 64 | "ListKeys command was expected, but something else was parsed out from {input}" 65 | ); 66 | }; 67 | assert_eq!( 68 | shell_words::join(KeysArgs::to_cli_args(&keys_args, "testnet".to_string())), 69 | expected_output 70 | ); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/js_command_match/keys/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod add; 2 | pub mod delete; 3 | pub mod list; 4 | -------------------------------------------------------------------------------- /src/js_command_match/mod.rs: -------------------------------------------------------------------------------- 1 | mod constants; 2 | 3 | mod account; 4 | mod contract; 5 | mod deprecated; 6 | mod keys; 7 | mod transactions; 8 | 9 | #[derive(Debug, Clone, clap::Parser)] 10 | /// Legacy CLI commands are only supported at best-effort 11 | pub enum JsCmd { 12 | #[clap(alias("create"))] 13 | CreateAccount(self::account::create::CreateAccountArgs), 14 | #[clap(alias("delete"))] 15 | DeleteAccount(self::account::delete::DeleteAccountArgs), 16 | #[clap(alias("import-account"))] 17 | Login(self::account::login::LoginArgs), 18 | State(self::account::state::StateArgs), 19 | 20 | Call(self::contract::call::CallArgs), 21 | Deploy(self::contract::deploy::DeployArgs), 22 | #[clap(alias("storage"))] 23 | ViewState(self::contract::storage::ViewStateArgs), 24 | View(self::contract::view::ViewArgs), 25 | 26 | AddKey(self::keys::add::AddKeyArgs), 27 | DeleteKey(self::keys::delete::DeleteKeyArgs), 28 | #[clap(alias("keys"))] 29 | ListKeys(self::keys::list::KeysArgs), 30 | 31 | #[clap(alias("send-near"))] 32 | Send(self::transactions::send::SendArgs), 33 | TxStatus(self::transactions::status::TxStatusArgs), 34 | 35 | Validators(self::deprecated::ValidatorsArgs), 36 | #[clap(alias("validator-stake"))] 37 | Stake(self::deprecated::StakeArgs), 38 | } 39 | 40 | impl JsCmd { 41 | pub fn rust_command_generation(&self) -> Vec { 42 | let network = std::env::var("NEAR_NETWORK") 43 | .or_else(|_| std::env::var("NEAR_ENV")) 44 | .unwrap_or_else(|_| "testnet".to_owned()); 45 | 46 | match self { 47 | Self::CreateAccount(args) => args.to_cli_args(network), 48 | Self::DeleteAccount(args) => args.to_cli_args(network), 49 | Self::Login(args) => args.to_cli_args(network), 50 | Self::State(args) => args.to_cli_args(network), 51 | 52 | Self::Call(args) => args.to_cli_args(network), 53 | Self::Deploy(args) => args.to_cli_args(network), 54 | Self::ViewState(args) => args.to_cli_args(network), 55 | Self::View(args) => args.to_cli_args(network), 56 | 57 | Self::AddKey(args) => args.to_cli_args(network), 58 | Self::DeleteKey(args) => args.to_cli_args(network), 59 | Self::ListKeys(args) => args.to_cli_args(network), 60 | 61 | Self::Send(args) => args.to_cli_args(network), 62 | Self::TxStatus(args) => args.to_cli_args(network), 63 | 64 | Self::Validators(args) => args.to_cli_args(network), 65 | Self::Stake(args) => args.to_cli_args(network), 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/js_command_match/transactions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod send; 2 | pub mod status; 3 | -------------------------------------------------------------------------------- /src/js_command_match/transactions/status.rs: -------------------------------------------------------------------------------- 1 | use crate::js_command_match::constants::NETWORK_ID_ALIASES; 2 | 3 | #[derive(Debug, Clone, clap::Parser)] 4 | pub struct TxStatusArgs { 5 | hash: String, 6 | #[clap(long, aliases = NETWORK_ID_ALIASES)] 7 | network_id: Option, 8 | #[clap(allow_hyphen_values = true, num_args = 0..)] 9 | _unknown_args: Vec, 10 | } 11 | 12 | impl TxStatusArgs { 13 | pub fn to_cli_args(&self, network_config: String) -> Vec { 14 | let network_id = self.network_id.clone().unwrap_or(network_config); 15 | 16 | let command = vec![ 17 | "transaction".to_string(), 18 | "view-status".to_string(), 19 | self.hash.to_owned(), 20 | "network-config".to_string(), 21 | network_id, 22 | ]; 23 | 24 | command 25 | } 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::super::super::JsCmd; 31 | use super::*; 32 | use clap::Parser; 33 | 34 | #[test] 35 | fn tx_status() { 36 | for (input, expected_output) in [ 37 | ( 38 | "near tx-status 4HxfV69Brk7fJd3NC63ti2H3QCgwiUiMAPvwNmGWbVXo".to_string(), 39 | "transaction view-status 4HxfV69Brk7fJd3NC63ti2H3QCgwiUiMAPvwNmGWbVXo network-config testnet" 40 | ), 41 | ( 42 | format!("near tx-status 4HxfV69Brk7fJd3NC63ti2H3QCgwiUiMAPvwNmGWbVXo --{} testnet", NETWORK_ID_ALIASES[0]), 43 | "transaction view-status 4HxfV69Brk7fJd3NC63ti2H3QCgwiUiMAPvwNmGWbVXo network-config testnet" 44 | ), 45 | ( 46 | format!("near tx-status 4HxfV69Brk7fJd3NC63ti2H3QCgwiUiMAPvwNmGWbVXo --{} mainnet", NETWORK_ID_ALIASES[1]), 47 | "transaction view-status 4HxfV69Brk7fJd3NC63ti2H3QCgwiUiMAPvwNmGWbVXo network-config mainnet" 48 | ), 49 | ] { 50 | let input_cmd = shell_words::split(&input).expect("Input command must be a valid shell command"); 51 | let JsCmd::TxStatus(tx_status_args) = JsCmd::parse_from(&input_cmd) else { 52 | panic!("TxStatus command was expected, but something else was parsed out from {input}"); 53 | }; 54 | assert_eq!( 55 | shell_words::join(TxStatusArgs::to_cli_args(&tx_status_args, "testnet".to_string())), 56 | expected_output 57 | ); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/network/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 2 | #[interactive_clap(input_context = NetworkContext)] 3 | #[interactive_clap(output_context = NetworkOutputContext)] 4 | pub struct Network { 5 | #[interactive_clap(long)] 6 | #[interactive_clap(skip_interactive_input)] 7 | wallet_url: Option, 8 | /// What is the name of the network? 9 | #[interactive_clap(skip_default_input_arg)] 10 | network_name: String, 11 | } 12 | 13 | pub type OnAfterGettingNetworkCallback = 14 | std::sync::Arc crate::CliResult>; 15 | 16 | #[derive(Clone)] 17 | pub struct NetworkContext { 18 | pub config: crate::config::Config, 19 | pub interacting_with_account_ids: Vec, 20 | pub on_after_getting_network_callback: OnAfterGettingNetworkCallback, 21 | } 22 | 23 | #[derive(Clone)] 24 | pub struct NetworkOutputContext; 25 | 26 | impl NetworkOutputContext { 27 | pub fn from_previous_context( 28 | previous_context: NetworkContext, 29 | scope: &::InteractiveClapContextScope, 30 | ) -> color_eyre::eyre::Result { 31 | let network_connection = previous_context.config.network_connection; 32 | let mut network_config = network_connection 33 | .get(&scope.network_name) 34 | .expect("Failed to get network config!") 35 | .clone(); 36 | if let Some(url) = scope.wallet_url.clone() { 37 | network_config.wallet_url = url.into(); 38 | } 39 | 40 | (previous_context.on_after_getting_network_callback)(&network_config)?; 41 | Ok(Self) 42 | } 43 | } 44 | 45 | impl Network { 46 | fn input_network_name(context: &NetworkContext) -> color_eyre::eyre::Result> { 47 | crate::common::input_network_name(&context.config, &context.interacting_with_account_ids) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/transaction_signature_options/display/mod.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)] 2 | #[interactive_clap(input_context = super::SubmitContext)] 3 | #[interactive_clap(output_context = DisplayContext)] 4 | pub struct Display; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct DisplayContext; 8 | 9 | impl DisplayContext { 10 | pub fn from_previous_context( 11 | previous_context: super::SubmitContext, 12 | _scope: &::InteractiveClapContextScope, 13 | ) -> color_eyre::eyre::Result { 14 | let storage_message = (previous_context.on_before_sending_transaction_callback)( 15 | &previous_context.signed_transaction_or_signed_delegate_action, 16 | &previous_context.network_config, 17 | ) 18 | .map_err(color_eyre::Report::msg)?; 19 | 20 | match previous_context.signed_transaction_or_signed_delegate_action { 21 | super::SignedTransactionOrSignedDelegateAction::SignedTransaction( 22 | signed_transaction, 23 | ) => { 24 | eprintln!( 25 | "\nSigned transaction (serialized as base64):\n{}\n", 26 | crate::types::signed_transaction::SignedTransactionAsBase64::from( 27 | signed_transaction 28 | ) 29 | ); 30 | eprintln!( 31 | "This base64-encoded signed transaction is ready to be sent to the network. You can call RPC server directly, or use a helper command on near CLI:\n$ {} transaction send-signed-transaction\n", 32 | crate::common::get_near_exec_path() 33 | ); 34 | eprintln!("{storage_message}"); 35 | } 36 | super::SignedTransactionOrSignedDelegateAction::SignedDelegateAction( 37 | signed_delegate_action, 38 | ) => { 39 | eprintln!( 40 | "\nSigned delegate action (serialized as base64):\n{}\n", 41 | crate::types::signed_delegate_action::SignedDelegateActionAsBase64::from( 42 | signed_delegate_action 43 | ) 44 | ); 45 | eprintln!( 46 | "This base64-encoded signed delegate action is ready to be sent to the meta-transaction relayer. There is a helper command on near CLI that can do that:\n$ {} transaction send-meta-transaction\n", 47 | crate::common::get_near_exec_path() 48 | ); 49 | eprintln!("{storage_message}"); 50 | } 51 | } 52 | Ok(Self) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/transaction_signature_options/sign_later/display.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)] 2 | #[interactive_clap(input_context = super::SignLaterContext)] 3 | #[interactive_clap(output_context = DisplayContext)] 4 | pub struct Display; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct DisplayContext; 8 | 9 | impl DisplayContext { 10 | pub fn from_previous_context( 11 | previous_context: super::SignLaterContext, 12 | _scope: &::InteractiveClapContextScope, 13 | ) -> color_eyre::eyre::Result { 14 | let info_str = format!( 15 | "\nTransaction hash to sign:\n{}.\n\nUnsigned transaction (serialized as base64):\n{}\n\nThis base64-encoded transaction can be signed and sent later. There is a helper command on near CLI that can do that:\n$ {} transaction sign-transaction\n", 16 | hex::encode(previous_context.unsigned_transaction.get_hash_and_size().0), 17 | crate::types::transaction::TransactionAsBase64::from(previous_context.unsigned_transaction), 18 | crate::common::get_near_exec_path() 19 | ); 20 | if let crate::Verbosity::Quiet = previous_context.global_context.verbosity { 21 | println!("{}", info_str); 22 | } 23 | tracing::info!( 24 | parent: &tracing::Span::none(), 25 | "{}", 26 | crate::common::indent_payload(&info_str) 27 | ); 28 | Ok(Self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/transaction_signature_options/sign_later/mod.rs: -------------------------------------------------------------------------------- 1 | use near_primitives::transaction::TransactionV0; 2 | use strum::{EnumDiscriminants, EnumIter, EnumMessage}; 3 | 4 | mod display; 5 | mod save_to_file; 6 | 7 | #[derive(Debug, Clone, interactive_clap::InteractiveClap)] 8 | #[interactive_clap(input_context = crate::commands::TransactionContext)] 9 | #[interactive_clap(output_context = SignLaterContext)] 10 | pub struct SignLater { 11 | #[interactive_clap(long)] 12 | /// Enter sender (signer) public key: 13 | signer_public_key: crate::types::public_key::PublicKey, 14 | #[interactive_clap(long)] 15 | /// Enter a nonce for the access key: 16 | nonce: u64, 17 | #[interactive_clap(long)] 18 | /// Enter recent block hash: 19 | block_hash: crate::types::crypto_hash::CryptoHash, 20 | #[interactive_clap(subcommand)] 21 | output: Output, 22 | } 23 | 24 | #[derive(Debug, Clone)] 25 | pub struct SignLaterContext { 26 | global_context: crate::GlobalContext, 27 | unsigned_transaction: near_primitives::transaction::Transaction, 28 | } 29 | 30 | impl SignLaterContext { 31 | pub fn from_previous_context( 32 | previous_context: crate::commands::TransactionContext, 33 | scope: &::InteractiveClapContextScope, 34 | ) -> color_eyre::eyre::Result { 35 | let unsigned_transaction = near_primitives::transaction::Transaction::V0(TransactionV0 { 36 | signer_id: previous_context.prepopulated_transaction.signer_id, 37 | public_key: scope.signer_public_key.clone().into(), 38 | nonce: scope.nonce, 39 | receiver_id: previous_context.prepopulated_transaction.receiver_id, 40 | block_hash: scope.block_hash.into(), 41 | actions: previous_context.prepopulated_transaction.actions, 42 | }); 43 | Ok(Self { 44 | global_context: previous_context.global_context, 45 | unsigned_transaction, 46 | }) 47 | } 48 | } 49 | 50 | #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] 51 | #[interactive_clap(context = SignLaterContext)] 52 | #[strum_discriminants(derive(EnumMessage, EnumIter))] 53 | /// How would you like to proceed? 54 | pub enum Output { 55 | #[strum_discriminants(strum( 56 | message = "save-to-file - Save the unsigned transaction to file" 57 | ))] 58 | /// Save the unsigned transaction to file 59 | SaveToFile(self::save_to_file::SaveToFile), 60 | #[strum_discriminants(strum( 61 | message = "display - Print the unsigned transaction to terminal" 62 | ))] 63 | /// Print the unsigned transaction to terminal 64 | Display(self::display::Display), 65 | } 66 | -------------------------------------------------------------------------------- /src/transaction_signature_options/sign_later/save_to_file.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | use color_eyre::eyre::Context; 4 | use inquire::CustomType; 5 | 6 | #[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)] 7 | #[interactive_clap(input_context = super::SignLaterContext)] 8 | #[interactive_clap(output_context = SaveToFileContext)] 9 | pub struct SaveToFile { 10 | #[interactive_clap(skip_default_input_arg)] 11 | /// What is the location of the file to save the unsigned transaction (path/to/signed-transaction-info.json)? 12 | file_path: crate::types::path_buf::PathBuf, 13 | } 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct SaveToFileContext; 17 | 18 | impl SaveToFileContext { 19 | pub fn from_previous_context( 20 | previous_context: super::SignLaterContext, 21 | scope: &::InteractiveClapContextScope, 22 | ) -> color_eyre::eyre::Result { 23 | let file_path: std::path::PathBuf = scope.file_path.clone().into(); 24 | 25 | let data_unsigned_transaction = serde_json::json!({ 26 | "Transaction hash to sign": hex::encode(previous_context.unsigned_transaction.get_hash_and_size().0).to_string(), 27 | "Unsigned transaction (serialized as base64)": crate::types::transaction::TransactionAsBase64::from(previous_context.unsigned_transaction).to_string(), 28 | }); 29 | 30 | std::fs::File::create(&file_path) 31 | .wrap_err_with(|| format!("Failed to create file: {:?}", &file_path))? 32 | .write(&serde_json::to_vec_pretty(&data_unsigned_transaction)?) 33 | .wrap_err_with(|| format!("Failed to write to file: {:?}", &file_path))?; 34 | tracing::info!( 35 | parent: &tracing::Span::none(), 36 | "{}", 37 | crate::common::indent_payload(&format!( 38 | "\nThe file {:?} was created successfully. It has a unsigned transaction (serialized as base64).\nThis base64-encoded transaction can be signed and sent later. There is a helper command on near CLI that can do that:\n$ {} transaction sign-transaction\n", 39 | &file_path, 40 | crate::common::get_near_exec_path() 41 | )) 42 | ); 43 | Ok(Self) 44 | } 45 | } 46 | 47 | impl SaveToFile { 48 | fn input_file_path( 49 | _context: &super::SignLaterContext, 50 | ) -> color_eyre::eyre::Result> { 51 | Ok(Some( 52 | CustomType::new("What is the location of the file to save the unsigned transaction?") 53 | .with_starting_input("unsigned-transaction-info.json") 54 | .prompt()?, 55 | )) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/types/account_id.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | #[derive(Eq, Ord, Hash, Clone, Debug, PartialEq, PartialOrd)] 4 | pub struct AccountId(pub near_primitives::types::AccountId); 5 | 6 | impl From for near_primitives::types::AccountId { 7 | fn from(account_id: AccountId) -> Self { 8 | account_id.0 9 | } 10 | } 11 | 12 | impl From for AccountId { 13 | fn from(account_id: near_primitives::types::AccountId) -> Self { 14 | Self(account_id) 15 | } 16 | } 17 | 18 | impl std::fmt::Display for AccountId { 19 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 20 | self.0.fmt(f) 21 | } 22 | } 23 | 24 | impl std::str::FromStr for AccountId { 25 | type Err = ::Err; 26 | 27 | fn from_str(account_id: &str) -> Result { 28 | let account_id = near_primitives::types::AccountId::from_str(account_id)?; 29 | Ok(Self(account_id)) 30 | } 31 | } 32 | 33 | impl AsRef for AccountId { 34 | fn as_ref(&self) -> &str { 35 | self.0.as_ref() 36 | } 37 | } 38 | 39 | impl AsRef for AccountId { 40 | fn as_ref(&self) -> &near_primitives::types::AccountId { 41 | &self.0 42 | } 43 | } 44 | 45 | impl interactive_clap::ToCli for AccountId { 46 | type CliVariant = AccountId; 47 | } 48 | 49 | impl AccountId { 50 | pub fn get_parent_account_id_from_sub_account(self) -> Self { 51 | let owner_account_id = self.to_string(); 52 | let owner_account_id = owner_account_id.split_once('.').map_or("default", |s| s.1); 53 | Self::from_str(owner_account_id).unwrap() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/types/api_key.rs: -------------------------------------------------------------------------------- 1 | #[derive(Eq, Hash, Clone, Debug, PartialEq)] 2 | pub struct ApiKey(pub near_jsonrpc_client::auth::ApiKey); 3 | 4 | impl From for near_jsonrpc_client::auth::ApiKey { 5 | fn from(api_key: ApiKey) -> Self { 6 | api_key.0 7 | } 8 | } 9 | 10 | impl std::fmt::Display for ApiKey { 11 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 12 | write!(f, "{}", self.0.to_str().map_err(|_| std::fmt::Error)?) 13 | } 14 | } 15 | 16 | impl std::str::FromStr for ApiKey { 17 | type Err = color_eyre::eyre::Report; 18 | 19 | fn from_str(api_key: &str) -> Result { 20 | Ok(Self(near_jsonrpc_client::auth::ApiKey::new(api_key)?)) 21 | } 22 | } 23 | 24 | impl serde::ser::Serialize for ApiKey { 25 | fn serialize(&self, serializer: S) -> Result 26 | where 27 | S: serde::ser::Serializer, 28 | { 29 | serializer.serialize_str(self.0.to_str().map_err(serde::ser::Error::custom)?) 30 | } 31 | } 32 | 33 | impl<'de> serde::de::Deserialize<'de> for ApiKey { 34 | fn deserialize(deserializer: D) -> Result 35 | where 36 | D: serde::de::Deserializer<'de>, 37 | { 38 | String::deserialize(deserializer)? 39 | .parse() 40 | .map_err(|err: color_eyre::eyre::Report| serde::de::Error::custom(err.to_string())) 41 | } 42 | } 43 | 44 | impl interactive_clap::ToCli for ApiKey { 45 | type CliVariant = ApiKey; 46 | } 47 | -------------------------------------------------------------------------------- /src/types/base64_bytes.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct Base64Bytes { 3 | inner: Vec, 4 | } 5 | 6 | impl interactive_clap::ToCli for Base64Bytes { 7 | type CliVariant = Base64Bytes; 8 | } 9 | 10 | impl std::str::FromStr for Base64Bytes { 11 | type Err = String; 12 | fn from_str(s: &str) -> Result { 13 | Ok(Self { 14 | inner: near_primitives::serialize::from_base64(s).map_err(|err| { 15 | format!( 16 | "parsing action {s} failed due to invalid base64 sequence: {}", 17 | err 18 | ) 19 | })?, 20 | }) 21 | } 22 | } 23 | 24 | impl std::fmt::Display for Base64Bytes { 25 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 26 | write!(f, "{}", near_primitives::serialize::to_base64(&self.inner)) 27 | } 28 | } 29 | 30 | impl Base64Bytes { 31 | pub fn as_bytes(&self) -> &[u8] { 32 | &self.inner 33 | } 34 | 35 | pub fn into_bytes(self) -> Vec { 36 | self.inner 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/types/crypto_hash.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Copy, Clone)] 2 | pub struct CryptoHash(pub near_primitives::hash::CryptoHash); 3 | 4 | impl From for near_primitives::hash::CryptoHash { 5 | fn from(item: CryptoHash) -> Self { 6 | item.0 7 | } 8 | } 9 | 10 | impl std::fmt::Display for CryptoHash { 11 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 12 | self.0.fmt(f) 13 | } 14 | } 15 | 16 | impl std::str::FromStr for CryptoHash { 17 | type Err = color_eyre::eyre::Error; 18 | 19 | fn from_str(s: &str) -> Result { 20 | let crypto_hash = near_primitives::hash::CryptoHash::from_str(s) 21 | .map_err(color_eyre::eyre::Report::msg)?; 22 | Ok(Self(crypto_hash)) 23 | } 24 | } 25 | 26 | impl interactive_clap::ToCli for CryptoHash { 27 | type CliVariant = CryptoHash; 28 | } 29 | -------------------------------------------------------------------------------- /src/types/file_bytes.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::Context; 2 | 3 | #[derive(Debug, Clone, derive_more::FromStr)] 4 | pub struct FileBytes { 5 | inner: std::path::PathBuf, 6 | } 7 | 8 | impl interactive_clap::ToCli for FileBytes { 9 | type CliVariant = FileBytes; 10 | } 11 | 12 | impl std::fmt::Display for FileBytes { 13 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 14 | write!(f, "{}", self.inner.display()) 15 | } 16 | } 17 | 18 | impl FileBytes { 19 | pub fn read_bytes(&self) -> color_eyre::Result> { 20 | std::fs::read(&self.inner) 21 | .wrap_err_with(|| format!("Error reading data from file: {}", self.inner.display())) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/types/json.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::WrapErr; 2 | use serde_json::Value; 3 | 4 | #[derive(Debug, Clone, derive_more::FromStr)] 5 | pub struct Json { 6 | inner: Value, 7 | } 8 | 9 | impl From for Value { 10 | fn from(item: Json) -> Self { 11 | item.inner 12 | } 13 | } 14 | 15 | impl std::fmt::Display for Json { 16 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 17 | self.inner.fmt(f) 18 | } 19 | } 20 | 21 | impl interactive_clap::ToCli for Json { 22 | type CliVariant = Json; 23 | } 24 | 25 | impl Json { 26 | pub fn try_into_bytes(&self) -> color_eyre::Result> { 27 | serde_json::to_vec(&self.inner).wrap_err("Data not in JSON format!") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod account_id; 2 | pub mod api_key; 3 | pub mod base64_bytes; 4 | pub mod crypto_hash; 5 | pub mod file_bytes; 6 | pub mod ft_properties; 7 | pub mod json; 8 | pub mod near_allowance; 9 | pub mod near_token; 10 | pub mod path_buf; 11 | pub mod public_key; 12 | pub mod public_key_list; 13 | pub mod secret_key; 14 | pub mod signature; 15 | pub mod signed_delegate_action; 16 | pub mod signed_transaction; 17 | pub mod slip10; 18 | pub mod transaction; 19 | pub mod url; 20 | pub mod vec_string; 21 | -------------------------------------------------------------------------------- /src/types/path_buf.rs: -------------------------------------------------------------------------------- 1 | #[derive( 2 | Debug, 3 | Default, 4 | Clone, 5 | derive_more::AsRef, 6 | derive_more::From, 7 | derive_more::Into, 8 | derive_more::FromStr, 9 | )] 10 | #[as_ref(forward)] 11 | pub struct PathBuf(pub std::path::PathBuf); 12 | 13 | impl std::fmt::Display for PathBuf { 14 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 15 | write!(f, "{}", self.0.display()) 16 | } 17 | } 18 | 19 | impl interactive_clap::ToCli for PathBuf { 20 | type CliVariant = PathBuf; 21 | } 22 | -------------------------------------------------------------------------------- /src/types/public_key.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)] 2 | pub struct PublicKey(pub near_crypto::PublicKey); 3 | 4 | impl std::fmt::Display for PublicKey { 5 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 6 | self.0.fmt(f) 7 | } 8 | } 9 | 10 | impl std::str::FromStr for PublicKey { 11 | type Err = near_crypto::ParseKeyError; 12 | 13 | fn from_str(s: &str) -> Result { 14 | let public_key = near_crypto::PublicKey::from_str(s)?; 15 | Ok(Self(public_key)) 16 | } 17 | } 18 | 19 | impl From for near_crypto::PublicKey { 20 | fn from(item: PublicKey) -> Self { 21 | item.0 22 | } 23 | } 24 | 25 | impl From for PublicKey { 26 | fn from(item: near_crypto::PublicKey) -> Self { 27 | Self(item) 28 | } 29 | } 30 | 31 | impl interactive_clap::ToCli for PublicKey { 32 | type CliVariant = PublicKey; 33 | } 34 | -------------------------------------------------------------------------------- /src/types/public_key_list.rs: -------------------------------------------------------------------------------- 1 | use interactive_clap::ToCli; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct PublicKeyList(Vec); 5 | 6 | impl std::fmt::Display for PublicKeyList { 7 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 8 | let keys: Vec = self.0.iter().map(|key| key.to_string()).collect(); 9 | write!(f, "{}", keys.join(",")) 10 | } 11 | } 12 | 13 | impl std::str::FromStr for PublicKeyList { 14 | type Err = color_eyre::eyre::ErrReport; 15 | 16 | fn from_str(s: &str) -> Result { 17 | let keys: Vec = s 18 | .split(',') 19 | .map(|str| str.trim().parse()) 20 | .collect::, _>>()?; 21 | Ok(Self(keys)) 22 | } 23 | } 24 | 25 | impl From for Vec { 26 | fn from(item: PublicKeyList) -> Self { 27 | item.0 28 | } 29 | } 30 | 31 | impl From> for PublicKeyList { 32 | fn from(item: Vec) -> Self { 33 | Self(item) 34 | } 35 | } 36 | 37 | impl ToCli for PublicKeyList { 38 | type CliVariant = PublicKeyList; 39 | } 40 | -------------------------------------------------------------------------------- /src/types/secret_key.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, PartialEq, Eq)] 2 | pub struct SecretKey(pub near_crypto::SecretKey); 3 | 4 | impl std::fmt::Display for SecretKey { 5 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 6 | self.0.fmt(f) 7 | } 8 | } 9 | 10 | impl std::str::FromStr for SecretKey { 11 | type Err = near_crypto::ParseKeyError; 12 | 13 | fn from_str(s: &str) -> Result { 14 | let private_key = near_crypto::SecretKey::from_str(s)?; 15 | Ok(Self(private_key)) 16 | } 17 | } 18 | 19 | impl From for near_crypto::SecretKey { 20 | fn from(item: SecretKey) -> Self { 21 | item.0 22 | } 23 | } 24 | 25 | impl interactive_clap::ToCli for SecretKey { 26 | type CliVariant = SecretKey; 27 | } 28 | -------------------------------------------------------------------------------- /src/types/signature.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct Signature(pub near_crypto::Signature); 3 | 4 | impl std::fmt::Display for Signature { 5 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 6 | self.0.fmt(f) 7 | } 8 | } 9 | 10 | impl std::str::FromStr for Signature { 11 | type Err = near_crypto::ParseSignatureError; 12 | 13 | fn from_str(s: &str) -> Result { 14 | let signature = near_crypto::Signature::from_str(s)?; 15 | Ok(Self(signature)) 16 | } 17 | } 18 | 19 | impl From for near_crypto::Signature { 20 | fn from(item: Signature) -> Self { 21 | item.0 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/types/signed_transaction.rs: -------------------------------------------------------------------------------- 1 | use near_primitives::{borsh, borsh::BorshDeserialize}; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct SignedTransactionAsBase64 { 5 | pub inner: near_primitives::transaction::SignedTransaction, 6 | } 7 | 8 | impl From for near_primitives::transaction::SignedTransaction { 9 | fn from(transaction: SignedTransactionAsBase64) -> Self { 10 | transaction.inner 11 | } 12 | } 13 | 14 | impl std::str::FromStr for SignedTransactionAsBase64 { 15 | type Err = String; 16 | fn from_str(s: &str) -> Result { 17 | Ok(Self { 18 | inner: near_primitives::transaction::SignedTransaction::try_from_slice( 19 | &near_primitives::serialize::from_base64(s) 20 | .map_err(|err| format!("base64 transaction sequence is invalid: {}", err))?, 21 | ) 22 | .map_err(|err| format!("transaction could not be parsed: {}", err))?, 23 | }) 24 | } 25 | } 26 | 27 | impl std::fmt::Display for SignedTransactionAsBase64 { 28 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 29 | let base64_signed_transaction = near_primitives::serialize::to_base64( 30 | &borsh::to_vec(&self.inner) 31 | .expect("Transaction is not expected to fail on serialization"), 32 | ); 33 | write!(f, "{}", base64_signed_transaction) 34 | } 35 | } 36 | 37 | impl interactive_clap::ToCli for SignedTransactionAsBase64 { 38 | type CliVariant = SignedTransactionAsBase64; 39 | } 40 | 41 | impl From for SignedTransactionAsBase64 { 42 | fn from(value: near_primitives::transaction::SignedTransaction) -> Self { 43 | Self { inner: value } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/types/slip10.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] 2 | pub struct BIP32Path(pub slipped10::BIP32Path); 3 | 4 | impl std::fmt::Display for BIP32Path { 5 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 6 | self.0.fmt(f) 7 | } 8 | } 9 | 10 | impl std::str::FromStr for BIP32Path { 11 | type Err = color_eyre::eyre::Report; 12 | 13 | fn from_str(s: &str) -> Result { 14 | let bip32path = slipped10::BIP32Path::from_str(s).map_err(Self::Err::msg)?; 15 | Ok(Self(bip32path)) 16 | } 17 | } 18 | 19 | impl From for slipped10::BIP32Path { 20 | fn from(item: BIP32Path) -> Self { 21 | item.0 22 | } 23 | } 24 | 25 | impl From for BIP32Path { 26 | fn from(item: slipped10::BIP32Path) -> Self { 27 | Self(item) 28 | } 29 | } 30 | 31 | impl serde::ser::Serialize for BIP32Path { 32 | fn serialize(&self, serializer: S) -> Result 33 | where 34 | S: serde::ser::Serializer, 35 | { 36 | serializer.serialize_str(&self.0.to_string()) 37 | } 38 | } 39 | 40 | impl<'de> serde::de::Deserialize<'de> for BIP32Path { 41 | fn deserialize(deserializer: D) -> Result 42 | where 43 | D: serde::de::Deserializer<'de>, 44 | { 45 | String::deserialize(deserializer)? 46 | .parse() 47 | .map_err(|err: color_eyre::eyre::Report| serde::de::Error::custom(err.to_string())) 48 | } 49 | } 50 | 51 | impl interactive_clap::ToCli for crate::types::slip10::BIP32Path { 52 | type CliVariant = crate::types::slip10::BIP32Path; 53 | } 54 | -------------------------------------------------------------------------------- /src/types/transaction.rs: -------------------------------------------------------------------------------- 1 | use near_primitives::{borsh, borsh::BorshDeserialize}; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct TransactionAsBase64 { 5 | pub inner: near_primitives::transaction::TransactionV0, 6 | } 7 | 8 | impl From for near_primitives::transaction::TransactionV0 { 9 | fn from(transaction: TransactionAsBase64) -> Self { 10 | transaction.inner 11 | } 12 | } 13 | 14 | impl From for TransactionAsBase64 { 15 | fn from(value: near_primitives::transaction::Transaction) -> Self { 16 | Self { 17 | inner: near_primitives::transaction::TransactionV0 { 18 | public_key: value.public_key().clone(), 19 | nonce: value.nonce(), 20 | signer_id: value.signer_id().clone(), 21 | receiver_id: value.receiver_id().clone(), 22 | block_hash: *value.block_hash(), 23 | actions: value.take_actions(), 24 | }, 25 | } 26 | } 27 | } 28 | 29 | impl From for TransactionAsBase64 { 30 | fn from(value: near_primitives::transaction::TransactionV0) -> Self { 31 | Self { inner: value } 32 | } 33 | } 34 | 35 | impl From for near_primitives::transaction::Transaction { 36 | fn from(transaction: TransactionAsBase64) -> Self { 37 | Self::V0(transaction.inner) 38 | } 39 | } 40 | 41 | impl interactive_clap::ToCli for TransactionAsBase64 { 42 | type CliVariant = TransactionAsBase64; 43 | } 44 | 45 | impl std::str::FromStr for TransactionAsBase64 { 46 | type Err = String; 47 | fn from_str(s: &str) -> Result { 48 | Ok(Self { 49 | inner: near_primitives::transaction::TransactionV0::try_from_slice( 50 | &near_primitives::serialize::from_base64(s) 51 | .map_err(|err| format!("base64 transaction sequence is invalid: {}", err))?, 52 | ) 53 | .map_err(|err| format!("transaction could not be parsed: {}", err))?, 54 | }) 55 | } 56 | } 57 | 58 | impl std::fmt::Display for TransactionAsBase64 { 59 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 60 | let base64_unsigned_transaction = near_primitives::serialize::to_base64( 61 | &borsh::to_vec(&self.inner) 62 | .expect("Transaction is not expected to fail on serialization"), 63 | ); 64 | write!(f, "{}", base64_unsigned_transaction) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/types/url.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct Url(pub url::Url); 3 | 4 | impl From for url::Url { 5 | fn from(url: Url) -> Self { 6 | url.0 7 | } 8 | } 9 | 10 | impl From for Url { 11 | fn from(url: url::Url) -> Self { 12 | Self(url) 13 | } 14 | } 15 | 16 | impl std::fmt::Display for Url { 17 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 18 | self.0.fmt(f) 19 | } 20 | } 21 | 22 | impl std::str::FromStr for Url { 23 | type Err = url::ParseError; 24 | 25 | fn from_str(s: &str) -> Result { 26 | let url = url::Url::parse(s)?; 27 | Ok(Self(url)) 28 | } 29 | } 30 | 31 | impl interactive_clap::ToCli for Url { 32 | type CliVariant = Url; 33 | } 34 | -------------------------------------------------------------------------------- /src/types/vec_string.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Default, Clone)] 2 | pub struct VecString(pub Vec); 3 | 4 | impl std::fmt::Display for VecString { 5 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 6 | write!(f, "{}", self.0.join(",")) 7 | } 8 | } 9 | 10 | impl std::str::FromStr for VecString { 11 | type Err = color_eyre::eyre::ErrReport; 12 | 13 | fn from_str(s: &str) -> Result { 14 | if s.is_empty() { 15 | return Ok(Self(vec![])); 16 | } 17 | let vec_str: Vec = s.split(',').map(|str| str.trim().to_string()).collect(); 18 | Ok(Self(vec_str)) 19 | } 20 | } 21 | 22 | impl From for Vec { 23 | fn from(item: VecString) -> Self { 24 | item.0 25 | } 26 | } 27 | 28 | impl From> for VecString { 29 | fn from(item: Vec) -> Self { 30 | Self(item) 31 | } 32 | } 33 | 34 | impl interactive_clap::ToCli for VecString { 35 | type CliVariant = VecString; 36 | } 37 | -------------------------------------------------------------------------------- /src/utils_command/generate_keypair_subcommand/mod.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | /// Generate a key pair of private and public keys (use it anywhere you need 4 | /// Ed25519 keys) 5 | #[derive(Debug, Clone, clap::Parser)] 6 | pub struct CliGenerateKeypair { 7 | #[clap(long)] 8 | pub master_seed_phrase: Option, 9 | #[clap(long, default_value = "12")] 10 | pub new_master_seed_phrase_words_count: usize, 11 | #[clap(long, default_value = "m/44'/397'/0'")] 12 | pub seed_phrase_hd_path: crate::types::slip10::BIP32Path, 13 | #[clap(long, default_value = "plaintext")] 14 | pub format: crate::common::OutputFormat, 15 | } 16 | 17 | impl Default for CliGenerateKeypair { 18 | fn default() -> Self { 19 | Self { 20 | master_seed_phrase: None, 21 | new_master_seed_phrase_words_count: 12, 22 | seed_phrase_hd_path: crate::types::slip10::BIP32Path::from_str("m/44'/397'/0'") 23 | .unwrap(), 24 | format: crate::common::OutputFormat::Json, 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/utils_command/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod generate_keypair_subcommand; 2 | --------------------------------------------------------------------------------