From 52eb689b1ed98864e82c86188ac75e1d947b168b Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Wed, 18 Sep 2024 15:40:50 -0700 Subject: [PATCH 1/5] wip --- FULL_HELP_DOCS.md | 48 ------------- .../fixtures/test_custom_types/README.md | 47 +++++++++--- .../soroban-spec-typescript/ts-tests/.env | 1 + .../ts-tests/initialize.sh | 8 +-- .../soroban-spec-typescript/ts-tests/soroban | 3 - .../ts-tests/src/util.ts | 2 +- .../soroban-spec-typescript/ts-tests/stellar | 3 + cmd/crates/soroban-test/src/lib.rs | 66 ++++------------- cmd/crates/soroban-test/tests/it/config.rs | 12 ++-- .../tests/it/integration/bindings.rs | 18 ++--- .../tests/it/integration/cookbook.rs | 6 +- .../tests/it/integration/custom_types.rs | 2 +- .../tests/it/integration/dotenv.rs | 6 +- .../soroban-test/tests/it/integration/fund.rs | 6 +- .../tests/it/integration/hello_world.rs | 16 ++--- .../tests/it/integration/snapshot.rs | 2 +- .../soroban-test/tests/it/integration/tx.rs | 6 +- .../soroban-test/tests/it/integration/wrap.rs | 13 ++-- cmd/soroban-cli/src/commands/network/add.rs | 28 ++++++-- cmd/soroban-cli/src/commands/network/mod.rs | 2 +- cmd/soroban-cli/src/config/locator.rs | 11 ++- cmd/soroban-cli/src/config/network.rs | 71 ++++++------------- 22 files changed, 156 insertions(+), 221 deletions(-) delete mode 100755 cmd/crates/soroban-spec-typescript/ts-tests/soroban create mode 100755 cmd/crates/soroban-spec-typescript/ts-tests/stellar diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index 479ac6720..44a6d1479 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -116,8 +116,6 @@ Get Id of builtin Soroban Asset Contract. Deprecated, use `stellar contract id a ###### **Options:** * `--asset ` — ID of the Stellar classic asset to wrap, e.g. "USDC:G...5" -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -135,8 +133,6 @@ Deploy builtin Soroban Asset Contract ###### **Options:** * `--asset ` — ID of the Stellar classic asset to wrap, e.g. "USDC:G...5" -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -181,8 +177,6 @@ Remove contract alias * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config @@ -201,8 +195,6 @@ Add contract alias * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--overwrite` — Overwrite the contract alias if it already exists * `--id ` — The contract id that will be associated with the alias @@ -223,8 +215,6 @@ Show the contract id associated with a given alias * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config @@ -294,8 +284,6 @@ Generate a TypeScript / JavaScript package * `--contract-id ` — The contract ID/address on the network * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config @@ -360,8 +348,6 @@ If no keys are specified the contract itself is extended. - `temporary`: Temporary -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -388,8 +374,6 @@ Deploy a wasm contract * `--wasm ` — WASM file to deploy * `--wasm-hash ` — Hash of the already installed/deployed WASM file * `--salt ` — Custom salt 32-byte salt for the token id -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -421,8 +405,6 @@ Fetch a contract's Wasm binary * `-o`, `--out-file ` — Where to write output otherwise stdout is used * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config @@ -449,8 +431,6 @@ Deploy builtin Soroban Asset Contract ###### **Options:** * `--asset ` — ID of the Stellar classic asset to wrap, e.g. "USDC:G...5" -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -468,8 +448,6 @@ Deploy normal Wasm Contract ###### **Options:** * `--salt ` — ID of the Soroban contract -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -509,8 +487,6 @@ Outputs no data when no data is present in the contract. * `--wasm ` — Wasm file to extract the data from * `--wasm-hash ` — Wasm hash to get the data for * `--id ` — Contract id to get the data for -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." @@ -548,8 +524,6 @@ Outputs no data when no data is present in the contract. * `--wasm ` — Wasm file to extract the data from * `--wasm-hash ` — Wasm hash to get the data for * `--id ` — Contract id to get the data for -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." @@ -587,8 +561,6 @@ Outputs no data when no data is present in the contract. * `--wasm ` — Wasm file to extract the data from * `--wasm-hash ` — Wasm hash to get the data for * `--id ` — Contract id to get the data for -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." @@ -666,8 +638,6 @@ Install a WASM file to the ledger without creating a contract instance ###### **Options:** -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -705,8 +675,6 @@ stellar contract invoke ... -- --help * `--id ` — Contract ID to invoke * `--is-view` — View the result simulating and do not sign and submit transaction. Deprecated use `--send=no` -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -782,8 +750,6 @@ Print the current value of a contract-data ledger entry - `temporary`: Temporary -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -819,8 +785,6 @@ If no keys are specificed the contract itself is restored. * `--ledgers-to-extend ` — Number of ledgers to extend the entry * `--ttl-ledger-only` — Only print the new Time To Live ledger -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -879,8 +843,6 @@ Watch the network for contract events * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config @@ -952,8 +914,6 @@ Fund an identity on a test network ###### **Options:** -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--hd-path ` — If identity is a seed phrase use this hd path, default is 0 * `--global` — Use global config @@ -980,8 +940,6 @@ Generate a new identity with a seed phrase, currently 12 words * `--config-dir ` — Location of config directory, default is "." * `--hd-path ` — When generating a secret key, which `hd_path` should be used from the original `seed_phrase` * `-d`, `--default-seed` — Generate the default seed phrase. Useful for testing. Equivalent to --seed 0000000000000000 -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config @@ -1274,8 +1232,6 @@ If a contract is a Stellar asset contract, it includes the asset issuer's accoun Default value: `snapshot.json` * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--archive-url ` — Archive URL @@ -1304,8 +1260,6 @@ Simulate a transaction envelope from stdin ###### **Options:** -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` or `--sim-only` flags were NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail * `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` @@ -1322,8 +1276,6 @@ Calculate the hash of a transaction envelope from stdin ###### **Options:** -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/README.md b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/README.md index 03f87f30b..40c40550f 100644 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/README.md +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/README.md @@ -1,24 +1,32 @@ # test_custom_types JS -JS library for interacting with [Soroban](https://soroban.stellar.org/) smart contract `test_custom_types` via Soroban RPC. +JS library for interacting with [Soroban](https://soroban.stellar.org/) smart +contract `test_custom_types` via Soroban RPC. -This library was automatically generated by Soroban CLI using a command similar to: +This library was automatically generated by Soroban CLI using a command similar +to: ```bash soroban contract bindings ts \ --rpc-url https://rpc-futurenet.stellar.org:443 \ - --network-passphrase "Test SDF Future Network ; October 2022" \ + --network "futurenet" \ --contract-id CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK \ --output-dir ./path/to/test_custom_types ``` -The network passphrase and contract ID are exported from [index.ts](./src/index.ts) in the `networks` constant. If you are the one who generated this library and you know that this contract is also deployed to other networks, feel free to update `networks` with other valid options. This will help your contract consumers use this library more easily. +The network passphrase and contract ID are exported from +[index.ts](./src/index.ts) in the `networks` constant. If you are the one who +generated this library and you know that this contract is also deployed to other +networks, feel free to update `networks` with other valid options. This will +help your contract consumers use this library more easily. # To publish or not to publish -This library is suitable for publishing to NPM. You can publish it to NPM using the `npm publish` command. +This library is suitable for publishing to NPM. You can publish it to NPM using +the `npm publish` command. -But you don't need to publish this library to NPM to use it. You can add it to your project's `package.json` using a file path: +But you don't need to publish this library to NPM to use it. You can add it to +your project's `package.json` using a file path: ```json "dependencies": { @@ -26,19 +34,30 @@ But you don't need to publish this library to NPM to use it. You can add it to y } ``` -However, we've actually encountered [frustration](https://github.com/stellar/soroban-example-dapp/pull/117#discussion_r1232873560) using local libraries with NPM in this way. Though it seems a bit messy, we suggest generating the library directly to your `node_modules` folder automatically after each install by using a `postinstall` script. We've had the least trouble with this approach. NPM will automatically remove what it sees as erroneous directories during the `install` step, and then regenerate them when it gets to your `postinstall` step, which will keep the library up-to-date with your contract. +However, we've actually encountered +[frustration](https://github.com/stellar/soroban-example-dapp/pull/117#discussion_r1232873560) +using local libraries with NPM in this way. Though it seems a bit messy, we +suggest generating the library directly to your `node_modules` folder +automatically after each install by using a `postinstall` script. We've had the +least trouble with this approach. NPM will automatically remove what it sees as +erroneous directories during the `install` step, and then regenerate them when +it gets to your `postinstall` step, which will keep the library up-to-date with +your contract. ```json "scripts": { - "postinstall": "soroban contract bindings ts --rpc-url https://rpc-futurenet.stellar.org:443 --network-passphrase \"Test SDF Future Network ; October 2022\" --id CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK --name test_custom_types" + "postinstall": "soroban contract bindings ts --rpc-url https://rpc-futurenet.stellar.org:443 --network futurenet --id CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK --name test_custom_types" } ``` -Obviously you need to adjust the above command based on the actual command you used to generate the library. +Obviously you need to adjust the above command based on the actual command you +used to generate the library. # Use it -Now that you have your library up-to-date and added to your project, you can import it in a file and see inline documentation for all of its exported methods: +Now that you have your library up-to-date and added to your project, you can +import it in a file and see inline documentation for all of its exported +methods: ```js import { Contract, networks } from "test_custom_types" @@ -51,4 +70,10 @@ const contract = new Contract({ contract.| ``` -As long as your editor is configured to show JavaScript/TypeScript documentation, you can pause your typing at that `|` to get a list of all exports and inline-documentation for each. It exports a separate [async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) function for each method in the smart contract, with documentation for each generated from the comments the contract's author included in the original source code. +As long as your editor is configured to show JavaScript/TypeScript +documentation, you can pause your typing at that `|` to get a list of all +exports and inline-documentation for each. It exports a separate +[async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) +function for each method in the smart contract, with documentation for each +generated from the comments the contract's author included in the original +source code. diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/.env b/cmd/crates/soroban-spec-typescript/ts-tests/.env index 93bb4be67..cb3d0c631 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/.env +++ b/cmd/crates/soroban-spec-typescript/ts-tests/.env @@ -1,3 +1,4 @@ +SOROBAN_NETWORK=local SOROBAN_NETWORK_PASSPHRASE="Standalone Network ; February 2017" SOROBAN_RPC_URL="http://localhost:8000/soroban/rpc" SOROBAN_FRIENDBOT_URL="http://localhost:8000/friendbot" diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh b/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh index d85eff115..d4cc25bd3 100755 --- a/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh +++ b/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh @@ -26,17 +26,17 @@ fi exe() { echo"${@/eval/}" ; "$@" ; } function fund_all() { - exe eval "./soroban keys generate root" - exe eval "./soroban keys fund root" + exe eval "./stellar keys generate root" + exe eval "./stellar keys fund root" } function deploy() { - exe eval "(./soroban contract deploy --quiet --source root --wasm $1 --ignore-checks) > $2" + exe eval "(./stellar contract deploy --quiet --source root --wasm $1 --ignore-checks) > $2" } function deploy_all() { deploy ../../../../target/wasm32-unknown-unknown/test-wasms/test_custom_types.wasm contract-id-custom-types.txt } function bind() { - exe eval "./soroban contract bindings typescript --contract-id $(cat $1) --output-dir ./node_modules/$2 --overwrite" + exe eval "./stellar contract bindings typescript --contract-id $(cat $1) --output-dir ./node_modules/$2 --overwrite" } function bind_all() { bind contract-id-custom-types.txt test-custom-types diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/soroban b/cmd/crates/soroban-spec-typescript/ts-tests/soroban deleted file mode 100755 index d98f247c9..000000000 --- a/cmd/crates/soroban-spec-typescript/ts-tests/soroban +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -cargo run --quiet -p soroban-cli -- "$@" diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts index a5315a643..c2408f180 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts @@ -3,7 +3,7 @@ import { Address, Keypair } from "@stellar/stellar-sdk"; import { basicNodeSigner } from "@stellar/stellar-sdk/contract"; const rootKeypair = Keypair.fromSecret( - spawnSync("./soroban", ["keys", "show", "root"], { + spawnSync("./stellar", ["keys", "show", "root"], { shell: true, encoding: "utf8", }).stdout.trim(), diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/stellar b/cmd/crates/soroban-spec-typescript/ts-tests/stellar new file mode 100755 index 000000000..e37763bec --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/ts-tests/stellar @@ -0,0 +1,3 @@ +#!/bin/bash + +cargo run --quiet -p stellar-cli -- "$@" diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 544e2d59e..56d30c4d6 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -64,10 +64,15 @@ pub struct TestEnv { impl Default for TestEnv { fn default() -> Self { let temp_dir = TempDir::new().unwrap(); - Self { + + let env = Self { temp_dir, - rpc_url: "http://localhost:8889/soroban/rpc".to_string(), - } + rpc_url: "http://localhost:8000/soroban/rpc".to_string(), + }; + + env.generate_account("test", None).assert().success(); + + env } } @@ -90,43 +95,13 @@ impl TestEnv { f(&test_env); } - pub fn with_default_network(f: F) { - let test_env = TestEnv::new(); - f(&test_env); - } - - pub fn with_port(host_port: u16) -> TestEnv { - Self::with_rpc_url(&format!("http://localhost:{host_port}/soroban/rpc")) - } - - pub fn with_rpc_url(rpc_url: &str) -> TestEnv { - let env = TestEnv { - rpc_url: rpc_url.to_string(), - ..Default::default() - }; - env.generate_account("test", None).assert().success(); - env - } - - pub fn new() -> TestEnv { - if let Ok(rpc_url) = std::env::var("SOROBAN_RPC_URL") { - return Self::with_rpc_url(&rpc_url); - } - let host_port = std::env::var("SOROBAN_PORT") - .as_deref() - .ok() - .and_then(|n| n.parse().ok()) - .unwrap_or(8000); - Self::with_port(host_port) - } /// Create a new `assert_cmd::Command` for a given subcommand and set's the current directory /// to be the internal `temp_dir`. pub fn new_assert_cmd(&self, subcommand: &str) -> Command { let mut cmd: Command = self.bin(); cmd.arg(subcommand) .env("SOROBAN_ACCOUNT", TEST_ACCOUNT) - .env("SOROBAN_RPC_URL", &self.rpc_url) - .env("SOROBAN_NETWORK_PASSPHRASE", LOCAL_NETWORK_PASSPHRASE) + .env("SOROBAN_NETWORK", "local") .env("XDG_CONFIG_HOME", self.temp_dir.join("config").as_os_str()) .env("XDG_DATA_HOME", self.temp_dir.join("data").as_os_str()) .current_dir(&self.temp_dir); @@ -134,15 +109,18 @@ impl TestEnv { } pub fn bin(&self) -> Command { - Command::cargo_bin("soroban").unwrap_or_else(|_| Command::new("soroban")) + Command::cargo_bin("stellar").unwrap_or_else(|_| Command::new("stellar")) } pub fn generate_account(&self, account: &str, seed: Option) -> Command { let mut cmd = self.new_assert_cmd("keys"); + cmd.arg("generate").arg(account); + if let Some(seed) = seed { cmd.arg(format!("--seed={seed}")); } + cmd } @@ -204,12 +182,7 @@ impl TestEnv { &self, command_str: &[I], ) -> T { - let mut arg = vec![ - "--network=local", - "--rpc-url=http", - "--network-passphrase=AA", - "--source-account=test", - ]; + let mut arg = vec!["--network=local", "--source-account=test"]; let input = command_str .iter() .map(AsRef::as_ref) @@ -223,9 +196,7 @@ impl TestEnv { let config_dir = Some(self.dir().to_path_buf()); config::Args { network: network::Args { - rpc_url: Some(self.rpc_url.clone()), - network_passphrase: Some(LOCAL_NETWORK_PASSPHRASE.to_string()), - network: None, + network: Some("local".to_string()), }, source_account: account.to_string(), locator: config::locator::Args { @@ -279,13 +250,6 @@ impl TestEnv { .to_string() } - /// Copy the contents of the current `TestEnv` to another `TestEnv` - pub fn fork(&self) -> Result { - let this = TestEnv::new(); - self.save(&this.temp_dir)?; - Ok(this) - } - /// Save the current state of the `TestEnv` to the given directory. pub fn save(&self, dst: &Path) -> Result<(), Error> { fs_extra::dir::copy(&self.temp_dir, dst, &CopyOptions::new())?; diff --git a/cmd/crates/soroban-test/tests/it/config.rs b/cmd/crates/soroban-test/tests/it/config.rs index 70dfaa693..9fac5e8f9 100644 --- a/cmd/crates/soroban-test/tests/it/config.rs +++ b/cmd/crates/soroban-test/tests/it/config.rs @@ -25,9 +25,13 @@ fn set_and_remove_network() { let dir = sandbox.dir().join(".soroban").join("network"); let mut read_dir = std::fs::read_dir(dir).unwrap(); let file = read_dir.next().unwrap().unwrap(); + assert_eq!(file.file_name().to_str().unwrap(), "local.toml"); + let res = ls(sandbox); - assert_eq!(res[0], "local"); + + assert_eq!(res[1], "local"); + sandbox .new_assert_cmd("network") .arg("rm") @@ -117,7 +121,7 @@ fn set_and_remove_global_network() { .arg("ls") .arg("--global") .assert() - .stdout("global\n"); + .stdout("futurenet\nglobal\nlocal\nmainnet\ntestnet\n"); sandbox .new_assert_cmd("network") @@ -133,7 +137,7 @@ fn set_and_remove_global_network() { .env("XDG_CONFIG_HOME", dir.to_str().unwrap()) .arg("ls") .assert() - .stdout("\n"); + .stdout("futurenet\nlocal\nmainnet\ntestnet\n"); } #[test] @@ -221,7 +225,7 @@ fn generate_key_on_testnet() { .new_assert_cmd("keys") .arg("generate") .arg("--rpc-url=https://soroban-testnet.stellar.org:443") - .arg("--network-passphrase=Test SDF Network ; September 2015") + .arg("--network=local") .arg("test_2") .assert() .stdout("") diff --git a/cmd/crates/soroban-test/tests/it/integration/bindings.rs b/cmd/crates/soroban-test/tests/it/integration/bindings.rs index feb7f2ef8..f29a52f57 100644 --- a/cmd/crates/soroban-test/tests/it/integration/bindings.rs +++ b/cmd/crates/soroban-test/tests/it/integration/bindings.rs @@ -1,19 +1,17 @@ use super::util::deploy_custom_account; use super::util::deploy_swap; -use soroban_test::{TestEnv, LOCAL_NETWORK_PASSPHRASE}; +use soroban_test::TestEnv; const OUTPUT_DIR: &str = "./bindings-output"; #[tokio::test] async fn invoke_test_generate_typescript_bindings() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); let contract_id = deploy_swap(sandbox).await; let outdir = sandbox.dir().join(OUTPUT_DIR); let cmd = sandbox.cmd_arr::(&[ - "--network-passphrase", - LOCAL_NETWORK_PASSPHRASE, - "--rpc-url", - &sandbox.rpc_url, + "--network", + "local", "--output-dir", &outdir.display().to_string(), "--overwrite", @@ -36,14 +34,12 @@ async fn invoke_test_generate_typescript_bindings() { #[tokio::test] async fn invoke_test_bindings_context_failure() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); let contract_id = deploy_custom_account(sandbox).await; let outdir = sandbox.dir().join(OUTPUT_DIR); let cmd = sandbox.cmd_arr::(&[ - "--network-passphrase", - LOCAL_NETWORK_PASSPHRASE, - "--rpc-url", - &sandbox.rpc_url, + "--network", + "local", "--output-dir", &outdir.display().to_string(), "--overwrite", diff --git a/cmd/crates/soroban-test/tests/it/integration/cookbook.rs b/cmd/crates/soroban-test/tests/it/integration/cookbook.rs index 65855d775..2c8cb52a5 100644 --- a/cmd/crates/soroban-test/tests/it/integration/cookbook.rs +++ b/cmd/crates/soroban-test/tests/it/integration/cookbook.rs @@ -1,6 +1,6 @@ use predicates::prelude::*; use soroban_cli::config::network::passphrase::LOCAL; -use soroban_test::TestEnv; +use soroban_test::{AssertExt, TestEnv}; use std::fs; use std::path::PathBuf; @@ -185,15 +185,13 @@ fn get_repo_root() -> PathBuf { #[cfg(test)] mod tests { - use soroban_test::AssertExt; - use crate::integration::util::{deploy_hello, HELLO_WORLD}; use super::*; #[tokio::test] async fn test_all_mdx_files() { - let sandbox = TestEnv::new(); + let sandbox = TestEnv::default(); let wasm = HELLO_WORLD; let wasm_path = wasm.path(); let wasm_hash = wasm.hash().expect("should exist").to_string(); diff --git a/cmd/crates/soroban-test/tests/it/integration/custom_types.rs b/cmd/crates/soroban-test/tests/it/integration/custom_types.rs index 6cdb61192..6e75d158f 100644 --- a/cmd/crates/soroban-test/tests/it/integration/custom_types.rs +++ b/cmd/crates/soroban-test/tests/it/integration/custom_types.rs @@ -15,7 +15,7 @@ fn invoke_custom(e: &TestEnv, id: &str, func: &str) -> assert_cmd::Command { #[tokio::test] async fn parse() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); let id = &deploy_custom(sandbox).await; extend_contract(sandbox, id).await; symbol(sandbox, id); diff --git a/cmd/crates/soroban-test/tests/it/integration/dotenv.rs b/cmd/crates/soroban-test/tests/it/integration/dotenv.rs index efdb01217..44eccf89a 100644 --- a/cmd/crates/soroban-test/tests/it/integration/dotenv.rs +++ b/cmd/crates/soroban-test/tests/it/integration/dotenv.rs @@ -11,7 +11,7 @@ fn write_env_file(e: &TestEnv, contents: &str) { #[tokio::test] async fn can_read_file() { - let e = &TestEnv::new(); + let e = &TestEnv::default(); std::thread::sleep(core::time::Duration::from_millis(1000)); let id = deploy_hello(e).await; println!("{id}"); @@ -28,7 +28,7 @@ async fn can_read_file() { #[tokio::test] async fn current_env_not_overwritten() { - let e = TestEnv::new(); + let e = TestEnv::default(); std::thread::sleep(core::time::Duration::from_millis(3000)); write_env_file(&e, &deploy_hello(&e).await); e.new_assert_cmd("contract") @@ -48,7 +48,7 @@ async fn current_env_not_overwritten() { #[tokio::test] async fn cli_args_have_priority() { - let e = &TestEnv::new(); + let e = &TestEnv::default(); std::thread::sleep(core::time::Duration::from_millis(6000)); let id = deploy_hello(e).await; write_env_file(e, &id); diff --git a/cmd/crates/soroban-test/tests/it/integration/fund.rs b/cmd/crates/soroban-test/tests/it/integration/fund.rs index 263775412..8f8357897 100644 --- a/cmd/crates/soroban-test/tests/it/integration/fund.rs +++ b/cmd/crates/soroban-test/tests/it/integration/fund.rs @@ -3,17 +3,17 @@ use soroban_test::TestEnv; #[tokio::test] #[allow(clippy::too_many_lines)] async fn fund() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); sandbox .new_assert_cmd("keys") .arg("generate") - .arg("test") + .arg("some-account") .assert() .success(); sandbox .new_assert_cmd("keys") .arg("fund") - .arg("test") + .arg("some-account") .assert() // Don't expect error if friendbot indicated that the account is // already fully funded to the starting balance, because the diff --git a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs index c982b0c40..a2e866a3f 100644 --- a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs +++ b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs @@ -7,7 +7,7 @@ use soroban_cli::{ config::{locator, secret}, }; use soroban_rpc::GetLatestLedgerResponse; -use soroban_test::{AssertExt, TestEnv, LOCAL_NETWORK_PASSPHRASE}; +use soroban_test::{AssertExt, TestEnv}; use crate::integration::util::extend_contract; @@ -16,7 +16,7 @@ use super::util::{deploy_hello, extend, HELLO_WORLD}; #[allow(clippy::too_many_lines)] #[tokio::test] async fn invoke_view_with_non_existent_source_account() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); let id = deploy_hello(sandbox).await; let world = "world"; let mut cmd = hello_world_cmd(&id, world); @@ -29,7 +29,7 @@ async fn invoke_view_with_non_existent_source_account() { #[tokio::test] #[allow(clippy::too_many_lines)] async fn invoke() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); let c = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); let GetLatestLedgerResponse { sequence, .. } = c.get_latest_ledger().await.unwrap(); sandbox @@ -257,7 +257,7 @@ fn contract_data_read_failure(sandbox: &TestEnv, id: &str) { #[tokio::test] async fn contract_data_read() { const KEY: &str = "COUNTER"; - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); let id = &deploy_hello(sandbox).await; let res = sandbox .invoke_with_test(&["--id", id, "--", "inc"]) @@ -316,7 +316,7 @@ async fn contract_data_read() { #[tokio::test] #[ignore] async fn half_max_instructions() { - let sandbox = TestEnv::new(); + let sandbox = TestEnv::default(); let wasm = HELLO_WORLD; sandbox .new_assert_cmd("contract") @@ -367,10 +367,8 @@ async fn handles_kebab_case(e: &TestEnv, id: &str) { async fn fetch(sandbox: &TestEnv, id: &str) { let f = sandbox.dir().join("contract.wasm"); let cmd = sandbox.cmd_arr::(&[ - "--rpc-url", - &sandbox.rpc_url, - "--network-passphrase", - LOCAL_NETWORK_PASSPHRASE, + "--network", + "local", "--id", id, "--out-file", diff --git a/cmd/crates/soroban-test/tests/it/integration/snapshot.rs b/cmd/crates/soroban-test/tests/it/integration/snapshot.rs index ceb52985f..d23f048e4 100644 --- a/cmd/crates/soroban-test/tests/it/integration/snapshot.rs +++ b/cmd/crates/soroban-test/tests/it/integration/snapshot.rs @@ -5,7 +5,7 @@ use soroban_test::{AssertExt, TestEnv}; #[test] #[allow(clippy::too_many_lines)] fn snapshot() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); // Create a couple accounts and a couple contracts, which we'll filter on to // make sure we only get the account and contract requested. sandbox diff --git a/cmd/crates/soroban-test/tests/it/integration/tx.rs b/cmd/crates/soroban-test/tests/it/integration/tx.rs index ef2d1e26c..67500f776 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx.rs @@ -4,8 +4,8 @@ use soroban_test::{AssertExt, TestEnv}; use crate::integration::util::{deploy_contract, DeployKind, HELLO_WORLD}; #[tokio::test] -async fn simulate() { - let sandbox = &TestEnv::new(); +async fn txn_simulate() { + let sandbox = &TestEnv::default(); let xdr_base64_build_only = deploy_contract(sandbox, HELLO_WORLD, DeployKind::BuildOnly).await; let xdr_base64_sim_only = deploy_contract(sandbox, HELLO_WORLD, DeployKind::SimOnly).await; let tx_env = @@ -33,7 +33,7 @@ async fn simulate() { #[tokio::test] async fn txn_hash() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); let xdr_base64 = "AAAAAgAAAACVk/0xt9tV/cUbF53iwQ3tkKLlq9zG2wV5qd9lRjZjlQAHt/sAFsKTAAAABAAAAAEAAAAAAAAAAAAAAABmOg6nAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABfcHs35M1GZ/JkY2+DHMs4dEUaqjynMnDYK/Gp0eulN8AAAAIdHJhbnNmZXIAAAADAAAAEgAAAAEFO1FR2Wg49QFY5KPOFAQ0bV5fN+7LD2GSQvOaHSH44QAAABIAAAAAAAAAAJWT/TG321X9xRsXneLBDe2QouWr3MbbBXmp32VGNmOVAAAACgAAAAAAAAAAAAAAADuaygAAAAABAAAAAQAAAAEFO1FR2Wg49QFY5KPOFAQ0bV5fN+7LD2GSQvOaHSH44QAAAY9SyLSVABbC/QAAABEAAAABAAAAAwAAAA8AAAASYXV0aGVudGljYXRvcl9kYXRhAAAAAAANAAAAJUmWDeWIDoxodDQXD2R2YFuP5K65ooYyx5lc87qDHZdjHQAAAAAAAAAAAAAPAAAAEGNsaWVudF9kYXRhX2pzb24AAAANAAAAcnsidHlwZSI6IndlYmF1dGhuLmdldCIsImNoYWxsZW5nZSI6ImhnMlRhOG8wWTliWFlyWlMyZjhzWk1kRFp6ektCSXhQNTZSd1FaNE90bTgiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjQ1MDcifQAAAAAADwAAAAlzaWduYXR1cmUAAAAAAAANAAAAQBcpuTFMxzkAdBs+5VIyJCBHaNuwEAva+kZVET4YuHVKF8gNII567RhxsnhBBSo5dDvssTN6vf2i42eEty66MtoAAAAAAAAAAX3B7N+TNRmfyZGNvgxzLOHRFGqo8pzJw2CvxqdHrpTfAAAACHRyYW5zZmVyAAAAAwAAABIAAAABBTtRUdloOPUBWOSjzhQENG1eXzfuyw9hkkLzmh0h+OEAAAASAAAAAAAAAACVk/0xt9tV/cUbF53iwQ3tkKLlq9zG2wV5qd9lRjZjlQAAAAoAAAAAAAAAAAAAAAA7msoAAAAAAAAAAAEAAAAAAAAAAwAAAAYAAAABfcHs35M1GZ/JkY2+DHMs4dEUaqjynMnDYK/Gp0eulN8AAAAUAAAAAQAAAAYAAAABBTtRUdloOPUBWOSjzhQENG1eXzfuyw9hkkLzmh0h+OEAAAAUAAAAAQAAAAeTiL4Gr2piUAmsXTev1ZzJ4kE2NUGZ0QMObd05iAMyzAAAAAMAAAAGAAAAAX3B7N+TNRmfyZGNvgxzLOHRFGqo8pzJw2CvxqdHrpTfAAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAABBTtRUdloOPUBWOSjzhQENG1eXzfuyw9hkkLzmh0h+OEAAAABAAAAAAAAAACVk/0xt9tV/cUbF53iwQ3tkKLlq9zG2wV5qd9lRjZjlQAAAAYAAAABBTtRUdloOPUBWOSjzhQENG1eXzfuyw9hkkLzmh0h+OEAAAAVAAABj1LItJUAAAAAAEyTowAAGMgAAAG4AAAAAAADJBsAAAABRjZjlQAAAEASFnAIzNqpfdzv6yT0rSLMUDFgt7a/inCHurNCG55Jp8Imho04qRH+JNdkq0BgMC7yAJqH4N6Y2iGflFt3Lp4L"; diff --git a/cmd/crates/soroban-test/tests/it/integration/wrap.rs b/cmd/crates/soroban-test/tests/it/integration/wrap.rs index c43f5b007..4b6f5121f 100644 --- a/cmd/crates/soroban-test/tests/it/integration/wrap.rs +++ b/cmd/crates/soroban-test/tests/it/integration/wrap.rs @@ -4,8 +4,7 @@ use soroban_test::{AssertExt, TestEnv, LOCAL_NETWORK_PASSPHRASE}; #[tokio::test] #[ignore] async fn burn() { - let sandbox = &TestEnv::new(); - let network_passphrase = LOCAL_NETWORK_PASSPHRASE.to_string(); + let sandbox = &TestEnv::default(); let address = sandbox .new_assert_cmd("keys") .arg("address") @@ -22,11 +21,11 @@ async fn burn() { .arg(&asset) .assert() .success(); - // wrap_cmd(&asset).run().await.unwrap(); + let asset = soroban_cli::utils::parsing::parse_asset(&asset).unwrap(); - let hash = contract_id_hash_from_asset(&asset, &network_passphrase); + let hash = contract_id_hash_from_asset(&asset, &LOCAL_NETWORK_PASSPHRASE); let id = stellar_strkey::Contract(hash.0).to_string(); - println!("{id}, {address}"); + sandbox .new_assert_cmd("contract") .args([ @@ -40,6 +39,7 @@ async fn burn() { ]) .assert() .stdout("\"9223372036854775807\"\n"); + sandbox .new_assert_cmd("contract") .arg("invoke") @@ -53,6 +53,7 @@ async fn burn() { ]) .assert() .stdout("true\n"); + sandbox .new_assert_cmd("contract") .args([ @@ -66,6 +67,7 @@ async fn burn() { ]) .assert() .stdout("\"9223372036854775807\"\n"); + sandbox .new_assert_cmd("contract") .arg("invoke") @@ -84,7 +86,6 @@ async fn burn() { .stdout("") .stderr(""); - println!("hi"); sandbox .new_assert_cmd("contract") .args([ diff --git a/cmd/soroban-cli/src/commands/network/add.rs b/cmd/soroban-cli/src/commands/network/add.rs index 20b1afa7b..2d50ce59d 100644 --- a/cmd/soroban-cli/src/commands/network/add.rs +++ b/cmd/soroban-cli/src/commands/network/add.rs @@ -1,3 +1,4 @@ +use crate::commands::HEADING_RPC; use crate::config::{locator, network, secret}; use clap::command; @@ -16,8 +17,21 @@ pub struct Cmd { /// Name of network pub name: String, - #[command(flatten)] - pub network: network::Network, + /// RPC server endpoint + #[arg( + long = "rpc-url", + env = "STELLAR_RPC_URL", + help_heading = HEADING_RPC, + )] + pub rpc_url: String, + + /// Network passphrase to sign the transaction sent to the rpc server + #[arg( + long, + env = "STELLAR_NETWORK_PASSPHRASE", + help_heading = HEADING_RPC, + )] + pub network_passphrase: String, #[command(flatten)] pub config_locator: locator::Args, @@ -25,8 +39,12 @@ pub struct Cmd { impl Cmd { pub fn run(&self) -> Result<(), Error> { - Ok(self - .config_locator - .write_network(&self.name, &self.network)?) + let network = network::Network { + rpc_url: self.rpc_url.clone(), + network_passphrase: self.network_passphrase.clone(), + name: self.name.clone(), + }; + + Ok(self.config_locator.write_network(&self.name, &network)?) } } diff --git a/cmd/soroban-cli/src/commands/network/mod.rs b/cmd/soroban-cli/src/commands/network/mod.rs index 772d0cbe8..1968cc73a 100644 --- a/cmd/soroban-cli/src/commands/network/mod.rs +++ b/cmd/soroban-cli/src/commands/network/mod.rs @@ -64,7 +64,7 @@ pub enum Error { #[error(transparent)] Config(#[from] locator::Error), - #[error("network arg or rpc url and network passphrase are required if using the network")] + #[error("please provide a network; use --network or set SOROBAN_NETWORK env var")] Network, #[error(transparent)] Http(#[from] http::Error), diff --git a/cmd/soroban-cli/src/config/locator.rs b/cmd/soroban-cli/src/config/locator.rs index bc167c977..570d90fc8 100644 --- a/cmd/soroban-cli/src/config/locator.rs +++ b/cmd/soroban-cli/src/config/locator.rs @@ -192,7 +192,11 @@ impl Args { .flatten() .map(|x| x.0); let default_networks = network::DEFAULTS.keys().map(ToString::to_string); - Ok(saved_networks.chain(default_networks).unique().collect()) + Ok(saved_networks + .chain(default_networks) + .unique() + .sorted_by(Ord::cmp) + .collect()) } pub fn list_networks_long(&self) -> Result, Error> { @@ -210,7 +214,10 @@ impl Args { let default_networks = network::DEFAULTS .into_iter() .map(|(name, network)| ((*name).to_string(), network.into(), "Default".to_owned())); - Ok(saved_networks.chain(default_networks).collect()) + Ok(saved_networks + .chain(default_networks) + .sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) + .collect()) } pub fn read_identity(&self, name: &str) -> Result { diff --git a/cmd/soroban-cli/src/config/network.rs b/cmd/soroban-cli/src/config/network.rs index 9e1eabee3..861c13135 100644 --- a/cmd/soroban-cli/src/config/network.rs +++ b/cmd/soroban-cli/src/config/network.rs @@ -19,7 +19,7 @@ pub enum Error { #[error(transparent)] Config(#[from] locator::Error), - #[error("network arg or rpc url and network passphrase are required if using the network")] + #[error("please provide a network; use --network or set SOROBAN_NETWORK env var")] Network, #[error(transparent)] Http(#[from] http::Error), @@ -38,72 +38,38 @@ pub enum Error { #[derive(Debug, clap::Args, Clone, Default)] #[group(skip)] pub struct Args { - /// RPC server endpoint - #[arg( - long = "rpc-url", - requires = "network_passphrase", - required_unless_present = "network", - env = "STELLAR_RPC_URL", - help_heading = HEADING_RPC, - )] - pub rpc_url: Option, - /// Network passphrase to sign the transaction sent to the rpc server - #[arg( - long = "network-passphrase", - requires = "rpc_url", - required_unless_present = "network", - env = "STELLAR_NETWORK_PASSPHRASE", - help_heading = HEADING_RPC, - )] - pub network_passphrase: Option, /// Name of network to use from config #[arg( long, - required_unless_present = "rpc_url", - required_unless_present = "network_passphrase", env = "STELLAR_NETWORK", help_heading = HEADING_RPC, + global = true, )] pub network: Option, } impl Args { pub fn get(&self, locator: &locator::Args) -> Result { - if let Some(name) = self.network.as_deref() { - if let Ok(network) = locator.read_network(name) { + if let Some(network) = &self.network { + if let Ok(network) = locator.read_network(network.as_str()) { return Ok(network); } } - if let (Some(rpc_url), Some(network_passphrase)) = - (self.rpc_url.clone(), self.network_passphrase.clone()) - { - Ok(Network { - rpc_url, - network_passphrase, - }) - } else { - Err(Error::Network) - } + + Err(Error::Network) } } -#[derive(Debug, clap::Args, Serialize, Deserialize, Clone)] -#[group(skip)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct Network { /// RPC server endpoint - #[arg( - long = "rpc-url", - env = "STELLAR_RPC_URL", - help_heading = HEADING_RPC, - )] pub rpc_url: String, + /// Network passphrase to sign the transaction sent to the rpc server - #[arg( - long, - env = "STELLAR_NETWORK_PASSPHRASE", - help_heading = HEADING_RPC, - )] pub network_passphrase: String, + + /// The alias name for the network entry + pub name: String, } impl Network { @@ -178,31 +144,36 @@ impl Network { } } -pub static DEFAULTS: phf::Map<&'static str, (&'static str, &'static str)> = phf_map! { +pub static DEFAULTS: phf::Map<&'static str, (&'static str, &'static str, &'static str)> = phf_map! { "local" => ( + "local", "http://localhost:8000/rpc", passphrase::LOCAL, ), "futurenet" => ( + "futurenet", "https://rpc-futurenet.stellar.org:443", passphrase::FUTURENET, ), "testnet" => ( + "testnet", "https://soroban-testnet.stellar.org", passphrase::TESTNET, ), "mainnet" => ( + "mainnet", "Bring Your Own: https://developers.stellar.org/docs/data/rpc/rpc-providers", passphrase::MAINNET, ), }; -impl From<&(&str, &str)> for Network { +impl From<&(&str, &str, &str)> for Network { /// Convert the return value of `DEFAULTS.get()` into a Network - fn from(n: &(&str, &str)) -> Self { + fn from(n: &(&str, &str, &str)) -> Self { Self { - rpc_url: n.0.to_string(), - network_passphrase: n.1.to_string(), + name: n.0.to_string(), + rpc_url: n.1.to_string(), + network_passphrase: n.2.to_string(), } } } From 1becb395ba090481e296849b1f36ff02ca2aea35 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Thu, 19 Sep 2024 10:18:13 -0700 Subject: [PATCH 2/5] Use the struct instead of string tuples. --- .../commands/contract/bindings/typescript.rs | 4 +- cmd/soroban-cli/src/config/locator.rs | 20 +++-- cmd/soroban-cli/src/config/network.rs | 81 +++++++++++-------- 3 files changed, 63 insertions(+), 42 deletions(-) diff --git a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs index 84e2b1762..8f7a0b7b1 100644 --- a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs +++ b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs @@ -124,10 +124,10 @@ impl NetworkRunnable for Cmd { network_passphrase, .. } = self.network.get(&self.locator).ok().unwrap_or_else(|| { - network::DEFAULTS + network::default_networks() .get("futurenet") .expect("why did we remove the default futurenet network?") - .into() + .to_owned() }); let absolute_path = self.output_dir.canonicalize()?; let file_name = absolute_path diff --git a/cmd/soroban-cli/src/config/locator.rs b/cmd/soroban-cli/src/config/locator.rs index 570d90fc8..73cfc3782 100644 --- a/cmd/soroban-cli/src/config/locator.rs +++ b/cmd/soroban-cli/src/config/locator.rs @@ -191,7 +191,9 @@ impl Args { .into_iter() .flatten() .map(|x| x.0); - let default_networks = network::DEFAULTS.keys().map(ToString::to_string); + let list = network::default_networks(); + let default_networks = list.keys().map(ToString::to_string); + Ok(saved_networks .chain(default_networks) .unique() @@ -211,9 +213,13 @@ impl Args { location.to_string(), )) }); - let default_networks = network::DEFAULTS - .into_iter() - .map(|(name, network)| ((*name).to_string(), network.into(), "Default".to_owned())); + let default_networks = network::default_networks().iter().map(|(name, network)| { + ( + (*name).to_string(), + network.to_owned(), + "Default".to_owned(), + ) + }); Ok(saved_networks .chain(default_networks) .sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) @@ -235,10 +241,12 @@ impl Args { pub fn read_network(&self, name: &str) -> Result { let res = KeyType::Network.read_with_global(name, &self.local_config()?); if let Err(Error::ConfigMissing(_, _)) = &res { - let Some(network) = network::DEFAULTS.get(name) else { + let list = network::default_networks(); + + let Some(network) = list.get(name) else { return res; }; - return Ok(network.into()); + return Ok(network.to_owned()); } res } diff --git a/cmd/soroban-cli/src/config/network.rs b/cmd/soroban-cli/src/config/network.rs index 861c13135..552040d92 100644 --- a/cmd/soroban-cli/src/config/network.rs +++ b/cmd/soroban-cli/src/config/network.rs @@ -1,7 +1,6 @@ -use std::str::FromStr; +use std::{collections::HashMap, str::FromStr, sync::OnceLock}; use clap::arg; -use phf::phf_map; use serde::{Deserialize, Serialize}; use serde_json::Value; use stellar_strkey::ed25519::PublicKey; @@ -144,36 +143,50 @@ impl Network { } } -pub static DEFAULTS: phf::Map<&'static str, (&'static str, &'static str, &'static str)> = phf_map! { - "local" => ( - "local", - "http://localhost:8000/rpc", - passphrase::LOCAL, - ), - "futurenet" => ( - "futurenet", - "https://rpc-futurenet.stellar.org:443", - passphrase::FUTURENET, - ), - "testnet" => ( - "testnet", - "https://soroban-testnet.stellar.org", - passphrase::TESTNET, - ), - "mainnet" => ( - "mainnet", - "Bring Your Own: https://developers.stellar.org/docs/data/rpc/rpc-providers", - passphrase::MAINNET, - ), -}; - -impl From<&(&str, &str, &str)> for Network { - /// Convert the return value of `DEFAULTS.get()` into a Network - fn from(n: &(&str, &str, &str)) -> Self { - Self { - name: n.0.to_string(), - rpc_url: n.1.to_string(), - network_passphrase: n.2.to_string(), - } - } +pub fn default_networks() -> &'static HashMap { + static HASHMAP: OnceLock> = OnceLock::new(); + + HASHMAP.get_or_init(|| { + let mut map = HashMap::new(); + + map.insert( + "local".to_string(), + Network { + name: "local".to_string(), + rpc_url: "http://localhost:8000/rpc".to_string(), + network_passphrase: passphrase::LOCAL.to_string(), + }, + ); + + map.insert( + "futurenet".to_string(), + Network { + name: "futurenet".to_string(), + rpc_url: "https://rpc-futurenet.stellar.org:443".to_string(), + network_passphrase: passphrase::FUTURENET.to_string(), + }, + ); + + map.insert( + "testnet".to_string(), + Network { + name: "testnet".to_string(), + rpc_url: "https://soroban-testnet.stellar.org".to_string(), + network_passphrase: passphrase::TESTNET.to_string(), + }, + ); + + map.insert( + "mainnet".to_string(), + Network { + name: "mainnet".to_string(), + rpc_url: + "Bring Your Own: https://developers.stellar.org/docs/data/rpc/rpc-providers" + .to_string(), + network_passphrase: passphrase::MAINNET.to_string(), + }, + ); + + map + }) } From bf247a8b6698127822231c59ce83e308c469e8f0 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Thu, 19 Sep 2024 13:09:49 -0700 Subject: [PATCH 3/5] Make network required, as it was before. --- FULL_HELP_DOCS.md | 48 +++++++++++++-------------- cmd/crates/soroban-test/src/lib.rs | 2 +- cmd/soroban-cli/src/config/network.rs | 9 ++--- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index 44a6d1479..a58cc2878 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -111,7 +111,7 @@ Utilities to deploy a Stellar Asset Contract or get its id Get Id of builtin Soroban Asset Contract. Deprecated, use `stellar contract id asset` instead -**Usage:** `stellar contract asset id [OPTIONS] --asset --source-account ` +**Usage:** `stellar contract asset id [OPTIONS] --asset --network --source-account ` ###### **Options:** @@ -128,7 +128,7 @@ Get Id of builtin Soroban Asset Contract. Deprecated, use `stellar contract id a Deploy builtin Soroban Asset Contract -**Usage:** `stellar contract asset deploy [OPTIONS] --asset --source-account ` +**Usage:** `stellar contract asset deploy [OPTIONS] --asset --network --source-account ` ###### **Options:** @@ -167,7 +167,7 @@ Utilities to manage contract aliases Remove contract alias -**Usage:** `stellar contract alias remove [OPTIONS] ` +**Usage:** `stellar contract alias remove [OPTIONS] --network ` ###### **Arguments:** @@ -185,7 +185,7 @@ Remove contract alias Add contract alias -**Usage:** `stellar contract alias add [OPTIONS] --id ` +**Usage:** `stellar contract alias add [OPTIONS] --network --id ` ###### **Arguments:** @@ -205,7 +205,7 @@ Add contract alias Show the contract id associated with a given alias -**Usage:** `stellar contract alias show [OPTIONS] ` +**Usage:** `stellar contract alias show [OPTIONS] --network ` ###### **Arguments:** @@ -274,7 +274,7 @@ Generate Rust bindings Generate a TypeScript / JavaScript package -**Usage:** `stellar contract bindings typescript [OPTIONS] --output-dir --contract-id ` +**Usage:** `stellar contract bindings typescript [OPTIONS] --output-dir --contract-id --network ` ###### **Options:** @@ -327,7 +327,7 @@ Extend the time to live ledger of a contract-data ledger entry. If no keys are specified the contract itself is extended. -**Usage:** `stellar contract extend [OPTIONS] --ledgers-to-extend --source-account ` +**Usage:** `stellar contract extend [OPTIONS] --ledgers-to-extend --network --source-account ` ###### **Options:** @@ -367,7 +367,7 @@ If no keys are specified the contract itself is extended. Deploy a wasm contract -**Usage:** `stellar contract deploy [OPTIONS] --source-account <--wasm |--wasm-hash >` +**Usage:** `stellar contract deploy [OPTIONS] --network --source-account <--wasm |--wasm-hash >` ###### **Options:** @@ -397,7 +397,7 @@ Deploy a wasm contract Fetch a contract's Wasm binary -**Usage:** `stellar contract fetch [OPTIONS] --id ` +**Usage:** `stellar contract fetch [OPTIONS] --id --network ` ###### **Options:** @@ -426,7 +426,7 @@ Generate the contract id for a given contract or asset Deploy builtin Soroban Asset Contract -**Usage:** `stellar contract id asset [OPTIONS] --asset --source-account ` +**Usage:** `stellar contract id asset [OPTIONS] --asset --network --source-account ` ###### **Options:** @@ -443,7 +443,7 @@ Deploy builtin Soroban Asset Contract Deploy normal Wasm Contract -**Usage:** `stellar contract id wasm [OPTIONS] --salt --source-account ` +**Usage:** `stellar contract id wasm [OPTIONS] --salt --network --source-account ` ###### **Options:** @@ -480,7 +480,7 @@ The data outputted by this command is a stream of `SCSpecEntry` XDR values. See Outputs no data when no data is present in the contract. -**Usage:** `stellar contract info interface [OPTIONS] <--wasm |--wasm-hash |--id >` +**Usage:** `stellar contract info interface [OPTIONS] --network <--wasm |--wasm-hash |--id >` ###### **Options:** @@ -517,7 +517,7 @@ The data outputted by this command is a stream of `SCMetaEntry` XDR values. See Outputs no data when no data is present in the contract. -**Usage:** `stellar contract info meta [OPTIONS] <--wasm |--wasm-hash |--id >` +**Usage:** `stellar contract info meta [OPTIONS] --network <--wasm |--wasm-hash |--id >` ###### **Options:** @@ -554,7 +554,7 @@ The data outputted by this command is a stream of `SCEnvMetaEntry` XDR values. S Outputs no data when no data is present in the contract. -**Usage:** `stellar contract info env-meta [OPTIONS] <--wasm |--wasm-hash |--id >` +**Usage:** `stellar contract info env-meta [OPTIONS] --network <--wasm |--wasm-hash |--id >` ###### **Options:** @@ -634,7 +634,7 @@ Inspect a WASM file listing contract functions, meta, etc Install a WASM file to the ledger without creating a contract instance -**Usage:** `stellar contract install [OPTIONS] --source-account --wasm ` +**Usage:** `stellar contract install [OPTIONS] --network --source-account --wasm ` ###### **Options:** @@ -665,7 +665,7 @@ Generates an "implicit CLI" for the specified contract on-the-fly using the cont stellar contract invoke ... -- --help -**Usage:** `stellar contract invoke [OPTIONS] --id --source-account [-- ...]` +**Usage:** `stellar contract invoke [OPTIONS] --id --network --source-account [-- ...]` ###### **Arguments:** @@ -719,7 +719,7 @@ Optimize a WASM file Print the current value of a contract-data ledger entry -**Usage:** `stellar contract read [OPTIONS] --source-account ` +**Usage:** `stellar contract read [OPTIONS] --network --source-account ` ###### **Options:** @@ -764,7 +764,7 @@ Restore an evicted value for a contract-data legder entry. If no keys are specificed the contract itself is restored. -**Usage:** `stellar contract restore [OPTIONS] --source-account ` +**Usage:** `stellar contract restore [OPTIONS] --network --source-account ` ###### **Options:** @@ -804,7 +804,7 @@ If no keys are specificed the contract itself is restored. Watch the network for contract events -**Usage:** `stellar events [OPTIONS]` +**Usage:** `stellar events [OPTIONS] --network ` ###### **Options:** @@ -906,7 +906,7 @@ Given an identity return its address (public key) Fund an identity on a test network -**Usage:** `stellar keys fund [OPTIONS] ` +**Usage:** `stellar keys fund [OPTIONS] --network ` ###### **Arguments:** @@ -925,7 +925,7 @@ Fund an identity on a test network Generate a new identity with a seed phrase, currently 12 words -**Usage:** `stellar keys generate [OPTIONS] ` +**Usage:** `stellar keys generate [OPTIONS] --network ` ###### **Arguments:** @@ -1216,7 +1216,7 @@ Contract addresses include the related wasm, contract data. If a contract is a Stellar asset contract, it includes the asset issuer's account and trust lines, but does not include all the trust lines of other accounts holding the asset. To include them specify the addresses of relevant accounts. -**Usage:** `stellar snapshot create [OPTIONS] --output ` +**Usage:** `stellar snapshot create [OPTIONS] --output --network ` ###### **Options:** @@ -1256,7 +1256,7 @@ Sign, Simulate, and Send transactions Simulate a transaction envelope from stdin -**Usage:** `stellar tx simulate [OPTIONS] --source-account ` +**Usage:** `stellar tx simulate [OPTIONS] --network --source-account ` ###### **Options:** @@ -1272,7 +1272,7 @@ Simulate a transaction envelope from stdin Calculate the hash of a transaction envelope from stdin -**Usage:** `stellar tx hash [OPTIONS]` +**Usage:** `stellar tx hash --network ` ###### **Options:** diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 56d30c4d6..4690a3519 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -196,7 +196,7 @@ impl TestEnv { let config_dir = Some(self.dir().to_path_buf()); config::Args { network: network::Args { - network: Some("local".to_string()), + network: "local".to_string(), }, source_account: account.to_string(), locator: config::locator::Args { diff --git a/cmd/soroban-cli/src/config/network.rs b/cmd/soroban-cli/src/config/network.rs index 552040d92..c6e7efa02 100644 --- a/cmd/soroban-cli/src/config/network.rs +++ b/cmd/soroban-cli/src/config/network.rs @@ -42,17 +42,14 @@ pub struct Args { long, env = "STELLAR_NETWORK", help_heading = HEADING_RPC, - global = true, )] - pub network: Option, + pub network: String, } impl Args { pub fn get(&self, locator: &locator::Args) -> Result { - if let Some(network) = &self.network { - if let Ok(network) = locator.read_network(network.as_str()) { - return Ok(network); - } + if let Ok(network) = locator.read_network(self.network.as_str()) { + return Ok(network); } Err(Error::Network) From 638917e231ad74fd076a01529fb7161be5af75ef Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Thu, 26 Sep 2024 15:42:31 -0700 Subject: [PATCH 4/5] Update docs. --- FULL_HELP_DOCS.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index a58cc2878..c07974ad8 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -1284,15 +1284,13 @@ Calculate the hash of a transaction envelope from stdin Sign a transaction envelope appending the signature to the envelope -**Usage:** `stellar tx sign [OPTIONS]` +**Usage:** `stellar tx sign [OPTIONS] --network ` ###### **Options:** * `--sign-with-key ` — Sign with a local key. Can be an identity (--sign-with-key alice), a secret key (--sign-with-key SC36…), or a seed phrase (--sign-with-key "kite urban…"). If using seed phrase, `--hd-path` defaults to the `0` path * `--hd-path ` — If using a seed phrase to sign, sets which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` * `--sign-with-lab` — Sign with https://lab.stellar.org -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." @@ -1303,12 +1301,10 @@ Sign a transaction envelope appending the signature to the envelope Send a transaction envelope to the network -**Usage:** `stellar tx send [OPTIONS]` +**Usage:** `stellar tx send [OPTIONS] --network ` ###### **Options:** -* `--rpc-url ` — RPC server endpoint -* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server * `--network ` — Name of network to use from config * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." From 3cbb8d4392a25a78bb5a6fa7a9f23703045a92cc Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Thu, 26 Sep 2024 15:54:20 -0700 Subject: [PATCH 5/5] new is no more. --- cmd/crates/soroban-test/tests/it/integration/tx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/crates/soroban-test/tests/it/integration/tx.rs b/cmd/crates/soroban-test/tests/it/integration/tx.rs index 67500f776..f130bd88b 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx.rs @@ -52,7 +52,7 @@ async fn txn_hash() { #[tokio::test] async fn build_simulate_sign_send() { - let sandbox = &TestEnv::new(); + let sandbox = &TestEnv::default(); sandbox .new_assert_cmd("contract") .arg("install")