diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index d913cf23d..45d74a243 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -157,6 +157,6 @@ jobs: repo: context.repo.repo, release_id: ${{ github.event.release.id }}, name: '${{ env.STELLAR_CLI_INSTALLER }}', - data: fs.readFileSync('Output/stellar-installer.exe'), + data: fs.readFileSync('${{ env.STELLAR_CLI_INSTALLER }}'), }); diff --git a/.github/workflows/bindings-ts.yml b/.github/workflows/bindings-ts.yml index 9b5f767ac..f6aaae499 100644 --- a/.github/workflows/bindings-ts.yml +++ b/.github/workflows/bindings-ts.yml @@ -19,7 +19,7 @@ jobs: NETWORK: local ENABLE_SOROBAN_RPC: true options: >- - --health-cmd "curl --no-progress-meter --fail-with-body -X POST \"http://localhost:8000/soroban/rpc\" -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":8675309,\"method\":\"getNetwork\"}' && curl --no-progress-meter \"http://localhost:8000/friendbot\" | grep '\"invalid_field\": \"addr\"'" + --health-cmd "curl --no-progress-meter --fail-with-body -X POST \"http://localhost:8000/rpc\" -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":8675309,\"method\":\"getNetwork\"}' && curl --no-progress-meter \"http://localhost:8000/friendbot\" | grep '\"invalid_field\": \"addr\"'" --health-interval 10s --health-timeout 5s --health-retries 50 diff --git a/Cargo.lock b/Cargo.lock index bf7893a4b..e07794ab1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4288,7 +4288,7 @@ dependencies = [ [[package]] name = "soroban-cli" -version = "22.0.1" +version = "22.1.0" dependencies = [ "assert_cmd", "assert_fs", @@ -4454,7 +4454,7 @@ dependencies = [ [[package]] name = "soroban-hello" -version = "22.0.1" +version = "22.1.0" [[package]] name = "soroban-ledger-snapshot" @@ -4525,7 +4525,7 @@ dependencies = [ [[package]] name = "soroban-spec-json" -version = "22.0.1" +version = "22.1.0" dependencies = [ "pretty_assertions", "serde", @@ -4555,7 +4555,7 @@ dependencies = [ [[package]] name = "soroban-spec-tools" -version = "22.0.1" +version = "22.1.0" dependencies = [ "base64 0.21.7", "ethnum", @@ -4573,7 +4573,7 @@ dependencies = [ [[package]] name = "soroban-spec-typescript" -version = "22.0.1" +version = "22.1.0" dependencies = [ "base64 0.21.7", "heck 0.4.1", @@ -4594,7 +4594,7 @@ dependencies = [ [[package]] name = "soroban-test" -version = "22.0.1" +version = "22.1.0" dependencies = [ "assert_cmd", "assert_fs", @@ -4602,6 +4602,7 @@ dependencies = [ "fs_extra", "hex", "home", + "httpmock", "predicates", "sep5", "serde_json", @@ -4666,18 +4667,18 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-bye" -version = "22.0.1" +version = "22.1.0" [[package]] name = "stellar-cli" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-cli", ] [[package]] name = "stellar-ledger" -version = "22.0.1" +version = "22.1.0" dependencies = [ "async-trait", "bollard", @@ -5024,42 +5025,42 @@ dependencies = [ [[package]] name = "test_constructor" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_custom_account" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_custom_types" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_hello_world" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_swap" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_token" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-sdk", "soroban-token-sdk", @@ -5067,7 +5068,7 @@ dependencies = [ [[package]] name = "test_udt" -version = "22.0.1" +version = "22.1.0" dependencies = [ "soroban-sdk", ] diff --git a/Cargo.toml b/Cargo.toml index cbfe6dd3c..702de93c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,24 +19,24 @@ exclude = [ ] [workspace.package] -version = "22.0.1" +version = "22.1.0" rust-version = "1.81.0" # Dependencies located in this repo: [workspace.dependencies.soroban-cli] -version = "=22.0.1" +version = "=22.1.0" path = "cmd/soroban-cli" [workspace.dependencies.soroban-spec-json] -version = "=22.0.1" +version = "=22.1.0" path = "./cmd/crates/soroban-spec-json" [workspace.dependencies.soroban-spec-typescript] -version = "22.0.1" +version = "22.1.0" path = "./cmd/crates/soroban-spec-typescript" [workspace.dependencies.soroban-spec-tools] -version = "22.0.1" +version = "22.1.0" path = "./cmd/crates/soroban-spec-tools" # Dependencies from the rs-stellar-xdr repo: @@ -105,6 +105,7 @@ toml_edit = "0.22.20" toml = "0.8.19" reqwest = "0.12.7" predicates = "3.1.2" +httpmock = "0.7.0" [profile.test-wasms] inherits = "release" diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index fc2a84335..6b67e32a0 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -45,7 +45,7 @@ Anything after the `--` double dash (the "slop") is parsed as arguments to the c * `contract` — Tools for smart contract developers * `events` — Watch the network for contract events -* `env` — Prints the current environment variables or defaults to the stdout, in a format that can be used as .env file. Environment variables have precedency over defaults +* `env` — Prints the environment variables * `keys` — Create and manage identities including keys and addresses * `network` — Configure connection to networks * `container` — Start local networks in containers @@ -290,20 +290,21 @@ Generate Rust bindings Generate a TypeScript / JavaScript package -**Usage:** `stellar contract bindings typescript [OPTIONS] --output-dir ` +**Usage:** `stellar contract bindings typescript [OPTIONS] --output-dir <--wasm |--wasm-hash |--contract-id >` ###### **Options:** -* `--wasm ` — Path to wasm file on local filesystem. You must either include this OR `--contract-id` -* `--contract-id ` — A contract ID/address on a network (if no network settings provided, Testnet will be assumed). You must either include this OR `--wasm` -* `--output-dir ` — Where to place generated project -* `--overwrite` — Whether to overwrite output directory if it already exists +* `--wasm ` — Wasm file path on local filesystem. Provide this OR `--wasm-hash` OR `--contract-id` +* `--wasm-hash ` — Hash of Wasm blob on a network. Provide this OR `--wasm` OR `--contract-id` +* `--contract-id ` — Contract ID/alias on a network. Provide this OR `--wasm-hash` OR `--wasm` * `--rpc-url ` — RPC server endpoint * `--rpc-header ` — RPC Header(s) to include in requests to the RPC provider * `--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 "." +* `--output-dir ` — Where to place generated project +* `--overwrite` — Whether to overwrite output directory if it already exists @@ -525,13 +526,13 @@ 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] <--wasm |--wasm-hash |--contract-id >` ###### **Options:** -* `--wasm ` — Wasm file to extract the data from -* `--wasm-hash ` — Wasm hash to get the data for -* `--id ` — Contract id or contract alias to get the data for +* `--wasm ` — Wasm file path on local filesystem. Provide this OR `--wasm-hash` OR `--contract-id` +* `--wasm-hash ` — Hash of Wasm blob on a network. Provide this OR `--wasm` OR `--contract-id` +* `--contract-id ` — Contract ID/alias on a network. Provide this OR `--wasm-hash` OR `--wasm` * `--rpc-url ` — RPC server endpoint * `--rpc-header ` — RPC Header(s) to include in requests to the RPC provider * `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server @@ -565,13 +566,13 @@ 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] <--wasm |--wasm-hash |--contract-id >` ###### **Options:** -* `--wasm ` — Wasm file to extract the data from -* `--wasm-hash ` — Wasm hash to get the data for -* `--id ` — Contract id or contract alias to get the data for +* `--wasm ` — Wasm file path on local filesystem. Provide this OR `--wasm-hash` OR `--contract-id` +* `--wasm-hash ` — Hash of Wasm blob on a network. Provide this OR `--wasm` OR `--contract-id` +* `--contract-id ` — Contract ID/alias on a network. Provide this OR `--wasm-hash` OR `--wasm` * `--rpc-url ` — RPC server endpoint * `--rpc-header ` — RPC Header(s) to include in requests to the RPC provider * `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server @@ -605,13 +606,13 @@ 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] <--wasm |--wasm-hash |--contract-id >` ###### **Options:** -* `--wasm ` — Wasm file to extract the data from -* `--wasm-hash ` — Wasm hash to get the data for -* `--id ` — Contract id or contract alias to get the data for +* `--wasm ` — Wasm file path on local filesystem. Provide this OR `--wasm-hash` OR `--contract-id` +* `--wasm-hash ` — Hash of Wasm blob on a network. Provide this OR `--wasm` OR `--contract-id` +* `--contract-id ` — Contract ID/alias on a network. Provide this OR `--wasm-hash` OR `--wasm` * `--rpc-url ` — RPC server endpoint * `--rpc-header ` — RPC Header(s) to include in requests to the RPC provider * `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server @@ -914,7 +915,11 @@ Watch the network for contract events ## `stellar env` -Prints the current environment variables or defaults to the stdout, in a format that can be used as .env file. Environment variables have precedency over defaults +Prints the environment variables + +Prints to stdout in a format that can be used as .env file. Environment variables have precedence over defaults. + +If there are no environment variables in use, prints the defaults. **Usage:** `stellar env [OPTIONS]` @@ -939,7 +944,7 @@ Create and manage identities including keys and addresses * `generate` — Generate a new identity with a seed phrase, currently 12 words * `ls` — List identities * `rm` — Remove an identity -* `show` — Given an identity return its private key +* `secret` — Output an identity's secret key * `use` — Set the default identity that will be used on all commands. This allows you to skip `--source-account` or setting a environment variable, while reusing this value in all commands that require it @@ -956,8 +961,8 @@ Add a new identity (keypair, ledger, macOS keychain) ###### **Options:** -* `--secret-key` — Add using `secret_key` Can provide with `SOROBAN_SECRET_KEY` -* `--seed-phrase` — Add using 12 word seed phrase to generate `secret_key` +* `--secret-key` — (deprecated) Enter secret (S) key when prompted +* `--seed-phrase` — (deprecated) Enter key using 12-24 word seed phrase * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." @@ -1064,11 +1069,11 @@ Remove an identity -## `stellar keys show` +## `stellar keys secret` -Given an identity return its private key +Output an identity's secret key -**Usage:** `stellar keys show [OPTIONS] ` +**Usage:** `stellar keys secret [OPTIONS] ` ###### **Arguments:** diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/.env b/cmd/crates/soroban-spec-typescript/ts-tests/.env index 93bb4be67..0ea150c3f 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/.env +++ b/cmd/crates/soroban-spec-typescript/ts-tests/.env @@ -1,3 +1,3 @@ -SOROBAN_NETWORK_PASSPHRASE="Standalone Network ; February 2017" -SOROBAN_RPC_URL="http://localhost:8000/soroban/rpc" -SOROBAN_FRIENDBOT_URL="http://localhost:8000/friendbot" +STELLAR_NETWORK_PASSPHRASE="Standalone Network ; February 2017" +STELLAR_RPC_URL="http://localhost:8000/rpc" +STELLAR_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 e872923c6..1fb84f081 100755 --- a/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh +++ b/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh @@ -10,10 +10,10 @@ done unset IFS echo Network -echo " RPC: $SOROBAN_RPC_URL" -echo " Passphrase: \"$SOROBAN_NETWORK_PASSPHRASE\"" +echo " RPC: $STELLAR_RPC_URL" +echo " Passphrase: \"$STELLAR_NETWORK_PASSPHRASE\"" -NETWORK_STATUS=$(curl -s -X POST "http://localhost:8000/soroban/rpc" -H "Content-Type: application/json" -d '{ "jsonrpc": "2.0", "id": 8675309, "method": "getHealth" }' | sed 's/.*"status":"\([^"]*\)".*/\1/') || { echo "Make sure you're running local RPC network on localhost:8000" && exit 1; } +NETWORK_STATUS=$(curl -s -X POST "http://localhost:8000/rpc" -H "Content-Type: application/json" -d '{ "jsonrpc": "2.0", "id": 8675309, "method": "getHealth" }' | sed 's/.*"status":"\([^"]*\)".*/\1/') || { echo "Make sure you're running local RPC network on localhost:8000" && exit 1; } echo " Status: $NETWORK_STATUS" if [[ "$NETWORK_STATUS" != "healthy" ]]; then @@ -22,28 +22,28 @@ if [[ "$NETWORK_STATUS" != "healthy" ]]; then fi # Print command before executing, from https://stackoverflow.com/a/23342259/249801 -# Discussion: https://github.com/stellar/soroban-tools/pull/1034#pullrequestreview-1690667116 +# Discussion: https://github.com/stellar/stellar-tools/pull/1034#pullrequestreview-1690667116 exe() { echo"${@/eval/}" ; "$@" ; } function fund_all() { - exe eval "./soroban keys generate root" - exe eval "./soroban keys fund root" + exe eval "./stellar keys generate --fund root" } function upload() { - exe eval "(./soroban contract $1 --quiet --source root --wasm $2 --ignore-checks) > $3" + exe eval "(./stellar contract $1 --quiet --source root --wasm $2 --ignore-checks) > $3" } function deploy_all() { upload deploy ../../../../target/wasm32-unknown-unknown/test-wasms/test_custom_types.wasm contract-id-custom-types.txt - # TODO: support `--wasm-hash` with `contract bindings` upload install ../../../../target/wasm32-unknown-unknown/test-wasms/test_constructor.wasm contract-wasm-hash-constructor.txt + exe eval "./stellar contract asset deploy --asset native --source root" } function bind() { - exe eval "./soroban contract bindings typescript $1 $2 --output-dir ./node_modules/$3 --overwrite" + exe eval "./stellar contract bindings typescript $1 $2 --output-dir ./node_modules/$3 --overwrite" exe eval "sh -c \"cd ./node_modules/$3 && npm install && npm run build\"" } function bind_all() { bind --contract-id $(cat contract-id-custom-types.txt) test-custom-types - bind --wasm ../../../../target/wasm32-unknown-unknown/test-wasms/test_constructor.wasm test-constructor + bind --wasm-hash $(cat contract-wasm-hash-constructor.txt) test-constructor + bind --contract-id $(./stellar contract id asset --asset native) xlm } fund_all diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-xlm-lib-from-sac.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-xlm-lib-from-sac.ts new file mode 100644 index 000000000..e39fb8b7d --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-xlm-lib-from-sac.ts @@ -0,0 +1,15 @@ +import test from "ava" +import { rpcUrl, root, signer } from "./util.js" +import { Client, networks } from "xlm" + +const contract = new Client({ + ...networks.standalone, + rpcUrl, + allowHttp: true, + publicKey: root.keypair.publicKey(), + ...signer, +}) + +test("can generate a lib from a Stellar Asset Contract", async (t) => { + t.is((await contract.symbol()).result, "native"); +}); 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..eacedbaec 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("./soroban", ["keys", "secret", "root"], { shell: true, encoding: "utf8", }).stdout.trim(), @@ -14,9 +14,9 @@ export const root = { address: Address.fromString(rootKeypair.publicKey()), }; -export const rpcUrl = process.env.SOROBAN_RPC_URL ?? "http://localhost:8000/"; +export const rpcUrl = process.env.STELLAR_RPC_URL ?? "http://localhost:8000/"; export const networkPassphrase = - process.env.SOROBAN_NETWORK_PASSPHRASE ?? + process.env.STELLAR_NETWORK_PASSPHRASE ?? "Standalone Network ; February 2017"; export const signer = basicNodeSigner(root.keypair, networkPassphrase); diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/soroban b/cmd/crates/soroban-spec-typescript/ts-tests/stellar similarity index 100% rename from cmd/crates/soroban-spec-typescript/ts-tests/soroban rename to cmd/crates/soroban-spec-typescript/ts-tests/stellar diff --git a/cmd/crates/soroban-test/Cargo.toml b/cmd/crates/soroban-test/Cargo.toml index 61fcc0bd8..eb03b7862 100644 --- a/cmd/crates/soroban-test/Cargo.toml +++ b/cmd/crates/soroban-test/Cargo.toml @@ -34,7 +34,6 @@ fs_extra = "1.3.0" toml = { workspace = true } home = "0.5.9" - [dev-dependencies] serde_json = "1.0.93" which = { workspace = true } @@ -43,6 +42,7 @@ walkdir = "2.4.0" ulid.workspace = true ed25519-dalek = { workspace = true } hex = { workspace = true } +httpmock = { workspace = true } [features] it = [] diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 96074e23d..4a826fe96 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -58,8 +58,7 @@ pub enum Error { /// its own `TempDir` where it will save test-specific configuration. pub struct TestEnv { pub temp_dir: TempDir, - pub rpc_url: String, - pub network_passphrase: String, + pub network: network::Network, } impl Default for TestEnv { @@ -67,8 +66,11 @@ impl Default for TestEnv { let temp_dir = TempDir::new().unwrap(); Self { temp_dir, - rpc_url: "http://localhost:8889/soroban/rpc".to_string(), - network_passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(), + network: network::Network { + rpc_url: "http://localhost:8889/soroban/rpc".to_string(), + network_passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(), + rpc_headers: [].to_vec(), + }, } } } @@ -102,12 +104,21 @@ impl TestEnv { } pub fn with_rpc_url(rpc_url: &str) -> TestEnv { - let mut env = TestEnv { - rpc_url: rpc_url.to_string(), - ..Default::default() + let mut env = TestEnv::default(); + env.network.rpc_url = rpc_url.to_string(); + if let Ok(network_passphrase) = std::env::var("STELLAR_NETWORK_PASSPHRASE") { + env.network.network_passphrase = network_passphrase; }; + env.generate_account("test", None).assert().success(); + env + } + + pub fn with_rpc_provider(rpc_url: &str, rpc_headers: Vec<(String, String)>) -> TestEnv { + let mut env = TestEnv::default(); + env.network.rpc_url = rpc_url.to_string(); + env.network.rpc_headers = rpc_headers; if let Ok(network_passphrase) = std::env::var("STELLAR_NETWORK_PASSPHRASE") { - env.network_passphrase = network_passphrase; + env.network.network_passphrase = network_passphrase; }; env.generate_account("test", None).assert().success(); env @@ -131,13 +142,25 @@ impl TestEnv { /// 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_RPC_URL", &self.network.rpc_url) .env("SOROBAN_NETWORK_PASSPHRASE", LOCAL_NETWORK_PASSPHRASE) .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); + + if !self.network.rpc_headers.is_empty() { + cmd.env( + "STELLAR_RPC_HEADERS", + format!( + "{}:{}", + &self.network.rpc_headers[0].0, &self.network.rpc_headers[0].1 + ), + ); + } + cmd } @@ -234,7 +257,7 @@ impl TestEnv { let config_dir = Some(self.dir().to_path_buf()); config::Args { network: network::Args { - rpc_url: Some(self.rpc_url.clone()), + rpc_url: Some(self.network.rpc_url.clone()), rpc_headers: [].to_vec(), network_passphrase: Some(LOCAL_NETWORK_PASSPHRASE.to_string()), network: None, @@ -285,7 +308,7 @@ impl TestEnv { /// Returns the private key corresponding to the test keys's `hd_path` pub fn test_show(&self, hd_path: usize) -> String { - self.cmd::(&format!("--hd-path={hd_path}")) + self.cmd::(&format!("--hd-path={hd_path}")) .private_key() .unwrap() .to_string() @@ -305,7 +328,7 @@ impl TestEnv { } pub fn client(&self) -> soroban_rpc::Client { - soroban_rpc::Client::new(&self.rpc_url).unwrap() + self.network.rpc_client().unwrap() } } diff --git a/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.toml index 4756225d2..5ca022099 100644 --- a/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stellar-bye" -version = "22.0.1" +version = "22.1.0" edition = "2021" publish = false diff --git a/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml index a2fb7b15c..73d7c781e 100644 --- a/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "soroban-hello" -version = "22.0.1" +version = "22.1.0" edition = "2021" publish = false diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/constructor/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/test-wasms/constructor/Cargo.toml index 9ccbb23d0..f7f9abac0 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/constructor/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/constructor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_constructor" -version = "22.0.1" +version = "22.1.0" authors = ["Stellar Development Foundation "] license = "Apache-2.0" edition = "2021" diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/Cargo.toml index e69dd96c9..081312a81 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_custom_account" -version = "22.0.1" +version = "22.1.0" authors = ["Stellar Development Foundation "] license = "Apache-2.0" edition = "2021" diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_type/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_type/Cargo.toml index 50b6d8a72..ebe2191e1 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_type/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_type/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_custom_types" -version = "22.0.1" +version = "22.1.0" authors = ["Stellar Development Foundation "] license = "Apache-2.0" edition = "2021" diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/Cargo.toml index a91a6ca62..14b386d2b 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_hello_world" -version = "22.0.1" +version = "22.1.0" authors = ["Stellar Development Foundation "] license = "Apache-2.0" edition = "2021" diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/Cargo.toml index 15c45c98e..70387d652 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_swap" -version = "22.0.1" +version = "22.1.0" authors = ["Stellar Development Foundation "] license = "Apache-2.0" edition = "2021" diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/Cargo.toml index d4e7e7436..681bb9b40 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/Cargo.toml +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_token" -version = "22.0.1" +version = "22.1.0" description = "Soroban standard token contract" authors = ["Stellar Development Foundation "] license = "Apache-2.0" diff --git a/cmd/crates/soroban-test/tests/it/config.rs b/cmd/crates/soroban-test/tests/it/config.rs index fb751ecf1..32db84748 100644 --- a/cmd/crates/soroban-test/tests/it/config.rs +++ b/cmd/crates/soroban-test/tests/it/config.rs @@ -290,7 +290,7 @@ fn use_env() { sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("bob") .assert() .success() @@ -337,7 +337,7 @@ fn config_dirs_precedence() { sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("alice") .arg("--verbose") .assert() diff --git a/cmd/crates/soroban-test/tests/it/integration/bindings.rs b/cmd/crates/soroban-test/tests/it/integration/bindings.rs index feb7f2ef8..4080cc110 100644 --- a/cmd/crates/soroban-test/tests/it/integration/bindings.rs +++ b/cmd/crates/soroban-test/tests/it/integration/bindings.rs @@ -13,7 +13,7 @@ async fn invoke_test_generate_typescript_bindings() { "--network-passphrase", LOCAL_NETWORK_PASSPHRASE, "--rpc-url", - &sandbox.rpc_url, + &sandbox.network.rpc_url, "--output-dir", &outdir.display().to_string(), "--overwrite", @@ -43,7 +43,7 @@ async fn invoke_test_bindings_context_failure() { "--network-passphrase", LOCAL_NETWORK_PASSPHRASE, "--rpc-url", - &sandbox.rpc_url, + &sandbox.network.rpc_url, "--output-dir", &outdir.display().to_string(), "--overwrite", 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 b9ed0196f..e63fdd4b4 100644 --- a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs +++ b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs @@ -27,7 +27,7 @@ async fn invoke_view_with_non_existent_source_account() { #[allow(clippy::too_many_lines)] async fn invoke() { let sandbox = &TestEnv::new(); - let c = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let c = sandbox.network.rpc_client().unwrap(); let GetLatestLedgerResponse { sequence, .. } = c.get_latest_ledger().await.unwrap(); sandbox .new_assert_cmd("keys") @@ -53,7 +53,7 @@ async fn invoke() { let secret_key = sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("test") .assert() .stdout_as_str(); @@ -65,7 +65,7 @@ async fn invoke() { .stdout_as_str(); let secret_key_1 = sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("test") .arg("--hd-path=1") .assert() @@ -115,7 +115,7 @@ async fn invoke() { assert_eq!(sk_from_file, format!("secret_key = \"{secret_key_1}\"\n")); let secret_key_1_readin = sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("testone") .assert() .stdout_as_str(); @@ -365,7 +365,7 @@ async fn fetch(sandbox: &TestEnv, id: &str) { let f = sandbox.dir().join("contract.wasm"); let cmd = sandbox.cmd_arr::(&[ "--rpc-url", - &sandbox.rpc_url, + &sandbox.network.rpc_url, "--network-passphrase", LOCAL_NETWORK_PASSPHRASE, "--id", diff --git a/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs b/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs index 1ce1f06c9..d9bc2ac63 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs @@ -66,7 +66,7 @@ async fn create_account() { .success() .stdout_as_str(); let test = test_address(sandbox); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test_account = client.get_account(&test).await.unwrap(); println!("test account has a balance of {}", test_account.balance); let starting_balance = ONE_XLM * 100; @@ -92,7 +92,7 @@ async fn create_account() { #[tokio::test] async fn payment() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, test1) = setup_accounts(sandbox); let test_account = client.get_account(&test).await.unwrap(); println!("test account has a balance of {}", test_account.balance); @@ -125,7 +125,7 @@ async fn payment() { #[tokio::test] async fn bump_sequence() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test = test_address(sandbox); let before = client.get_account(&test).await.unwrap(); let amount = 50; @@ -148,7 +148,7 @@ async fn bump_sequence() { #[tokio::test] async fn account_merge() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, test1) = setup_accounts(sandbox); let before = client.get_account(&test).await.unwrap(); let before1 = client.get_account(&test1).await.unwrap(); @@ -188,7 +188,7 @@ async fn set_trustline_flags() { .success(); let id = contract_id_hash_from_asset( asset.parse::().unwrap(), - &sandbox.network_passphrase, + &sandbox.network.network_passphrase, ); // sandbox // .new_assert_cmd("contract") @@ -224,7 +224,7 @@ async fn set_trustline_flags() { #[tokio::test] async fn set_options_add_signer() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, test1) = setup_accounts(sandbox); let before = client.get_account(&test).await.unwrap(); sandbox @@ -286,7 +286,7 @@ fn build_and_run(sandbox: &TestEnv, cmd: &str, args: &[&str]) -> String { #[tokio::test] async fn set_options() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, alice) = setup_accounts(sandbox); let before = client.get_account(&test).await.unwrap(); assert!(before.inflation_dest.is_none()); @@ -356,7 +356,7 @@ async fn set_options() { #[tokio::test] async fn set_some_options() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test = test_address(sandbox); let before = client.get_account(&test).await.unwrap(); assert!(before.inflation_dest.is_none()); @@ -451,7 +451,7 @@ async fn change_trust() { // wrap_cmd(&asset).run().await.unwrap(); let id = contract_id_hash_from_asset( asset.parse::().unwrap(), - &sandbox.network_passphrase, + &sandbox.network.network_passphrase, ); sandbox .new_assert_cmd("contract") @@ -529,7 +529,7 @@ async fn change_trust() { async fn manage_data() { let sandbox = &TestEnv::new(); let (test, _) = setup_accounts(sandbox); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let key = "test"; let value = "beefface"; sandbox @@ -573,7 +573,7 @@ async fn manage_data() { } async fn issue_asset(sandbox: &TestEnv, test: &str, asset: &str, limit: u64, initial_balance: u64) { - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test_before = client.get_account(test).await.unwrap(); sandbox .new_assert_cmd("tx") @@ -633,7 +633,7 @@ async fn issue_asset(sandbox: &TestEnv, test: &str, asset: &str, limit: u64, ini #[tokio::test] async fn multi_create_accounts() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let nums: Vec = (1..=3).collect(); let mut accounts: Vec<(String, String)> = nums .iter() diff --git a/cmd/crates/soroban-test/tests/it/main.rs b/cmd/crates/soroban-test/tests/it/main.rs index e06c1a47d..4dc54a194 100644 --- a/cmd/crates/soroban-test/tests/it/main.rs +++ b/cmd/crates/soroban-test/tests/it/main.rs @@ -6,5 +6,6 @@ mod init; // #[cfg(feature = "it")] mod integration; mod plugin; +mod rpc_provider; mod util; mod version; diff --git a/cmd/crates/soroban-test/tests/it/rpc_provider.rs b/cmd/crates/soroban-test/tests/it/rpc_provider.rs new file mode 100644 index 000000000..04c4c1bdc --- /dev/null +++ b/cmd/crates/soroban-test/tests/it/rpc_provider.rs @@ -0,0 +1,97 @@ +use httpmock::{prelude::*, Mock}; +use serde_json::json; +use soroban_rpc::{GetEventsResponse, GetNetworkResponse}; +use soroban_test::{TestEnv, LOCAL_NETWORK_PASSPHRASE}; + +#[tokio::test] +async fn test_use_rpc_provider_with_auth_header() { + // mock out http request to rpc provider + let server = MockServer::start(); + let generate_account_mock = mock_generate_account(&server); + let get_network_mock = mock_get_network(&server); + let get_events_mock = mock_get_events(&server); + + // create a new test environment with the mock server + let rpc_url = server.url(""); + let rpc_headers = vec![("Authorization".to_string(), "Bearer test-token".to_string())]; + let sandbox = &TestEnv::with_rpc_provider(&rpc_url, rpc_headers); + + sandbox + .new_assert_cmd("events") + .arg("--start-ledger") + .arg("1000") + .assert() + .success(); + + // generate account is being called in `with_rpc_provider` + generate_account_mock.assert(); + // get_network and get_events are being called in the `stellar events` command + get_network_mock.assert(); + get_events_mock.assert(); +} + +fn mock_generate_account(server: &MockServer) -> Mock { + server.mock(|when, then| { + when.method(GET) + .path("/friendbot") + .header("accept", "*/*") + .header("user-agent", "soroban-cli/22.0.1"); //update this to be future proof + then.status(200); + }) +} + +fn mock_get_network(server: &MockServer) -> Mock { + server.mock(|when, then| { + when.method(POST) + .path("/") + .header("authorization", "Bearer test-token") + .json_body(json!({ + "jsonrpc": "2.0", + "id": 0, + "method": "getNetwork" + })); + + then.status(200).json_body(json!({ + "jsonrpc": "2.0", + "id": 0, + "result": GetNetworkResponse { + friendbot_url: None, + passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(), + protocol_version: 22} + })); + }) +} + +fn mock_get_events(server: &MockServer) -> Mock { + server.mock(|when, then| { + when.method(POST) + .path("/") + .header("authorization", "Bearer test-token") + .json_body(json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "getEvents", + "params": { + "startLedger": 1000, + "filters": [ + { + "contractIds": [], + "topics": [] + } + ], + "pagination": { + "limit": 10 + } + } + })); + + then.status(200).json_body(json!({ + "jsonrpc": "2.0", + "id": 1, + "result": GetEventsResponse { + events: vec![], + latest_ledger: 1000 + } + })); + }) +} diff --git a/cmd/crates/stellar-ledger/Cargo.toml b/cmd/crates/stellar-ledger/Cargo.toml index b3d6318a4..f06d17a2b 100644 --- a/cmd/crates/stellar-ledger/Cargo.toml +++ b/cmd/crates/stellar-ledger/Cargo.toml @@ -51,7 +51,7 @@ log = "0.4.21" once_cell = "1.19.0" pretty_assertions = "1.2.1" serial_test = "3.0.0" -httpmock = "0.7.0-rc.1" +httpmock = { workspace = true } test-case = "3.3.1" testcontainers = "0.20.1" diff --git a/cmd/soroban-cli/src/commands/contract/bindings.rs b/cmd/soroban-cli/src/commands/contract/bindings.rs index a91c966aa..c0e1f288a 100644 --- a/cmd/soroban-cli/src/commands/contract/bindings.rs +++ b/cmd/soroban-cli/src/commands/contract/bindings.rs @@ -12,7 +12,7 @@ pub enum Cmd { Rust(rust::Cmd), /// Generate a TypeScript / JavaScript package - Typescript(typescript::Cmd), + Typescript(Box), /// Generate Python bindings Python(python::Cmd), diff --git a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs index ea1f63eed..1da64eaa5 100644 --- a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs +++ b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs @@ -1,44 +1,31 @@ use std::{ffi::OsString, fmt::Debug, path::PathBuf}; use clap::{command, Parser}; -use soroban_spec_tools::contract as contract_spec; -use soroban_spec_typescript::{self as typescript, boilerplate::Project}; -use stellar_strkey::DecodeError; +use soroban_spec_tools::contract as spec_tools; +use soroban_spec_typescript::boilerplate::Project; use crate::print::Print; -use crate::wasm; use crate::{ - commands::{contract::fetch, global, NetworkRunnable}, - config::{self, locator, network}, - get_spec::{self, get_remote_contract_spec}, - xdr::{Hash, ScAddress}, + commands::{contract::info::shared as contract_spec, global, NetworkRunnable}, + config, }; +use soroban_spec_tools::contract::Spec; #[derive(Parser, Debug, Clone)] #[group(skip)] pub struct Cmd { - /// Path to wasm file on local filesystem. You must either include this OR `--contract-id`. - #[arg(long)] - pub wasm: Option, - /// A contract ID/address on a network (if no network settings provided, Testnet will be assumed). You must either include this OR `--wasm`. - #[arg(long, visible_alias = "id")] - pub contract_id: Option, + #[command(flatten)] + pub wasm_or_hash_or_contract_id: contract_spec::Args, /// Where to place generated project #[arg(long)] pub output_dir: PathBuf, /// Whether to overwrite output directory if it already exists #[arg(long)] pub overwrite: bool, - #[command(flatten)] - pub network: network::Args, - #[command(flatten)] - pub locator: locator::Args, } #[derive(thiserror::Error, Debug)] pub enum Error { - #[error("failed generate TS from file: {0}")] - GenerateTSFromFile(typescript::GenerateFromFileError), #[error(transparent)] Io(#[from] std::io::Error), @@ -51,28 +38,14 @@ pub enum Error { #[error("--output-dir filepath not representable as utf-8: {0:?}")] NotUtf8(OsString), - #[error("must include either --wasm or --contract-id")] - MissingWasmOrContractId, - - #[error(transparent)] - Network(#[from] network::Error), - - #[error(transparent)] - Locator(#[from] locator::Error), - #[error(transparent)] - Fetch(#[from] fetch::Error), #[error(transparent)] - Spec(#[from] contract_spec::Error), - #[error(transparent)] - Wasm(#[from] wasm::Error), + Spec(#[from] spec_tools::Error), #[error("Failed to get file name from path: {0:?}")] FailedToGetFileName(PathBuf), - #[error("cannot parse contract ID {0}: {1}")] - CannotParseContractId(String, DecodeError), #[error(transparent)] - UtilsError(#[from] get_spec::Error), + WasmOrContract(#[from] contract_spec::Error), #[error(transparent)] - Config(#[from] config::Error), + Xdr(#[from] crate::xdr::Error), } #[async_trait::async_trait] @@ -83,51 +56,20 @@ impl NetworkRunnable for Cmd { async fn run_against_rpc_server( &self, global_args: Option<&global::Args>, - config: Option<&config::Args>, + _config: Option<&config::Args>, ) -> Result<(), Error> { let print = Print::new(global_args.is_some_and(|a| a.quiet)); - let (spec, contract_address, rpc_url, network_passphrase) = if let Some(wasm) = &self.wasm { - print.infoln("Loading contract spec from file..."); - let wasm: wasm::Args = wasm.into(); - (wasm.parse()?.spec, None, None, None) - } else { - let contract_id = self - .contract_id - .as_ref() - .ok_or(Error::MissingWasmOrContractId)?; - - let network = self.network.get(&self.locator).ok().unwrap_or_else(|| { - network::DEFAULTS - .get("testnet") - .expect("no network specified and testnet network not found") - .into() - }); - print.infoln(format!("Network: {}", network.network_passphrase)); - - let contract_id = self - .locator - .resolve_contract_id(contract_id, &network.network_passphrase)? - .0; + let contract_spec::Fetched { contract, source } = + contract_spec::fetch(&self.wasm_or_hash_or_contract_id, &print).await?; - let contract_address = ScAddress::Contract(Hash(contract_id)).to_string(); - print.globeln(format!("Downloading contract spec: {contract_address}")); - - ( - get_remote_contract_spec( - &contract_id, - &self.locator, - &self.network, - global_args, - config, - ) - .await - .map_err(Error::from)?, - Some(contract_address), - Some(network.rpc_url), - Some(network.network_passphrase), - ) + let spec = match contract { + contract_spec::Contract::Wasm { wasm_bytes } => Spec::new(&wasm_bytes)?.spec, + contract_spec::Contract::StellarAssetContract => { + soroban_spec::read::parse_raw(&soroban_sdk::token::StellarAssetSpec::spec_xdr())? + } }; + if self.output_dir.is_file() { return Err(Error::IsFile(self.output_dir.clone())); } @@ -147,14 +89,22 @@ impl NetworkRunnable for Cmd { let contract_name = &file_name .to_str() .ok_or_else(|| Error::NotUtf8(file_name.to_os_string()))?; - if let Some(contract_address) = contract_address.clone() { - print.infoln(format!("Embedding contract address: {contract_address}")); - } + let (resolved_address, network) = match source { + contract_spec::Source::Contract { + resolved_address, + network, + } => { + print.infoln(format!("Embedding contract address: {resolved_address}")); + (Some(resolved_address), Some(network)) + } + contract_spec::Source::Wasm { network, .. } => (None, Some(network)), + contract_spec::Source::File { .. } => (None, None), + }; p.init( contract_name, - contract_address.as_deref(), - rpc_url.as_deref(), - network_passphrase.as_deref(), + resolved_address.as_deref(), + network.as_ref().map(|n| n.rpc_url.as_ref()), + network.as_ref().map(|n| n.network_passphrase.as_ref()), &spec, )?; print.checkln("Generated!"); diff --git a/cmd/soroban-cli/src/commands/contract/info.rs b/cmd/soroban-cli/src/commands/contract/info.rs index 5ca03ab2c..6192c1c61 100644 --- a/cmd/soroban-cli/src/commands/contract/info.rs +++ b/cmd/soroban-cli/src/commands/contract/info.rs @@ -1,9 +1,11 @@ use std::fmt::Debug; +use crate::commands::global; + pub mod env_meta; pub mod interface; pub mod meta; -mod shared; +pub mod shared; #[derive(Debug, clap::Subcommand)] pub enum Cmd { @@ -60,11 +62,11 @@ pub enum Error { } impl Cmd { - pub async fn run(&self) -> Result<(), Error> { + pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { let result = match &self { - Cmd::Interface(interface) => interface.run().await?, - Cmd::Meta(meta) => meta.run().await?, - Cmd::EnvMeta(env_meta) => env_meta.run().await?, + Cmd::Interface(interface) => interface.run(global_args).await?, + Cmd::Meta(meta) => meta.run(global_args).await?, + Cmd::EnvMeta(env_meta) => env_meta.run(global_args).await?, }; println!("{result}"); Ok(()) diff --git a/cmd/soroban-cli/src/commands/contract/info/env_meta.rs b/cmd/soroban-cli/src/commands/contract/info/env_meta.rs index bc2d03bc6..02da6f439 100644 --- a/cmd/soroban-cli/src/commands/contract/info/env_meta.rs +++ b/cmd/soroban-cli/src/commands/contract/info/env_meta.rs @@ -6,10 +6,14 @@ use soroban_spec_tools::contract; use soroban_spec_tools::contract::Spec; use crate::{ - commands::contract::info::{ - env_meta::Error::{NoEnvMetaPresent, NoSACEnvMeta}, - shared::{self, fetch_wasm, MetasInfoOutput}, + commands::{ + contract::info::{ + env_meta::Error::{NoEnvMetaPresent, NoSACEnvMeta}, + shared::{self, fetch, Fetched, MetasInfoOutput}, + }, + global, }, + print::Print, xdr::{ScEnvMetaEntry, ScEnvMetaEntryInterfaceVersion}, }; @@ -37,13 +41,14 @@ pub enum Error { } impl Cmd { - pub async fn run(&self) -> Result { - let bytes = fetch_wasm(&self.common).await?; + pub async fn run(&self, global_args: &global::Args) -> Result { + let print = Print::new(global_args.quiet); + let Fetched { contract, .. } = fetch(&self.common, &print).await?; - let Some(bytes) = bytes else { - return Err(NoSACEnvMeta()); + let spec = match contract { + shared::Contract::Wasm { wasm_bytes } => Spec::new(&wasm_bytes)?, + shared::Contract::StellarAssetContract => return Err(NoSACEnvMeta()), }; - let spec = Spec::new(&bytes)?; let Some(env_meta_base64) = spec.env_meta_base64 else { return Err(NoEnvMetaPresent()); diff --git a/cmd/soroban-cli/src/commands/contract/info/interface.rs b/cmd/soroban-cli/src/commands/contract/info/interface.rs index cf96fd700..0c896bc3d 100644 --- a/cmd/soroban-cli/src/commands/contract/info/interface.rs +++ b/cmd/soroban-cli/src/commands/contract/info/interface.rs @@ -1,8 +1,9 @@ use std::fmt::Debug; use crate::commands::contract::info::interface::Error::NoInterfacePresent; -use crate::commands::contract::info::shared; -use crate::commands::contract::info::shared::fetch_wasm; +use crate::commands::contract::info::shared::{self, fetch, Fetched}; +use crate::commands::global; +use crate::print::Print; use clap::{command, Parser}; use soroban_spec_rust::ToFormattedString; use soroban_spec_tools::contract; @@ -43,19 +44,23 @@ pub enum Error { } impl Cmd { - pub async fn run(&self) -> Result { - let bytes = fetch_wasm(&self.common).await?; + pub async fn run(&self, global_args: &global::Args) -> Result { + let print = Print::new(global_args.quiet); + let Fetched { contract, .. } = fetch(&self.common, &print).await?; - let (base64, spec) = if bytes.is_none() { - Spec::spec_to_base64(&soroban_sdk::token::StellarAssetSpec::spec_xdr())? - } else { - let spec = Spec::new(&bytes.unwrap())?; + let (base64, spec) = match contract { + shared::Contract::Wasm { wasm_bytes } => { + let spec = Spec::new(&wasm_bytes)?; - if spec.env_meta_base64.is_none() { - return Err(NoInterfacePresent()); - } + if spec.env_meta_base64.is_none() { + return Err(NoInterfacePresent()); + } - (spec.spec_base64.unwrap(), spec.spec) + (spec.spec_base64.unwrap(), spec.spec) + } + shared::Contract::StellarAssetContract => { + Spec::spec_to_base64(&soroban_sdk::token::StellarAssetSpec::spec_xdr())? + } }; let res = match self.output { diff --git a/cmd/soroban-cli/src/commands/contract/info/meta.rs b/cmd/soroban-cli/src/commands/contract/info/meta.rs index e3e2122c8..736e8f432 100644 --- a/cmd/soroban-cli/src/commands/contract/info/meta.rs +++ b/cmd/soroban-cli/src/commands/contract/info/meta.rs @@ -1,8 +1,9 @@ use std::fmt::Debug; use crate::commands::contract::info::meta::Error::{NoMetaPresent, NoSACMeta}; -use crate::commands::contract::info::shared; -use crate::commands::contract::info::shared::{fetch_wasm, MetasInfoOutput}; +use crate::commands::contract::info::shared::{self, fetch, Fetched, MetasInfoOutput}; +use crate::commands::global; +use crate::print::Print; use clap::{command, Parser}; use soroban_spec_tools::contract; use soroban_spec_tools::contract::Spec; @@ -32,13 +33,14 @@ pub enum Error { } impl Cmd { - pub async fn run(&self) -> Result { - let bytes = fetch_wasm(&self.common).await?; + pub async fn run(&self, global_args: &global::Args) -> Result { + let print = Print::new(global_args.quiet); + let Fetched { contract, .. } = fetch(&self.common, &print).await?; - let Some(bytes) = bytes else { - return Err(NoSACMeta()); + let spec = match contract { + shared::Contract::Wasm { wasm_bytes } => Spec::new(&wasm_bytes)?, + shared::Contract::StellarAssetContract => return Err(NoSACMeta()), }; - let spec = Spec::new(&bytes)?; let Some(meta_base64) = spec.meta_base64 else { return Err(NoMetaPresent()); diff --git a/cmd/soroban-cli/src/commands/contract/info/shared.rs b/cmd/soroban-cli/src/commands/contract/info/shared.rs index 33a95b607..6023b03cf 100644 --- a/cmd/soroban-cli/src/commands/contract/info/shared.rs +++ b/cmd/soroban-cli/src/commands/contract/info/shared.rs @@ -4,7 +4,11 @@ use clap::arg; use crate::{ commands::contract::info::shared::Error::InvalidWasmHash, - config::{self, locator, network}, + config::{ + self, locator, + network::{self, Network}, + }, + print::Print, utils::rpc::get_remote_wasm_from_hash, wasm::{self, Error::ContractIsStellarAsset}, xdr, @@ -18,14 +22,31 @@ use crate::{ ))] #[group(skip)] pub struct Args { - /// Wasm file to extract the data from - #[arg(long, group = "Source")] + /// Wasm file path on local filesystem. Provide this OR `--wasm-hash` OR `--contract-id`. + #[arg( + long, + group = "Source", + conflicts_with = "contract_id", + conflicts_with = "wasm_hash" + )] pub wasm: Option, - /// Wasm hash to get the data for - #[arg(long = "wasm-hash", group = "Source")] + /// Hash of Wasm blob on a network. Provide this OR `--wasm` OR `--contract-id`. + #[arg( + long = "wasm-hash", + group = "Source", + conflicts_with = "contract_id", + conflicts_with = "wasm" + )] pub wasm_hash: Option, - /// Contract id or contract alias to get the data for - #[arg(long = "id", env = "STELLAR_CONTRACT_ID", group = "Source")] + /// Contract ID/alias on a network. Provide this OR `--wasm-hash` OR `--wasm`. + #[arg( + long, + env = "STELLAR_CONTRACT_ID", + group = "Source", + visible_alias = "id", + conflicts_with = "wasm", + conflicts_with = "wasm_hash" + )] pub contract_id: Option, #[command(flatten)] pub network: network::Args, @@ -54,23 +75,66 @@ pub enum Error { Wasm(#[from] wasm::Error), #[error("provided wasm hash is invalid {0:?}")] InvalidWasmHash(String), + #[error("must provide one of --wasm, --wasm-hash, or --contract-id")] + MissingArg, #[error(transparent)] Rpc(#[from] soroban_rpc::Error), #[error(transparent)] Locator(#[from] locator::Error), } -pub async fn fetch_wasm(args: &Args) -> Result>, Error> { +pub struct Fetched { + pub contract: Contract, + pub source: Source, +} + +pub enum Contract { + Wasm { wasm_bytes: Vec }, + StellarAssetContract, +} + +pub enum Source { + File { + path: PathBuf, + }, + Wasm { + hash: String, + network: Network, + }, + Contract { + resolved_address: String, + network: Network, + }, +} + +impl Source { + pub fn network(&self) -> Option<&Network> { + match self { + Source::File { .. } => None, + Source::Wasm { ref network, .. } | Source::Contract { ref network, .. } => { + Some(network) + } + } + } +} + +pub async fn fetch(args: &Args, print: &Print) -> Result { // Check if a local WASM file path is provided if let Some(path) = &args.wasm { // Read the WASM file and return its contents + print.infoln("Loading contract spec from file..."); let wasm_bytes = wasm::Args { wasm: path.clone() }.read()?; - return Ok(Some(wasm_bytes)); + return Ok(Fetched { + contract: Contract::Wasm { wasm_bytes }, + source: Source::File { path: path.clone() }, + }); } // If no local wasm, then check for wasm_hash and fetch from the network let network = &args.network.get(&args.locator)?; - let wasm = if let Some(wasm_hash) = &args.wasm_hash { + print.infoln(format!("Network: {}", network.network_passphrase)); + + if let Some(wasm_hash) = &args.wasm_hash { let hash = hex::decode(wasm_hash) .map_err(|_| InvalidWasmHash(wasm_hash.clone()))? .try_into() @@ -84,18 +148,40 @@ pub async fn fetch_wasm(args: &Args) -> Result>, Error> { .verify_network_passphrase(Some(&network.network_passphrase)) .await?; - get_remote_wasm_from_hash(&client, &hash).await? + print.globeln(format!( + "Downloading contract spec for wasm hash: {wasm_hash}" + )); + let wasm_bytes = get_remote_wasm_from_hash(&client, &hash).await?; + Ok(Fetched { + contract: Contract::Wasm { wasm_bytes }, + source: Source::Wasm { + hash: wasm_hash.clone(), + network: network.clone(), + }, + }) } else if let Some(contract_id) = &args.contract_id { let contract_id = contract_id.resolve_contract_id(&args.locator, &network.network_passphrase)?; + let derived_address = xdr::ScAddress::Contract(xdr::Hash(contract_id.0)).to_string(); + print.globeln(format!("Downloading contract spec: {derived_address}")); let res = wasm::fetch_from_contract(&contract_id, network).await; if let Some(ContractIsStellarAsset) = res.as_ref().err() { - return Ok(None); + return Ok(Fetched { + contract: Contract::StellarAssetContract, + source: Source::Contract { + resolved_address: derived_address, + network: network.clone(), + }, + }); } - res? + Ok(Fetched { + contract: Contract::Wasm { wasm_bytes: res? }, + source: Source::Contract { + resolved_address: derived_address, + network: network.clone(), + }, + }) } else { - unreachable!("One of contract location arguments must be passed"); - }; - - Ok(Some(wasm)) + return Err(Error::MissingArg); + } } diff --git a/cmd/soroban-cli/src/commands/contract/mod.rs b/cmd/soroban-cli/src/commands/contract/mod.rs index d72ce62b6..42792a70d 100644 --- a/cmd/soroban-cli/src/commands/contract/mod.rs +++ b/cmd/soroban-cli/src/commands/contract/mod.rs @@ -151,7 +151,7 @@ impl Cmd { Cmd::Alias(alias) => alias.run(global_args)?, Cmd::Deploy(deploy) => deploy.run(global_args).await?, Cmd::Id(id) => id.run()?, - Cmd::Info(info) => info.run().await?, + Cmd::Info(info) => info.run(global_args).await?, Cmd::Init(init) => init.run(global_args)?, Cmd::Inspect(inspect) => inspect.run(global_args)?, Cmd::Install(install) => install.run(global_args).await?, diff --git a/cmd/soroban-cli/src/commands/keys/add.rs b/cmd/soroban-cli/src/commands/keys/add.rs index d8f528bae..af829fe6f 100644 --- a/cmd/soroban-cli/src/commands/keys/add.rs +++ b/cmd/soroban-cli/src/commands/keys/add.rs @@ -1,6 +1,10 @@ use clap::command; -use crate::config::{locator, secret}; +use crate::{ + commands::global, + config::{locator, secret}, + print::Print, +}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -25,9 +29,11 @@ pub struct Cmd { } impl Cmd { - pub fn run(&self) -> Result<(), Error> { - Ok(self - .config_locator - .write_identity(&self.name, &self.secrets.read_secret()?)?) + pub fn run(&self, global_args: &global::Args) -> Result<(), Error> { + let print = Print::new(global_args.quiet); + let secret = self.secrets.read_secret()?; + let path = self.config_locator.write_identity(&self.name, &secret)?; + print.checkln(format!("Key saved with alias {:?} in {path:?}", self.name)); + Ok(()) } } diff --git a/cmd/soroban-cli/src/commands/keys/fund.rs b/cmd/soroban-cli/src/commands/keys/fund.rs index d7100c6cb..2419c4be2 100644 --- a/cmd/soroban-cli/src/commands/keys/fund.rs +++ b/cmd/soroban-cli/src/commands/keys/fund.rs @@ -1,6 +1,6 @@ use clap::command; -use crate::config::network; +use crate::{commands::global, config::network, print::Print}; use super::address; @@ -23,12 +23,15 @@ pub struct Cmd { } impl Cmd { - pub async fn run(&self) -> Result<(), Error> { + pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { + let print = Print::new(global_args.quiet); let addr = self.address.public_key()?; - self.network - .get(&self.address.locator)? - .fund_address(&addr) - .await?; + let network = self.network.get(&self.address.locator)?; + network.fund_address(&addr).await?; + print.checkln(format!( + "Account {:?} funded on {:?}", + self.address.name, network.network_passphrase + )); Ok(()) } } diff --git a/cmd/soroban-cli/src/commands/keys/generate.rs b/cmd/soroban-cli/src/commands/keys/generate.rs index c6623386c..fda6a3d98 100644 --- a/cmd/soroban-cli/src/commands/keys/generate.rs +++ b/cmd/soroban-cli/src/commands/keys/generate.rs @@ -96,7 +96,8 @@ impl Cmd { seed_phrase }; - self.config_locator.write_identity(&self.name, &secret)?; + let path = self.config_locator.write_identity(&self.name, &secret)?; + print.checkln(format!("Key saved with alias {:?} in {path:?}", self.name)); if !self.no_fund { let addr = secret.public_key(self.hd_path)?; @@ -108,6 +109,10 @@ impl Cmd { tracing::warn!("fund_address failed: {e}"); }) .unwrap_or_default(); + print.checkln(format!( + "Account {:?} funded on {:?}", + self.name, network.network_passphrase + )); } Ok(()) diff --git a/cmd/soroban-cli/src/commands/keys/mod.rs b/cmd/soroban-cli/src/commands/keys/mod.rs index 8729ee9af..b5520abf6 100644 --- a/cmd/soroban-cli/src/commands/keys/mod.rs +++ b/cmd/soroban-cli/src/commands/keys/mod.rs @@ -8,7 +8,7 @@ pub mod fund; pub mod generate; pub mod ls; pub mod rm; -pub mod show; +pub mod secret; #[derive(Debug, Parser)] pub enum Cmd { @@ -30,8 +30,8 @@ pub enum Cmd { /// Remove an identity Rm(rm::Cmd), - /// Given an identity return its private key - Show(show::Cmd), + /// Output an identity's secret key + Secret(secret::Cmd), /// Set the default identity that will be used on all commands. /// This allows you to skip `--source-account` or setting a environment @@ -61,7 +61,7 @@ pub enum Error { Ls(#[from] ls::Error), #[error(transparent)] - Show(#[from] show::Error), + Show(#[from] secret::Error), #[error(transparent)] Default(#[from] default::Error), @@ -70,13 +70,13 @@ pub enum Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { match self { - Cmd::Add(cmd) => cmd.run()?, + Cmd::Add(cmd) => cmd.run(global_args)?, Cmd::Address(cmd) => cmd.run()?, - Cmd::Fund(cmd) => cmd.run().await?, + Cmd::Fund(cmd) => cmd.run(global_args).await?, Cmd::Generate(cmd) => cmd.run(global_args).await?, Cmd::Ls(cmd) => cmd.run()?, Cmd::Rm(cmd) => cmd.run()?, - Cmd::Show(cmd) => cmd.run()?, + Cmd::Secret(cmd) => cmd.run()?, Cmd::Default(cmd) => cmd.run(global_args)?, }; Ok(()) diff --git a/cmd/soroban-cli/src/commands/keys/show.rs b/cmd/soroban-cli/src/commands/keys/secret.rs similarity index 95% rename from cmd/soroban-cli/src/commands/keys/show.rs rename to cmd/soroban-cli/src/commands/keys/secret.rs index 58c47740c..d28445247 100644 --- a/cmd/soroban-cli/src/commands/keys/show.rs +++ b/cmd/soroban-cli/src/commands/keys/secret.rs @@ -16,6 +16,7 @@ pub enum Error { #[derive(Debug, clap::Parser, Clone)] #[group(skip)] +#[command(name = "secret", alias = "show")] pub struct Cmd { /// Name of identity to lookup, default is test identity pub name: String, diff --git a/cmd/soroban-cli/src/commands/mod.rs b/cmd/soroban-cli/src/commands/mod.rs index 25d61364d..a12347126 100644 --- a/cmd/soroban-cli/src/commands/mod.rs +++ b/cmd/soroban-cli/src/commands/mod.rs @@ -143,9 +143,12 @@ pub enum Cmd { /// Watch the network for contract events Events(events::Cmd), - /// Prints the current environment variables or defaults to the stdout, in - /// a format that can be used as .env file. Environment variables have - /// precedency over defaults. + /// Prints the environment variables + /// + /// Prints to stdout in a format that can be used as .env file. Environment + /// variables have precedence over defaults. + /// + /// If there are no environment variables in use, prints the defaults. Env(env::Cmd), /// Create and manage identities including keys and addresses diff --git a/cmd/soroban-cli/src/commands/network/add.rs b/cmd/soroban-cli/src/commands/network/add.rs index 20b1afa7b..feeea9030 100644 --- a/cmd/soroban-cli/src/commands/network/add.rs +++ b/cmd/soroban-cli/src/commands/network/add.rs @@ -25,8 +25,8 @@ pub struct Cmd { impl Cmd { pub fn run(&self) -> Result<(), Error> { - Ok(self - .config_locator - .write_network(&self.name, &self.network)?) + self.config_locator + .write_network(&self.name, &self.network)?; + Ok(()) } } diff --git a/cmd/soroban-cli/src/commands/snapshot/create.rs b/cmd/soroban-cli/src/commands/snapshot/create.rs index 6ce48d3f2..a3ba865fa 100644 --- a/cmd/soroban-cli/src/commands/snapshot/create.rs +++ b/cmd/soroban-cli/src/commands/snapshot/create.rs @@ -274,7 +274,13 @@ impl Cmd { } BucketEntry::Deadentry(k) => (k, None), BucketEntry::Metaentry(m) => { - snapshot.protocol_version = m.ledger_version; + if m.ledger_version > snapshot.protocol_version { + snapshot.protocol_version = m.ledger_version; + print.infoln(format!( + "Protocol version: {}", + snapshot.protocol_version + )); + } continue; } }; diff --git a/cmd/soroban-cli/src/config/locator.rs b/cmd/soroban-cli/src/config/locator.rs index b6f5c75c1..7e97f6796 100644 --- a/cmd/soroban-cli/src/config/locator.rs +++ b/cmd/soroban-cli/src/config/locator.rs @@ -162,11 +162,11 @@ impl Args { ) } - pub fn write_identity(&self, name: &str, secret: &Secret) -> Result<(), Error> { + pub fn write_identity(&self, name: &str, secret: &Secret) -> Result { KeyType::Identity.write(name, secret, &self.config_dir()?) } - pub fn write_network(&self, name: &str, network: &Network) -> Result<(), Error> { + pub fn write_network(&self, name: &str, network: &Network) -> Result { KeyType::Network.write(name, network, &self.config_dir()?) } @@ -441,10 +441,14 @@ impl KeyType { key: &str, value: &T, pwd: &Path, - ) -> Result<(), Error> { + ) -> Result { let filepath = ensure_directory(self.path(pwd, key))?; let data = toml::to_string(value).map_err(|_| Error::ConfigSerialization)?; - std::fs::write(&filepath, data).map_err(|error| Error::IdCreationFailed { filepath, error }) + std::fs::write(&filepath, data).map_err(|error| Error::IdCreationFailed { + filepath: filepath.clone(), + error, + })?; + Ok(filepath) } fn root(&self, pwd: &Path) -> PathBuf { diff --git a/cmd/soroban-cli/src/config/network.rs b/cmd/soroban-cli/src/config/network.rs index 829716753..e64a0ee77 100644 --- a/cmd/soroban-cli/src/config/network.rs +++ b/cmd/soroban-cli/src/config/network.rs @@ -170,7 +170,7 @@ impl Network { local_url.set_query(Some(&format!("addr={addr}"))); Ok(local_url) } else { - let client = Client::new(&self.rpc_url)?; + let client = self.rpc_client()?; let network = client.get_network().await?; tracing::debug!("network {network:?}"); let url = client.friendbot_url().await?; diff --git a/cmd/soroban-cli/src/config/secret.rs b/cmd/soroban-cli/src/config/secret.rs index a7fd86fda..00cec12f6 100644 --- a/cmd/soroban-cli/src/config/secret.rs +++ b/cmd/soroban-cli/src/config/secret.rs @@ -11,8 +11,6 @@ use crate::{ #[derive(thiserror::Error, Debug)] pub enum Error { - #[error("invalid secret key")] - InvalidSecretKey, // #[error("seed_phrase must be 12 words long, found {len}")] // InvalidSeedPhrase { len: usize }, #[error("secret input error")] @@ -23,8 +21,8 @@ pub enum Error { SeedPhrase(#[from] sep5::error::Error), #[error(transparent)] Ed25519(#[from] ed25519_dalek::SignatureError), - #[error("Invalid address {0}")] - InvalidAddress(String), + #[error("cannot parse secret (S) or seed phrase (12 or 24 word)")] + InvalidSecretOrSeedPhrase, #[error(transparent)] Signer(#[from] signer::Error), } @@ -32,12 +30,11 @@ pub enum Error { #[derive(Debug, clap::Args, Clone)] #[group(skip)] pub struct Args { - /// Add using `secret_key` - /// Can provide with `SOROBAN_SECRET_KEY` - #[arg(long, conflicts_with = "seed_phrase")] + /// (deprecated) Enter secret (S) key when prompted + #[arg(long)] pub secret_key: bool, - /// Add using 12 word seed phrase to generate `secret_key` - #[arg(long, conflicts_with = "secret_key")] + /// (deprecated) Enter key using 12-24 word seed phrase + #[arg(long)] pub seed_phrase: bool, } @@ -45,30 +42,12 @@ impl Args { pub fn read_secret(&self) -> Result { if let Ok(secret_key) = std::env::var("SOROBAN_SECRET_KEY") { Ok(Secret::SecretKey { secret_key }) - } else if self.secret_key { - println!("Type a secret key: "); - let secret_key = read_password()?; - let secret_key = PrivateKey::from_string(&secret_key) - .map_err(|_| Error::InvalidSecretKey)? - .to_string(); - Ok(Secret::SecretKey { secret_key }) - } else if self.seed_phrase { - println!("Type a 12 word seed phrase: "); - let seed_phrase = read_password()?; - let seed_phrase: Vec<&str> = seed_phrase.split_whitespace().collect(); - // if seed_phrase.len() != 12 { - // let len = seed_phrase.len(); - // return Err(Error::InvalidSeedPhrase { len }); - // } - Ok(Secret::SeedPhrase { - seed_phrase: seed_phrase - .into_iter() - .map(ToString::to_string) - .collect::>() - .join(" "), - }) } else { - Err(Error::PasswordRead {}) + println!("Type a secret key or 12/24 word seed phrase:"); + let secret_key = read_password()?; + secret_key + .parse() + .map_err(|_| Error::InvalidSecretOrSeedPhrase) } } } @@ -93,7 +72,7 @@ impl FromStr for Secret { seed_phrase: s.to_string(), }) } else { - Err(Error::InvalidAddress(s.to_string())) + Err(Error::InvalidSecretOrSeedPhrase) } } } @@ -144,7 +123,7 @@ impl Secret { let seed_phrase = if let Some(seed) = seed.map(str::as_bytes) { sep5::SeedPhrase::from_entropy(seed) } else { - sep5::SeedPhrase::random(sep5::MnemonicType::Words12) + sep5::SeedPhrase::random(sep5::MnemonicType::Words24) }? .seed_phrase .into_phrase(); diff --git a/cmd/soroban-cli/src/get_spec.rs b/cmd/soroban-cli/src/get_spec.rs index 26e609543..f2da15863 100644 --- a/cmd/soroban-cli/src/get_spec.rs +++ b/cmd/soroban-cli/src/get_spec.rs @@ -44,7 +44,7 @@ pub async fn get_remote_contract_spec( |c| c.get_network().map_err(Error::from), )?; tracing::trace!(?network); - let client = rpc::Client::new(&network.rpc_url)?; + let client = network.rpc_client()?; // Get contract data let r = client.get_contract_data(contract_id).await?; tracing::trace!("{r:?}"); diff --git a/deny.toml b/deny.toml index 9817c3e79..600bfec02 100644 --- a/deny.toml +++ b/deny.toml @@ -110,6 +110,7 @@ allow = [ "Unicode-DFS-2016", "ISC", "BSD-2-Clause", + "CC0-1.0", ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses