diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index d913cf23d..48e2e5657 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -46,7 +46,7 @@ jobs: - run: rustup target add ${{ matrix.sys.target }} - if: matrix.sys.target == 'aarch64-unknown-linux-gnu' - run: sudo apt-get update && sudo apt-get -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libudev-dev + run: sudo apt-get update && sudo apt-get -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libudev-dev libdbus-1-dev - name: Setup vars run: | @@ -69,6 +69,7 @@ jobs: env: CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc working-directory: ${{ env.BUILD_WORKING_DIR }} + run: sudo apt-get update && sudo apt-get -y install libdbus-1-dev run: cargo build --target-dir="$GITHUB_WORKSPACE/target" --package ${{ matrix.crate.name }} --features opt --release --target ${{ matrix.sys.target }} - name: Build provenance for attestation (release only) @@ -157,6 +158,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 957661c4c..7f87baf08 100644 --- a/.github/workflows/bindings-ts.yml +++ b/.github/workflows/bindings-ts.yml @@ -19,11 +19,14 @@ 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 steps: + - uses: actions/setup-node@v4 + with: + node-version: '22.x' - uses: actions/checkout@v4 - uses: actions/cache@v4 with: @@ -35,6 +38,7 @@ jobs: target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - run: rustup update + - run: sudo apt install -y libdbus-1-dev - run: cargo build - run: rustup target add wasm32-unknown-unknown - run: make build-test-wasms diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ac0f6ca20..25beb9440 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,10 +9,9 @@ defaults: shell: bash jobs: - publish: uses: stellar/actions/.github/workflows/rust-publish.yml@main with: - additional-deb-packages: libudev-dev + additional-deb-packages: libudev-dev libdbus-1-dev secrets: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/rpc-tests.yml b/.github/workflows/rpc-tests.yml index 75b6d7760..5392d9830 100644 --- a/.github/workflows/rpc-tests.yml +++ b/.github/workflows/rpc-tests.yml @@ -39,6 +39,7 @@ jobs: target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - run: rustup update + - run: sudo apt install -y libdbus-1-dev - run: cargo build - run: rustup target add wasm32-unknown-unknown - run: make build-test-wasms diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f3c9b1920..b9334c7d5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -49,6 +49,7 @@ jobs: - uses: actions/checkout@v4 - uses: stellar/actions/rust-cache@main - run: rustup update + - run: sudo apt install -y libdbus-1-dev - run: make generate-full-help-doc - run: git add -N . && git diff HEAD --exit-code @@ -90,7 +91,7 @@ jobs: - run: rustup target add ${{ matrix.sys.target }} - run: rustup target add wasm32-unknown-unknown - if: runner.os == 'Linux' - run: sudo apt-get update && sudo apt-get -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libudev-dev + run: sudo apt-get update && sudo apt-get -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libudev-dev libdbus-1-dev - run: cargo clippy --all-targets --target ${{ matrix.sys.target }} - run: make test env: @@ -106,12 +107,12 @@ jobs: - os: ubuntu-latest-16-cores target: x86_64-unknown-linux-gnu cargo-hack-feature-options: --feature-powerset - additional-deb-packages: libudev-dev + additional-deb-packages: libudev-dev libdbus-1-dev # TODO: add back ARM support #- os: ubuntu-latest-16-cores # target: aarch64-unknown-linux-gnu # cargo-hack-feature-options: --feature-powerset - # additional-deb-packages: libudev-dev libssl-dev + # additional-deb-packages: libudev-dev libssl-dev libdbus-1-dev - os: macos-latest target: x86_64-apple-darwin cargo-hack-feature-options: --feature-powerset diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..582ca41ec --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,23 @@ +name: 'Stale Issues / PRs' + +on: + workflow_dispatch: + schedule: + - cron: '0 18 * * *' # approx 9:30am daily + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + debug-only: false + days-before-stale: 30 + days-before-close: 90 + stale-issue-message: 'This issue is stale because it has been assigned for 30 days with no activity. It will be closed in 90 days unless the stale label is removed, and the assignee is removed or updated.' + stale-pr-message: 'This pull request is stale because it has been open for 30 days with no activity. It will be closed in 90 days unless the stale label is removed.' + stale-issue-label: stale + stale-pr-label: stale + remove-stale-when-updated: true + delete-branch: true + include-only-assigned: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c54767c6..c74ad1eb8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,7 +73,7 @@ should initially look like this. > origin https://github.com/YOUR_USERNAME/stellar-cli.git (push) ``` -* Set the `stellar/stellar-cli` repo as new remote upstream repository that will +* Set the `stellar/stellar-cli` repo as the remote upstream repository that will sync with your fork. ``` git remote add upstream https://github.com/stellar/stellar-cli.git diff --git a/Cargo.lock b/Cargo.lock index fe1980fc5..b6f61ec26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -510,7 +516,7 @@ checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -535,7 +541,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -596,6 +602,25 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" +dependencies = [ + "bincode_derive", + "serde", +] + +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c" +dependencies = [ + "virtue", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -748,7 +773,7 @@ dependencies = [ "num-bigint", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -868,7 +893,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1058,12 +1083,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1090,7 +1115,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1117,7 +1142,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1134,7 +1159,7 @@ checksum = "b45506e3c66512b0a65d291a6b452128b7b1dd9841e20d1e151addbd2c00ea50" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1158,7 +1183,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1169,7 +1194,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1178,6 +1203,30 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "dbus" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +dependencies = [ + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "dbus-secret-service" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42a16374481d92aed73ae45b1f120207d8e71d24fb89f357fadbd8f946fd84b" +dependencies = [ + "dbus", + "futures-util", + "num", + "once_cell", + "rand", +] + [[package]] name = "der" version = "0.7.9" @@ -1217,7 +1266,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1428,7 +1477,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -1564,7 +1613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.4", ] [[package]] @@ -1702,7 +1751,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -2580,6 +2629,18 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keyring" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fa83d1ca02db069b5fbe94b23b584d588e989218310c9c15015bb5571ef1a94" +dependencies = [ + "byteorder 1.5.0", + "dbus-secret-service", + "security-framework", + "windows-sys 0.59.0", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -2681,6 +2742,15 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libdbus-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "pkg-config", +] + [[package]] name = "libm" version = "0.2.8" @@ -2697,6 +2767,23 @@ dependencies = [ "libc", ] +[[package]] +name = "license-fetcher" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904bd80dd046aa1c625ddfd81c88a85a54ff3ca0ddcce0ca1ad9c8d7b6db185d" +dependencies = [ + "bincode", + "directories", + "log", + "miniz_oxide 0.8.3", + "once_cell", + "regex", + "serde", + "serde_json", + "simplelog", +] + [[package]] name = "link-cplusplus" version = "1.0.9" @@ -2788,6 +2875,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.1" @@ -2869,6 +2965,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -2880,6 +2990,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2894,7 +3013,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -2907,6 +3026,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -2916,6 +3058,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.32.2" @@ -2971,7 +3122,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -3067,7 +3218,7 @@ dependencies = [ "regex", "regex-syntax 0.8.4", "structmeta", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -3137,7 +3288,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -3181,7 +3332,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -3322,7 +3473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -3629,7 +3780,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.77", + "syn 2.0.87", "walkdir", ] @@ -3881,7 +4032,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -3971,9 +4122,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.192" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -3991,13 +4142,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -4008,16 +4159,17 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -4040,7 +4192,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -4091,7 +4243,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -4116,7 +4268,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -4199,6 +4351,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -4275,19 +4438,19 @@ dependencies = [ [[package]] name = "soroban-builtin-sdk-macros" -version = "22.0.0-rc.3" +version = "22.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c45d2492cd44f05cc79eeb857985f153f12a4423ce51b4b746b5925024c473b1" +checksum = "8ebed97f583127b391cc8137d5e475e66ba4e12f428dd6c9aed7a914bbd2353e" dependencies = [ "itertools 0.10.5", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] name = "soroban-cli" -version = "22.0.1" +version = "22.2.0" dependencies = [ "assert_cmd", "assert_fs", @@ -4319,6 +4482,8 @@ dependencies = [ "itertools 0.10.5", "jsonrpsee-core", "jsonrpsee-http-client", + "keyring", + "license-fetcher", "mockito", "num-bigint", "open", @@ -4369,13 +4534,15 @@ dependencies = [ "wasm-opt", "wasmparser", "which", + "whoami", + "zeroize", ] [[package]] name = "soroban-env-common" -version = "22.0.0-rc.3" +version = "22.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39b6d2ec8955243394278e1fae88be3b367fcfed9cf74e5044799a90786a8642" +checksum = "94ce037307fcd6d775f2b567ae10d5eb9b99eacb2b1110e9b23ed92b351e47f4" dependencies = [ "arbitrary", "crate-git-revision", @@ -4392,9 +4559,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "22.0.0-rc.3" +version = "22.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4002fc582cd20cc9b9fbb73959bc5d6b5b15feda11485cbfab0c28e78ecbab3e" +checksum = "b395eaf56d155529a3951c0ad54420599184a810db86d7316b97cc59b97e5b85" dependencies = [ "soroban-env-common", "static_assertions", @@ -4402,9 +4569,9 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "22.0.0-rc.3" +version = "22.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb9be0260d39a648db0d33e1c6f8f494ec0c4f5be2b8a0a4e15ed4b7c6a92b0" +checksum = "cb980b49637cc428fab2442a97800ac2ed9ced39422acf4840f77ab596858cae" dependencies = [ "ark-bls12-381", "ark-ec", @@ -4438,9 +4605,9 @@ dependencies = [ [[package]] name = "soroban-env-macros" -version = "22.0.0-rc.3" +version = "22.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a328297a568ae98999fdb06902e3362dfd8a2bfa9abea40beaeb7dc93a402fe7" +checksum = "ef84a5b3bfffc84250b22454d6ce9df6750afd5ed900faf7d02968400b9c8bd0" dependencies = [ "itertools 0.10.5", "proc-macro2", @@ -4448,18 +4615,18 @@ dependencies = [ "serde", "serde_json", "stellar-xdr", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] name = "soroban-hello" -version = "22.0.1" +version = "22.2.0" [[package]] name = "soroban-ledger-snapshot" -version = "22.0.0-rc.3" +version = "22.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56375490f176006a636db0e50c2269c55626e0ff7222711bb78d77028376fe0d" +checksum = "ac26413e0aac51844bec4ec60b5b86dc854c0152694637c78d9d9ccbc3b3c4b4" dependencies = [ "serde", "serde_json", @@ -4471,13 +4638,14 @@ dependencies = [ [[package]] name = "soroban-sdk" -version = "22.0.0-rc.3" +version = "22.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d063d0df000aaec20105aab3d743660322bc0269934ea95d79fa19aa8792385" +checksum = "cca32fb960f5cdd847cdb711f2f674748cc2cadf3887712d48fc00b9b5acb2ec" dependencies = [ "arbitrary", "bytes-lit", "ctor", + "derive_arbitrary", "ed25519-dalek", "rand", "rustc_version", @@ -4492,9 +4660,9 @@ dependencies = [ [[package]] name = "soroban-sdk-macros" -version = "22.0.0-rc.3" +version = "22.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "508c9d819a05109120664aab86c371e1b72c5bea20b1a13158b4ef7948d9f673" +checksum = "9fa7d8701b627f0e6a02a6a86a745401fb81e77a2b67aca3002332398625d7f1" dependencies = [ "crate-git-revision", "darling", @@ -4507,14 +4675,14 @@ dependencies = [ "soroban-spec", "soroban-spec-rust", "stellar-xdr", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] name = "soroban-spec" -version = "22.0.0-rc.3" +version = "22.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69001c97783ed3ce197eac2404e7beeabedd16e40e6f0aa210d1bc6a13063c33" +checksum = "413559f8b6c77af0cc97cd52cca0ecb59ad81004d3fd064711d91ea50274965a" dependencies = [ "base64 0.13.1", "stellar-xdr", @@ -4524,7 +4692,7 @@ dependencies = [ [[package]] name = "soroban-spec-json" -version = "22.0.1" +version = "22.2.0" dependencies = [ "pretty_assertions", "serde", @@ -4538,9 +4706,9 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "22.0.0-rc.3" +version = "22.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45dbf346f91ed23ea63b1c256c522da9e6f0e2db1887b990a8f0f1d842a3093" +checksum = "202e759a3f416b2a852c87beec1cbe8955d49d6c8b590b8386baef12e065261d" dependencies = [ "prettyplease", "proc-macro2", @@ -4548,13 +4716,13 @@ dependencies = [ "sha2 0.10.8", "soroban-spec", "stellar-xdr", - "syn 2.0.77", + "syn 2.0.87", "thiserror", ] [[package]] name = "soroban-spec-tools" -version = "22.0.1" +version = "22.2.0" dependencies = [ "base64 0.21.7", "ethnum", @@ -4572,7 +4740,7 @@ dependencies = [ [[package]] name = "soroban-spec-typescript" -version = "22.0.1" +version = "22.2.0" dependencies = [ "base64 0.21.7", "heck 0.4.1", @@ -4593,13 +4761,15 @@ dependencies = [ [[package]] name = "soroban-test" -version = "22.0.1" +version = "22.2.0" dependencies = [ "assert_cmd", "assert_fs", "ed25519-dalek", "fs_extra", "hex", + "home", + "httpmock", "predicates", "sep5", "serde_json", @@ -4620,9 +4790,9 @@ dependencies = [ [[package]] name = "soroban-token-sdk" -version = "22.0.0-rc.3" +version = "22.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bb933a3dcf41d234f6d669b077eb755663773630c6899a1c8a30dddf950f52" +checksum = "c14961339f6830772941bc28616951259bf75864558e70796a03f83e809faa07" dependencies = [ "soroban-sdk", ] @@ -4664,18 +4834,18 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-bye" -version = "22.0.1" +version = "22.2.0" [[package]] name = "stellar-cli" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-cli", ] [[package]] name = "stellar-ledger" -version = "22.0.1" +version = "22.2.0" dependencies = [ "async-trait", "bollard", @@ -4713,9 +4883,9 @@ dependencies = [ [[package]] name = "stellar-rpc-client" -version = "22.0.0-rc.1" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaba3219c517ceba11f99e1f9adb1e801fe8416bc9ff35c6842b5fe8cac19290" +checksum = "d7c4daeb7f113802cc4bcce8736be32bde243e8e2bf29dda76614b949ed445cf" dependencies = [ "clap", "hex", @@ -4771,9 +4941,9 @@ dependencies = [ [[package]] name = "stellar-xdr" -version = "22.0.0-rc.1.1" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c88dc0e928b9cb65ea43836b52560bb4ead3e32895f5019ca223dc7cd1966cbf" +checksum = "2ce69db907e64d1e70a3dce8d4824655d154749426a6132b25395c49136013e4" dependencies = [ "arbitrary", "base64 0.13.1", @@ -4817,7 +4987,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -4828,7 +4998,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -4887,9 +5057,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -5005,7 +5175,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -5016,48 +5186,48 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", "test-case-core", ] [[package]] name = "test_constructor" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_custom_account" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_custom_types" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_hello_world" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_swap" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-sdk", ] [[package]] name = "test_token" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-sdk", "soroban-token-sdk", @@ -5065,7 +5235,7 @@ dependencies = [ [[package]] name = "test_udt" -version = "22.0.1" +version = "22.2.0" dependencies = [ "soroban-sdk", ] @@ -5116,7 +5286,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -5137,7 +5307,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -5229,7 +5401,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -5393,7 +5565,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -5546,6 +5718,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" + [[package]] name = "wait-timeout" version = "0.2.0" @@ -5586,6 +5764,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -5607,7 +5791,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -5641,7 +5825,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5794,6 +5978,17 @@ dependencies = [ "rustix 0.38.34", ] +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "wasite", + "web-sys", +] + [[package]] name = "widestring" version = "1.1.0" @@ -6061,7 +6256,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] [[package]] @@ -6081,5 +6276,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.87", ] diff --git a/Cargo.toml b/Cargo.toml index cbfe6dd3c..8f1a64a62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,54 +16,55 @@ default-members = [ exclude = [ "cmd/crates/soroban-test/tests/fixtures/hello", "cmd/crates/soroban-test/tests/fixtures/bye", + "cmd/crates/soroban-test/tests/fixtures/eth_abi", ] [workspace.package] -version = "22.0.1" +version = "22.2.0" rust-version = "1.81.0" # Dependencies located in this repo: [workspace.dependencies.soroban-cli] -version = "=22.0.1" +version = "=22.2.0" path = "cmd/soroban-cli" [workspace.dependencies.soroban-spec-json] -version = "=22.0.1" +version = "=22.2.0" path = "./cmd/crates/soroban-spec-json" [workspace.dependencies.soroban-spec-typescript] -version = "22.0.1" +version = "22.2.0" path = "./cmd/crates/soroban-spec-typescript" [workspace.dependencies.soroban-spec-tools] -version = "22.0.1" +version = "22.2.0" path = "./cmd/crates/soroban-spec-tools" # Dependencies from the rs-stellar-xdr repo: [workspace.dependencies.stellar-xdr] -version = "=22.0.0-rc.1.1" +version = "=22.1.0" default-features = true # Dependencies from the rs-soroban-sdk repo: [workspace.dependencies.soroban-spec] -version = "=22.0.0-rc.3" +version = "=22.0.4" [workspace.dependencies.soroban-spec-rust] -version = "=22.0.0-rc.3" +version = "=22.0.4" [workspace.dependencies.soroban-sdk] -version = "=22.0.0-rc.3" +version = "=22.0.4" [workspace.dependencies.soroban-token-sdk] -version = "=22.0.0-rc.3" +version = "=22.0.4" [workspace.dependencies.soroban-ledger-snapshot] -version = "=22.0.0-rc.3" +version = "=22.0.4" # Dependencies from the rs-stellar-rpc-client repo: [workspace.dependencies.soroban-rpc] package = "stellar-rpc-client" -version = "=22.0.0-rc.1" +version = "=22.0.0" # Dependencies from elsewhere shared by crates: [workspace.dependencies] @@ -105,6 +106,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 02555161d..c6b5c0c21 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 @@ -55,6 +55,7 @@ Anything after the `--` double dash (the "slop") is parsed as arguments to the c * `completion` — Print shell completion code for the specified shell * `cache` — Cache for transactions and contract specs * `version` — Print version information +* `licenses` — Show dependency licenses ###### **Options:** @@ -151,6 +152,7 @@ Deploy builtin Soroban Asset Contract * `--instructions ` — Number of instructions to simulate * `--build-only` — Build the transaction and only write the base64 xdr to stdout * `--sim-only` — (Deprecated) simulate the transaction and only write the base64 xdr to stdout +* `--alias ` — The alias that will be used to save the assets's id. Whenever used, `--alias` will always overwrite the existing contract id configuration without asking for confirmation @@ -290,7 +292,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 <--wasm |--wasm-hash |--contract-id >` ###### **Options:** @@ -304,6 +306,10 @@ Generate a TypeScript / JavaScript package * `--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 +531,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 +571,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 +611,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 +920,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]` @@ -933,20 +943,20 @@ Create and manage identities including keys and addresses ###### **Subcommands:** -* `add` — Add a new identity (keypair, ledger, macOS keychain) +* `add` — Add a new identity (keypair, ledger, OS specific secure store) * `address` — Given an identity return its address (public key) * `fund` — Fund an identity on a test network * `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 ## `stellar keys add` -Add a new identity (keypair, ledger, macOS keychain) +Add a new identity (keypair, ledger, OS specific secure store) **Usage:** `stellar keys add [OPTIONS] ` @@ -956,8 +966,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 "." @@ -1018,6 +1028,7 @@ Generate a new identity with a seed phrase, currently 12 words * `--no-fund` — Do not fund address * `--seed ` — Optional seed to use when generating seed phrase. Random otherwise * `-s`, `--as-secret` — Output the generated identity as a secret key +* `--secure-store` — Save in OS-specific secure store * `--global` — Use global config * `--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` @@ -1064,11 +1075,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:** @@ -1455,11 +1466,12 @@ Sign, Simulate, and Send transactions ###### **Subcommands:** -* `simulate` — Simulate a transaction envelope from stdin * `hash` — Calculate the hash of a transaction envelope from stdin -* `sign` — Sign a transaction envelope appending the signature to the envelope -* `send` — Send a transaction envelope to the network * `new` — Create a new transaction +* `operation` — Manipulate the operations in a transaction, including adding new operations +* `send` — Send a transaction envelope to the network +* `sign` — Sign a transaction envelope appending the signature to the envelope +* `simulate` — Simulate a transaction envelope from stdin @@ -1497,43 +1509,6 @@ Calculate the hash of a transaction envelope from stdin -## `stellar tx sign` - -Sign a transaction envelope appending the signature to the envelope - -**Usage:** `stellar tx sign [OPTIONS]` - -###### **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 -* `--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 "." - - - -## `stellar tx send` - -Send a transaction envelope to the network - -**Usage:** `stellar tx send [OPTIONS]` - -###### **Options:** - -* `--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 "." - - - ## `stellar tx new` Create a new transaction @@ -1544,12 +1519,26 @@ Create a new transaction * `account-merge` — Transfers the XLM balance of an account to another account and removes the source account from the ledger * `bump-sequence` — Bumps forward the sequence number of the source account to the given sequence number, invalidating any transaction with a smaller sequence number -* `change-trust` — Creates, updates, or deletes a trustline Learn more about trustlines https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines +* `change-trust` — Creates, updates, or deletes a trustline +Learn more about trustlines +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines * `create-account` — Creates and funds a new account with the specified starting balance -* `manage-data` — Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account Learn more about entries and subentries: https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries +* `manage-data` — Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account +Learn more about entries and subentries: +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries * `payment` — Sends an amount in a specific asset to a destination account -* `set-options` — Set option for an account such as flags, inflation destination, signers, home domain, and master key weight Learn more about flags: https://developers.stellar.org/docs/learn/glossary#flags Learn more about the home domain: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md Learn more about signers operations and key weight: https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig -* `set-trustline-flags` — Allows issuing account to configure authorization and trustline flags to an asset The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. Learn more about flags: https://developers.stellar.org/docs/learn/glossary#flags +* `set-options` — Set option for an account such as flags, inflation destination, signers, home domain, and master key weight +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags +Learn more about the home domain: +https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md +Learn more about signers operations and key weight: +https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig +* `set-trustline-flags` — Allows issuing account to configure authorization and trustline flags to an asset +The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. +If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags @@ -1609,7 +1598,9 @@ Bumps forward the sequence number of the source account to the given sequence nu ## `stellar tx new change-trust` -Creates, updates, or deletes a trustline Learn more about trustlines https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines +Creates, updates, or deletes a trustline +Learn more about trustlines +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines **Usage:** `stellar tx new change-trust [OPTIONS] --source-account --line ` @@ -1669,7 +1660,9 @@ Creates and funds a new account with the specified starting balance ## `stellar tx new manage-data` -Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account Learn more about entries and subentries: https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries +Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account +Learn more about entries and subentries: +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries **Usage:** `stellar tx new manage-data [OPTIONS] --source-account --data-name ` @@ -1728,7 +1721,13 @@ Sends an amount in a specific asset to a destination account ## `stellar tx new set-options` -Set option for an account such as flags, inflation destination, signers, home domain, and master key weight Learn more about flags: https://developers.stellar.org/docs/learn/glossary#flags Learn more about the home domain: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md Learn more about signers operations and key weight: https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig +Set option for an account such as flags, inflation destination, signers, home domain, and master key weight +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags +Learn more about the home domain: +https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md +Learn more about signers operations and key weight: +https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig **Usage:** `stellar tx new set-options [OPTIONS] --source-account ` @@ -1770,7 +1769,11 @@ Set option for an account such as flags, inflation destination, signers, home do ## `stellar tx new set-trustline-flags` -Allows issuing account to configure authorization and trustline flags to an asset The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. Learn more about flags: https://developers.stellar.org/docs/learn/glossary#flags +Allows issuing account to configure authorization and trustline flags to an asset +The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. +If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags **Usage:** `stellar tx new set-trustline-flags [OPTIONS] --source-account --trustor --asset ` @@ -1802,6 +1805,274 @@ Allows issuing account to configure authorization and trustline flags to an asse +## `stellar tx operation` + +Manipulate the operations in a transaction, including adding new operations + +**Usage:** `stellar tx operation ` + +###### **Subcommands:** + +* `add` — Add Operation to a transaction + + + +## `stellar tx operation add` + +Add Operation to a transaction + +**Usage:** `stellar tx operation add ` + +###### **Subcommands:** + +* `account-merge` — Transfers the XLM balance of an account to another account and removes the source account from the ledger +* `bump-sequence` — Bumps forward the sequence number of the source account to the given sequence number, invalidating any transaction with a smaller sequence number +* `change-trust` — Creates, updates, or deletes a trustline +Learn more about trustlines +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines +* `create-account` — Creates and funds a new account with the specified starting balance +* `manage-data` — Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account +Learn more about entries and subentries: +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries +* `payment` — Sends an amount in a specific asset to a destination account +* `set-options` — Set option for an account such as flags, inflation destination, signers, home domain, and master key weight +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags +Learn more about the home domain: +https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md +Learn more about signers operations and key weight: +https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig +* `set-trustline-flags` — Allows issuing account to configure authorization and trustline flags to an asset +The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. +If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags + + + +## `stellar tx operation add account-merge` + +Transfers the XLM balance of an account to another account and removes the source account from the ledger + +**Usage:** `stellar tx operation add account-merge [OPTIONS] --account ` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--account ` — Muxed Account to merge with, e.g. `GBX...`, 'MBX...' + + + +## `stellar tx operation add bump-sequence` + +Bumps forward the sequence number of the source account to the given sequence number, invalidating any transaction with a smaller sequence number + +**Usage:** `stellar tx operation add bump-sequence [OPTIONS] --bump-to ` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--bump-to ` — Sequence number to bump to + + + +## `stellar tx operation add change-trust` + +Creates, updates, or deletes a trustline +Learn more about trustlines +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines + +**Usage:** `stellar tx operation add change-trust [OPTIONS] --line ` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--line ` +* `--limit ` — Limit for the trust line, 0 to remove the trust line + + Default value: `9223372036854775807` + + + +## `stellar tx operation add create-account` + +Creates and funds a new account with the specified starting balance + +**Usage:** `stellar tx operation add create-account [OPTIONS] --destination ` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--destination ` — Account Id to create, e.g. `GBX...` +* `--starting-balance ` — Initial balance in stroops of the account, default 1 XLM + + Default value: `10_000_000` + + + +## `stellar tx operation add manage-data` + +Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account +Learn more about entries and subentries: +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries + +**Usage:** `stellar tx operation add manage-data [OPTIONS] --data-name ` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--data-name ` — String up to 64 bytes long. If this is a new Name it will add the given name/value pair to the account. If this Name is already present then the associated value will be modified +* `--data-value ` — Up to 64 bytes long hex string If not present then the existing Name will be deleted. If present then this value will be set in the `DataEntry` + + + +## `stellar tx operation add payment` + +Sends an amount in a specific asset to a destination account + +**Usage:** `stellar tx operation add payment [OPTIONS] --destination --amount ` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--destination ` — Account to send to, e.g. `GBX...` +* `--asset ` — Asset to send, default native, e.i. XLM + + Default value: `native` +* `--amount ` — Amount of the aforementioned asset to send. e.g. `10_000_000` (1 XLM) + + + +## `stellar tx operation add set-options` + +Set option for an account such as flags, inflation destination, signers, home domain, and master key weight +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags +Learn more about the home domain: +https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md +Learn more about signers operations and key weight: +https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig + +**Usage:** `stellar tx operation add set-options [OPTIONS]` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--inflation-dest ` — Account of the inflation destination +* `--master-weight ` — A number from 0-255 (inclusive) representing the weight of the master key. If the weight of the master key is updated to 0, it is effectively disabled +* `--low-threshold ` — A number from 0-255 (inclusive) representing the threshold this account sets on all operations it performs that have a low threshold. https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig +* `--med-threshold ` — A number from 0-255 (inclusive) representing the threshold this account sets on all operations it performs that have a medium threshold. https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig +* `--high-threshold ` — A number from 0-255 (inclusive) representing the threshold this account sets on all operations it performs that have a high threshold. https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig +* `--home-domain ` — Sets the home domain of an account. See https://developers.stellar.org/docs/learn/encyclopedia/network-configuration/federation +* `--signer ` — Add, update, or remove a signer from an account +* `--signer-weight ` — Signer weight is a number from 0-255 (inclusive). The signer is deleted if the weight is 0 +* `--set-required` — When enabled, an issuer must approve an account before that account can hold its asset. https://developers.stellar.org/docs/tokens/control-asset-access#authorization-required-0x1 +* `--set-revocable` — When enabled, an issuer can revoke an existing trustline's authorization, thereby freezing the asset held by an account. https://developers.stellar.org/docs/tokens/control-asset-access#authorization-revocable-0x2 +* `--set-clawback-enabled` — Enables the issuing account to take back (burning) all of the asset. https://developers.stellar.org/docs/tokens/control-asset-access#clawback-enabled-0x8 +* `--set-immutable` — With this setting, none of the other authorization flags (`AUTH_REQUIRED_FLAG`, `AUTH_REVOCABLE_FLAG`) can be set, and the issuing account can't be merged. https://developers.stellar.org/docs/tokens/control-asset-access#authorization-immutable-0x4 +* `--clear-required` +* `--clear-revocable` +* `--clear-immutable` +* `--clear-clawback-enabled` + + + +## `stellar tx operation add set-trustline-flags` + +Allows issuing account to configure authorization and trustline flags to an asset +The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. +If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags + +**Usage:** `stellar tx operation add set-trustline-flags [OPTIONS] --trustor --asset ` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." +* `--operation-source-account ` — Source account used for the operation +* `--trustor ` — Account to set trustline flags for +* `--asset ` — Asset to set trustline flags for +* `--set-authorize` — Signifies complete authorization allowing an account to transact freely with the asset to make and receive payments and place orders +* `--set-authorize-to-maintain-liabilities` — Denotes limited authorization that allows an account to maintain current orders but not to otherwise transact with the asset +* `--set-trustline-clawback-enabled` — Enables the issuing account to take back (burning) all of the asset. See our section on Clawbacks: https://developers.stellar.org/docs/learn/encyclopedia/transactions-specialized/clawbacks +* `--clear-authorize` +* `--clear-authorize-to-maintain-liabilities` +* `--clear-trustline-clawback-enabled` + + + +## `stellar tx send` + +Send a transaction envelope to the network + +**Usage:** `stellar tx send [OPTIONS]` + +###### **Options:** + +* `--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 "." + + + +## `stellar tx sign` + +Sign a transaction envelope appending the signature to the envelope + +**Usage:** `stellar tx sign [OPTIONS]` + +###### **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 +* `--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 "." + + + +## `stellar tx simulate` + +Simulate a transaction envelope from stdin + +**Usage:** `stellar tx simulate [OPTIONS] --source-account ` + +###### **Options:** + +* `--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 +* `--source-account ` — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a muxed account (--source MDA…), 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` +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." + + + ## `stellar xdr` Decode and encode XDR @@ -2090,3 +2361,15 @@ Print version information +## `stellar licenses` + +Show dependency licenses + +**Usage:** `stellar licenses [OPTIONS]` + +###### **Options:** + +* `-v`, `--verbose` — Display the license text + + + diff --git a/Makefile b/Makefile index 92cdacd73..7aa1832ba 100644 --- a/Makefile +++ b/Makefile @@ -71,9 +71,11 @@ publish: typescript-bindings-fixtures: build-test-wasms cargo run -- contract bindings typescript \ --wasm ./target/wasm32-unknown-unknown/test-wasms/test_custom_types.wasm \ - --contract-id CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK \ - --network futurenet \ --output-dir ./cmd/crates/soroban-spec-typescript/fixtures/test_custom_types \ + --overwrite && \ + cargo run -- contract bindings typescript \ + --wasm ./target/wasm32-unknown-unknown/test-wasms/test_constructor.wasm \ + --output-dir ./cmd/crates/soroban-spec-typescript/fixtures/test_constructor \ --overwrite diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/.gitignore b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/.gitignore new file mode 100644 index 000000000..72aae85fa --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +out/ diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/README.md b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/README.md new file mode 100644 index 000000000..28bfd61c9 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/README.md @@ -0,0 +1,54 @@ +# test_constructor JS + +JS library for interacting with [Soroban](https://soroban.stellar.org/) smart contract `test_constructor` via Soroban RPC. + +This library was automatically generated by Soroban CLI using a command similar to: + +```bash +soroban contract bindings ts \ + --rpc-url INSERT_RPC_URL_HERE \ + --network-passphrase "INSERT_NETWORK_PASSPHRASE_HERE" \ + --contract-id INSERT_CONTRACT_ID_HERE \ + --output-dir ./path/to/test_constructor +``` + +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. + +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": { + "test_constructor": "./path/to/this/folder" +} +``` + +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 INSERT_RPC_URL_HERE --network-passphrase \"INSERT_NETWORK_PASSPHRASE_HERE\" --id INSERT_CONTRACT_ID_HERE --name test_constructor" +} +``` + +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: + +```js +import { Contract, networks } from "test_constructor" + +const contract = new Contract({ + ...networks.futurenet, // for example; check which networks this library exports + rpcUrl: '...', // use your own, or find one for testing at https://soroban.stellar.org/docs/reference/rpc#public-rpc-providers +}) + +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. diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/package.json b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/package.json new file mode 100644 index 000000000..8db466c05 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/package.json @@ -0,0 +1,17 @@ +{ + "version": "0.0.0", + "name": "test_constructor", + "type": "module", + "exports": "./dist/index.js", + "typings": "dist/index.d.ts", + "scripts": { + "build": "tsc" + }, + "dependencies": { + "@stellar/stellar-sdk": "13.0.0", + "buffer": "6.0.3" + }, + "devDependencies": { + "typescript": "^5.6.2" + } +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/src/index.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/src/index.ts new file mode 100644 index 000000000..f416e5a24 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/src/index.ts @@ -0,0 +1,90 @@ +import { Buffer } from "buffer"; +import { Address } from '@stellar/stellar-sdk'; +import { + AssembledTransaction, + Client as ContractClient, + ClientOptions as ContractClientOptions, + MethodOptions, + Result, + Spec as ContractSpec, +} from '@stellar/stellar-sdk/contract'; +import type { + u32, + i32, + u64, + i64, + u128, + i128, + u256, + i256, + Option, + Typepoint, + Duration, +} from '@stellar/stellar-sdk/contract'; +export * from '@stellar/stellar-sdk' +export * as contract from '@stellar/stellar-sdk/contract' +export * as rpc from '@stellar/stellar-sdk/rpc' + +if (typeof window !== 'undefined') { + //@ts-ignore Buffer exists + window.Buffer = window.Buffer || Buffer; +} + + + + +export const Errors = { + +} + +export interface Client { + /** + * Construct and simulate a counter transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Counter value + */ + counter: (options?: { + /** + * The fee to pay for the transaction. Default: BASE_FEE + */ + fee?: number; + + /** + * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT + */ + timeoutInSeconds?: number; + + /** + * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true + */ + simulate?: boolean; + }) => Promise> + +} +export class Client extends ContractClient { + static async deploy( + /** Constructor/Initialization Args for the contract's `__constructor` method */ + {counter}: {counter: u32}, + /** Options for initalizing a Client as well as for calling a method, with extras specific to deploying. */ + options: MethodOptions & + Omit & { + /** The hash of the Wasm blob, which must already be installed on-chain. */ + wasmHash: Buffer | string; + /** Salt used to generate the contract's ID. Passed through to {@link Operation.createCustomContract}. Default: random. */ + salt?: Buffer | Uint8Array; + /** The format used to decode `wasmHash`, if it's provided as a string. */ + format?: "hex" | "base64"; + } + ): Promise> { + return ContractClient.deploy({counter}, options) + } + constructor(public readonly options: ContractClientOptions) { + super( + new ContractSpec([ "AAAAAAAAABNFeGFtcGxlIGNvbnN0cnVjdG9yAAAAAA1fX2NvbnN0cnVjdG9yAAAAAAAAAQAAAAAAAAAHY291bnRlcgAAAAAEAAAAAA==", + "AAAAAAAAAA1Db3VudGVyIHZhbHVlAAAAAAAAB2NvdW50ZXIAAAAAAAAAAAEAAAAE" ]), + options + ) + } + public readonly fromJSON = { + counter: this.txFromJSON + } +} \ No newline at end of file diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/tsconfig.json b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/tsconfig.json new file mode 100644 index 000000000..acac14220 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_constructor/tsconfig.json @@ -0,0 +1,98 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "NodeNext", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + // "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + // "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + // "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": [ + "src/*" + ] +} \ No newline at end of file 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..5f90613a7 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 @@ -6,9 +6,9 @@ This library was automatically generated by Soroban CLI using a command similar ```bash soroban contract bindings ts \ - --rpc-url https://rpc-futurenet.stellar.org:443 \ - --network-passphrase "Test SDF Future Network ; October 2022" \ - --contract-id CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK \ + --rpc-url INSERT_RPC_URL_HERE \ + --network-passphrase "INSERT_NETWORK_PASSPHRASE_HERE" \ + --contract-id INSERT_CONTRACT_ID_HERE \ --output-dir ./path/to/test_custom_types ``` @@ -30,7 +30,7 @@ However, we've actually encountered [frustration](https://github.com/stellar/sor ```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 INSERT_RPC_URL_HERE --network-passphrase \"INSERT_NETWORK_PASSPHRASE_HERE\" --id INSERT_CONTRACT_ID_HERE --name test_custom_types" } ``` diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/index.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/index.d.ts deleted file mode 100644 index cd888cc04..000000000 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/index.d.ts +++ /dev/null @@ -1,628 +0,0 @@ -import { Buffer } from "buffer"; -import { AssembledTransaction, Client as ContractClient, ClientOptions as ContractClientOptions, Result } from '@stellar/stellar-sdk/contract'; -import type { u32, i32, i64, u128, i128, u256, i256, Option } from '@stellar/stellar-sdk/contract'; -export * from '@stellar/stellar-sdk'; -export * as contract from '@stellar/stellar-sdk/contract'; -export * as rpc from '@stellar/stellar-sdk/rpc'; -export declare const networks: { - readonly futurenet: { - readonly networkPassphrase: "Test SDF Future Network ; October 2022"; - readonly contractId: "CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK"; - }; -}; -/** - * This is from the rust doc above the struct Test - */ -export interface Test { - a: u32; - b: boolean; - c: string; -} -export type SimpleEnum = { - tag: "First"; - values: void; -} | { - tag: "Second"; - values: void; -} | { - tag: "Third"; - values: void; -}; -export declare enum RoyalCard { - Jack = 11, - Queen = 12, - King = 13 -} -export type TupleStruct = readonly [Test, SimpleEnum]; -export type ComplexEnum = { - tag: "Struct"; - values: readonly [Test]; -} | { - tag: "Tuple"; - values: readonly [TupleStruct]; -} | { - tag: "Enum"; - values: readonly [SimpleEnum]; -} | { - tag: "Asset"; - values: readonly [string, i128]; -} | { - tag: "Void"; - values: void; -}; -export declare const Errors: { - /** - * Please provide an odd number - */ - 1: { - message: string; - }; -}; -export interface Client { - /** - * Construct and simulate a hello transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - hello: ({ hello }: { - hello: string; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a woid transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - woid: (options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a val transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - val: (options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a u32_fail_on_even transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - u32_fail_on_even: ({ u32_ }: { - u32_: u32; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>>; - /** - * Construct and simulate a u32_ transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - u32_: ({ u32_ }: { - u32_: u32; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a i32_ transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - i32_: ({ i32_ }: { - i32_: i32; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a i64_ transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - i64_: ({ i64_ }: { - i64_: i64; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a strukt_hel transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - * Example contract method which takes a struct - */ - strukt_hel: ({ strukt }: { - strukt: Test; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>>; - /** - * Construct and simulate a strukt transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - strukt: ({ strukt }: { - strukt: Test; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a simple transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - simple: ({ simple }: { - simple: SimpleEnum; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a complex transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - complex: ({ complex }: { - complex: ComplexEnum; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a addresse transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - addresse: ({ addresse }: { - addresse: string; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a bytes transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - bytes: ({ bytes }: { - bytes: Buffer; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a bytes_n transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - bytes_n: ({ bytes_n }: { - bytes_n: Buffer; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a card transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - card: ({ card }: { - card: RoyalCard; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a boolean transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - boolean: ({ boolean }: { - boolean: boolean; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a not transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - * Negates a boolean value - */ - not: ({ boolean }: { - boolean: boolean; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a i128 transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - i128: ({ i128 }: { - i128: i128; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a u128 transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - u128: ({ u128 }: { - u128: u128; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a multi_args transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - multi_args: ({ a, b }: { - a: u32; - b: boolean; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a map transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - map: ({ map }: { - map: Map; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>>; - /** - * Construct and simulate a vec transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - vec: ({ vec }: { - vec: Array; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>>; - /** - * Construct and simulate a tuple transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - tuple: ({ tuple }: { - tuple: readonly [string, u32]; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a option transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - * Example of an optional argument - */ - option: ({ option }: { - option: Option; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>>; - /** - * Construct and simulate a u256 transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - u256: ({ u256 }: { - u256: u256; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a i256 transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - i256: ({ i256 }: { - i256: i256; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a string transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - string: ({ string }: { - string: string; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; - /** - * Construct and simulate a tuple_strukt transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - */ - tuple_strukt: ({ tuple_strukt }: { - tuple_strukt: TupleStruct; - }, options?: { - /** - * The fee to pay for the transaction. Default: BASE_FEE - */ - fee?: number; - /** - * The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT - */ - timeoutInSeconds?: number; - /** - * Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true - */ - simulate?: boolean; - }) => Promise>; -} -export declare class Client extends ContractClient { - readonly options: ContractClientOptions; - constructor(options: ContractClientOptions); - readonly fromJSON: { - hello: (json: string) => AssembledTransaction; - woid: (json: string) => AssembledTransaction; - val: (json: string) => AssembledTransaction; - u32_fail_on_even: (json: string) => AssembledTransaction>; - u32_: (json: string) => AssembledTransaction; - i32_: (json: string) => AssembledTransaction; - i64_: (json: string) => AssembledTransaction; - strukt_hel: (json: string) => AssembledTransaction; - strukt: (json: string) => AssembledTransaction; - simple: (json: string) => AssembledTransaction; - complex: (json: string) => AssembledTransaction; - addresse: (json: string) => AssembledTransaction; - bytes: (json: string) => AssembledTransaction; - bytes_n: (json: string) => AssembledTransaction; - card: (json: string) => AssembledTransaction; - boolean: (json: string) => AssembledTransaction; - not: (json: string) => AssembledTransaction; - i128: (json: string) => AssembledTransaction; - u128: (json: string) => AssembledTransaction; - multi_args: (json: string) => AssembledTransaction; - map: (json: string) => AssembledTransaction>; - vec: (json: string) => AssembledTransaction; - tuple: (json: string) => AssembledTransaction; - option: (json: string) => AssembledTransaction>; - u256: (json: string) => AssembledTransaction; - i256: (json: string) => AssembledTransaction; - string: (json: string) => AssembledTransaction; - tuple_strukt: (json: string) => AssembledTransaction; - }; -} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/index.js b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/index.js deleted file mode 100644 index 4286b2a68..000000000 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/index.js +++ /dev/null @@ -1,97 +0,0 @@ -import { Buffer } from "buffer"; -import { Client as ContractClient, Spec as ContractSpec, } from '@stellar/stellar-sdk/contract'; -export * from '@stellar/stellar-sdk'; -export * as contract from '@stellar/stellar-sdk/contract'; -export * as rpc from '@stellar/stellar-sdk/rpc'; -if (typeof window !== 'undefined') { - //@ts-ignore Buffer exists - window.Buffer = window.Buffer || Buffer; -} -export const networks = { - futurenet: { - networkPassphrase: "Test SDF Future Network ; October 2022", - contractId: "CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK", - } -}; -export var RoyalCard; -(function (RoyalCard) { - RoyalCard[RoyalCard["Jack"] = 11] = "Jack"; - RoyalCard[RoyalCard["Queen"] = 12] = "Queen"; - RoyalCard[RoyalCard["King"] = 13] = "King"; -})(RoyalCard || (RoyalCard = {})); -export const Errors = { - /** - * Please provide an odd number - */ - 1: { message: "NumberMustBeOdd" } -}; -export class Client extends ContractClient { - options; - constructor(options) { - super(new ContractSpec(["AAAAAQAAAC9UaGlzIGlzIGZyb20gdGhlIHJ1c3QgZG9jIGFib3ZlIHRoZSBzdHJ1Y3QgVGVzdAAAAAAAAAAABFRlc3QAAAADAAAAAAAAAAFhAAAAAAAABAAAAAAAAAABYgAAAAAAAAEAAAAAAAAAAWMAAAAAAAAR", - "AAAAAgAAAAAAAAAAAAAAClNpbXBsZUVudW0AAAAAAAMAAAAAAAAAAAAAAAVGaXJzdAAAAAAAAAAAAAAAAAAABlNlY29uZAAAAAAAAAAAAAAAAAAFVGhpcmQAAAA=", - "AAAAAwAAAAAAAAAAAAAACVJveWFsQ2FyZAAAAAAAAAMAAAAAAAAABEphY2sAAAALAAAAAAAAAAVRdWVlbgAAAAAAAAwAAAAAAAAABEtpbmcAAAAN", - "AAAAAQAAAAAAAAAAAAAAC1R1cGxlU3RydWN0AAAAAAIAAAAAAAAAATAAAAAAAAfQAAAABFRlc3QAAAAAAAAAATEAAAAAAAfQAAAAClNpbXBsZUVudW0AAA==", - "AAAAAgAAAAAAAAAAAAAAC0NvbXBsZXhFbnVtAAAAAAUAAAABAAAAAAAAAAZTdHJ1Y3QAAAAAAAEAAAfQAAAABFRlc3QAAAABAAAAAAAAAAVUdXBsZQAAAAAAAAEAAAfQAAAAC1R1cGxlU3RydWN0AAAAAAEAAAAAAAAABEVudW0AAAABAAAH0AAAAApTaW1wbGVFbnVtAAAAAAABAAAAAAAAAAVBc3NldAAAAAAAAAIAAAATAAAACwAAAAAAAAAAAAAABFZvaWQ=", - "AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAAAQAAABxQbGVhc2UgcHJvdmlkZSBhbiBvZGQgbnVtYmVyAAAAD051bWJlck11c3RCZU9kZAAAAAAB", - "AAAAAAAAAAAAAAAFaGVsbG8AAAAAAAABAAAAAAAAAAVoZWxsbwAAAAAAABEAAAABAAAAEQ==", - "AAAAAAAAAAAAAAAEd29pZAAAAAAAAAAA", - "AAAAAAAAAAAAAAADdmFsAAAAAAAAAAABAAAAAA==", - "AAAAAAAAAAAAAAAQdTMyX2ZhaWxfb25fZXZlbgAAAAEAAAAAAAAABHUzMl8AAAAEAAAAAQAAA+kAAAAEAAAAAw==", - "AAAAAAAAAAAAAAAEdTMyXwAAAAEAAAAAAAAABHUzMl8AAAAEAAAAAQAAAAQ=", - "AAAAAAAAAAAAAAAEaTMyXwAAAAEAAAAAAAAABGkzMl8AAAAFAAAAAQAAAAU=", - "AAAAAAAAAAAAAAAEaTY0XwAAAAEAAAAAAAAABGk2NF8AAAAHAAAAAQAAAAc=", - "AAAAAAAAACxFeGFtcGxlIGNvbnRyYWN0IG1ldGhvZCB3aGljaCB0YWtlcyBhIHN0cnVjdAAAAApzdHJ1a3RfaGVsAAAAAAABAAAAAAAAAAZzdHJ1a3QAAAAAB9AAAAAEVGVzdAAAAAEAAAPqAAAAEQ==", - "AAAAAAAAAAAAAAAGc3RydWt0AAAAAAABAAAAAAAAAAZzdHJ1a3QAAAAAB9AAAAAEVGVzdAAAAAEAAAfQAAAABFRlc3Q=", - "AAAAAAAAAAAAAAAGc2ltcGxlAAAAAAABAAAAAAAAAAZzaW1wbGUAAAAAB9AAAAAKU2ltcGxlRW51bQAAAAAAAQAAB9AAAAAKU2ltcGxlRW51bQAA", - "AAAAAAAAAAAAAAAHY29tcGxleAAAAAABAAAAAAAAAAdjb21wbGV4AAAAB9AAAAALQ29tcGxleEVudW0AAAAAAQAAB9AAAAALQ29tcGxleEVudW0A", - "AAAAAAAAAAAAAAAIYWRkcmVzc2UAAAABAAAAAAAAAAhhZGRyZXNzZQAAABMAAAABAAAAEw==", - "AAAAAAAAAAAAAAAFYnl0ZXMAAAAAAAABAAAAAAAAAAVieXRlcwAAAAAAAA4AAAABAAAADg==", - "AAAAAAAAAAAAAAAHYnl0ZXNfbgAAAAABAAAAAAAAAAdieXRlc19uAAAAA+4AAAAJAAAAAQAAA+4AAAAJ", - "AAAAAAAAAAAAAAAEY2FyZAAAAAEAAAAAAAAABGNhcmQAAAfQAAAACVJveWFsQ2FyZAAAAAAAAAEAAAfQAAAACVJveWFsQ2FyZAAAAA==", - "AAAAAAAAAAAAAAAHYm9vbGVhbgAAAAABAAAAAAAAAAdib29sZWFuAAAAAAEAAAABAAAAAQ==", - "AAAAAAAAABdOZWdhdGVzIGEgYm9vbGVhbiB2YWx1ZQAAAAADbm90AAAAAAEAAAAAAAAAB2Jvb2xlYW4AAAAAAQAAAAEAAAAB", - "AAAAAAAAAAAAAAAEaTEyOAAAAAEAAAAAAAAABGkxMjgAAAALAAAAAQAAAAs=", - "AAAAAAAAAAAAAAAEdTEyOAAAAAEAAAAAAAAABHUxMjgAAAAKAAAAAQAAAAo=", - "AAAAAAAAAAAAAAAKbXVsdGlfYXJncwAAAAAAAgAAAAAAAAABYQAAAAAAAAQAAAAAAAAAAWIAAAAAAAABAAAAAQAAAAQ=", - "AAAAAAAAAAAAAAADbWFwAAAAAAEAAAAAAAAAA21hcAAAAAPsAAAABAAAAAEAAAABAAAD7AAAAAQAAAAB", - "AAAAAAAAAAAAAAADdmVjAAAAAAEAAAAAAAAAA3ZlYwAAAAPqAAAABAAAAAEAAAPqAAAABA==", - "AAAAAAAAAAAAAAAFdHVwbGUAAAAAAAABAAAAAAAAAAV0dXBsZQAAAAAAA+0AAAACAAAAEQAAAAQAAAABAAAD7QAAAAIAAAARAAAABA==", - "AAAAAAAAAB9FeGFtcGxlIG9mIGFuIG9wdGlvbmFsIGFyZ3VtZW50AAAAAAZvcHRpb24AAAAAAAEAAAAAAAAABm9wdGlvbgAAAAAD6AAAAAQAAAABAAAD6AAAAAQ=", - "AAAAAAAAAAAAAAAEdTI1NgAAAAEAAAAAAAAABHUyNTYAAAAMAAAAAQAAAAw=", - "AAAAAAAAAAAAAAAEaTI1NgAAAAEAAAAAAAAABGkyNTYAAAANAAAAAQAAAA0=", - "AAAAAAAAAAAAAAAGc3RyaW5nAAAAAAABAAAAAAAAAAZzdHJpbmcAAAAAABAAAAABAAAAEA==", - "AAAAAAAAAAAAAAAMdHVwbGVfc3RydWt0AAAAAQAAAAAAAAAMdHVwbGVfc3RydWt0AAAH0AAAAAtUdXBsZVN0cnVjdAAAAAABAAAH0AAAAAtUdXBsZVN0cnVjdAA="]), options); - this.options = options; - } - fromJSON = { - hello: (this.txFromJSON), - woid: (this.txFromJSON), - val: (this.txFromJSON), - u32_fail_on_even: (this.txFromJSON), - u32_: (this.txFromJSON), - i32_: (this.txFromJSON), - i64_: (this.txFromJSON), - strukt_hel: (this.txFromJSON), - strukt: (this.txFromJSON), - simple: (this.txFromJSON), - complex: (this.txFromJSON), - addresse: (this.txFromJSON), - bytes: (this.txFromJSON), - bytes_n: (this.txFromJSON), - card: (this.txFromJSON), - boolean: (this.txFromJSON), - not: (this.txFromJSON), - i128: (this.txFromJSON), - u128: (this.txFromJSON), - multi_args: (this.txFromJSON), - map: (this.txFromJSON), - vec: (this.txFromJSON), - tuple: (this.txFromJSON), - option: (this.txFromJSON), - u256: (this.txFromJSON), - i256: (this.txFromJSON), - string: (this.txFromJSON), - tuple_strukt: (this.txFromJSON) - }; -} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/package-lock.json b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/package-lock.json deleted file mode 100644 index a4e3759e2..000000000 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/package-lock.json +++ /dev/null @@ -1,355 +0,0 @@ -{ - "name": "test_custom_types", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "test_custom_types", - "version": "0.0.0", - "dependencies": { - "@stellar/stellar-sdk": "13.0.0", - "buffer": "6.0.3" - }, - "devDependencies": { - "typescript": "^5.6.2" - } - }, - "node_modules/@stellar/js-xdr": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", - "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==", - "license": "Apache-2.0" - }, - "node_modules/@stellar/stellar-base": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-13.0.1.tgz", - "integrity": "sha512-Xbd12mc9Oj/130Tv0URmm3wXG77XMshZtZ2yNCjqX5ZbMD5IYpbBs3DVCteLU/4SLj/Fnmhh1dzhrQXnk4r+pQ==", - "license": "Apache-2.0", - "dependencies": { - "@stellar/js-xdr": "^3.1.2", - "base32.js": "^0.1.0", - "bignumber.js": "^9.1.2", - "buffer": "^6.0.3", - "sha.js": "^2.3.6", - "tweetnacl": "^1.0.3" - }, - "optionalDependencies": { - "sodium-native": "^4.3.0" - } - }, - "node_modules/@stellar/stellar-sdk": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-13.0.0.tgz", - "integrity": "sha512-+wvmKi+XWwu27nLYTM17EgBdpbKohEkOfCIK4XKfsI4WpMXAqvnqSm98i9h5dAblNB+w8BJqzGs1JY0PtTGm4A==", - "license": "Apache-2.0", - "dependencies": { - "@stellar/stellar-base": "^13.0.1", - "axios": "^1.7.7", - "bignumber.js": "^9.1.2", - "eventsource": "^2.0.2", - "feaxios": "^0.0.20", - "randombytes": "^2.1.0", - "toml": "^3.0.0", - "urijs": "^1.19.1" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/base32.js": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", - "integrity": "sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/eventsource": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/feaxios": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/feaxios/-/feaxios-0.0.20.tgz", - "integrity": "sha512-g3hm2YDNffNxA3Re3Hd8ahbpmDee9Fv1Pb1C/NoWsjY7mtD8nyNeJytUzn+DK0Hyl9o6HppeWOrtnqgmhOYfWA==", - "license": "MIT", - "dependencies": { - "is-retry-allowed": "^3.0.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/is-retry-allowed": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-3.0.0.tgz", - "integrity": "sha512-9xH0xvoggby+u0uGF7cZXdrutWiBiaFG8ZT4YFPXL8NzkyAwX3AKGLeFQLvzDpM430+nDFBZ1LHkie/8ocL06A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.3.tgz", - "integrity": "sha512-EMS95CMJzdoSKoIiXo8pxKoL8DYxwIZXYlLmgPb8KUv794abpnLK6ynsCAWNliOjREKruYKdzbh76HHYUHX7nw==", - "license": "MIT", - "optional": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/sodium-native": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.3.1.tgz", - "integrity": "sha512-YdP64gAdpIKHfL4ttuX4aIfjeunh9f+hNeQJpE9C8UMndB3zkgZ7YmmGT4J2+v6Ibyp6Wem8D1TcSrtdW0bqtg==", - "license": "MIT", - "optional": true, - "dependencies": { - "node-gyp-build": "^4.8.0" - } - }, - "node_modules/toml": { - "version": "3.0.0", - "license": "MIT" - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "license": "Unlicense" - }, - "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/urijs": { - "version": "1.19.11", - "license": "MIT" - } - } -} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/index.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/index.ts index 7f2d5b000..92a28ee5a 100644 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/index.ts +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/index.ts @@ -4,6 +4,7 @@ import { AssembledTransaction, Client as ContractClient, ClientOptions as ContractClientOptions, + MethodOptions, Result, Spec as ContractSpec, } from '@stellar/stellar-sdk/contract'; @@ -30,12 +31,7 @@ if (typeof window !== 'undefined') { } -export const networks = { - futurenet: { - networkPassphrase: "Test SDF Future Network ; October 2022", - contractId: "CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK", - } -} as const + /** @@ -631,6 +627,20 @@ export interface Client { } export class Client extends ContractClient { + static async deploy( + /** Options for initalizing a Client as well as for calling a method, with extras specific to deploying. */ + options: MethodOptions & + Omit & { + /** The hash of the Wasm blob, which must already be installed on-chain. */ + wasmHash: Buffer | string; + /** Salt used to generate the contract's ID. Passed through to {@link Operation.createCustomContract}. Default: random. */ + salt?: Buffer | Uint8Array; + /** The format used to decode `wasmHash`, if it's provided as a string. */ + format?: "hex" | "base64"; + } + ): Promise> { + return ContractClient.deploy(null, options) + } constructor(public readonly options: ContractClientOptions) { super( new ContractSpec([ "AAAAAQAAAC9UaGlzIGlzIGZyb20gdGhlIHJ1c3QgZG9jIGFib3ZlIHRoZSBzdHJ1Y3QgVGVzdAAAAAAAAAAABFRlc3QAAAADAAAAAAAAAAFhAAAAAAAABAAAAAAAAAABYgAAAAAAAAEAAAAAAAAAAWMAAAAAAAAR", diff --git a/cmd/crates/soroban-spec-typescript/src/boilerplate.rs b/cmd/crates/soroban-spec-typescript/src/boilerplate.rs index 501d51434..bf5631eda 100644 --- a/cmd/crates/soroban-spec-typescript/src/boilerplate.rs +++ b/cmd/crates/soroban-spec-typescript/src/boilerplate.rs @@ -47,9 +47,9 @@ impl Project { pub fn init( &self, contract_name: &str, - contract_id: &str, - rpc_url: &str, - network_passphrase: &str, + contract_id: Option<&str>, + rpc_url: Option<&str>, + network_passphrase: Option<&str>, spec: &[ScSpecEntry], ) -> std::io::Result<()> { self.replace_placeholder_patterns(contract_name, contract_id, rpc_url, network_passphrase)?; @@ -59,9 +59,9 @@ impl Project { fn replace_placeholder_patterns( &self, contract_name: &str, - contract_id: &str, - rpc_url: &str, - network_passphrase: &str, + contract_id: Option<&str>, + rpc_url: Option<&str>, + network_passphrase: Option<&str>, ) -> std::io::Result<()> { let replacement_strings = &[ ("INSERT_CONTRACT_NAME_HERE", contract_name), @@ -73,9 +73,18 @@ impl Project { "INSERT_CAMEL_CASE_CONTRACT_NAME_HERE", &contract_name.to_lower_camel_case(), ), - ("INSERT_CONTRACT_ID_HERE", contract_id), - ("INSERT_NETWORK_PASSPHRASE_HERE", network_passphrase), - ("INSERT_RPC_URL_HERE", rpc_url), + ( + "INSERT_CONTRACT_ID_HERE", + contract_id.unwrap_or("INSERT_CONTRACT_ID_HERE"), + ), + ( + "INSERT_RPC_URL_HERE", + rpc_url.unwrap_or("INSERT_RPC_URL_HERE"), + ), + ( + "INSERT_NETWORK_PASSPHRASE_HERE", + network_passphrase.unwrap_or("INSERT_NETWORK_PASSPHRASE_HERE"), + ), ]; let root: &Path = self.as_ref(); ["package.json", "README.md", "src/index.ts"] @@ -93,8 +102,8 @@ impl Project { fn append_index_ts( &self, spec: &[ScSpecEntry], - contract_id: &str, - network_passphrase: &str, + contract_id: Option<&str>, + network_passphrase: Option<&str>, ) -> std::io::Result<()> { let networks = Project::format_networks_object(contract_id, network_passphrase); let types_and_fns = generate(spec); @@ -104,7 +113,15 @@ impl Project { .write_all(format!("\n\n{networks}\n\n{types_and_fns}").as_bytes()) } - fn format_networks_object(contract_id: &str, network_passphrase: &str) -> String { + fn format_networks_object( + contract_id: Option<&str>, + network_passphrase: Option<&str>, + ) -> String { + if contract_id.is_none() || network_passphrase.is_none() { + return String::new(); + } + let contract_id = contract_id.unwrap(); + let network_passphrase = network_passphrase.unwrap(); let network = match network_passphrase { NETWORK_PASSPHRASE_TESTNET => "testnet", NETWORK_PASSPHRASE_FUTURENET => "futurenet", @@ -138,9 +155,9 @@ mod test { let p: Project = root.as_ref().to_path_buf().try_into()?; p.init( "test_custom_types", - "CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE", - "https://rpc-futurenet.stellar.org:443", - "Test SDF Future Network ; October 2022", + Some("CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE"), + Some("https://rpc-futurenet.stellar.org:443"), + Some("Test SDF Future Network ; October 2022"), &spec, ) .unwrap(); diff --git a/cmd/crates/soroban-spec-typescript/src/lib.rs b/cmd/crates/soroban-spec-typescript/src/lib.rs index 94b5bb192..ee98a514d 100644 --- a/cmd/crates/soroban-spec-typescript/src/lib.rs +++ b/cmd/crates/soroban-spec-typescript/src/lib.rs @@ -59,7 +59,26 @@ pub fn generate_from_wasm(wasm: &[u8]) -> Result { Ok(json) } -fn generate_class(fns: &[Entry], spec: &[ScSpecEntry]) -> String { +fn generate_class( + fns: &[Entry], + constructor_args: Option>, + spec: &[ScSpecEntry], +) -> String { + let (constructor_args_in, constructor_args_out) = if let Some(inputs) = constructor_args { + let Some((args, arg_types)) = args_to_ts(&inputs) else { + panic!("inputs is present but couldn't be parsed by args_to_ts()"); + }; + ( + format!( + " + /** Constructor/Initialization Args for the contract's `__constructor` method */ + {args}: {arg_types},", + ), + args, + ) + } else { + (String::new(), "null".to_string()) + }; let method_types = fns.iter().map(entry_to_method_type).join(""); let from_jsons = fns .iter() @@ -74,6 +93,20 @@ fn generate_class(fns: &[Entry], spec: &[ScSpecEntry]) -> String { r#"export interface Client {{{method_types} }} export class Client extends ContractClient {{ + static async deploy({constructor_args_in} + /** Options for initalizing a Client as well as for calling a method, with extras specific to deploying. */ + options: MethodOptions & + Omit & {{ + /** The hash of the Wasm blob, which must already be installed on-chain. */ + wasmHash: Buffer | string; + /** Salt used to generate the contract's ID. Passed through to {{@link Operation.createCustomContract}}. Default: random. */ + salt?: Buffer | Uint8Array; + /** The format used to decode `wasmHash`, if it's provided as a string. */ + format?: "hex" | "base64"; + }} + ): Promise> {{ + return ContractClient.deploy({constructor_args_out}, options) + }} constructor(public readonly options: ContractClientOptions) {{ super( new ContractSpec([ {spec} ]), @@ -96,13 +129,20 @@ pub fn generate(spec: &[ScSpecEntry]) -> String { cases: vec![], }); } + let mut constructor_args: Option> = None; // Filter out function entries with names that start with "__" and partition the results + collected.iter().for_each(|entry| match entry { + Entry::Function { name, inputs, .. } if name == "__constructor" => { + constructor_args = Some(inputs.clone()); + } + _ => {} + }); let (fns, other): (Vec<_>, Vec<_>) = collected .into_iter() .filter(|entry| !matches!(entry, Entry::Function { name, .. } if name.starts_with("__"))) .partition(|entry| matches!(entry, Entry::Function { .. })); let top = other.iter().map(entry_to_method_type).join("\n"); - let bottom = generate_class(&fns, spec); + let bottom = generate_class(&fns, constructor_args, spec); format!("{top}\n\n{bottom}") } @@ -174,6 +214,18 @@ pub fn outputs_to_return_type(outputs: &[Type]) -> String { } } +/// Convert a function's inputs to TypeScript arguments. Returns a tuple with the arguments +/// as they'll actually be used in JS, as well as TS type definitions for the arguments. +pub fn args_to_ts(inputs: &[types::FunctionInput]) -> Option<(String, String)> { + if inputs.is_empty() { + None + } else { + let input_vals = inputs.iter().map(func_input_to_arg_name).join(", "); + let input_types = inputs.iter().map(func_input_to_ts).join(", "); + Some((format!("{{{input_vals}}}"), format!("{{{input_types}}}"))) + } +} + #[allow(clippy::too_many_lines)] pub fn entry_to_method_type(entry: &Entry) -> String { match entry { @@ -184,15 +236,11 @@ pub fn entry_to_method_type(entry: &Entry) -> String { outputs, .. } => { - let input_vals = inputs.iter().map(func_input_to_arg_name).join(", "); - let input = (!inputs.is_empty()) - .then(|| { - format!( - "{{{input_vals}}}: {{{}}}, ", - inputs.iter().map(func_input_to_ts).join(", ") - ) - }) - .unwrap_or_default(); + let input = if let Some((args, arg_types)) = args_to_ts(inputs) { + format!("{args}: {arg_types}, ") + } else { + String::new() + }; let doc = doc_to_ts_doc(doc, Some(name), 0); let return_type = outputs_to_return_type(outputs); format!( diff --git a/cmd/crates/soroban-spec-typescript/src/project_template/src/index.ts b/cmd/crates/soroban-spec-typescript/src/project_template/src/index.ts index 057d4ef72..b344a1c60 100644 --- a/cmd/crates/soroban-spec-typescript/src/project_template/src/index.ts +++ b/cmd/crates/soroban-spec-typescript/src/project_template/src/index.ts @@ -4,6 +4,7 @@ import { AssembledTransaction, Client as ContractClient, ClientOptions as ContractClientOptions, + MethodOptions, Result, Spec as ContractSpec, } from '@stellar/stellar-sdk/contract'; 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 031061cca..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,25 +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 deploy() { - exe eval "(./soroban contract deploy --quiet --source root --wasm $1 --ignore-checks) > $2" +function upload() { + exe eval "(./stellar contract $1 --quiet --source root --wasm $2 --ignore-checks) > $3" } function deploy_all() { - deploy ../../../../target/wasm32-unknown-unknown/test-wasms/test_custom_types.wasm contract-id-custom-types.txt + upload deploy ../../../../target/wasm32-unknown-unknown/test-wasms/test_custom_types.wasm contract-id-custom-types.txt + 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 --contract-id $(cat $1) --output-dir ./node_modules/$2 --overwrite" - exe eval "sh -c \"cd ./node_modules/$2 && npm install && npm run build\"" + 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-custom-types.txt test-custom-types + bind --contract-id $(cat contract-id-custom-types.txt) test-custom-types + 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/package-lock.json b/cmd/crates/soroban-spec-typescript/ts-tests/package-lock.json index 45cc97a67..786edd8ee 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/package-lock.json +++ b/cmd/crates/soroban-spec-typescript/ts-tests/package-lock.json @@ -2340,9 +2340,9 @@ "dev": true }, "node_modules/node-gyp-build": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.3.tgz", - "integrity": "sha512-EMS95CMJzdoSKoIiXo8pxKoL8DYxwIZXYlLmgPb8KUv794abpnLK6ynsCAWNliOjREKruYKdzbh76HHYUHX7nw==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "dev": true, "license": "MIT", "optional": true, diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-constructor-args.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-constructor-args.ts new file mode 100644 index 000000000..a4f8bbfc4 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-constructor-args.ts @@ -0,0 +1,29 @@ +import { readFileSync } from "node:fs" +import { join } from "node:path" +import test from "ava" +import { networkPassphrase, rpcUrl, root, signer } from "./util.js" +import { Client } from "test-constructor" + +const wasmHash = readFileSync( + join(import.meta.dirname, "..", "contract-wasm-hash-constructor.txt"), + { encoding: "utf8" } +); + +const INIT_VALUE = 42; + +test("has correctly-typed result", async (t) => { + const deploy = await Client.deploy( + { counter: INIT_VALUE }, + { + networkPassphrase, + rpcUrl, + allowHttp: true, + wasmHash, + publicKey: root.keypair.publicKey(), + ...signer, + }, + ); + const { result: client } = await deploy.signAndSend(); + const { result } = await client.counter(); + t.is(result, INIT_VALUE); +}); 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..47504c368 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", "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 d035652d1..eb03b7862 100644 --- a/cmd/crates/soroban-test/Cargo.toml +++ b/cmd/crates/soroban-test/Cargo.toml @@ -32,7 +32,7 @@ assert_fs = "1.0.7" predicates = { workspace = true } fs_extra = "1.3.0" toml = { workspace = true } - +home = "0.5.9" [dev-dependencies] serde_json = "1.0.93" @@ -42,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/README.md b/cmd/crates/soroban-test/README.md index c5fdefc3c..c2a192bd0 100644 --- a/cmd/crates/soroban-test/README.md +++ b/cmd/crates/soroban-test/README.md @@ -53,7 +53,7 @@ fn invoke() { } ``` -Itegration tests in Crate +Integration tests in Crate ============== -Currently all tests that require an RPC server are hidden behind a `it` feature, [found here](./tests/it/integration). To allow Rust-Analyzer to see the tests in vscode, `.vscode/settings.json`. Without RA, you can't follow through definitions and more importantly see errors before running tests tests. \ No newline at end of file +Currently all tests that require an RPC server are hidden behind a `it` feature, [found here](./tests/it/integration). To allow Rust-Analyzer to see the tests in vscode, `.vscode/settings.json`. Without RA, you can't follow through definitions and more importantly see errors before running tests. diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 2c62578ef..4f36a0b33 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..bf8ce501d 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.2.0" edition = "2021" publish = false diff --git a/cmd/crates/soroban-test/tests/fixtures/eth_abi/Cargo.lock b/cmd/crates/soroban-test/tests/fixtures/eth_abi/Cargo.lock new file mode 100644 index 000000000..748affd34 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/eth_abi/Cargo.lock @@ -0,0 +1,2323 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "alloy-primitives" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "600d34d8de81e23b6d909c094e23b3d357e01ca36b78a8c5424c501eedbe86f0" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +dependencies = [ + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86ec0a47740b20bc5613b8712d0d321d031c4efc58e9645af96085d5cccfc27" +dependencies = [ + "const-hex", + "dunce", + "heck", + "indexmap 2.6.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.79", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-types" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad09ec5853fa700d12d778ad224dcdec636af424d29fad84fb9a2f16a5b0ef09" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + +[[package]] +name = "bytes-lit" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0adabf37211a5276e46335feabcbb1530c95eb3fdf85f324c7db942770aa025d" +dependencies = [ + "num-bigint", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "cc" +version = "1.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + +[[package]] +name = "const-hex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crate-git-revision" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c521bf1f43d31ed2f73441775ed31935d77901cb3451e44b38a1c1612fcbaf98" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.79", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.79", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.79", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "escape-bytes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2" + +[[package]] +name = "ethnum" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pest" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn 2.0.79", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.6.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "soroban-builtin-sdk-macros" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df6c3137afcdb5a62b9ed3b1994ff9439351eaa795d8d33f758b4386ce2d0060" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "soroban-env-common" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24deb45507c219d3608f04768c3b700b627bc345cc4c19e31c4cc57fc7d77be9" +dependencies = [ + "arbitrary", + "crate-git-revision", + "ethnum", + "num-derive", + "num-traits", + "serde", + "soroban-env-macros", + "soroban-wasmi", + "static_assertions", + "stellar-xdr", + "wasmparser", +] + +[[package]] +name = "soroban-env-guest" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b010a822db635139fcfdb29be8a333606e5204c445e044d3450a5c47eaba20a" +dependencies = [ + "soroban-env-common", + "static_assertions", +] + +[[package]] +name = "soroban-env-host" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee57de1756bae449a52da032c8312113f355cbcf7e906fbb8957a44827999dc" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "curve25519-dalek", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "generic-array", + "getrandom", + "hex-literal", + "hmac", + "k256", + "num-derive", + "num-integer", + "num-traits", + "p256", + "rand", + "rand_chacha", + "sec1", + "sha2", + "sha3", + "soroban-builtin-sdk-macros", + "soroban-env-common", + "soroban-wasmi", + "static_assertions", + "stellar-strkey", + "wasmparser", +] + +[[package]] +name = "soroban-env-macros" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1528c2d0d19ab70e9947f930f8707fdc0e9bfd4baf6d275b8a2f67482c2f2d99" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "serde", + "serde_json", + "stellar-xdr", + "syn 2.0.79", +] + +[[package]] +name = "soroban-eth-abi" +version = "0.1.0" +dependencies = [ + "alloy-sol-types", + "soroban-sdk", +] + +[[package]] +name = "soroban-ledger-snapshot" +version = "22.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06e52ea3d90c64d3e91c38bc028dc9d4efacb6c5fc9551dc4a7965a6bd2457d" +dependencies = [ + "serde", + "serde_json", + "serde_with", + "soroban-env-common", + "soroban-env-host", + "thiserror", +] + +[[package]] +name = "soroban-sdk" +version = "22.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a905c0899728cd744f712486ae423a29e84d6f0a5f273e7731955fec0926eb01" +dependencies = [ + "arbitrary", + "bytes-lit", + "ctor", + "derive_arbitrary", + "ed25519-dalek", + "rand", + "rustc_version 0.4.1", + "serde", + "serde_json", + "soroban-env-guest", + "soroban-env-host", + "soroban-ledger-snapshot", + "soroban-sdk-macros", + "stellar-strkey", +] + +[[package]] +name = "soroban-sdk-macros" +version = "22.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76115bd7be33f2d4424d1e6138a7e362713092f1ede069d24c8bf195da30270b" +dependencies = [ + "crate-git-revision", + "darling", + "itertools", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "sha2", + "soroban-env-common", + "soroban-spec", + "soroban-spec-rust", + "stellar-xdr", + "syn 2.0.79", +] + +[[package]] +name = "soroban-spec" +version = "22.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e068bfda25b447ace1a11d1ed61cc6206cd7ef5ff1c7534042ca8b667ab7413" +dependencies = [ + "base64 0.13.1", + "stellar-xdr", + "thiserror", + "wasmparser", +] + +[[package]] +name = "soroban-spec-rust" +version = "22.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18ff7db55d4db2477a458ede3bc03fee81057e5e128311e4f9a8813f27cbf4c" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "sha2", + "soroban-spec", + "stellar-xdr", + "syn 2.0.79", + "thiserror", +] + +[[package]] +name = "soroban-wasmi" +version = "0.31.1-soroban.20.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710403de32d0e0c35375518cb995d4fc056d0d48966f2e56ea471b8cb8fc9719" +dependencies = [ + "smallvec", + "spin", + "wasmi_arena", + "wasmi_core", + "wasmparser-nostd", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stellar-strkey" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" +dependencies = [ + "crate-git-revision", + "data-encoding", + "thiserror", +] + +[[package]] +name = "stellar-xdr" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c2130275cc730d042b3082f51145f0486f5a543d6d72fced02ed9048b82b57" +dependencies = [ + "arbitrary", + "base64 0.13.1", + "crate-git-revision", + "escape-bytes", + "hex", + "serde", + "serde_with", + "stellar-strkey", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3d0961cd53c23ea94eeec56ba940f636f6394788976e9f16ca5ee0aca7464a" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.79", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "wasmi_arena" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073" + +[[package]] +name = "wasmi_core" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" +dependencies = [ + "downcast-rs", + "libm", + "num-traits", + "paste", +] + +[[package]] +name = "wasmparser" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" +dependencies = [ + "indexmap 2.6.0", + "semver 1.0.23", +] + +[[package]] +name = "wasmparser-nostd" +version = "0.100.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a015fe95f3504a94bb1462c717aae75253e39b9dd6c3fb1062c934535c64aa" +dependencies = [ + "indexmap-nostd", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] diff --git a/cmd/crates/soroban-test/tests/fixtures/eth_abi/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/eth_abi/Cargo.toml new file mode 100644 index 000000000..36e05fd87 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/eth_abi/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "soroban-eth-abi" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] +doctest = false + +[dependencies] +soroban-sdk = { version = "22.0.1", features = ["alloc"] } +alloy-sol-types = {version="0.6.3" } + +[dev-dependencies] +soroban-sdk = { version = "22.0.1", features = ["testutils"] } + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +[profile.release-with-logs] +inherits = "release" +debug-assertions = true diff --git a/cmd/crates/soroban-test/tests/fixtures/eth_abi/Makefile b/cmd/crates/soroban-test/tests/fixtures/eth_abi/Makefile new file mode 100644 index 000000000..7f774ad12 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/eth_abi/Makefile @@ -0,0 +1,16 @@ +default: build + +all: test + +test: build + cargo test + +build: + stellar contract build + @ls -l target/wasm32-unknown-unknown/release/*.wasm + +fmt: + cargo fmt --all + +clean: + cargo clean diff --git a/cmd/crates/soroban-test/tests/fixtures/eth_abi/src/lib.rs b/cmd/crates/soroban-test/tests/fixtures/eth_abi/src/lib.rs new file mode 100644 index 000000000..7cc6748c9 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/eth_abi/src/lib.rs @@ -0,0 +1,46 @@ +#![no_std] +extern crate alloc; +use alloy_sol_types::{sol, SolValue}; +use soroban_sdk::{contract, contracterror, contractimpl, Bytes, Env}; + +#[cfg(test)] +mod test; + +#[contracterror] +#[repr(u32)] +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum Error { + Decode = 1, +} + +#[contract] +pub struct Contract; + +sol! { + struct Input { + bytes32 a; + uint256 b; + uint256 c; + } + struct Output { + bytes32 a; + uint256 r; + } +} + +#[contractimpl] +impl Contract { + pub fn exec(e: &Env, input: Bytes) -> Result { + let mut input_buf = [0u8; 128]; + let mut input_slice = &mut input_buf[..input.len() as usize]; + input.copy_into_slice(&mut input_slice); + + let input = Input::abi_decode(&input_slice, false).map_err(|_| Error::Decode)?; + let output = Output { + a: input.a, + r: input.b + input.c, + }; + let output_encoded = output.abi_encode(); + Ok(Bytes::from_slice(e, &output_encoded)) + } +} diff --git a/cmd/crates/soroban-test/tests/fixtures/eth_abi/src/test.rs b/cmd/crates/soroban-test/tests/fixtures/eth_abi/src/test.rs new file mode 100644 index 000000000..18b615efb --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/eth_abi/src/test.rs @@ -0,0 +1,33 @@ +use crate::{Contract, ContractClient}; +use soroban_sdk::{Bytes, Env}; + +#[test] +fn test_exec() { + let e = Env::default(); + let contract_id = e.register(Contract, ()); + let client = ContractClient::new(&e, &contract_id); + let input = Bytes::from_slice( + &e, + &[ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + ], + ); + let output = client.exec(&input); + let expected_output = Bytes::from_slice( + &e, + &[ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + ], + ); + assert_eq!(output, expected_output); +} diff --git a/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml index a2fb7b15c..1a515dfa0 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.2.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..095b49379 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.2.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..75a8fa357 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.2.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..ecee573f5 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.2.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..f4db468eb 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.2.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..6d8900756 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.2.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..809172526 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.2.0" description = "Soroban standard token contract" authors = ["Stellar Development Foundation "] license = "Apache-2.0" diff --git a/cmd/crates/soroban-test/tests/it/build.rs b/cmd/crates/soroban-test/tests/it/build.rs index cb63ae907..3bdacbbb7 100644 --- a/cmd/crates/soroban-test/tests/it/build.rs +++ b/cmd/crates/soroban-test/tests/it/build.rs @@ -185,3 +185,55 @@ fn build_with_metadata() { assert_eq!(entries, expected_entries); } + +// Test that bins don't contain absolute paths to the local crate registry. +// +// See make_rustflags_to_remap_absolute_paths +#[test] +fn remap_absolute_paths() { + #[derive(Eq, PartialEq, Copy, Clone)] + enum Remap { + Yes, + No, + } + + fn run(contract_name: &str, manifest_path: &std::path::Path, remap: Remap) -> bool { + let sandbox_remap = TestEnv::default(); + let mut cmd = sandbox_remap.new_assert_cmd("contract"); + + if remap == Remap::No { + // This will prevent stellar-cli from setting CARGO_BUILD_RUSTFLAGS, + // and removing absolute paths. + // See docs for `make_rustflags_to_remap_absolute_paths`. + cmd.env("RUSTFLAGS", ""); + } + + cmd.current_dir(manifest_path) + .arg("build") + .assert() + .success(); + + let wasm_path = manifest_path + .join("target/wasm32-unknown-unknown/release") + .join(format!("{contract_name}.wasm")); + + let cargo_home = home::cargo_home().unwrap(); + let registry_prefix = format!("{}/registry/src/", &cargo_home.display()); + + let wasm_buf = std::fs::read(wasm_path).unwrap(); + let wasm_str = String::from_utf8_lossy(&wasm_buf); + + wasm_str.contains(®istry_prefix) + } + + let cargo_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let fixture_path = cargo_dir.join("tests/fixtures/eth_abi/"); + + // The eth_abi example is known to exhibit this problem. + // Compile it both with and without path remapping to verify. + let remap_has_abs_paths = run("soroban_eth_abi", &fixture_path, Remap::Yes); + let noremap_has_abs_paths = run("soroban_eth_abi", &fixture_path, Remap::No); + + assert!(!remap_has_abs_paths); + assert!(noremap_has_abs_paths); +} diff --git a/cmd/crates/soroban-test/tests/it/config.rs b/cmd/crates/soroban-test/tests/it/config.rs index b796910a8..2e5bc21c1 100644 --- a/cmd/crates/soroban-test/tests/it/config.rs +++ b/cmd/crates/soroban-test/tests/it/config.rs @@ -283,7 +283,7 @@ fn use_env() { sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("bob") .assert() .success() @@ -330,7 +330,7 @@ fn config_dirs_precedence() { sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("alice") .arg("--verbose") .assert() @@ -393,3 +393,47 @@ fn set_default_network() { .stdout(predicate::str::contains("STELLAR_NETWORK=testnet")) .success(); } + +#[test] +fn cannot_create_contract_with_test_name() { + let sandbox = TestEnv::default(); + sandbox + .new_assert_cmd("keys") + .arg("generate") + .arg("--no-fund") + .arg("d") + .assert() + .success(); + sandbox + .new_assert_cmd("contract") + .arg("alias") + .arg("add") + .arg("d") + .arg("--id=CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE") + .assert() + .stderr(predicate::str::contains("cannot overlap with key")) + .failure(); +} + +#[test] +fn cannot_create_key_with_alias() { + let sandbox = TestEnv::default(); + sandbox + .new_assert_cmd("contract") + .arg("alias") + .arg("add") + .arg("t") + .arg("--id=CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE") + .assert() + .success(); + sandbox + .new_assert_cmd("keys") + .arg("generate") + .arg("--no-fund") + .arg("t") + .assert() + .stderr(predicate::str::contains( + "cannot overlap with contract alias", + )) + .failure(); +} 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/custom_types.rs b/cmd/crates/soroban-test/tests/it/integration/custom_types.rs index 6cdb61192..f4c2be61b 100644 --- a/cmd/crates/soroban-test/tests/it/integration/custom_types.rs +++ b/cmd/crates/soroban-test/tests/it/integration/custom_types.rs @@ -5,7 +5,7 @@ use soroban_test::TestEnv; use crate::integration::util::{deploy_custom, extend_contract}; -use super::util::invoke_with_roundtrip; +use super::util::{invoke, invoke_with_roundtrip}; fn invoke_custom(e: &TestEnv, id: &str, func: &str) -> assert_cmd::Command { let mut s = e.new_assert_cmd("contract"); @@ -40,7 +40,9 @@ async fn parse() { negative_i32(sandbox, id).await; negative_i64(sandbox, id).await; account_address(sandbox, id).await; + account_address_with_alias(sandbox, id).await; contract_address(sandbox, id).await; + contract_address_with_alias(sandbox, id).await; bytes(sandbox, id).await; const_enum(sandbox, id).await; number_arg_return_ok(sandbox, id); @@ -237,6 +239,12 @@ async fn account_address(sandbox: &TestEnv, id: &str) { .await; } +async fn account_address_with_alias(sandbox: &TestEnv, id: &str) { + let res = invoke(sandbox, id, "addresse", &json!("test").to_string()).await; + let test = format!("\"{}\"", super::tx::operations::test_address(sandbox)); + assert_eq!(test, res); +} + async fn contract_address(sandbox: &TestEnv, id: &str) { invoke_with_roundtrip( sandbox, @@ -247,6 +255,22 @@ async fn contract_address(sandbox: &TestEnv, id: &str) { .await; } +async fn contract_address_with_alias(sandbox: &TestEnv, id: &str) { + sandbox + .new_assert_cmd("contract") + .arg("alias") + .arg("add") + .arg("test_contract") + .arg("--id=CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE") + .assert() + .success(); + let res = invoke(sandbox, id, "addresse", &json!("test_contract").to_string()).await; + assert_eq!( + res, + "\"CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE\"" + ); +} + async fn bytes(sandbox: &TestEnv, id: &str) { invoke_with_roundtrip(sandbox, id, "bytes", json!("7374656c6c6172")).await; } 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 fd38c2012..e63fdd4b4 100644 --- a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs +++ b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs @@ -1,10 +1,9 @@ -use predicates::boolean::PredicateBooleanExt; use soroban_cli::{ commands::{ contract::{self, fetch}, txn_result::TxnResult, }, - config::{address::Address, locator, secret}, + config::{locator, secret}, }; use soroban_rpc::GetLatestLedgerResponse; use soroban_test::{AssertExt, TestEnv, LOCAL_NETWORK_PASSPHRASE}; @@ -19,7 +18,7 @@ async fn invoke_view_with_non_existent_source_account() { let sandbox = &TestEnv::new(); let id = deploy_hello(sandbox).await; let world = "world"; - let mut cmd = hello_world_cmd(&id, world); + let cmd = hello_world_cmd(&id, world); let res = sandbox.run_cmd_with(cmd, "").await.unwrap(); assert_eq!(res, TxnResult::Res(format!(r#"["Hello",{world:?}]"#))); } @@ -28,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") @@ -54,7 +53,7 @@ async fn invoke() { let secret_key = sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("test") .assert() .stdout_as_str(); @@ -66,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() @@ -116,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(); @@ -366,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/keys.rs b/cmd/crates/soroban-test/tests/it/integration/keys.rs index 267a0b095..28723b3a1 100644 --- a/cmd/crates/soroban-test/tests/it/integration/keys.rs +++ b/cmd/crates/soroban-test/tests/it/integration/keys.rs @@ -3,13 +3,12 @@ use soroban_test::AssertExt; use soroban_test::TestEnv; fn pubkey_for_identity(sandbox: &TestEnv, name: &str) -> String { - let output = sandbox + sandbox .new_assert_cmd("keys") .arg("address") .arg(name) .assert() - .stdout_as_str(); - return output; + .stdout_as_str() } #[tokio::test] @@ -61,7 +60,7 @@ async fn overwrite_identity() { "error: An identity with the name 'test2' already exists", )); - assert_eq!(initial_pubkey, pubkey_for_identity(&sandbox, "test2")); + assert_eq!(initial_pubkey, pubkey_for_identity(sandbox, "test2")); sandbox .new_assert_cmd("keys") @@ -72,5 +71,5 @@ async fn overwrite_identity() { .stderr(predicate::str::contains("Overwriting identity 'test2'")) .success(); - assert_ne!(initial_pubkey, pubkey_for_identity(&sandbox, "test2")); + assert_ne!(initial_pubkey, pubkey_for_identity(sandbox, "test2")); } diff --git a/cmd/crates/soroban-test/tests/it/integration/tx.rs b/cmd/crates/soroban-test/tests/it/integration/tx.rs index c3cd2693b..3fa85bc09 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx.rs @@ -4,7 +4,7 @@ use soroban_test::{AssertExt, TestEnv}; use crate::integration::util::{deploy_contract, DeployKind, HELLO_WORLD}; -mod operations; +pub mod operations; #[tokio::test] async fn simulate() { 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 9988b2cdd..8c894e5dc 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs @@ -3,6 +3,7 @@ use soroban_cli::{ utils::contract_id_hash_from_asset, xdr::{self, ReadXdr, SequenceNumber}, }; +use soroban_rpc::LedgerEntryResult; use soroban_test::{AssertExt, TestEnv}; use crate::integration::{ @@ -10,7 +11,7 @@ use crate::integration::{ util::{deploy_contract, DeployKind, HELLO_WORLD}, }; -fn test_address(sandbox: &TestEnv) -> String { +pub fn test_address(sandbox: &TestEnv) -> String { sandbox .new_assert_cmd("keys") .arg("address") @@ -30,6 +31,20 @@ fn new_account(sandbox: &TestEnv, name: &str) -> String { .stdout_as_str() } +fn gen_account_no_fund(sandbox: &TestEnv, name: &str) -> String { + sandbox + .new_assert_cmd("keys") + .args(["generate", "--no-fund", name]) + .assert() + .success(); + sandbox + .new_assert_cmd("keys") + .args(["address", name]) + .assert() + .success() + .stdout_as_str() +} + // returns test and test1 addresses fn setup_accounts(sandbox: &TestEnv) -> (String, String) { (test_address(sandbox), new_account(sandbox, "test1")) @@ -51,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; @@ -77,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); @@ -110,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; @@ -133,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(); @@ -173,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") @@ -209,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 @@ -271,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()); @@ -341,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()); @@ -436,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") @@ -514,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 @@ -558,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") @@ -614,3 +629,86 @@ async fn issue_asset(sandbox: &TestEnv, test: &str, asset: &str, limit: u64, ini .assert() .success(); } + +#[tokio::test] +async fn multi_create_accounts() { + let sandbox = &TestEnv::new(); + let client = sandbox.network.rpc_client().unwrap(); + let nums: Vec = (1..=3).collect(); + let mut accounts: Vec<(String, String)> = nums + .iter() + .map(|x| { + let name = format!("test_{x}"); + let address = gen_account_no_fund(sandbox, &name); + (name, address) + }) + .collect(); + let (_, test_99_address) = accounts.pop().unwrap(); + + let input = sandbox + .new_assert_cmd("tx") + .args([ + "new", + "create-account", + "--fee=1000000", + "--build-only", + "--destination", + &test_99_address, + ]) + .assert() + .success() + .stdout_as_str(); + + let final_tx = accounts.iter().fold(input, |tx_env, (_, address)| { + sandbox + .new_assert_cmd("tx") + .args(["op", "add", "create-account", "--destination", address]) + .write_stdin(tx_env.as_bytes()) + .assert() + .success() + .stdout_as_str() + }); + let out = sandbox + .new_assert_cmd("tx") + .arg("send") + .write_stdin( + sandbox + .new_assert_cmd("tx") + .arg("sign") + .arg("--sign-with-key=test") + .write_stdin(final_tx.as_bytes()) + .assert() + .success() + .stdout_as_str() + .as_bytes(), + ) + .assert() + .success() + .stdout_as_str(); + println!("{out}"); + let keys = accounts + .iter() + .map(|(_, address)| { + xdr::LedgerKey::Account(xdr::LedgerKeyAccount { + account_id: address.parse().unwrap(), + }) + }) + .collect::>(); + + let account = client.get_account(&test_99_address).await.unwrap(); + println!("{account:#?}"); + let entries = client.get_ledger_entries(&keys).await.unwrap(); + println!("{entries:#?}"); + entries + .entries + .unwrap() + .iter() + .for_each(|LedgerEntryResult { xdr, .. }| { + let xdr::LedgerEntryData::Account(value) = + xdr::LedgerEntryData::from_xdr_base64(xdr, xdr::Limits::none()).unwrap() + else { + panic!("Expected Account"); + }; + assert_eq!(value.balance, 10_000_000); + }); +} diff --git a/cmd/crates/soroban-test/tests/it/integration/util.rs b/cmd/crates/soroban-test/tests/it/integration/util.rs index 486b00a1b..fc7f824b6 100644 --- a/cmd/crates/soroban-test/tests/it/integration/util.rs +++ b/cmd/crates/soroban-test/tests/it/integration/util.rs @@ -11,16 +11,19 @@ pub const CUSTOM_TYPES: &Wasm = &Wasm::Custom("test-wasms", "test_custom_types") pub const CUSTOM_ACCOUNT: &Wasm = &Wasm::Custom("test-wasms", "test_custom_account"); pub const SWAP: &Wasm = &Wasm::Custom("test-wasms", "test_swap"); +pub async fn invoke(sandbox: &TestEnv, id: &str, func: &str, data: &str) -> String { + sandbox + .invoke_with_test(&["--id", id, "--", func, &format!("--{func}"), data]) + .await + .unwrap() +} pub async fn invoke_with_roundtrip(e: &TestEnv, id: &str, func: &str, data: D) where D: Display, { let data = data.to_string(); println!("{data}"); - let res = e - .invoke_with_test(&["--id", id, "--", func, &format!("--{func}"), &data]) - .await - .unwrap(); + let res = invoke(e, id, func, &data).await; assert_eq!(res, data); } diff --git a/cmd/crates/soroban-test/tests/it/main.rs b/cmd/crates/soroban-test/tests/it/main.rs index 5a0b2a07f..4dc54a194 100644 --- a/cmd/crates/soroban-test/tests/it/main.rs +++ b/cmd/crates/soroban-test/tests/it/main.rs @@ -3,8 +3,9 @@ mod build; mod config; mod help; mod init; -#[cfg(feature = "it")] +// #[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/Cargo.toml b/cmd/soroban-cli/Cargo.toml index ebb31c7e1..ba3fc505e 100644 --- a/cmd/soroban-cli/Cargo.toml +++ b/cmd/soroban-cli/Cargo.toml @@ -67,7 +67,8 @@ rand = "0.8.5" wasmparser = { workspace = true } sha2 = { workspace = true } csv = "1.1.6" -ed25519-dalek = { workspace = true } +# zeroize feature ensures that all sensitive data is zeroed out when dropped +ed25519-dalek = { workspace = true, features = ["zeroize"] } reqwest = { version = "0.12.7", default-features = false, features = [ "rustls-tls", "http2", @@ -118,9 +119,15 @@ fqdn = "0.3.12" open = "5.3.0" url = "2.5.2" wasm-gen = "0.1.4" +zeroize = "1.8.1" +keyring = { version = "3", features = ["apple-native", "windows-native", "sync-secret-service"] } +whoami = "1.5.2" +license-fetcher = "0.5.0" + [build-dependencies] crate-git-revision = "0.0.6" +license-fetcher = { version = "0.5.0", features = ["build"] } serde.workspace = true thiserror.workspace = true diff --git a/cmd/soroban-cli/build.rs b/cmd/soroban-cli/build.rs index b6e6dd92a..bcd2f3636 100644 --- a/cmd/soroban-cli/build.rs +++ b/cmd/soroban-cli/build.rs @@ -1,3 +1,10 @@ +use license_fetcher::build_script::generate_package_list_with_licenses; + fn main() { crate_git_revision::init(); + + generate_package_list_with_licenses().write(); + println!("cargo::rerun-if-changed=build.rs"); + println!("cargo::rerun-if-changed=Cargo.lock"); + println!("cargo::rerun-if-changed=Cargo.toml"); } diff --git a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs index 21fa2f383..bb2d2aa76 100644 --- a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs +++ b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs @@ -9,12 +9,14 @@ use ed25519_dalek::SigningKey; use heck::ToKebabCase; use crate::xdr::{ - self, Hash, InvokeContractArgs, ScAddress, ScSpecEntry, ScSpecFunctionV0, ScSpecTypeDef, ScVal, - ScVec, + self, Hash, InvokeContractArgs, ScSpecEntry, ScSpecFunctionV0, ScSpecTypeDef, ScVal, ScVec, }; use crate::commands::txn_result::TxnResult; -use crate::config::{self}; +use crate::config::{ + self, + sc_address::{self, UnresolvedScAddress}, +}; use soroban_spec_tools::Spec; #[derive(thiserror::Error, Debug)] @@ -43,6 +45,10 @@ pub enum Error { MissingArgument(String), #[error("")] MissingFileArg(PathBuf), + #[error(transparent)] + ScAddress(#[from] sc_address::Error), + #[error(transparent)] + Config(#[from] config::Error), } pub fn build_host_function_parameters( @@ -80,18 +86,18 @@ pub fn build_host_function_parameters( .map(|i| { let name = i.name.to_utf8_string()?; if let Some(mut val) = matches_.get_raw(&name) { - let mut s = val.next().unwrap().to_string_lossy().to_string(); + let mut s = val + .next() + .unwrap() + .to_string_lossy() + .trim_matches('"') + .to_string(); if matches!(i.type_, ScSpecTypeDef::Address) { - let cmd = crate::commands::keys::address::Cmd { - name: s.clone(), - hd_path: Some(0), - locator: config.locator.clone(), - }; - if let Ok(address) = cmd.public_key() { - s = address.to_string(); - } - if let Ok(key) = cmd.private_key() { - signers.push(key); + let addr = resolve_address(&s, config)?; + let signer = resolve_signer(&s, config); + s = addr; + if let Some(signer) = signer { + signers.push(signer); } } spec.from_string(&s, &i.type_) @@ -125,7 +131,7 @@ pub fn build_host_function_parameters( }) .collect::, Error>>()?; - let contract_address_arg = ScAddress::Contract(Hash(contract_id.0)); + let contract_address_arg = xdr::ScAddress::Contract(Hash(contract_id.0)); let function_symbol_arg = function .try_into() .map_err(|()| Error::FunctionNameTooLong(function.clone()))?; @@ -246,3 +252,22 @@ pub fn output_to_string( } Ok(TxnResult::Res(res_str)) } + +fn resolve_address(addr_or_alias: &str, config: &config::Args) -> Result { + let sc_address: UnresolvedScAddress = addr_or_alias.parse().unwrap(); + let account = match sc_address { + UnresolvedScAddress::Resolved(addr) => addr.to_string(), + addr @ UnresolvedScAddress::Alias(_) => { + let addr = addr.resolve(&config.locator, &config.get_network()?.network_passphrase)?; + match addr { + xdr::ScAddress::Account(account) => account.to_string(), + contract @ xdr::ScAddress::Contract(_) => contract.to_string(), + } + } + }; + Ok(account) +} + +fn resolve_signer(addr_or_alias: &str, config: &config::Args) -> Option { + config.locator.key(addr_or_alias).ok()?.key_pair(None).ok() +} 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 679e757f4..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 optional wasm binary - #[arg(long)] - pub wasm: 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, - /// The contract ID/address on the network - #[arg(long, visible_alias = "id")] - pub contract_id: String, - #[command(flatten)] - pub locator: locator::Args, - #[command(flatten)] - pub network: network::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), @@ -52,24 +39,13 @@ pub enum Error { NotUtf8(OsString), #[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] @@ -80,39 +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 network = self.network.get(&self.locator).ok().unwrap_or_else(|| { - network::DEFAULTS - .get("testnet") - .expect("no network specified and testnet network not found") - .into() - }); + let contract_spec::Fetched { contract, source } = + contract_spec::fetch(&self.wasm_or_hash_or_contract_id, &print).await?; - let contract_id = self - .locator - .resolve_contract_id(&self.contract_id, &network.network_passphrase)? - .0; - let contract_address = ScAddress::Contract(Hash(contract_id)); - - let spec = if let Some(wasm) = &self.wasm { - print.infoln("Loading contract spec from file..."); - let wasm: wasm::Args = wasm.into(); - wasm.parse()?.spec - } else { - 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)? + 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())); } @@ -125,7 +82,6 @@ impl NetworkRunnable for Cmd { } std::fs::create_dir_all(&self.output_dir)?; let p: Project = self.output_dir.clone().try_into()?; - print.infoln(format!("Network: {}", network.network_passphrase)); let absolute_path = self.output_dir.canonicalize()?; let file_name = absolute_path .file_name() @@ -133,12 +89,22 @@ impl NetworkRunnable for Cmd { let contract_name = &file_name .to_str() .ok_or_else(|| Error::NotUtf8(file_name.to_os_string()))?; - 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.to_string(), - &network.rpc_url, - &network.network_passphrase, + 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/deploy.rs b/cmd/soroban-cli/src/commands/contract/deploy.rs index 812fb4c77..3e6dcf3ea 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy.rs @@ -1,6 +1,7 @@ use crate::commands::global; pub mod asset; +pub mod utils; pub mod wasm; #[derive(Debug, clap::Subcommand)] diff --git a/cmd/soroban-cli/src/commands/contract/deploy/asset.rs b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs index 04a0380ed..8c4419277 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy/asset.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs @@ -1,3 +1,4 @@ +use crate::config::locator; use crate::xdr::{ Asset, ContractDataDurability, ContractExecutable, ContractIdPreimage, CreateContractArgs, Error as XdrError, Hash, HostFunction, InvokeHostFunctionOp, LedgerKey::ContractData, @@ -21,6 +22,8 @@ use crate::{ utils::contract_id_hash_from_asset, }; +use crate::commands::contract::deploy::utils::alias_validator; + #[derive(thiserror::Error, Debug)] pub enum Error { #[error("error parsing int: {0}")] @@ -39,6 +42,8 @@ pub enum Error { Network(#[from] network::Error), #[error(transparent)] Builder(#[from] builder::Error), + #[error(transparent)] + Locator(#[from] locator::Error), } impl From for Error { @@ -56,8 +61,15 @@ pub struct Cmd { #[command(flatten)] pub config: config::Args, + #[command(flatten)] pub fee: crate::fee::Args, + + /// The alias that will be used to save the assets's id. + /// Whenever used, `--alias` will always overwrite the existing contract id + /// configuration without asking for confirmation. + #[arg(long, value_parser = clap::builder::ValueParser::new(alias_validator))] + pub alias: Option, } impl Cmd { @@ -66,6 +78,16 @@ impl Cmd { match res { TxnEnvelopeResult::TxnEnvelope(tx) => println!("{}", tx.to_xdr_base64(Limits::none())?), TxnEnvelopeResult::Res(contract) => { + let network = self.config.get_network()?; + + if let Some(alias) = self.alias.clone() { + self.config.locator.save_contract_id( + &network.network_passphrase, + &contract, + &alias, + )?; + } + println!("{contract}"); } } diff --git a/cmd/soroban-cli/src/commands/contract/deploy/utils.rs b/cmd/soroban-cli/src/commands/contract/deploy/utils.rs new file mode 100644 index 000000000..2a698e2a8 --- /dev/null +++ b/cmd/soroban-cli/src/commands/contract/deploy/utils.rs @@ -0,0 +1,56 @@ +use regex::Regex; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error( + "alias must be 1-30 chars long, and have only letters, numbers, underscores and dashes" + )] + InvalidAliasFormat { alias: String }, +} + +pub fn alias_validator(alias: &str) -> Result { + let regex = Regex::new(r"^[a-zA-Z0-9_-]{1,30}$").unwrap(); + + if regex.is_match(alias) { + Ok(alias.into()) + } else { + Err(Error::InvalidAliasFormat { + alias: alias.into(), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_alias_validator_with_valid_inputs() { + let valid_inputs = [ + "hello", + "123", + "hello123", + "hello_123", + "123_hello", + "123-hello", + "hello-123", + "HeLlo-123", + ]; + + for input in valid_inputs { + let result = alias_validator(input); + assert!(result.is_ok()); + assert!(result.unwrap() == input); + } + } + + #[test] + fn test_alias_validator_with_invalid_inputs() { + let invalid_inputs = ["", "invalid!", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]; + + for input in invalid_inputs { + let result = alias_validator(input); + assert!(result.is_err()); + } + } +} diff --git a/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs index 1d85832b0..9bd8fed68 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs @@ -1,3 +1,4 @@ +use crate::commands::contract::deploy::utils::alias_validator; use std::array::TryFromSliceError; use std::ffi::OsString; use std::fmt::Debug; @@ -12,7 +13,6 @@ use crate::xdr::{ }; use clap::{arg, command, Parser}; use rand::Rng; -use regex::Regex; use soroban_spec_tools::contract as contract_spec; @@ -152,18 +152,6 @@ impl Cmd { } } -fn alias_validator(alias: &str) -> Result { - let regex = Regex::new(r"^[a-zA-Z0-9_-]{1,30}$").unwrap(); - - if regex.is_match(alias) { - Ok(alias.into()) - } else { - Err(Error::InvalidAliasFormat { - alias: alias.into(), - }) - } -} - #[async_trait::async_trait] impl NetworkRunnable for Cmd { type Error = Error; @@ -390,34 +378,4 @@ mod tests { assert!(result.is_ok()); } - - #[test] - fn test_alias_validator_with_valid_inputs() { - let valid_inputs = [ - "hello", - "123", - "hello123", - "hello_123", - "123_hello", - "123-hello", - "hello-123", - "HeLlo-123", - ]; - - for input in valid_inputs { - let result = alias_validator(input); - assert!(result.is_ok()); - assert!(result.unwrap() == input); - } - } - - #[test] - fn test_alias_validator_with_invalid_inputs() { - let invalid_inputs = ["", "invalid!", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]; - - for input in invalid_inputs { - let result = alias_validator(input); - assert!(result.is_err()); - } - } } diff --git a/cmd/soroban-cli/src/commands/contract/fetch.rs b/cmd/soroban-cli/src/commands/contract/fetch.rs index 31ed191ff..d73aac3b7 100644 --- a/cmd/soroban-cli/src/commands/contract/fetch.rs +++ b/cmd/soroban-cli/src/commands/contract/fetch.rs @@ -22,7 +22,7 @@ use crate::{ pub struct Cmd { /// Contract ID to fetch #[arg(long = "id", env = "STELLAR_CONTRACT_ID")] - pub contract_id: config::ContractAddress, + pub contract_id: config::UnresolvedContract, /// Where to write output otherwise stdout is used #[arg(long, short = 'o')] pub out_file: Option, 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..13355268f 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,15 +22,32 @@ 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")] - pub contract_id: Option, + /// 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, #[command(flatten)] @@ -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/init.rs b/cmd/soroban-cli/src/commands/contract/init.rs index 9147bacf0..d111ed5e0 100644 --- a/cmd/soroban-cli/src/commands/contract/init.rs +++ b/cmd/soroban-cli/src/commands/contract/init.rs @@ -322,12 +322,11 @@ mod tests { .unwrap() .as_array() .unwrap() - .get(0) - .unwrap() - .as_str() - .unwrap(), - "cdylib", - "expected [lib.crate-type] to be 'cdylib'" + .iter() + .map(|v| v.as_str().unwrap()) + .collect::>(), + ["lib", "cdylib"], + "expected [lib.crate-type] to be lib,cdylib" ); } diff --git a/cmd/soroban-cli/src/commands/contract/invoke.rs b/cmd/soroban-cli/src/commands/contract/invoke.rs index c7b631343..bd069698d 100644 --- a/cmd/soroban-cli/src/commands/contract/invoke.rs +++ b/cmd/soroban-cli/src/commands/contract/invoke.rs @@ -40,7 +40,7 @@ use soroban_spec_tools::contract; pub struct Cmd { /// Contract ID to invoke #[arg(long = "id", env = "STELLAR_CONTRACT_ID")] - pub contract_id: config::ContractAddress, + pub contract_id: config::UnresolvedContract, // For testing only #[arg(skip)] pub wasm: Option, 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/events.rs b/cmd/soroban-cli/src/commands/events.rs index 48d79c1b7..16ef410bd 100644 --- a/cmd/soroban-cli/src/commands/events.rs +++ b/cmd/soroban-cli/src/commands/events.rs @@ -42,7 +42,7 @@ pub struct Cmd { num_args = 1..=6, help_heading = "FILTERS" )] - contract_ids: Vec, + contract_ids: Vec, /// A set of (up to 4) topic filters to filter event topics on. A single /// topic filter can contain 1-4 different segment filters, separated by /// commas, with an asterisk (`*` character) indicating a wildcard segment. diff --git a/cmd/soroban-cli/src/commands/keys/add.rs b/cmd/soroban-cli/src/commands/keys/add.rs index d8f528bae..4c5ddbd9b 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::{address::KeyName, locator, secret}, + print::Print, +}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -15,7 +19,7 @@ pub enum Error { #[group(skip)] pub struct Cmd { /// Name of identity - pub name: String, + pub name: KeyName, #[command(flatten)] pub secrets: secret::Args, @@ -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/address.rs b/cmd/soroban-cli/src/commands/keys/address.rs index d13381b49..51ce90ed2 100644 --- a/cmd/soroban-cli/src/commands/keys/address.rs +++ b/cmd/soroban-cli/src/commands/keys/address.rs @@ -1,25 +1,21 @@ -use crate::commands::config::secret; - -use super::super::config::locator; use clap::arg; +use crate::{ + commands::config::{address, locator}, + config::UnresolvedMuxedAccount, +}; + #[derive(thiserror::Error, Debug)] pub enum Error { #[error(transparent)] - Config(#[from] locator::Error), - - #[error(transparent)] - Secret(#[from] secret::Error), - - #[error(transparent)] - StrKey(#[from] stellar_strkey::DecodeError), + Address(#[from] address::Error), } #[derive(Debug, clap::Parser, Clone)] #[group(skip)] pub struct Cmd { /// Name of identity to lookup, default test identity used if not provided - pub name: String, + pub name: UnresolvedMuxedAccount, /// If identity is a seed phrase use this hd path, default is 0 #[arg(long)] @@ -35,20 +31,14 @@ impl Cmd { Ok(()) } - pub fn private_key(&self) -> Result { - Ok(self - .locator - .read_identity(&self.name)? - .key_pair(self.hd_path)?) - } - pub fn public_key(&self) -> Result { - if let Ok(key) = stellar_strkey::ed25519::PublicKey::from_string(&self.name) { - Ok(key) - } else { - Ok(stellar_strkey::ed25519::PublicKey::from_payload( - self.private_key()?.verifying_key().as_bytes(), - )?) - } + let muxed = self + .name + .resolve_muxed_account(&self.locator, self.hd_path)?; + let bytes = match muxed { + soroban_sdk::xdr::MuxedAccount::Ed25519(uint256) => uint256.0, + soroban_sdk::xdr::MuxedAccount::MuxedEd25519(muxed_account) => muxed_account.ed25519.0, + }; + Ok(stellar_strkey::ed25519::PublicKey(bytes)) } } 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..8ec0158bb 100644 --- a/cmd/soroban-cli/src/commands/keys/generate.rs +++ b/cmd/soroban-cli/src/commands/keys/generate.rs @@ -1,10 +1,16 @@ use clap::{arg, command}; +use sep5::SeedPhrase; use super::super::config::{ locator, network, secret::{self, Secret}, }; -use crate::{commands::global, print::Print}; +use crate::{ + commands::global, + config::address::KeyName, + print::Print, + signer::keyring::{self, StellarEntry}, +}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -19,6 +25,9 @@ pub enum Error { #[error("An identity with the name '{0}' already exists")] IdentityAlreadyExists(String), + + #[error(transparent)] + Keyring(#[from] keyring::Error), } #[derive(Debug, clap::Parser, Clone)] @@ -26,10 +35,12 @@ pub enum Error { #[allow(clippy::struct_excessive_bools)] pub struct Cmd { /// Name of identity - pub name: String, + pub name: KeyName, + /// Do not fund address #[arg(long)] pub no_fund: bool, + /// Optional seed to use when generating seed phrase. /// Random otherwise. #[arg(long, conflicts_with = "default_seed")] @@ -39,6 +50,10 @@ pub struct Cmd { #[arg(long, short = 's')] pub as_secret: bool, + /// Save in OS-specific secure store + #[arg(long)] + pub secure_store: bool, + #[command(flatten)] pub config_locator: locator::Args, @@ -69,10 +84,10 @@ impl Cmd { if self.config_locator.read_identity(&self.name).is_ok() { if !self.overwrite { - return Err(Error::IdentityAlreadyExists(self.name.clone())); + return Err(Error::IdentityAlreadyExists(self.name.to_string())); } - print.exclaimln(format!("Overwriting identity '{}'", &self.name)); + print.exclaimln(format!("Overwriting identity '{}'", &self.name.to_string())); } if !self.fund { @@ -83,20 +98,9 @@ impl Cmd { warning. It can be suppressed with -q flag.", ); } - - let seed_phrase = if self.default_seed { - Secret::test_seed_phrase() - } else { - Secret::from_seed(self.seed.as_deref()) - }?; - - let secret = if self.as_secret { - seed_phrase.private_key(self.hd_path)?.into() - } else { - seed_phrase - }; - - self.config_locator.write_identity(&self.name, &secret)?; + let secret = self.secret(&print)?; + 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,8 +112,139 @@ impl Cmd { tracing::warn!("fund_address failed: {e}"); }) .unwrap_or_default(); + print.checkln(format!( + "Account {:?} funded on {:?}", + self.name, network.network_passphrase + )); } Ok(()) } + + fn secret(&self, print: &Print) -> Result { + let seed_phrase = self.seed_phrase()?; + if self.secure_store { + // secure_store:org.stellar.cli: + let entry_name_with_prefix = format!( + "{}{}-{}", + keyring::SECURE_STORE_ENTRY_PREFIX, + keyring::SECURE_STORE_ENTRY_SERVICE, + self.name + ); + + //checking that the entry name is valid before writing to the secure store + let secret: Secret = entry_name_with_prefix.parse()?; + + if let Secret::SecureStore { entry_name } = &secret { + Self::write_to_secure_store(entry_name, seed_phrase, print)?; + } + + return Ok(secret); + } + let secret: Secret = seed_phrase.into(); + Ok(if self.as_secret { + secret.private_key(self.hd_path)?.into() + } else { + secret + }) + } + + fn seed_phrase(&self) -> Result { + Ok(if self.default_seed { + secret::test_seed_phrase() + } else { + secret::seed_phrase_from_seed(self.seed.as_deref()) + }?) + } + + fn write_to_secure_store( + entry_name: &String, + seed_phrase: SeedPhrase, + print: &Print, + ) -> Result<(), Error> { + print.infoln(format!("Writing to secure store: {entry_name}")); + let entry = StellarEntry::new(entry_name)?; + if let Ok(key) = entry.get_public_key(None) { + print.warnln(format!("A key for {entry_name} already exists in your operating system's secure store: {key}")); + } else { + print.infoln(format!( + "Saving a new key to your operating system's secure store: {entry_name}" + )); + entry.set_seed_phrase(seed_phrase)?; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::config::{address::KeyName, secret::Secret}; + use keyring::{mock, set_default_credential_builder}; + + fn set_up_test() -> (super::locator::Args, super::Cmd) { + let temp_dir = tempfile::tempdir().unwrap(); + let locator = super::locator::Args { + global: false, + config_dir: Some(temp_dir.path().to_path_buf()), + }; + + let cmd = super::Cmd { + name: KeyName("test_name".to_string()), + no_fund: true, + seed: None, + as_secret: false, + secure_store: false, + config_locator: locator.clone(), + hd_path: None, + default_seed: false, + network: super::network::Args::default(), + fund: false, + overwrite: false, + }; + + (locator, cmd) + } + + fn global_args() -> super::global::Args { + super::global::Args { + quiet: true, + ..Default::default() + } + } + + #[tokio::test] + async fn test_storing_secret_as_a_seed_phrase() { + let (test_locator, cmd) = set_up_test(); + let global_args = global_args(); + + let result = cmd.run(&global_args).await; + assert!(result.is_ok()); + let identity = test_locator.read_identity("test_name").unwrap(); + assert!(matches!(identity, Secret::SeedPhrase { .. })); + } + + #[tokio::test] + async fn test_storing_secret_as_a_secret_key() { + let (test_locator, mut cmd) = set_up_test(); + cmd.as_secret = true; + let global_args = global_args(); + + let result = cmd.run(&global_args).await; + assert!(result.is_ok()); + let identity = test_locator.read_identity("test_name").unwrap(); + assert!(matches!(identity, Secret::SecretKey { .. })); + } + + #[tokio::test] + async fn test_storing_secret_in_secure_store() { + set_default_credential_builder(mock::default_credential_builder()); + let (test_locator, mut cmd) = set_up_test(); + cmd.secure_store = true; + let global_args = global_args(); + + let result = cmd.run(&global_args).await; + assert!(result.is_ok()); + let identity = test_locator.read_identity("test_name").unwrap(); + assert!(matches!(identity, Secret::SecureStore { .. })); + } } diff --git a/cmd/soroban-cli/src/commands/keys/mod.rs b/cmd/soroban-cli/src/commands/keys/mod.rs index 8729ee9af..3e36df085 100644 --- a/cmd/soroban-cli/src/commands/keys/mod.rs +++ b/cmd/soroban-cli/src/commands/keys/mod.rs @@ -8,11 +8,11 @@ pub mod fund; pub mod generate; pub mod ls; pub mod rm; -pub mod show; +pub mod secret; #[derive(Debug, Parser)] pub enum Cmd { - /// Add a new identity (keypair, ledger, macOS keychain) + /// Add a new identity (keypair, ledger, OS specific secure store) Add(add::Cmd), /// Given an identity return its address (public key) @@ -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/licenses.rs b/cmd/soroban-cli/src/commands/licenses.rs new file mode 100644 index 000000000..8e60073af --- /dev/null +++ b/cmd/soroban-cli/src/commands/licenses.rs @@ -0,0 +1,48 @@ +use clap::Parser; +use std::fmt::Debug; + +use license_fetcher::get_package_list_macro; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + /// Display the license text. + #[arg(long, short)] + pub verbose: bool, +} + +impl Cmd { + #[allow(clippy::unused_self)] + pub fn run(&self) { + let package_list = get_package_list_macro!(); + + package_list.iter().for_each(|pkg| { + println!( + "Name: {name}\nVersion: {version}\nLicense: {license}", + name = pkg.name, + version = pkg.version, + license = pkg + .license_identifier + .clone() + .unwrap_or("Unknown".to_string()), + ); + + if let Some(repo) = pkg.repository.clone() { + println!("Repo: {repo}"); + } + + if let Some(url) = pkg.homepage.clone() { + println!("URL: {url}"); + } + + if self.verbose { + if let Some(text) = pkg.license_text.clone() { + println!("{text}"); + println!("———"); + } + } + + println!(); + }); + } +} diff --git a/cmd/soroban-cli/src/commands/mod.rs b/cmd/soroban-cli/src/commands/mod.rs index 25d61364d..7d86fc003 100644 --- a/cmd/soroban-cli/src/commands/mod.rs +++ b/cmd/soroban-cli/src/commands/mod.rs @@ -13,6 +13,7 @@ pub mod env; pub mod events; pub mod global; pub mod keys; +pub mod licenses; pub mod network; pub mod plugin; pub mod snapshot; @@ -117,6 +118,7 @@ impl Root { Cmd::Container(container) => container.run(&self.global_args).await?, Cmd::Snapshot(snapshot) => snapshot.run(&self.global_args).await?, Cmd::Version(version) => version.run(), + Cmd::Licenses(licenses) => licenses.run(), Cmd::Keys(id) => id.run(&self.global_args).await?, Cmd::Tx(tx) => tx.run(&self.global_args).await?, Cmd::Cache(cache) => cache.run()?, @@ -143,9 +145,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 @@ -181,6 +186,9 @@ pub enum Cmd { /// Print version information Version(version::Cmd), + + /// Show dependency licenses + Licenses(licenses::Cmd), } #[derive(thiserror::Error, Debug)] 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..9ad39953f 100644 --- a/cmd/soroban-cli/src/commands/snapshot/create.rs +++ b/cmd/soroban-cli/src/commands/snapshot/create.rs @@ -34,7 +34,7 @@ use crate::{ tx::builder, utils::get_name_from_stellar_asset_contract_storage, }; -use crate::{config::address::Address, utils::http}; +use crate::{config::address::UnresolvedMuxedAccount, utils::http}; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)] pub enum Output { @@ -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; } }; @@ -407,7 +413,7 @@ impl Cmd { // Resolve an account address to an account id. The address can be a // G-address or a key name (as in `stellar keys address NAME`). fn resolve_account(&self, address: &str) -> Option { - let address: Address = address.parse().ok()?; + let address: UnresolvedMuxedAccount = address.parse().ok()?; Some(AccountId(xdr::PublicKey::PublicKeyTypeEd25519( match address.resolve_muxed_account(&self.locator, None).ok()? { diff --git a/cmd/soroban-cli/src/commands/tx/help.rs b/cmd/soroban-cli/src/commands/tx/help.rs new file mode 100644 index 000000000..c3d15d41d --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/help.rs @@ -0,0 +1,24 @@ +pub const ACCOUNT_MERGE:&str = "Transfers the XLM balance of an account to another account and removes the source account from the ledger"; +pub const BUMP_SEQUENCE: &str = "Bumps forward the sequence number of the source account to the given sequence number, invalidating any transaction with a smaller sequence number"; +pub const CHANGE_TRUST: &str = r"Creates, updates, or deletes a trustline +Learn more about trustlines +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines"; + +pub const CREATE_ACCOUNT: &str = + "Creates and funds a new account with the specified starting balance"; +pub const MANAGE_DATA: &str = r"Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account +Learn more about entries and subentries: +https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries"; +pub const PAYMENT: &str = "Sends an amount in a specific asset to a destination account"; +pub const SET_OPTIONS: &str = r"Set option for an account such as flags, inflation destination, signers, home domain, and master key weight +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags +Learn more about the home domain: +https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md +Learn more about signers operations and key weight: +https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig"; +pub const SET_TRUSTLINE_FLAGS: &str = r"Allows issuing account to configure authorization and trustline flags to an asset +The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. +If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. +Learn more about flags: +https://developers.stellar.org/docs/learn/glossary#flags"; diff --git a/cmd/soroban-cli/src/commands/tx/mod.rs b/cmd/soroban-cli/src/commands/tx/mod.rs index c0390f92e..d9fd79faf 100644 --- a/cmd/soroban-cli/src/commands/tx/mod.rs +++ b/cmd/soroban-cli/src/commands/tx/mod.rs @@ -2,7 +2,9 @@ use super::global; pub mod args; pub mod hash; +pub mod help; pub mod new; +pub mod op; pub mod send; pub mod sign; pub mod simulate; @@ -12,17 +14,20 @@ pub use args::Args; #[derive(Debug, clap::Subcommand)] pub enum Cmd { - /// Simulate a transaction envelope from stdin - Simulate(simulate::Cmd), /// Calculate the hash of a transaction envelope from stdin Hash(hash::Cmd), - /// Sign a transaction envelope appending the signature to the envelope - Sign(sign::Cmd), - /// Send a transaction envelope to the network - Send(send::Cmd), /// Create a new transaction #[command(subcommand)] New(new::Cmd), + /// Manipulate the operations in a transaction, including adding new operations + #[command(subcommand, visible_alias = "op")] + Operation(op::Cmd), + /// Send a transaction envelope to the network + Send(send::Cmd), + /// Sign a transaction envelope appending the signature to the envelope + Sign(sign::Cmd), + /// Simulate a transaction envelope from stdin + Simulate(simulate::Cmd), } #[derive(thiserror::Error, Debug)] @@ -32,21 +37,24 @@ pub enum Error { #[error(transparent)] New(#[from] new::Error), #[error(transparent)] - Simulate(#[from] simulate::Error), + Op(#[from] op::Error), + #[error(transparent)] + Send(#[from] send::Error), #[error(transparent)] Sign(#[from] sign::Error), #[error(transparent)] - Send(#[from] send::Error), + Simulate(#[from] simulate::Error), } impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { match self { - Cmd::Simulate(cmd) => cmd.run(global_args).await?, Cmd::Hash(cmd) => cmd.run(global_args)?, Cmd::New(cmd) => cmd.run(global_args).await?, - Cmd::Sign(cmd) => cmd.run(global_args).await?, + Cmd::Operation(cmd) => cmd.run(global_args)?, Cmd::Send(cmd) => cmd.run(global_args).await?, + Cmd::Sign(cmd) => cmd.run(global_args).await?, + Cmd::Simulate(cmd) => cmd.run(global_args).await?, }; Ok(()) } diff --git a/cmd/soroban-cli/src/commands/tx/new/account_merge.rs b/cmd/soroban-cli/src/commands/tx/new/account_merge.rs index ce01f5e1f..0d07fce91 100644 --- a/cmd/soroban-cli/src/commands/tx/new/account_merge.rs +++ b/cmd/soroban-cli/src/commands/tx/new/account_merge.rs @@ -7,13 +7,19 @@ use crate::{commands::tx, xdr}; pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +pub struct Args { /// Muxed Account to merge with, e.g. `GBX...`, 'MBX...' #[arg(long)] pub account: xdr::MuxedAccount, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { xdr::OperationBody::AccountMerge(cmd.account.clone()) } } diff --git a/cmd/soroban-cli/src/commands/tx/new/bump_sequence.rs b/cmd/soroban-cli/src/commands/tx/new/bump_sequence.rs index dfb521f23..ff04e96a0 100644 --- a/cmd/soroban-cli/src/commands/tx/new/bump_sequence.rs +++ b/cmd/soroban-cli/src/commands/tx/new/bump_sequence.rs @@ -7,13 +7,19 @@ use crate::{commands::tx, xdr}; pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +pub struct Args { /// Sequence number to bump to #[arg(long)] pub bump_to: i64, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { xdr::OperationBody::BumpSequence(xdr::BumpSequenceOp { bump_to: cmd.bump_to.into(), }) diff --git a/cmd/soroban-cli/src/commands/tx/new/change_trust.rs b/cmd/soroban-cli/src/commands/tx/new/change_trust.rs index da9acc8cf..2013db75b 100644 --- a/cmd/soroban-cli/src/commands/tx/new/change_trust.rs +++ b/cmd/soroban-cli/src/commands/tx/new/change_trust.rs @@ -7,6 +7,12 @@ use crate::{commands::tx, tx::builder, xdr}; pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +pub struct Args { #[arg(long)] pub line: builder::Asset, /// Limit for the trust line, 0 to remove the trust line @@ -14,8 +20,8 @@ pub struct Cmd { pub limit: i64, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { let line = match cmd.line.0.clone() { xdr::Asset::CreditAlphanum4(asset) => xdr::ChangeTrustAsset::CreditAlphanum4(asset), xdr::Asset::CreditAlphanum12(asset) => xdr::ChangeTrustAsset::CreditAlphanum12(asset), diff --git a/cmd/soroban-cli/src/commands/tx/new/create_account.rs b/cmd/soroban-cli/src/commands/tx/new/create_account.rs index 2826439e9..acdfd6e2d 100644 --- a/cmd/soroban-cli/src/commands/tx/new/create_account.rs +++ b/cmd/soroban-cli/src/commands/tx/new/create_account.rs @@ -7,16 +7,22 @@ use crate::{commands::tx, tx::builder, xdr}; pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +pub struct Args { /// Account Id to create, e.g. `GBX...` - #[arg(long)] + #[arg(long, alias = "dest")] pub destination: xdr::AccountId, /// Initial balance in stroops of the account, default 1 XLM #[arg(long, default_value = "10_000_000")] pub starting_balance: builder::Amount, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { xdr::OperationBody::CreateAccount(xdr::CreateAccountOp { destination: cmd.destination.clone(), starting_balance: cmd.starting_balance.into(), diff --git a/cmd/soroban-cli/src/commands/tx/new/manage_data.rs b/cmd/soroban-cli/src/commands/tx/new/manage_data.rs index 4f4ab480d..30e9a36fd 100644 --- a/cmd/soroban-cli/src/commands/tx/new/manage_data.rs +++ b/cmd/soroban-cli/src/commands/tx/new/manage_data.rs @@ -7,6 +7,12 @@ use crate::{commands::tx, xdr}; pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +pub struct Args { /// String up to 64 bytes long. /// If this is a new Name it will add the given name/value pair to the account. /// If this Name is already present then the associated value will be modified. @@ -19,8 +25,8 @@ pub struct Cmd { pub data_value: Option>, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { let data_value = cmd.data_value.clone().map(Into::into); let data_name = cmd.data_name.clone().into(); xdr::OperationBody::ManageData(xdr::ManageDataOp { diff --git a/cmd/soroban-cli/src/commands/tx/new/mod.rs b/cmd/soroban-cli/src/commands/tx/new/mod.rs index e5923f4ec..24c25995f 100644 --- a/cmd/soroban-cli/src/commands/tx/new/mod.rs +++ b/cmd/soroban-cli/src/commands/tx/new/mod.rs @@ -2,47 +2,33 @@ use clap::Parser; use super::global; -mod account_merge; -mod bump_sequence; -mod change_trust; -mod create_account; -mod manage_data; -mod payment; -mod set_options; -mod set_trustline_flags; +pub mod account_merge; +pub mod bump_sequence; +pub mod change_trust; +pub mod create_account; +pub mod manage_data; +pub mod payment; +pub mod set_options; +pub mod set_trustline_flags; #[derive(Debug, Parser)] #[allow(clippy::doc_markdown)] pub enum Cmd { - /// Transfers the XLM balance of an account to another account and removes the source account from the ledger + #[command(about = super::help::ACCOUNT_MERGE)] AccountMerge(account_merge::Cmd), - /// Bumps forward the sequence number of the source account to the given sequence number, invalidating any transaction with a smaller sequence number + #[command(about = super::help::BUMP_SEQUENCE)] BumpSequence(bump_sequence::Cmd), - /// Creates, updates, or deletes a trustline - /// Learn more about trustlines - /// https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines + #[command(about = super::help::CHANGE_TRUST)] ChangeTrust(change_trust::Cmd), - /// Creates and funds a new account with the specified starting balance + #[command(about = super::help::CREATE_ACCOUNT)] CreateAccount(create_account::Cmd), - /// Sets, modifies, or deletes a data entry (name/value pair) that is attached to an account - /// Learn more about entries and subentries: - /// https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#subentries + #[command(about = super::help::MANAGE_DATA)] ManageData(manage_data::Cmd), - /// Sends an amount in a specific asset to a destination account + #[command(about = super::help::PAYMENT)] Payment(payment::Cmd), - /// Set option for an account such as flags, inflation destination, signers, home domain, and master key weight - /// Learn more about flags: - /// https://developers.stellar.org/docs/learn/glossary#flags - /// Learn more about the home domain: - /// https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md - /// Learn more about signers operations and key weight: - /// https://developers.stellar.org/docs/learn/encyclopedia/security/signatures-multisig#multisig + #[command(about = super::help::SET_OPTIONS)] SetOptions(set_options::Cmd), - /// Allows issuing account to configure authorization and trustline flags to an asset - /// The Asset parameter is of the `TrustLineAsset` type. If you are modifying a trustline to a regular asset (i.e. one in a Code:Issuer format), this is equivalent to the Asset type. - /// If you are modifying a trustline to a pool share, however, this is composed of the liquidity pool's unique ID. - /// Learn more about flags: - /// https://developers.stellar.org/docs/learn/glossary#flags + #[command(about = super::help::SET_TRUSTLINE_FLAGS)] SetTrustlineFlags(set_trustline_flags::Cmd), } @@ -55,14 +41,14 @@ pub enum Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { match self { - Cmd::AccountMerge(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, - Cmd::BumpSequence(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, - Cmd::ChangeTrust(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, - Cmd::CreateAccount(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, - Cmd::ManageData(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, - Cmd::Payment(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, - Cmd::SetOptions(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, - Cmd::SetTrustlineFlags(cmd) => cmd.tx.handle_and_print(cmd, global_args).await, + Cmd::AccountMerge(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, + Cmd::BumpSequence(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, + Cmd::ChangeTrust(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, + Cmd::CreateAccount(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, + Cmd::ManageData(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, + Cmd::Payment(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, + Cmd::SetOptions(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, + Cmd::SetTrustlineFlags(cmd) => cmd.tx.handle_and_print(&cmd.op, global_args).await, }?; Ok(()) } diff --git a/cmd/soroban-cli/src/commands/tx/new/payment.rs b/cmd/soroban-cli/src/commands/tx/new/payment.rs index 3cebfa532..683b2731c 100644 --- a/cmd/soroban-cli/src/commands/tx/new/payment.rs +++ b/cmd/soroban-cli/src/commands/tx/new/payment.rs @@ -7,8 +7,14 @@ use crate::{commands::tx, tx::builder, xdr}; pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +pub struct Args { /// Account to send to, e.g. `GBX...` - #[arg(long)] + #[arg(long, visible_alias = "dest")] pub destination: xdr::MuxedAccount, /// Asset to send, default native, e.i. XLM #[arg(long, default_value = "native")] @@ -18,8 +24,8 @@ pub struct Cmd { pub amount: builder::Amount, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { xdr::OperationBody::Payment(xdr::PaymentOp { destination: cmd.destination.clone(), asset: cmd.asset.clone().into(), diff --git a/cmd/soroban-cli/src/commands/tx/new/set_options.rs b/cmd/soroban-cli/src/commands/tx/new/set_options.rs index 69cd10745..77c7c0895 100644 --- a/cmd/soroban-cli/src/commands/tx/new/set_options.rs +++ b/cmd/soroban-cli/src/commands/tx/new/set_options.rs @@ -3,11 +3,17 @@ use clap::{command, Parser}; use crate::{commands::tx, xdr}; #[derive(Parser, Debug, Clone)] -#[allow(clippy::struct_excessive_bools, clippy::doc_markdown)] #[group(skip)] pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +#[allow(clippy::struct_excessive_bools, clippy::doc_markdown)] +pub struct Args { #[arg(long)] /// Account of the inflation destination. pub inflation_dest: Option, @@ -61,8 +67,8 @@ pub struct Cmd { pub clear_clawback_enabled: bool, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { let mut set_flags = None; let mut set_flag = |flag: xdr::AccountFlags| { *set_flags.get_or_insert(0) |= flag as u32; diff --git a/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs b/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs index d9b70ecbd..482dd3a90 100644 --- a/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs +++ b/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs @@ -2,12 +2,18 @@ use clap::{command, Parser}; use crate::{commands::tx, tx::builder, xdr}; -#[allow(clippy::struct_excessive_bools, clippy::doc_markdown)] #[derive(Parser, Debug, Clone)] #[group(skip)] pub struct Cmd { #[command(flatten)] pub tx: tx::Args, + #[clap(flatten)] + pub op: Args, +} + +#[derive(Debug, clap::Args, Clone)] +#[allow(clippy::struct_excessive_bools, clippy::doc_markdown)] +pub struct Args { /// Account to set trustline flags for #[arg(long)] pub trustor: xdr::AccountId, @@ -32,8 +38,8 @@ pub struct Cmd { pub clear_trustline_clawback_enabled: bool, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { +impl From<&Args> for xdr::OperationBody { + fn from(cmd: &Args) -> Self { let mut set_flags = 0; let mut set_flag = |flag: xdr::TrustLineFlags| set_flags |= flag as u32; diff --git a/cmd/soroban-cli/src/commands/tx/op/add/account_merge.rs b/cmd/soroban-cli/src/commands/tx/op/add/account_merge.rs new file mode 100644 index 000000000..bd643c199 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/account_merge.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::account_merge::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/args.rs b/cmd/soroban-cli/src/commands/tx/op/add/args.rs new file mode 100644 index 000000000..51ee4d476 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/args.rs @@ -0,0 +1,46 @@ +use super::xdr::add_op; +use crate::{ + config::{address, locator}, + xdr, +}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Address(#[from] address::Error), + #[error(transparent)] + TxXdr(#[from] super::xdr::Error), +} + +#[derive(Debug, clap::Args, Clone)] +#[group(skip)] +pub struct Args { + #[clap(flatten)] + pub locator: locator::Args, + /// Source account used for the operation + #[arg( + long, + visible_alias = "op-source", + env = "STELLAR_OPERATION_SOURCE_ACCOUNT" + )] + pub operation_source_account: Option, +} + +impl Args { + pub fn add_op( + &self, + op_body: impl Into, + tx_env: xdr::TransactionEnvelope, + ) -> Result { + let source_account = self + .operation_source_account + .as_ref() + .map(|a| a.resolve_muxed_account(&self.locator, None)) + .transpose()?; + let op = xdr::Operation { + source_account, + body: op_body.into(), + }; + Ok(add_op(tx_env, op)?) + } +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/bump_sequence.rs b/cmd/soroban-cli/src/commands/tx/op/add/bump_sequence.rs new file mode 100644 index 000000000..907d8d2d6 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/bump_sequence.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::bump_sequence::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/change_trust.rs b/cmd/soroban-cli/src/commands/tx/op/add/change_trust.rs new file mode 100644 index 000000000..af9afae1b --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/change_trust.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::change_trust::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/create_account.rs b/cmd/soroban-cli/src/commands/tx/op/add/create_account.rs new file mode 100644 index 000000000..e30ff20a1 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/create_account.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::create_account::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/manage_data.rs b/cmd/soroban-cli/src/commands/tx/op/add/manage_data.rs new file mode 100644 index 000000000..962233a84 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/manage_data.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::manage_data::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/mod.rs b/cmd/soroban-cli/src/commands/tx/op/add/mod.rs new file mode 100644 index 000000000..b94fc74ce --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/mod.rs @@ -0,0 +1,65 @@ +use clap::Parser; + +use super::super::{global, help, xdr::tx_envelope_from_stdin}; +use crate::xdr::WriteXdr; + +pub(crate) use super::super::{new, xdr}; + +mod account_merge; +mod args; +mod bump_sequence; +mod change_trust; +mod create_account; +mod manage_data; +mod payment; +mod set_options; +mod set_trustline_flags; + +#[derive(Debug, Parser)] +#[allow(clippy::doc_markdown)] +pub enum Cmd { + #[command(about = help::ACCOUNT_MERGE)] + AccountMerge(account_merge::Cmd), + #[command(about = help::BUMP_SEQUENCE)] + BumpSequence(bump_sequence::Cmd), + #[command(about = help::CHANGE_TRUST)] + ChangeTrust(change_trust::Cmd), + #[command(about = help::CREATE_ACCOUNT)] + CreateAccount(create_account::Cmd), + #[command(about = help::MANAGE_DATA)] + ManageData(manage_data::Cmd), + #[command(about = help::PAYMENT)] + Payment(payment::Cmd), + #[command(about = help::SET_OPTIONS)] + SetOptions(set_options::Cmd), + #[command(about = help::SET_TRUSTLINE_FLAGS)] + SetTrustlineFlags(set_trustline_flags::Cmd), +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Args(#[from] args::Error), + #[error(transparent)] + TxXdr(#[from] super::super::xdr::Error), + #[error(transparent)] + Xdr(#[from] crate::xdr::Error), +} + +impl Cmd { + pub fn run(&self, _: &global::Args) -> Result<(), Error> { + let tx_env = tx_envelope_from_stdin()?; + let res = match self { + Cmd::AccountMerge(cmd) => cmd.args.add_op(&cmd.op, tx_env), + Cmd::BumpSequence(cmd) => cmd.args.add_op(&cmd.op, tx_env), + Cmd::ChangeTrust(cmd) => cmd.args.add_op(&cmd.op, tx_env), + Cmd::CreateAccount(cmd) => cmd.args.add_op(&cmd.op, tx_env), + Cmd::ManageData(cmd) => cmd.args.add_op(&cmd.op, tx_env), + Cmd::Payment(cmd) => cmd.args.add_op(&cmd.op, tx_env), + Cmd::SetOptions(cmd) => cmd.args.add_op(&cmd.op, tx_env), + Cmd::SetTrustlineFlags(cmd) => cmd.args.add_op(&cmd.op, tx_env), + }?; + println!("{}", res.to_xdr_base64(crate::xdr::Limits::none())?); + Ok(()) + } +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/payment.rs b/cmd/soroban-cli/src/commands/tx/op/add/payment.rs new file mode 100644 index 000000000..d8146c91a --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/payment.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::payment::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/set_options.rs b/cmd/soroban-cli/src/commands/tx/op/add/set_options.rs new file mode 100644 index 000000000..75b43124a --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/set_options.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::set_options::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/add/set_trustline_flags.rs b/cmd/soroban-cli/src/commands/tx/op/add/set_trustline_flags.rs new file mode 100644 index 000000000..8ffee7a7b --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/add/set_trustline_flags.rs @@ -0,0 +1,14 @@ +use clap::{command, Parser}; + +use std::fmt::Debug; + +use super::new; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub args: super::args::Args, + #[command(flatten)] + pub op: new::set_trustline_flags::Args, +} diff --git a/cmd/soroban-cli/src/commands/tx/op/mod.rs b/cmd/soroban-cli/src/commands/tx/op/mod.rs new file mode 100644 index 000000000..9c38ecfd3 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/op/mod.rs @@ -0,0 +1,25 @@ +use super::global; + +pub mod add; + +#[derive(Debug, clap::Subcommand)] +pub enum Cmd { + /// Add Operation to a transaction + #[command(subcommand)] + Add(add::Cmd), +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Add(#[from] add::Error), +} + +impl Cmd { + pub fn run(&self, global_args: &global::Args) -> Result<(), Error> { + match self { + Cmd::Add(cmd) => cmd.run(global_args)?, + }; + Ok(()) + } +} diff --git a/cmd/soroban-cli/src/commands/tx/xdr.rs b/cmd/soroban-cli/src/commands/tx/xdr.rs index fcacce9ac..0e6e253e6 100644 --- a/cmd/soroban-cli/src/commands/tx/xdr.rs +++ b/cmd/soroban-cli/src/commands/tx/xdr.rs @@ -3,7 +3,9 @@ use std::{ path::PathBuf, }; -use crate::xdr::{Limits, ReadXdr, Transaction, TransactionEnvelope, TransactionV1Envelope}; +use crate::xdr::{ + Limits, Operation, ReadXdr, Transaction, TransactionEnvelope, TransactionV1Envelope, +}; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -17,6 +19,8 @@ pub enum Error { Io(#[from] std::io::Error), #[error("only transaction v1 is supported")] OnlyTransactionV1Supported, + #[error("too many operations, limited to 100 operations in a transaction")] + TooManyOperations, } pub fn tx_envelope_from_stdin() -> Result { @@ -36,3 +40,11 @@ pub fn unwrap_envelope_v1(tx_env: TransactionEnvelope) -> Result Result { + let mut tx = unwrap_envelope_v1(tx_env)?; + let mut ops = tx.operations.to_vec(); + ops.push(op); + tx.operations = ops.try_into().map_err(|_| Error::TooManyOperations)?; + Ok(tx.into()) +} diff --git a/cmd/soroban-cli/src/config/address.rs b/cmd/soroban-cli/src/config/address.rs index 066bc8d91..f86f88ecb 100644 --- a/cmd/soroban-cli/src/config/address.rs +++ b/cmd/soroban-cli/src/config/address.rs @@ -1,4 +1,7 @@ -use std::str::FromStr; +use std::{ + fmt::{self, Display, Formatter}, + str::FromStr, +}; use crate::xdr; @@ -6,14 +9,14 @@ use super::{locator, secret}; /// Address can be either a public key or eventually an alias of a address. #[derive(Clone, Debug)] -pub enum Address { - MuxedAccount(xdr::MuxedAccount), +pub enum UnresolvedMuxedAccount { + Resolved(xdr::MuxedAccount), AliasOrSecret(String), } -impl Default for Address { +impl Default for UnresolvedMuxedAccount { fn default() -> Self { - Address::AliasOrSecret(String::default()) + UnresolvedMuxedAccount::AliasOrSecret(String::default()) } } @@ -25,39 +28,95 @@ pub enum Error { Secret(#[from] secret::Error), #[error("Address cannot be used to sign {0}")] CannotSign(xdr::MuxedAccount), + #[error("Invalid key name: {0}\n only alphanumeric characters, underscores (_), and hyphens (-) are allowed.")] + InvalidKeyNameCharacters(String), + #[error("Invalid key name: {0}\n keys cannot exceed 250 characters")] + InvalidKeyNameLength(String), + #[error("Invalid key name: {0}\n keys cannot be the word \"ledger\"")] + InvalidKeyName(String), } -impl FromStr for Address { +impl FromStr for UnresolvedMuxedAccount { type Err = Error; fn from_str(value: &str) -> Result { Ok(xdr::MuxedAccount::from_str(value).map_or_else( - |_| Address::AliasOrSecret(value.to_string()), - Address::MuxedAccount, + |_| UnresolvedMuxedAccount::AliasOrSecret(value.to_string()), + UnresolvedMuxedAccount::Resolved, )) } } -impl Address { +impl UnresolvedMuxedAccount { pub fn resolve_muxed_account( &self, locator: &locator::Args, hd_path: Option, ) -> Result { match self { - Address::MuxedAccount(muxed_account) => Ok(muxed_account.clone()), - Address::AliasOrSecret(alias) => alias.parse().or_else(|_| { - Ok(xdr::MuxedAccount::Ed25519( - locator.read_identity(alias)?.public_key(hd_path)?.0.into(), - )) - }), + UnresolvedMuxedAccount::Resolved(muxed_account) => Ok(muxed_account.clone()), + UnresolvedMuxedAccount::AliasOrSecret(alias_or_secret) => { + Self::resolve_muxed_account_with_alias(alias_or_secret, locator, hd_path) + } } } + pub fn resolve_muxed_account_with_alias( + alias: &str, + locator: &locator::Args, + hd_path: Option, + ) -> Result { + alias.parse().or_else(|_| { + Ok(xdr::MuxedAccount::Ed25519( + locator.read_identity(alias)?.public_key(hd_path)?.0.into(), + )) + }) + } + pub fn resolve_secret(&self, locator: &locator::Args) -> Result { match &self { - Address::MuxedAccount(muxed_account) => Err(Error::CannotSign(muxed_account.clone())), - Address::AliasOrSecret(alias) => Ok(locator.read_identity(alias)?), + UnresolvedMuxedAccount::Resolved(muxed_account) => { + Err(Error::CannotSign(muxed_account.clone())) + } + UnresolvedMuxedAccount::AliasOrSecret(alias_or_secret) => { + Ok(locator.key(alias_or_secret)?) + } + } + } +} + +#[derive(Clone, Debug)] +pub struct KeyName(pub String); + +impl std::ops::Deref for KeyName { + type Target = str; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::str::FromStr for KeyName { + type Err = Error; + fn from_str(s: &str) -> Result { + if !s.chars().all(allowed_char) { + return Err(Error::InvalidKeyNameCharacters(s.to_string())); + } + if s == "ledger" { + return Err(Error::InvalidKeyName(s.to_string())); + } + if s.len() > 250 { + return Err(Error::InvalidKeyNameLength(s.to_string())); } + Ok(KeyName(s.to_string())) } } + +impl Display for KeyName { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +fn allowed_char(c: char) -> bool { + c.is_ascii_alphanumeric() || c == '_' || c == '-' +} diff --git a/cmd/soroban-cli/src/config/alias.rs b/cmd/soroban-cli/src/config/alias.rs index 9d1d8c11b..734925c4e 100644 --- a/cmd/soroban-cli/src/config/alias.rs +++ b/cmd/soroban-cli/src/config/alias.rs @@ -11,39 +11,49 @@ pub struct Data { /// Address can be either a contract address, C.. or eventually an alias of a contract address. #[derive(Clone, Debug)] -pub enum ContractAddress { - ContractId(stellar_strkey::Contract), +pub enum UnresolvedContract { + Resolved(stellar_strkey::Contract), Alias(String), } -impl Default for ContractAddress { +impl Default for UnresolvedContract { fn default() -> Self { - ContractAddress::Alias(String::default()) + UnresolvedContract::Alias(String::default()) } } -impl FromStr for ContractAddress { +impl FromStr for UnresolvedContract { type Err = Infallible; fn from_str(value: &str) -> Result { Ok(stellar_strkey::Contract::from_str(value).map_or_else( - |_| ContractAddress::Alias(value.to_string()), - ContractAddress::ContractId, + |_| UnresolvedContract::Alias(value.to_string()), + UnresolvedContract::Resolved, )) } } -impl ContractAddress { +impl UnresolvedContract { pub fn resolve_contract_id( &self, locator: &locator::Args, network_passphrase: &str, ) -> Result { match self { - ContractAddress::ContractId(muxed_account) => Ok(*muxed_account), - ContractAddress::Alias(alias) => locator - .get_contract_id(alias, network_passphrase)? - .ok_or_else(|| locator::Error::ContractNotFound(alias.to_owned())), + UnresolvedContract::Resolved(contract) => Ok(*contract), + UnresolvedContract::Alias(alias) => { + Self::resolve_alias(alias, locator, network_passphrase) + } } } + + pub fn resolve_alias( + alias: &str, + locator: &locator::Args, + network_passphrase: &str, + ) -> Result { + locator + .get_contract_id(alias, network_passphrase)? + .ok_or_else(|| locator::Error::ContractNotFound(alias.to_owned())) + } } diff --git a/cmd/soroban-cli/src/config/locator.rs b/cmd/soroban-cli/src/config/locator.rs index b6f5c75c1..1e26bbf7f 100644 --- a/cmd/soroban-cli/src/config/locator.rs +++ b/cmd/soroban-cli/src/config/locator.rs @@ -83,6 +83,10 @@ pub enum Error { UpgradeCheckReadFailed { path: PathBuf, error: io::Error }, #[error("Failed to write upgrade check file: {path}: {error}")] UpgradeCheckWriteFailed { path: PathBuf, error: io::Error }, + #[error("Contract alias {0}, cannot overlap with key")] + ContractAliasCannotOverlapWithKey(String), + #[error("Key cannot {0} cannot overlap with contract alias")] + KeyCannotOverlapWithContractAlias(String), } #[derive(Debug, clap::Args, Default, Clone)] @@ -162,11 +166,14 @@ impl Args { ) } - pub fn write_identity(&self, name: &str, secret: &Secret) -> Result<(), Error> { + pub fn write_identity(&self, name: &str, secret: &Secret) -> Result { + if let Ok(Some(_)) = self.load_contract_from_alias(name) { + return Err(Error::KeyCannotOverlapWithContractAlias(name.to_owned())); + } 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()?) } @@ -286,6 +293,9 @@ impl Args { contract_id: &stellar_strkey::Contract, alias: &str, ) -> Result<(), Error> { + if self.read_identity(alias).is_ok() { + return Err(Error::ContractAliasCannotOverlapWithKey(alias.to_owned())); + } let path = self.alias_path(alias)?; let dir = path.parent().ok_or(Error::CannotAccessConfigDir)?; @@ -441,10 +451,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/mod.rs b/cmd/soroban-cli/src/config/mod.rs index a429ff434..1188d3bfa 100644 --- a/cmd/soroban-cli/src/config/mod.rs +++ b/cmd/soroban-cli/src/config/mod.rs @@ -1,4 +1,3 @@ -use address::Address; use clap::{arg, command}; use serde::{Deserialize, Serialize}; use std::{ @@ -19,11 +18,14 @@ pub mod alias; pub mod data; pub mod locator; pub mod network; +pub mod sc_address; pub mod secret; pub mod sign_with; pub mod upgrade_check; -pub use alias::ContractAddress; +pub use address::UnresolvedMuxedAccount; +pub use alias::UnresolvedContract; +pub use sc_address::UnresolvedScAddress; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -56,7 +58,7 @@ pub struct Args { /// 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. - pub source_account: Address, + pub source_account: UnresolvedMuxedAccount, #[arg(long)] /// If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` 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/sc_address.rs b/cmd/soroban-cli/src/config/sc_address.rs new file mode 100644 index 000000000..fc9c168f2 --- /dev/null +++ b/cmd/soroban-cli/src/config/sc_address.rs @@ -0,0 +1,67 @@ +use std::str::FromStr; + +use crate::xdr; + +use super::{address, locator, UnresolvedContract}; + +/// `ScAddress` can be either a resolved `xdr::ScAddress` or an alias of a `Contract` or `MuxedAccount`. +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Debug)] +pub enum UnresolvedScAddress { + Resolved(xdr::ScAddress), + Alias(String), +} + +impl Default for UnresolvedScAddress { + fn default() -> Self { + UnresolvedScAddress::Alias(String::default()) + } +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Locator(#[from] locator::Error), + #[error(transparent)] + Address(#[from] address::Error), + #[error("Account alias not Found{0}")] + AccountAliasNotFound(String), +} + +impl FromStr for UnresolvedScAddress { + type Err = Error; + + fn from_str(value: &str) -> Result { + Ok(xdr::ScAddress::from_str(value).map_or_else( + |_| UnresolvedScAddress::Alias(value.to_string()), + UnresolvedScAddress::Resolved, + )) + } +} + +impl UnresolvedScAddress { + pub fn resolve( + self, + locator: &locator::Args, + network_passphrase: &str, + ) -> Result { + let alias = match self { + UnresolvedScAddress::Resolved(addr) => return Ok(addr), + UnresolvedScAddress::Alias(alias) => alias, + }; + let contract = UnresolvedContract::resolve_alias(&alias, locator, network_passphrase); + let muxed_account = + super::UnresolvedMuxedAccount::resolve_muxed_account_with_alias(&alias, locator, None); + match (contract, muxed_account) { + (Ok(contract), Ok(_)) => { + eprintln!( + "Warning: ScAddress alias {alias} is ambiguous, assuming it is a contract" + ); + Ok(xdr::ScAddress::Contract(xdr::Hash(contract.0))) + } + (Ok(contract), _) => Ok(xdr::ScAddress::Contract(xdr::Hash(contract.0))), + (_, Ok(muxed_account)) => Ok(xdr::ScAddress::Account(muxed_account.account_id())), + _ => Err(Error::AccountAliasNotFound(alias)), + } + } +} diff --git a/cmd/soroban-cli/src/config/secret.rs b/cmd/soroban-cli/src/config/secret.rs index a7fd86fda..f32b291e8 100644 --- a/cmd/soroban-cli/src/config/secret.rs +++ b/cmd/soroban-cli/src/config/secret.rs @@ -1,18 +1,18 @@ use clap::arg; use serde::{Deserialize, Serialize}; use std::{io::Write, str::FromStr}; + +use sep5::SeedPhrase; use stellar_strkey::ed25519::{PrivateKey, PublicKey}; use crate::{ print::Print, - signer::{self, LocalKey, Signer, SignerKind}, + signer::{self, keyring, LocalKey, SecureStoreEntry, Signer, SignerKind}, utils, }; #[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,21 +23,24 @@ 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), + #[error(transparent)] + Keyring(#[from] keyring::Error), + #[error("Secure Store does not reveal secret key")] + SecureStoreDoesNotRevealSecretKey, } #[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 +48,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) } } } @@ -78,6 +63,7 @@ impl Args { pub enum Secret { SecretKey { secret_key: String }, SeedPhrase { seed_phrase: String }, + SecureStore { entry_name: String }, } impl FromStr for Secret { @@ -92,8 +78,12 @@ impl FromStr for Secret { Ok(Secret::SeedPhrase { seed_phrase: s.to_string(), }) + } else if s.starts_with(keyring::SECURE_STORE_ENTRY_PREFIX) { + Ok(Secret::SecureStore { + entry_name: s.to_string(), + }) } else { - Err(Error::InvalidAddress(s.to_string())) + Err(Error::InvalidSecretOrSeedPhrase) } } } @@ -106,6 +96,14 @@ impl From for Secret { } } +impl From for Secret { + fn from(value: SeedPhrase) -> Self { + Secret::SeedPhrase { + seed_phrase: value.seed_phrase.into_phrase(), + } + } +} + impl Secret { pub fn private_key(&self, index: Option) -> Result { Ok(match self { @@ -116,22 +114,34 @@ impl Secret { .private() .0, )?, + Secret::SecureStore { .. } => { + return Err(Error::SecureStoreDoesNotRevealSecretKey); + } }) } pub fn public_key(&self, index: Option) -> Result { - let key = self.key_pair(index)?; - Ok(stellar_strkey::ed25519::PublicKey::from_payload( - key.verifying_key().as_bytes(), - )?) + if let Secret::SecureStore { entry_name } = self { + let entry = keyring::StellarEntry::new(entry_name)?; + Ok(entry.get_public_key(index)?) + } else { + let key = self.key_pair(index)?; + Ok(stellar_strkey::ed25519::PublicKey::from_payload( + key.verifying_key().as_bytes(), + )?) + } } - pub fn signer(&self, index: Option, print: Print) -> Result { + pub fn signer(&self, hd_path: Option, print: Print) -> Result { let kind = match self { Secret::SecretKey { .. } | Secret::SeedPhrase { .. } => { - let key = self.key_pair(index)?; + let key = self.key_pair(hd_path)?; SignerKind::Local(LocalKey { key }) } + Secret::SecureStore { entry_name } => SignerKind::SecureStore(SecureStoreEntry { + name: entry_name.to_string(), + hd_path, + }), }; Ok(Signer { kind, print }) } @@ -141,14 +151,7 @@ impl Secret { } pub fn from_seed(seed: Option<&str>) -> Result { - let seed_phrase = if let Some(seed) = seed.map(str::as_bytes) { - sep5::SeedPhrase::from_entropy(seed) - } else { - sep5::SeedPhrase::random(sep5::MnemonicType::Words12) - }? - .seed_phrase - .into_phrase(); - Ok(Secret::SeedPhrase { seed_phrase }) + Ok(seed_phrase_from_seed(seed)?.into()) } pub fn test_seed_phrase() -> Result { @@ -156,7 +159,71 @@ impl Secret { } } +pub fn seed_phrase_from_seed(seed: Option<&str>) -> Result { + Ok(if let Some(seed) = seed.map(str::as_bytes) { + sep5::SeedPhrase::from_entropy(seed)? + } else { + sep5::SeedPhrase::random(sep5::MnemonicType::Words24)? + }) +} + +pub fn test_seed_phrase() -> Result { + Ok("0000000000000000".parse()?) +} + fn read_password() -> Result { std::io::stdout().flush().map_err(|_| Error::PasswordRead)?; rpassword::read_password().map_err(|_| Error::PasswordRead) } + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_PUBLIC_KEY: &str = "GAREAZZQWHOCBJS236KIE3AWYBVFLSBK7E5UW3ICI3TCRWQKT5LNLCEZ"; + const TEST_SECRET_KEY: &str = "SBF5HLRREHMS36XZNTUSKZ6FTXDZGNXOHF4EXKUL5UCWZLPBX3NGJ4BH"; + const TEST_SEED_PHRASE: &str = + "depth decade power loud smile spatial sign movie judge february rate broccoli"; + + #[test] + fn test_from_str_for_secret_key() { + let secret = Secret::from_str(TEST_SECRET_KEY).unwrap(); + let public_key = secret.public_key(None).unwrap(); + let private_key = secret.private_key(None).unwrap(); + + assert!(matches!(secret, Secret::SecretKey { .. })); + assert_eq!(public_key.to_string(), TEST_PUBLIC_KEY); + assert_eq!(private_key.to_string(), TEST_SECRET_KEY); + } + + #[test] + fn test_secret_from_seed_phrase() { + let secret = Secret::from_str(TEST_SEED_PHRASE).unwrap(); + let public_key = secret.public_key(None).unwrap(); + let private_key = secret.private_key(None).unwrap(); + + assert!(matches!(secret, Secret::SeedPhrase { .. })); + assert_eq!(public_key.to_string(), TEST_PUBLIC_KEY); + assert_eq!(private_key.to_string(), TEST_SECRET_KEY); + } + + #[test] + fn test_secret_from_secure_store() { + //todo: add assertion for getting public key - will need to mock the keychain and add the keypair to the keychain + let secret = Secret::from_str("secure_store:org.stellar.cli-alice").unwrap(); + assert!(matches!(secret, Secret::SecureStore { .. })); + + let private_key_result = secret.private_key(None); + assert!(private_key_result.is_err()); + assert!(matches!( + private_key_result.unwrap_err(), + Error::SecureStoreDoesNotRevealSecretKey + )); + } + + #[test] + fn test_secret_from_invalid_string() { + let secret = Secret::from_str("invalid"); + assert!(secret.is_err()); + } +} 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/cmd/soroban-cli/src/key.rs b/cmd/soroban-cli/src/key.rs index b704541c4..c3fd7ed89 100644 --- a/cmd/soroban-cli/src/key.rs +++ b/cmd/soroban-cli/src/key.rs @@ -34,7 +34,7 @@ pub struct Args { required_unless_present = "wasm", required_unless_present = "wasm_hash" )] - pub contract_id: Option, + pub contract_id: Option, /// Storage key (symbols only) #[arg(long = "key", conflicts_with = "key_xdr")] pub key: Option>, diff --git a/cmd/soroban-cli/src/signer.rs b/cmd/soroban-cli/src/signer.rs index 5bf22499c..ebd650d40 100644 --- a/cmd/soroban-cli/src/signer.rs +++ b/cmd/soroban-cli/src/signer.rs @@ -1,4 +1,5 @@ use ed25519_dalek::ed25519::signature::Signer as _; +use keyring::StellarEntry; use sha2::{Digest, Sha256}; use crate::xdr::{ @@ -11,6 +12,8 @@ use crate::xdr::{ use crate::{config::network::Network, print::Print, utils::transaction_hash}; +pub mod keyring; + #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Contract addresses are not supported to sign auth entries {address}")] @@ -33,6 +36,8 @@ pub enum Error { Open(#[from] std::io::Error), #[error("Returning a signature from Lab is not yet supported; Transaction can be found and submitted in lab")] ReturningSignatureFromLab, + #[error(transparent)] + Keyring(#[from] keyring::Error), } fn requires_auth(txn: &Transaction) -> Option { @@ -207,6 +212,7 @@ pub struct Signer { pub enum SignerKind { Local(LocalKey), Lab, + SecureStore(SecureStoreEntry), } impl Signer { @@ -235,6 +241,7 @@ impl Signer { let decorated_signature = match &self.kind { SignerKind::Local(key) => key.sign_tx_hash(tx_hash)?, SignerKind::Lab => Lab::sign_tx_env(tx_env, network, &self.print)?, + SignerKind::SecureStore(entry) => entry.sign_tx_hash(tx_hash)?, }; let mut sigs = signatures.clone().into_vec(); sigs.push(decorated_signature); @@ -284,3 +291,18 @@ impl Lab { Err(Error::ReturningSignatureFromLab) } } + +pub struct SecureStoreEntry { + pub name: String, + pub hd_path: Option, +} + +impl SecureStoreEntry { + pub fn sign_tx_hash(&self, tx_hash: [u8; 32]) -> Result { + let entry = StellarEntry::new(&self.name)?; + let hint = SignatureHint(entry.get_public_key(self.hd_path)?.0[28..].try_into()?); + let signed_tx_hash = entry.sign_data(&tx_hash, self.hd_path)?; + let signature = Signature(signed_tx_hash.clone().try_into()?); + Ok(DecoratedSignature { hint, signature }) + } +} diff --git a/cmd/soroban-cli/src/signer/keyring.rs b/cmd/soroban-cli/src/signer/keyring.rs new file mode 100644 index 000000000..0e6c49137 --- /dev/null +++ b/cmd/soroban-cli/src/signer/keyring.rs @@ -0,0 +1,147 @@ +use ed25519_dalek::Signer; +use keyring::Entry; +use sep5::seed_phrase::SeedPhrase; +use zeroize::Zeroize; + +pub(crate) const SECURE_STORE_ENTRY_PREFIX: &str = "secure_store:"; +pub(crate) const SECURE_STORE_ENTRY_SERVICE: &str = "org.stellar.cli"; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Keyring(#[from] keyring::Error), + #[error(transparent)] + Sep5(#[from] sep5::error::Error), +} + +pub struct StellarEntry { + keyring: Entry, +} + +impl StellarEntry { + pub fn new(name: &str) -> Result { + Ok(StellarEntry { + keyring: Entry::new(name, &whoami::username())?, + }) + } + + pub fn set_seed_phrase(&self, seed_phrase: SeedPhrase) -> Result<(), Error> { + let mut data = seed_phrase.seed_phrase.into_phrase(); + self.keyring.set_password(&data)?; + data.zeroize(); + Ok(()) + } + + fn get_seed_phrase(&self) -> Result { + Ok(self.keyring.get_password()?.parse()?) + } + + fn use_key( + &self, + f: impl FnOnce(ed25519_dalek::SigningKey) -> Result, + hd_path: Option, + ) -> Result { + // The underlying Mnemonic type is zeroized when dropped + let mut key_bytes: [u8; 32] = { + self.get_seed_phrase()? + .from_path_index(hd_path.unwrap_or_default(), None)? + .private() + .0 + }; + let result = { + // Use this scope to ensure the keypair is zeroized when dropped + let keypair = ed25519_dalek::SigningKey::from_bytes(&key_bytes); + f(keypair)? + }; + key_bytes.zeroize(); + Ok(result) + } + + pub fn get_public_key( + &self, + hd_path: Option, + ) -> Result { + self.use_key( + |keypair| { + Ok(stellar_strkey::ed25519::PublicKey( + *keypair.verifying_key().as_bytes(), + )) + }, + hd_path, + ) + } + + pub fn sign_data(&self, data: &[u8], hd_path: Option) -> Result, Error> { + self.use_key( + |keypair| { + let signature = keypair.sign(data); + Ok(signature.to_bytes().to_vec()) + }, + hd_path, + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + use keyring::{mock, set_default_credential_builder}; + + #[test] + fn test_get_password() { + set_default_credential_builder(mock::default_credential_builder()); + + let seed_phrase = crate::config::secret::seed_phrase_from_seed(None).unwrap(); + let seed_phrase_clone = seed_phrase.clone(); + + let entry = StellarEntry::new("test").unwrap(); + + // set the seed phrase + let set_seed_phrase_result = entry.set_seed_phrase(seed_phrase); + assert!(set_seed_phrase_result.is_ok()); + + // get_seed_phrase should return the same seed phrase we set + let get_seed_phrase_result = entry.get_seed_phrase(); + assert!(get_seed_phrase_result.is_ok()); + assert_eq!( + seed_phrase_clone.phrase(), + get_seed_phrase_result.unwrap().phrase() + ); + } + + #[test] + fn test_get_public_key() { + set_default_credential_builder(mock::default_credential_builder()); + + let seed_phrase = crate::config::secret::seed_phrase_from_seed(None).unwrap(); + let public_key = seed_phrase.from_path_index(0, None).unwrap().public().0; + + let entry = StellarEntry::new("test").unwrap(); + + // set the seed_phrase + let set_seed_phrase_result = entry.set_seed_phrase(seed_phrase); + assert!(set_seed_phrase_result.is_ok()); + + // confirm that we can get the public key from the entry and that it matches the one we set + let get_public_key_result = entry.get_public_key(None); + assert!(get_public_key_result.is_ok()); + assert_eq!(public_key, get_public_key_result.unwrap().0); + } + + #[test] + fn test_sign_data() { + set_default_credential_builder(mock::default_credential_builder()); + + //create a seed phrase + let seed_phrase = crate::config::secret::seed_phrase_from_seed(None).unwrap(); + + // create a keyring entry and set the seed_phrase + let entry = StellarEntry::new("test").unwrap(); + entry.set_seed_phrase(seed_phrase).unwrap(); + + let tx_xdr = r"AAAAAgAAAADh6eOnZEq1xQgKioffuH7/8D8x8+OdGFEkiYC6QKMWzQAAAGQAAACuAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAYAAAAAQAAAAAAAAAAAAAAAOHp46dkSrXFCAqKh9+4fv/wPzHz450YUSSJgLpAoxbNoFT1s8jZPCv9IJ2DsqGTA8pOtavv58JF53aDycpRPcEAAAAA+N2m5zc3EfWUmLvigYPOHKXhSy8OrWfVibc6y6PrQoYAAAAAAAAAAAAAAAA"; + + let sign_tx_env_result = entry.sign_data(tx_xdr.as_bytes(), None); + assert!(sign_tx_env_result.is_ok()); + } +} diff --git a/cmd/soroban-cli/src/utils/contract-template/Cargo.toml.removeextension b/cmd/soroban-cli/src/utils/contract-template/Cargo.toml.removeextension index 8da1aed87..ccf1fc93d 100644 --- a/cmd/soroban-cli/src/utils/contract-template/Cargo.toml.removeextension +++ b/cmd/soroban-cli/src/utils/contract-template/Cargo.toml.removeextension @@ -5,7 +5,7 @@ edition = "2021" publish = false [lib] -crate-type = ["cdylib"] +crate-type = ["lib", "cdylib"] doctest = false [dependencies] diff --git a/cmd/soroban-cli/src/utils/contract-workspace-template/Cargo.toml.removeextension b/cmd/soroban-cli/src/utils/contract-workspace-template/Cargo.toml.removeextension index c0d6366e0..1c9265386 100644 --- a/cmd/soroban-cli/src/utils/contract-workspace-template/Cargo.toml.removeextension +++ b/cmd/soroban-cli/src/utils/contract-workspace-template/Cargo.toml.removeextension @@ -5,7 +5,7 @@ members = [ ] [workspace.dependencies] -soroban-sdk = "21.0.0" +soroban-sdk = "22" [profile.release] opt-level = "z" diff --git a/cookbook/tx-new.mdx b/cookbook/tx-new.mdx new file mode 100644 index 000000000..481d13d59 --- /dev/null +++ b/cookbook/tx-new.mdx @@ -0,0 +1,187 @@ +--- +title: `tx` Commands +hide_table_of_contents: true +description: Create stellar transactions using the Stellar CLI +--- + +So far the examples of the CLI interacting with the blockchain have been through the `contract` command. Uploading contracts, deploying contracts, and invoking them. +Each of these are different types of transactions, which must be signed and submitted to the network (and in the case of contract related transations simulated first). + +Technically these three are different operations, of which a transaction can contain upto 100 operations. However, in the case of contract related operations a transaction is limited to just one. + +So for all other transactions the CLI provides the `tx` subcommands. These are: + +- `new` +- `sign` +- `send` +- `simulate` + + +## `tx new` + +For the following examples we will use the following accounts: + +```sh +stellar keys generate --fund alice --network testnet +stellar keys generate --no-fund bob +# You can add a public key to the keys +stellar keys add --public-key GCXLHURQS5LX77PBQWEGJLYDPXGVR2F5ME2OPBWQBGJKG2IOBBO2XY5O charlie +## and use testnet +stellar network use testnet +``` + +### Create Account + +Creates and funds a new Stellar account. Above `alice` was funded by friendbot[citation here]. However, +`bob` and `charlie` were not. So we can use the `create-account` command to fund them. + +`bob` will receive 10 XLM and `charlie` will get 1 XLM. + +```sh +stellar tx new create-account \ + --source alice \ + --destination bob \ + --starting-balance 100_000_000 + +stellar tx new create-account \ + --source alice \ + --destination charlie \ + --starting-balance 10_000_000 +``` + +Notes: +- `--starting-balance`: Initial balance in stroops to fund the account with (1 XLM = 10,000,000 stroops) + +### Payment + +`bob` feels bad that `charlie` only got 1 XLM, so they will send 4 more XLM to `charlie`. + +```sh +stellar tx new payment \ + --source bob \ + --destination charlie \ + --asset native \ + --amount 40_000_000 +``` + +Notes: +- `--asset`: The asset to send - either "native" for XLM or "CODE:ISSUER" format for other assets + + +### Bump Sequence + +Bump an account's sequence number forward: + +```sh +stellar tx new bump-sequence \ + --source alice \ + --bump-to 123450 +``` + + +### Account Merge + +Merge one account into another, transferring all XLM. + +`bob` decides to continue spreading the wealth and merges their account into `charlie`'s. + +```sh +stellar tx new account-merge \ + --source bob \ + --account chalrie +``` + +Notes: +- `--source`: The account to remove from the ledger, thus this is its final tranaction + +### Set Trustline Flags + +Modify authorization flags on a trustline: + +```sh +stellar tx new set-trustline-flags \ + --source alice \ + --asset USDC:GCXLHURQS5LX77PBQWEGJLYDPXGVR2F5ME2OPBWQBGJKG2IOBBO2XY5O \ + --trustor charlie \ + --set-authorize \ + --set-authorize-to-maintain-liabilities \ + --set-trustline-clawback-enabled +``` + +Arguments: +- `--source`: The issuing account setting the flags (must be the asset issuer) +- `--asset`: The asset in CODE:ISSUER format +- `--trustor`: The account whose trustline flags to modify +- `--set-authorize`: Enable full authorization +- `--set-authorize-to-maintain-liabilities`: Enable limited authorization +- `--set-trustline-clawback-enabled`: Enable clawback for this trustline +- `--clear-*`: Corresponding clear flags to remove each setting + +### Set Options + +Configure account settings: + +```sh +stellar tx new set-options \ + --source alice \ + --inflation-dest GCXLHURQS5LX77PBQWEGJLYDPXGVR2F5ME2OPBWQBGJKG2IOBBO2XY5O \ + --home-domain "example.com" \ + --master-weight 100 \ + --med-threshold 100 \ + --low-threshold 100 \ + --high-threshold 100 \ + --signer GBXSGN5GX4PZOSBHB4JJF67CEGSGT7DGBGGUGWXI4WOQMQEA4SFV2HTJ \ + --signer-weight 1 \ + --set-required \ + --set-revocable \ + --set-clawback-enabled \ + --set-immutable +``` + +Notes: +- `--source`: Account to modify settings for +- `--inflation-dest`: Set inflation destination account +- `--home-domain`: Set home domain for federation/compliance +- `--master-weight`: Weight of the account's master key (0-255) +- `--low-threshold`: Weight threshold for low security operations +- `--med-threshold`: Weight threshold for medium security operations +- `--high-threshold`: Weight threshold for high security operations +- `--signer`: Add a new signer public key +- `--signer-weight`: Weight for the new signer (0 removes the signer) +- `--set-required`: Enable requiring authorization for new trustlines +- `--set-revocable`: Enable revoking of trustlines +- `--set-clawback-enabled`: Enable clawback for asset issuing account +- `--set-immutable`: Make account settings immutable +- `--clear-*`: Corresponding clear flags to remove each setting + +### Change Trust + +Create or modify a trustline: + +```sh +stellar tx new change-trust \ + --source alice \ + --line USDC:ISSUER \ + --limit 100000000 +``` + +Arguments: +- `--source`: Account creating/modifying the trustline +- `--line`: Asset to create trustline for in CODE:ISSUER format +- `--limit`: Maximum amount that can be held (0 removes trustline) + +### Manage Data + +Manage account data entries: + +```sh +stellar tx new manage-data \ + --source alice \ + --data-name config \ + --data-value 7465737476616c7565 # hex encoded +``` + +Notes: +- `--data-name`: Name of the data entry (up to 64 bytes) +- `--data-value`: Hex encoded value to store (up to 64 bytes, omit to delete) +``` diff --git a/cookbook/tx-op-add.mdx b/cookbook/tx-op-add.mdx new file mode 100644 index 000000000..562fdca0d --- /dev/null +++ b/cookbook/tx-op-add.mdx @@ -0,0 +1,51 @@ +--- +title: `tx op add` +hide_table_of_contents: true +description: Create stellar transactions using the Stellar CLI +--- + +As see before you can use pipes to pass a transaction envolope between commands. Before we have only been looking at transactions with one operation, +however, as mentioned there can be up to 100 operations in a single transaction. + +To add an operation to a transaction you can use the `tx op add` command. This command takes the transaction envolope from the previous command and adds an operation to it. + +Let's consider a more complicated example. Consider issuing an asset, here `USDC` with the requirement that only the issuer can transfer funds to the distrubtor. + +```sh + +stellar keys generate --fund issuer +stellar keys generate --fund distributor + +ISSUER_PK=$(stellar keys address issuer) + +ASSET="USDC:$ISSUER_PK" + +# Issue the asset by setting its options, establishing a trustline, and +# transferring the smallest amount possible to the distributor. Then +# deauthorize the distributor so that people can only send Claimable Balances, +# rather than transferring assets directly. + +# first the issuer sets the options for being able to clawback and revoke the asset +stellar tx new set-options --fee 1000 --source issuer --set-clawback-enabled --set-revocable --build-only \ +# next the distributor establishes a trustline with the asset. Note that here the distributor the source account for the operation, not the issuer +| stellar tx op add change-trust --op-source distributor --line $ASSET \ +# then the issuer sends the smallest amount possible to the distributor +| stellar tx op add payment --destination distributor --asset $ASSET --amount 1 \ +# finally the issuer deauthorizes the distributor from being able to send the asset +| stellar tx op add set-trustline-flags --asset $ASSET --trustor distributor --clear-authorize \ +# Then both accounts need to sign the transaction +| stellar tx sign --sign-with-key issuer \ +| stellar tx sign --sign-with-key distributor \ +| stellar tx send + +# Next is an example of sandwiching an operation. That is giving permission in one operation, preforming the operation, and then removing the permission in a third operation. +# Here is an example of minting new assets to the distributor with a sandwich transaction +# First authorize the distributor to receive the asset +stellar tx new set-trustline-flags --fee 1000 --build-only --source issuer --asset $ASSET --trustor $distributor_PK --set-authorize \ +# Then mint the asset to the distributor +| stellar tx op add payment --destination distributor --asset $ASSET --amount 1_000_000_000_000 \ +# Finally remove the authorization +| stellar tx op add set-trustline-flags --asset $ASSET --trustor distributor --clear-authorize \ +| stellar tx sign --sign-with-key issuer \ +| stellar tx send +``` \ No newline at end of file diff --git a/cookbook/tx-sign.mdx b/cookbook/tx-sign.mdx new file mode 100644 index 000000000..9aa2a9cab --- /dev/null +++ b/cookbook/tx-sign.mdx @@ -0,0 +1,72 @@ +--- +title: `tx sign` and `tx send` +hide_table_of_contents: true +description: Create stellar transactions using the Stellar CLI +--- + +The previous examples of using `tx new` showed how to create transactions. However, these transactions were immediately ready to be signed and submitted to the network. + +To avoid this each of the subcommands has the `--build-only` argument, which as the name suggests only builds the transaction and prints the transaction envolope. + +## `tx sign` + +Let's return to the first example of creating `bob`s account: + + ```sh +stellar tx new create-account \ + --source alice \ + --destination bob \ + --starting-balance 100_000_000 \ + --build-only + ``` + would output something like: + +```sh +AAAAAgAAAADwSUp9CwmVlPN40mKX1I1j39y6DmYc36QS1aK2x6eYVQAAAGQAEcMsAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAACTMkzn1TwPo8SIhnKvnyuv9K2/aWjpX9NTYfyiA7vXaAAAAAAX14QAAAAAAAAAAAA== +``` + +You can inspect it with [stellar lab!](https://lab.stellar.org/xdr/view?$=network$id=testnet&label=Testnet&horizonUrl=https:////horizon-testnet.stellar.org&rpcUrl=https:////soroban-testnet.stellar.org&passphrase=Test%20SDF%20Network%20/;%20September%202015;&xdr$blob=AAAAAgAAAADwSUp9CwmVlPN40mKX1I1j39y6DmYc36QS1aK2x6eYVQAAAGQAEcMsAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAACTMkzn1TwPo8SIhnKvnyuv9K2//aWjpX9NTYfyiA7vXaAAAAAAX14QAAAAAAAAAAAA==;;) Where you can also sign and send the transaction. + +However, you can also sign the transaction with the `tx sign` command. To do this you can pipe the output of the `tx new` command to the `tx sign` command: + +```sh +stellar tx new create-account \ + --source alice \ + --destination bob \ + --starting-balance 100_000_000 \ + --build-only \ + | stellar tx sign --sign-with-key alice +``` + +This should output something like: + +```sh +AAAAAgAAAADwSUp9CwmVlPN40mKX1I1j39y6DmYc36QS1aK2x6eYVQAAAGQAEcMsAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAACTMkzn1TwPo8SIhnKvnyuv9K2/aWjpX9NTYfyiA7vXaAAAAAAX14QAAAAAAAAAAAcenmFUAAABA2FCmaY4U8eFtqzJ1iEowvP1mashskYVxlqPjrM4miH0Q+QrF//A/NWflZPYzR+lySNrjJnRad851+4TbCekICw== +``` +You can again [view it in lab and see that there is now a signature attached to the transaction envolope](AAAAAgAAAADwSUp9CwmVlPN40mKX1I1j39y6DmYc36QS1aK2x6eYVQAAAGQAEcMsAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAACTMkzn1TwPo8SIhnKvnyuv9K2/aWjpX9NTYfyiA7vXaAAAAAAX14QAAAAAAAAAAAcenmFUAAABA2FCmaY4U8eFtqzJ1iEowvP1mashskYVxlqPjrM4miH0Q+QrF//A/NWflZPYzR+lySNrjJnRad851+4TbCekICw==). + +::tip +Or sign with lab! Though currently you must send it from lab and cannot return to the CLI (a work in progress!). +```sh +stellar tx new create-account \ + --source alice \ + --destination bob \ + --starting-balance 100_000_000 \ + --build-only \ + | stellar tx sign --sign-with-lab +``` +::: + +## `tx send` + +Finally, to submit the transaction to the network you can use the `tx send` command. This command will submit the transaction to the network. + +```sh +stellar tx new create-account \ + --source alice \ + --destination bob \ + --starting-balance 100_000_000 \ + --build-only \ + | stellar tx sign --sign-with-key alice \ + | stellar tx send +``` \ No newline at end of file diff --git a/deny.toml b/deny.toml index 9817c3e79..1d0738c60 100644 --- a/deny.toml +++ b/deny.toml @@ -110,6 +110,9 @@ allow = [ "Unicode-DFS-2016", "ISC", "BSD-2-Clause", + "CC0-1.0", + "Unicode-3.0", + "BSL-1.0", ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses @@ -309,6 +312,10 @@ skip = [ { crate = "idna", reason = "temp", version = "0.5.0" }, { crate = "bitflags", reason = "too many", version = "=1.3.2" }, + + { crate = "socket2", reason = "too many", version = "=0.4.10" }, + + { crate = "miniz_oxide", reason = "too many", version = "=0.7.4" }, ] # Similarly to `skip` allows you to skip certain crates during duplicate # detection. Unlike skip, it also includes the entire tree of transitive