diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 31fc28d1e..a355ff487 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -22,7 +22,7 @@ jobs: # core git ref should be latest commit for stable soroban functionality # the core bin can either be compiled in-line here as part of ci, - SYSTEM_TEST_CORE_GIT_REF: https://github.com/stellar/stellar-core.git#ecb24df104c2453a00fa5097d2e879d7731b9596 + SYSTEM_TEST_CORE_GIT_REF: https://github.com/stellar/stellar-core.git#v20.0.2 SYSTEM_TEST_CORE_COMPILE_CONFIGURE_FLAGS: "--disable-tests" # or set SYSTEM_TEST_CORE_GIT_REF to empty, and set SYSTEM_TEST_CORE_IMAGE # to pull a pre-compiled image from dockerhub instead @@ -36,22 +36,25 @@ jobs: # resolution options, using npm release or a gh ref: # # option #1, set the version of stellar-sdk based on a npm release version - SYSTEM_TEST_JS_STELLAR_SDK_NPM_VERSION: v11.0.0-beta.6 + SYSTEM_TEST_JS_STELLAR_SDK_NPM_VERSION: 11.1.0 # option #2, set the version of stellar-sdk used as a ref to a gh repo if # a value is set on SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO, it takes # precedence over any SYSTEM_TEST_JS_STELLAR_SDK_NPM_VERSION - SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO: - SYSTEM_TEST_JS_STELLAR_SDK_GH_REF: + SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO: + SYSTEM_TEST_JS_STELLAR_SDK_GH_REF: + + # the version of rs-stellar-xdr to use for quickstart + SYSTEM_TEST_RS_XDR_GIT_REF: v20.0.1 # system test will build quickstart image internally to use for running the service stack # configured in standalone network mode(core, rpc) - SYSTEM_TEST_QUICKSTART_GIT_REF: https://github.com/stellar/quickstart.git#69a1089eee9aaac4bafe4cbfc0639de18222db6a + SYSTEM_TEST_QUICKSTART_GIT_REF: https://github.com/stellar/quickstart.git#412bb828ddb4a93745227ab5ad97c623d43f3a5f # triggers system test to log out details from quickstart's logs and test steps SYSTEM_TEST_VERBOSE_OUTPUT: "true" # the soroban test cases will compile various contracts from the examples repo - SYSTEM_TEST_SOROBAN_EXAMPLES_GIT_HASH: "main" + SYSTEM_TEST_SOROBAN_EXAMPLES_GIT_HASH: "v20.0.0" SYSTEM_TEST_SOROBAN_EXAMPLES_GIT_REPO: "https://github.com/stellar/soroban-examples.git" steps: - uses: actions/checkout@v3 @@ -90,6 +93,7 @@ jobs: SOROBAN_RPC_GIT_REF=$SYSTEM_TEST_SOROBAN_TOOLS_REF \ SOROBAN_CLI_GIT_REF=$SYSTEM_TEST_SOROBAN_TOOLS_REF \ RUST_TOOLCHAIN_VERSION=$SYSTEM_TEST_RUST_TOOLCHAIN_VERSION \ + RS_XDR_GIT_REF=$SYSTEM_TEST_RS_XDR_GIT_REF \ QUICKSTART_GIT_REF=$SYSTEM_TEST_QUICKSTART_GIT_REF \ JS_STELLAR_SDK_NPM_VERSION=$JS_STELLAR_SDK_REF \ build diff --git a/.github/workflows/soroban-rpc.yml b/.github/workflows/soroban-rpc.yml index bbd1c647c..f26b2b376 100644 --- a/.github/workflows/soroban-rpc.yml +++ b/.github/workflows/soroban-rpc.yml @@ -112,7 +112,7 @@ jobs: env: SOROBAN_RPC_INTEGRATION_TESTS_ENABLED: true SOROBAN_RPC_INTEGRATION_TESTS_CAPTIVE_CORE_BIN: /usr/bin/stellar-core - PROTOCOL_20_CORE_DEBIAN_PKG_VERSION: 19.14.1-1553.f4c4e2fca.focal + PROTOCOL_20_CORE_DEBIAN_PKG_VERSION: 20.0.2-1633.669916b56.focal steps: - uses: actions/checkout@v3 with: diff --git a/Cargo.lock b/Cargo.lock index beaf4e359..b82c6d9d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.5.0" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" dependencies = [ "anstyle", "anstyle-parse", @@ -57,36 +57,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -97,9 +97,9 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" -version = "1.3.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" dependencies = [ "derive_arbitrary", ] @@ -136,13 +136,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -186,9 +186,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -213,9 +213,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -237,12 +237,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", - "regex-automata 0.3.8", + "regex-automata 0.4.3", "serde", ] @@ -254,9 +254,9 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -273,7 +273,7 @@ dependencies = [ "num-bigint", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -287,9 +287,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" dependencies = [ "serde", ] @@ -336,14 +336,14 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "clap" -version = "4.4.4" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", @@ -360,9 +360,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.4" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -372,30 +372,30 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.1" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4110a1e6af615a9e6d0a36f805d5c99099f8bab9b8042f5bc1fa220a4a89e36f" +checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "codespan-reporting" @@ -421,9 +421,9 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -431,15 +431,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -468,28 +468,51 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", + "memoffset", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] [[package]] name = "crypto-bigint" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -519,9 +542,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" dependencies = [ "csv-core", "itoa", @@ -531,21 +554,21 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" dependencies = [ "memchr", ] [[package]] name = "ctor" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" +checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -580,20 +603,20 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "cxx" -version = "1.0.107" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe98ba1789d56fb3db3bee5e032774d4f421b685de7ba703643584ba24effbe" +checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" dependencies = [ "cc", "cxxbridge-flags", @@ -603,9 +626,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.107" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ce20f6b8433da4841b1dadfb9468709868022d829d5ca1f2ffbda928455ea3" +checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5" dependencies = [ "cc", "codespan-reporting", @@ -613,24 +636,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "cxxbridge-flags" -version = "1.0.107" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20888d9e1d2298e2ff473cee30efe7d5036e437857ab68bbfea84c74dba91da2" +checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" [[package]] name = "cxxbridge-macro" -version = "1.0.107" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fa16a70dd58129e4dfffdff535fb1bce66673f7bbeec4a5a1765a504e1ccd84" +checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -654,7 +677,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -665,7 +688,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -680,22 +703,23 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ + "powerfmt", "serde", ] [[package]] name = "derive_arbitrary" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -771,15 +795,15 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest 0.10.7", "elliptic-curve", "rfc6979", - "signature 2.1.0", + "signature 2.2.0", "spki", ] @@ -794,12 +818,12 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", - "signature 2.1.0", + "signature 2.2.0", ] [[package]] @@ -821,10 +845,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek 4.1.1", - "ed25519 2.2.2", + "ed25519 2.2.3", "rand_core 0.6.4", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "zeroize", ] @@ -836,9 +860,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" -version = "0.13.5" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", @@ -861,36 +885,31 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "escape-bytes" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] +checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2" [[package]] name = "ethnum" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8ff382b2fa527fb7fb06eeebfc5bbb3f17e3cc6b9d70b006c41daa8824adac" +checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "ff" @@ -904,9 +923,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" [[package]] name = "float-cmp" @@ -940,9 +959,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -955,55 +974,42 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", - "futures-macro", "futures-sink", "futures-task", "pin-project-lite", "pin-utils", - "slab", ] [[package]] @@ -1019,9 +1025,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "js-sys", @@ -1032,9 +1038,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "glob" @@ -1044,15 +1050,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -1079,9 +1085,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -1089,7 +1095,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -1104,9 +1110,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -1129,6 +1135,12 @@ 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.9.0" @@ -1154,14 +1166,14 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1170,9 +1182,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1208,7 +1220,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -1217,9 +1229,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", @@ -1246,16 +1258,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -1275,9 +1287,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1285,17 +1297,16 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060" dependencies = [ + "crossbeam-deque", "globset", - "lazy_static", "log", "memchr", - "regex", + "regex-automata 0.4.3", "same-file", - "thread_local", "walkdir", "winapi-util", ] @@ -1333,12 +1344,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "serde", ] @@ -1368,33 +1379,33 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonrpsee-core" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35dc957af59ce98373bcdde0c1698060ca6c2d2e9ae357b459c7158b6df33330" +checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" dependencies = [ "anyhow", "async-trait", @@ -1411,9 +1422,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd865d0072764cb937b0110a92b5f53e995f7101cb346beca03d93a2dea79de" +checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" dependencies = [ "async-trait", "hyper", @@ -1431,9 +1442,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9e25aec855b2a7d3ed90fded6c41e8c3fb72b63f071e1be3f0004eba19b625" +checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" dependencies = [ "anyhow", "beef", @@ -1453,8 +1464,8 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2 0.10.7", - "signature 2.1.0", + "sha2 0.10.8", + "signature 2.2.0", ] [[package]] @@ -1474,15 +1485,26 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] [[package]] name = "link-cplusplus" @@ -1495,15 +1517,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1526,9 +1548,18 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] [[package]] name = "miniz_oxide" @@ -1541,13 +1572,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1597,13 +1628,13 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -1618,9 +1649,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1646,9 +1677,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -1658,11 +1689,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -1679,7 +1710,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -1690,18 +1721,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.1.5+3.1.3" +version = "300.2.1+3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559068e4c12950d7dcaa1857a61725c0d38d4fc03ff8e070ab31a75d6e316491" +checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -1728,15 +1759,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1762,9 +1793,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" @@ -1783,7 +1814,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -1816,9 +1847,15 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.1.2" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + +[[package]] +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -1870,13 +1907,13 @@ dependencies = [ [[package]] name = "preflight" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ "anyhow", - "base64 0.21.4", + "base64 0.21.5", "libc", "rand", - "sha2 0.10.7", + "sha2 0.10.8", "soroban-env-host", "thiserror", ] @@ -1898,14 +1935,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -1957,43 +1994,34 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.9.5" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.8", - "regex-syntax 0.7.5", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -2007,13 +2035,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", ] [[package]] @@ -2024,9 +2052,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rfc6979" @@ -2040,38 +2068,37 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", + "getrandom", "libc", - "once_cell", - "spin 0.5.2", + "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -2097,22 +2124,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.14" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring", @@ -2134,18 +2161,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", @@ -2159,9 +2186,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -2178,7 +2205,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2195,9 +2222,9 @@ checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -2242,9 +2269,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" dependencies = [ "serde", ] @@ -2256,25 +2283,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afe34ccbd1fb6fa0b2fc7cccb037bd3d3f1e484c3befe1b713d7611884f336a" dependencies = [ "slip10", - "stellar-strkey 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "stellar-strkey 0.0.7", "thiserror", "tiny-bip39", ] [[package]] name = "serde" -version = "1.0.188" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] name = "serde-aux" -version = "4.2.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3dfe1b7eb6f9dcf011bd6fad169cdeaae75eda0d61b1a99a3f015b41b0cae39" +checksum = "184eba62ebddb71658697c8b08822edee89970bf318c5362189f0de27f85b498" dependencies = [ "chrono", "serde", @@ -2283,20 +2310,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -2305,15 +2332,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" +checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.0", + "indexmap 2.1.0", "serde", "serde_json", "serde_with_macros", @@ -2322,14 +2349,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" +checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -2347,9 +2374,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -2368,9 +2395,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -2398,9 +2425,9 @@ checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -2428,15 +2455,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -2444,32 +2471,32 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "soroban-builtin-sdk-macros" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-env?rev=2674d867d7c6aa4212abab05ff30e5804ff1db90#2674d867d7c6aa4212abab05ff30e5804ff1db90" +version = "20.0.2" +source = "git+https://github.com/stellar/rs-soroban-env?rev=81f6eb1eefd299af3e03fa0db7b20eb355b2b55f#81f6eb1eefd299af3e03fa0db7b20eb355b2b55f" dependencies = [ - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "soroban-cli" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ "assert_cmd", "assert_fs", - "base64 0.21.4", + "base64 0.21.5", "cargo_metadata", "chrono", "clap", @@ -2501,7 +2528,7 @@ dependencies = [ "serde-aux", "serde_derive", "serde_json", - "sha2 0.10.7", + "sha2 0.10.8", "shlex", "soroban-env-host", "soroban-ledger-snapshot", @@ -2511,7 +2538,8 @@ dependencies = [ "soroban-spec-rust", "soroban-spec-tools", "soroban-spec-typescript", - "stellar-strkey 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "stellar-strkey 0.0.7", + "stellar-xdr", "strsim", "termcolor", "termcolor_output", @@ -2528,8 +2556,8 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-env?rev=2674d867d7c6aa4212abab05ff30e5804ff1db90#2674d867d7c6aa4212abab05ff30e5804ff1db90" +version = "20.0.2" +source = "git+https://github.com/stellar/rs-soroban-env?rev=81f6eb1eefd299af3e03fa0db7b20eb355b2b55f#81f6eb1eefd299af3e03fa0db7b20eb355b2b55f" dependencies = [ "arbitrary", "crate-git-revision 0.0.6", @@ -2545,8 +2573,8 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-env?rev=2674d867d7c6aa4212abab05ff30e5804ff1db90#2674d867d7c6aa4212abab05ff30e5804ff1db90" +version = "20.0.2" +source = "git+https://github.com/stellar/rs-soroban-env?rev=81f6eb1eefd299af3e03fa0db7b20eb355b2b55f#81f6eb1eefd299af3e03fa0db7b20eb355b2b55f" dependencies = [ "soroban-env-common", "static_assertions", @@ -2554,53 +2582,56 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-env?rev=2674d867d7c6aa4212abab05ff30e5804ff1db90#2674d867d7c6aa4212abab05ff30e5804ff1db90" +version = "20.0.2" +source = "git+https://github.com/stellar/rs-soroban-env?rev=81f6eb1eefd299af3e03fa0db7b20eb355b2b55f#81f6eb1eefd299af3e03fa0db7b20eb355b2b55f" dependencies = [ "backtrace", "curve25519-dalek 4.1.1", "ed25519-dalek 2.0.0", "getrandom", + "hex-literal", + "hmac 0.12.1", "k256", "num-derive", "num-integer", "num-traits", "rand", "rand_chacha", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "soroban-builtin-sdk-macros", "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey 0.0.7 (git+https://github.com/stellar/rs-stellar-strkey?rev=e6ba45c60c16de28c7522586b80ed0150157df73)", + "stellar-strkey 0.0.8", ] [[package]] name = "soroban-env-macros" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-env?rev=2674d867d7c6aa4212abab05ff30e5804ff1db90#2674d867d7c6aa4212abab05ff30e5804ff1db90" +version = "20.0.2" +source = "git+https://github.com/stellar/rs-soroban-env?rev=81f6eb1eefd299af3e03fa0db7b20eb355b2b55f#81f6eb1eefd299af3e03fa0db7b20eb355b2b55f" dependencies = [ - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", "serde", "serde_json", "stellar-xdr", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "soroban-hello" -version = "20.0.0-rc4" +version = "20.1.1" [[package]] name = "soroban-ledger-snapshot" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=fb422beae0d4944dc0e83559a8940b31f5ebd89d#fb422beae0d4944dc0e83559a8940b31f5ebd89d" +version = "20.0.3" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=93b09e42e4efa841cbd034c0bff0dc362765086c#93b09e42e4efa841cbd034c0bff0dc362765086c" dependencies = [ "serde", "serde_json", + "serde_with", "soroban-env-common", "soroban-env-host", "thiserror", @@ -2608,44 +2639,46 @@ dependencies = [ [[package]] name = "soroban-sdk" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=fb422beae0d4944dc0e83559a8940b31f5ebd89d#fb422beae0d4944dc0e83559a8940b31f5ebd89d" +version = "20.0.3" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=93b09e42e4efa841cbd034c0bff0dc362765086c#93b09e42e4efa841cbd034c0bff0dc362765086c" dependencies = [ "arbitrary", "bytes-lit", "ctor", "ed25519-dalek 2.0.0", "rand", + "serde", + "serde_json", "soroban-env-guest", "soroban-env-host", "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey 0.0.7 (git+https://github.com/stellar/rs-stellar-strkey?rev=e6ba45c60c16de28c7522586b80ed0150157df73)", + "stellar-strkey 0.0.8", ] [[package]] name = "soroban-sdk-macros" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=fb422beae0d4944dc0e83559a8940b31f5ebd89d#fb422beae0d4944dc0e83559a8940b31f5ebd89d" +version = "20.0.3" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=93b09e42e4efa841cbd034c0bff0dc362765086c#93b09e42e4efa841cbd034c0bff0dc362765086c" dependencies = [ "crate-git-revision 0.0.6", "darling", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", "rustc_version", - "sha2 0.10.7", + "sha2 0.10.8", "soroban-env-common", "soroban-spec", "soroban-spec-rust", "stellar-xdr", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "soroban-spec" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=fb422beae0d4944dc0e83559a8940b31f5ebd89d#fb422beae0d4944dc0e83559a8940b31f5ebd89d" +version = "20.0.3" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=93b09e42e4efa841cbd034c0bff0dc362765086c#93b09e42e4efa841cbd034c0bff0dc362765086c" dependencies = [ "base64 0.13.1", "stellar-xdr", @@ -2655,7 +2688,7 @@ dependencies = [ [[package]] name = "soroban-spec-json" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ "pretty_assertions", "serde", @@ -2669,30 +2702,30 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "20.0.0-rc2" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=fb422beae0d4944dc0e83559a8940b31f5ebd89d#fb422beae0d4944dc0e83559a8940b31f5ebd89d" +version = "20.0.3" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=93b09e42e4efa841cbd034c0bff0dc362765086c#93b09e42e4efa841cbd034c0bff0dc362765086c" dependencies = [ "prettyplease", "proc-macro2", "quote", - "sha2 0.10.7", + "sha2 0.10.8", "soroban-spec", "stellar-xdr", - "syn 2.0.37", + "syn 2.0.39", "thiserror", ] [[package]] name = "soroban-spec-tools" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "ethnum", "hex", "itertools 0.10.5", "serde_json", "soroban-spec", - "stellar-strkey 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "stellar-strkey 0.0.7", "stellar-xdr", "thiserror", "tokio", @@ -2702,9 +2735,9 @@ dependencies = [ [[package]] name = "soroban-spec-typescript" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "heck", "include_dir", "itertools 0.10.5", @@ -2723,7 +2756,7 @@ dependencies = [ [[package]] name = "soroban-test" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ "assert_cmd", "assert_fs", @@ -2731,37 +2764,39 @@ dependencies = [ "predicates 2.1.5", "sep5", "serde_json", - "sha2 0.10.7", + "sha2 0.10.8", "soroban-cli", "soroban-env-host", "soroban-ledger-snapshot", "soroban-sdk", "soroban-spec", "soroban-spec-tools", - "stellar-strkey 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "stellar-strkey 0.0.7", "thiserror", "tokio", "which", ] +[[package]] +name = "soroban-token-sdk" +version = "20.0.3" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=93b09e42e4efa841cbd034c0bff0dc362765086c#93b09e42e4efa841cbd034c0bff0dc362765086c" +dependencies = [ + "soroban-sdk", +] + [[package]] name = "soroban-wasmi" -version = "0.31.0-soroban1" -source = "git+https://github.com/stellar/wasmi?rev=7e63b4c9e08c4163f417d118d81f7ea34789d0be#7e63b4c9e08c4163f417d118d81f7ea34789d0be" +version = "0.31.1-soroban.20.0.0" +source = "git+https://github.com/stellar/wasmi?rev=ab29800224d85ee64d4ac127bac84cdbb0276721#ab29800224d85ee64d4ac127bac84cdbb0276721" dependencies = [ "smallvec", - "spin 0.9.8", + "spin", "wasmi_arena", "wasmi_core", "wasmparser-nostd", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -2770,9 +2805,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -2796,24 +2831,32 @@ dependencies = [ [[package]] name = "stellar-strkey" -version = "0.0.7" -source = "git+https://github.com/stellar/rs-stellar-strkey?rev=e6ba45c60c16de28c7522586b80ed0150157df73#e6ba45c60c16de28c7522586b80ed0150157df73" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12d2bf45e114117ea91d820a846fd1afbe3ba7d717988fee094ce8227a3bf8bd" dependencies = [ "base32", + "crate-git-revision 0.0.6", "thiserror", ] [[package]] name = "stellar-xdr" -version = "20.0.0-rc1" -source = "git+https://github.com/stellar/rs-stellar-xdr?rev=9c97e4fa909a0b6455547a4f4a95800696b2a69a#9c97e4fa909a0b6455547a4f4a95800696b2a69a" +version = "20.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f00a85bd9b1617d4cb7e741733889c9940e6bdeca360db81752b0ef04fe3a5" dependencies = [ "arbitrary", "base64 0.13.1", + "clap", "crate-git-revision 0.0.6", + "escape-bytes", "hex", "serde", + "serde_json", "serde_with", + "stellar-strkey 0.0.8", + "thiserror", ] [[package]] @@ -2860,9 +2903,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -2877,22 +2920,22 @@ checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -2921,43 +2964,58 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_custom_types" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ "soroban-sdk", ] [[package]] name = "test_hello_world" -version = "20.0.0-rc4" +version = "20.1.1" +dependencies = [ + "soroban-sdk", +] + +[[package]] +name = "test_swap" +version = "20.1.1" dependencies = [ "soroban-sdk", ] +[[package]] +name = "test_token" +version = "20.1.1" +dependencies = [ + "soroban-sdk", + "soroban-token-sdk", +] + [[package]] name = "test_udt" -version = "20.0.0-rc4" +version = "20.1.1" dependencies = [ "soroban-sdk", ] [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -2972,12 +3030,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", "itoa", + "powerfmt", "serde", "time-core", "time-macros", @@ -2985,15 +3044,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -3010,7 +3069,7 @@ dependencies = [ "pbkdf2", "rand", "rustc-hash", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -3034,9 +3093,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ "backtrace", "bytes", @@ -3046,20 +3105,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] @@ -3084,9 +3143,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -3134,11 +3193,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -3147,31 +3205,32 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", + "thiserror", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -3179,20 +3238,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -3208,9 +3267,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -3220,9 +3279,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -3247,15 +3306,15 @@ checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -3322,9 +3381,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3332,24 +3391,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3357,28 +3416,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasm-opt" -version = "0.114.1" +version = "0.114.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d005a95f934878a1fb446a816d51c3601a0120ff929005ba3bab3c749cfd1c7" +checksum = "effbef3bd1dde18acb401f73e740a6f3d4a1bc651e9773bddc512fe4d8d68f67" dependencies = [ "anyhow", "libc", @@ -3392,9 +3451,9 @@ dependencies = [ [[package]] name = "wasm-opt-cxx-sys" -version = "0.114.1" +version = "0.114.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d04e240598162810fad3b2e96fa0dec6dba1eb65a03f3bd99a9248ab8b56caa" +checksum = "c09e24eb283919ace2ed5733bda4842a59ce4c8de110ef5c6d98859513d17047" dependencies = [ "anyhow", "cxx", @@ -3404,9 +3463,9 @@ dependencies = [ [[package]] name = "wasm-opt-sys" -version = "0.114.1" +version = "0.114.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efd2aaca519d64098c4faefc8b7433a97ed511caf4c9e516384eb6aef1ff4f9" +checksum = "36f2f817bed2e8d65eb779fa37317e74de15585751f903c9118342d1970703a4" dependencies = [ "anyhow", "cc", @@ -3417,12 +3476,12 @@ dependencies = [ [[package]] name = "wasmi_arena" version = "0.4.0" -source = "git+https://github.com/stellar/wasmi?rev=7e63b4c9e08c4163f417d118d81f7ea34789d0be#7e63b4c9e08c4163f417d118d81f7ea34789d0be" +source = "git+https://github.com/stellar/wasmi?rev=ab29800224d85ee64d4ac127bac84cdbb0276721#ab29800224d85ee64d4ac127bac84cdbb0276721" [[package]] name = "wasmi_core" version = "0.13.0" -source = "git+https://github.com/stellar/wasmi?rev=7e63b4c9e08c4163f417d118d81f7ea34789d0be#7e63b4c9e08c4163f417d118d81f7ea34789d0be" +source = "git+https://github.com/stellar/wasmi?rev=ab29800224d85ee64d4ac127bac84cdbb0276721#ab29800224d85ee64d4ac127bac84cdbb0276721" dependencies = [ "downcast-rs", "libm", @@ -3457,16 +3516,6 @@ dependencies = [ "indexmap-nostd", ] -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "which" version = "4.4.2" @@ -3512,12 +3561,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3526,7 +3575,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -3535,13 +3593,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -3550,42 +3623,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "yansi" version = "0.5.1" @@ -3594,9 +3709,9 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -3609,5 +3724,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.39", ] diff --git a/Cargo.toml b/Cargo.toml index a36ec9fd2..e0a4ee2a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,55 +11,58 @@ default-members = ["cmd/soroban-cli", "cmd/crates/soroban-test"] exclude = ["cmd/crates/soroban-test/tests/fixtures/hello"] [workspace.package] -version = "20.0.0-rc4" +version = "20.1.1" [workspace.dependencies.soroban-env-host] -version = "20.0.0-rc2" +version = "=20.0.2" git = "https://github.com/stellar/rs-soroban-env" -rev = "2674d867d7c6aa4212abab05ff30e5804ff1db90" +rev = "81f6eb1eefd299af3e03fa0db7b20eb355b2b55f" [workspace.dependencies.soroban-spec] -version = "20.0.0-rc2" +version = "=20.0.3" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "fb422beae0d4944dc0e83559a8940b31f5ebd89d" +rev = "93b09e42e4efa841cbd034c0bff0dc362765086c" # path = "../rs-soroban-sdk/soroban-spec" [workspace.dependencies.soroban-spec-rust] -version = "20.0.0-rc2" +version = "=20.0.3" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "fb422beae0d4944dc0e83559a8940b31f5ebd89d" +rev = "93b09e42e4efa841cbd034c0bff0dc362765086c" # path = "../rs-soroban-sdk/soroban-spec-rust" [workspace.dependencies.soroban-spec-json] -version = "20.0.0-rc4" +version = "20.1.1" path = "./cmd/crates/soroban-spec-json" [workspace.dependencies.soroban-spec-typescript] -version = "20.0.0-rc4" +version = "20.1.1" path = "./cmd/crates/soroban-spec-typescript" [workspace.dependencies.soroban-spec-tools] -version = "20.0.0-rc4" +version = "20.1.1" path = "./cmd/crates/soroban-spec-tools" [workspace.dependencies.soroban-sdk] -version = "20.0.0-rc2" +version = "=20.0.3" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "fb422beae0d4944dc0e83559a8940b31f5ebd89d" +rev = "93b09e42e4efa841cbd034c0bff0dc362765086c" + +[workspace.dependencies.soroban-token-sdk] +version = "=20.0.3" +git = "https://github.com/stellar/rs-soroban-sdk" +rev = "93b09e42e4efa841cbd034c0bff0dc362765086c" [workspace.dependencies.soroban-ledger-snapshot] -version = "20.0.0-rc2" +version = "=20.0.3" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "fb422beae0d4944dc0e83559a8940b31f5ebd89d" +rev = "93b09e42e4efa841cbd034c0bff0dc362765086c" [workspace.dependencies.soroban-cli] -version = "20.0.0-rc4" +version = "20.1.1" path = "cmd/soroban-cli" [workspace.dependencies.stellar-xdr] -version = "20.0.0-rc1" -git = "https://github.com/stellar/rs-stellar-xdr" -rev = "9c97e4fa909a0b6455547a4f4a95800696b2a69a" +version = "=20.0.2" default-features = true [workspace.dependencies] diff --git a/cmd/crates/soroban-spec-json/src/types.rs b/cmd/crates/soroban-spec-json/src/types.rs index 6fcc483e1..8e3b2177e 100644 --- a/cmd/crates/soroban-spec-json/src/types.rs +++ b/cmd/crates/soroban-spec-json/src/types.rs @@ -15,8 +15,8 @@ pub struct StructField { impl From<&ScSpecUdtStructFieldV0> for StructField { fn from(f: &ScSpecUdtStructFieldV0) -> Self { StructField { - doc: f.doc.to_string_lossy(), - name: f.name.to_string_lossy(), + doc: f.doc.to_utf8_string_lossy(), + name: f.name.to_utf8_string_lossy(), value: (&f.type_).into(), } } @@ -33,8 +33,8 @@ pub struct FunctionInput { impl From<&ScSpecFunctionInputV0> for FunctionInput { fn from(f: &ScSpecFunctionInputV0) -> Self { FunctionInput { - doc: f.doc.to_string_lossy(), - name: f.name.to_string_lossy(), + doc: f.doc.to_utf8_string_lossy(), + name: f.name.to_utf8_string_lossy(), value: (&f.type_).into(), } } @@ -51,12 +51,14 @@ pub struct UnionCase { impl From<&ScSpecUdtUnionCaseV0> for UnionCase { fn from(c: &ScSpecUdtUnionCaseV0) -> Self { let (doc, name, values) = match c { - ScSpecUdtUnionCaseV0::VoidV0(v) => { - (v.doc.to_string_lossy(), v.name.to_string_lossy(), vec![]) - } + ScSpecUdtUnionCaseV0::VoidV0(v) => ( + v.doc.to_utf8_string_lossy(), + v.name.to_utf8_string_lossy(), + vec![], + ), ScSpecUdtUnionCaseV0::TupleV0(t) => ( - t.doc.to_string_lossy(), - t.name.to_string_lossy(), + t.doc.to_utf8_string_lossy(), + t.name.to_utf8_string_lossy(), t.type_.iter().map(Type::from).collect(), ), }; @@ -75,8 +77,8 @@ pub struct EnumCase { impl From<&ScSpecUdtEnumCaseV0> for EnumCase { fn from(c: &ScSpecUdtEnumCaseV0) -> Self { EnumCase { - doc: c.doc.to_string_lossy(), - name: c.name.to_string_lossy(), + doc: c.doc.to_utf8_string_lossy(), + name: c.name.to_utf8_string_lossy(), value: c.value, } } @@ -93,8 +95,8 @@ pub struct ErrorEnumCase { impl From<&ScSpecUdtErrorEnumCaseV0> for EnumCase { fn from(c: &ScSpecUdtErrorEnumCaseV0) -> Self { EnumCase { - doc: c.doc.to_string_lossy(), - name: c.name.to_string_lossy(), + doc: c.doc.to_utf8_string_lossy(), + name: c.name.to_utf8_string_lossy(), value: c.value, } } @@ -184,7 +186,7 @@ impl From<&ScSpecTypeDef> for Type { element: Box::new(Type::from(vec.element_type.as_ref())), }, ScSpecTypeDef::Udt(udt) => Type::Custom { - name: udt.name.to_string_lossy(), + name: udt.name.to_utf8_string_lossy(), }, ScSpecTypeDef::BytesN(b) => Type::BytesN { n: b.n }, ScSpecTypeDef::Val => Type::Val, @@ -213,29 +215,29 @@ impl From<&ScSpecEntry> for Entry { fn from(spec: &ScSpecEntry) -> Self { match spec { ScSpecEntry::FunctionV0(f) => Entry::Function { - doc: f.doc.to_string_lossy(), - name: f.name.to_string_lossy(), + doc: f.doc.to_utf8_string_lossy(), + name: f.name.to_utf8_string_lossy(), inputs: f.inputs.iter().map(FunctionInput::from).collect(), outputs: f.outputs.iter().map(Type::from).collect(), }, ScSpecEntry::UdtStructV0(s) => Entry::Struct { - doc: s.doc.to_string_lossy(), - name: s.name.to_string_lossy(), + doc: s.doc.to_utf8_string_lossy(), + name: s.name.to_utf8_string_lossy(), fields: s.fields.iter().map(StructField::from).collect(), }, ScSpecEntry::UdtUnionV0(u) => Entry::Union { - doc: u.doc.to_string_lossy(), - name: u.name.to_string_lossy(), + doc: u.doc.to_utf8_string_lossy(), + name: u.name.to_utf8_string_lossy(), cases: u.cases.iter().map(UnionCase::from).collect(), }, ScSpecEntry::UdtEnumV0(e) => Entry::Enum { - doc: e.doc.to_string_lossy(), - name: e.name.to_string_lossy(), + doc: e.doc.to_utf8_string_lossy(), + name: e.name.to_utf8_string_lossy(), cases: e.cases.iter().map(EnumCase::from).collect(), }, ScSpecEntry::UdtErrorEnumV0(e) => Entry::Enum { - doc: e.doc.to_string_lossy(), - name: e.name.to_string_lossy(), + doc: e.doc.to_utf8_string_lossy(), + name: e.name.to_utf8_string_lossy(), cases: e.cases.iter().map(EnumCase::from).collect(), }, } diff --git a/cmd/crates/soroban-spec-tools/src/lib.rs b/cmd/crates/soroban-spec-tools/src/lib.rs index a95bc9454..e7b72d1b0 100644 --- a/cmd/crates/soroban-spec-tools/src/lib.rs +++ b/cmd/crates/soroban-spec-tools/src/lib.rs @@ -124,7 +124,7 @@ impl Spec { ), ScType::Option(type_) => return self.doc(name, &type_.value_type), ScType::Udt(ScSpecTypeUdt { name }) => { - let spec_type = self.find(&name.to_string_lossy())?; + let spec_type = self.find(&name.to_utf8_string_lossy())?; match spec_type { ScSpecEntry::FunctionV0(ScSpecFunctionV0 { doc, .. }) | ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 { doc, .. }) @@ -132,7 +132,7 @@ impl Spec { | ScSpecEntry::UdtEnumV0(ScSpecUdtEnumV0 { doc, .. }) | ScSpecEntry::UdtErrorEnumV0(ScSpecUdtErrorEnumV0 { doc, .. }) => doc, } - .to_string_lossy() + .to_utf8_string_lossy() } }; if let Some(mut ex) = self.example(type_) { @@ -164,11 +164,11 @@ impl Spec { .and_then(|specs| { specs.iter().find(|e| { let entry_name = match e { - ScSpecEntry::FunctionV0(x) => x.name.to_string_lossy(), - ScSpecEntry::UdtStructV0(x) => x.name.to_string_lossy(), - ScSpecEntry::UdtUnionV0(x) => x.name.to_string_lossy(), - ScSpecEntry::UdtEnumV0(x) => x.name.to_string_lossy(), - ScSpecEntry::UdtErrorEnumV0(x) => x.name.to_string_lossy(), + ScSpecEntry::FunctionV0(x) => x.name.to_utf8_string_lossy(), + ScSpecEntry::UdtStructV0(x) => x.name.to_utf8_string_lossy(), + ScSpecEntry::UdtUnionV0(x) => x.name.to_utf8_string_lossy(), + ScSpecEntry::UdtEnumV0(x) => x.name.to_utf8_string_lossy(), + ScSpecEntry::UdtErrorEnumV0(x) => x.name.to_utf8_string_lossy(), }; name == entry_name }) @@ -248,7 +248,7 @@ impl Spec { | ScType::Address => Ok(Value::String(s.to_owned())), ScType::Udt(ScSpecTypeUdt { name }) if matches!( - self.find(&name.to_string_lossy())?, + self.find(&name.to_utf8_string_lossy())?, ScSpecEntry::UdtUnionV0(_) | ScSpecEntry::UdtStructV0(_) ) => { @@ -321,13 +321,13 @@ impl Spec { } fn parse_udt(&self, name: &StringM<60>, value: &Value) -> Result { - let name = &name.to_string_lossy(); + let name = &name.to_utf8_string_lossy(); match (self.find(name)?, value) { (ScSpecEntry::UdtStructV0(strukt), Value::Object(map)) => { if strukt .fields .iter() - .any(|f| f.name.to_string_lossy() == "0") + .any(|f| f.name.to_utf8_string_lossy() == "0") { self.parse_tuple_strukt( strukt, @@ -379,7 +379,7 @@ impl Spec { .to_vec() .iter() .map(|f| { - let name = &f.name.to_string_lossy(); + let name = &f.name.to_utf8_string_lossy(); let v = map .get(name) .ok_or_else(|| Error::MissingKey(name.clone()))?; @@ -422,9 +422,11 @@ impl Spec { ScSpecUdtUnionCaseV0::VoidV0(v) => &v.name, ScSpecUdtUnionCaseV0::TupleV0(v) => &v.name, }; - enum_case == &name.to_string_lossy() + enum_case == &name.to_utf8_string_lossy() }) - .ok_or_else(|| Error::EnumCase(enum_case.to_string(), union.name.to_string_lossy()))?; + .ok_or_else(|| { + Error::EnumCase(enum_case.to_string(), union.name.to_utf8_string_lossy()) + })?; let mut res = vec![ScVal::Symbol(ScSymbol( enum_case.try_into().map_err(Error::Xdr)?, @@ -583,7 +585,7 @@ impl Spec { /// /// May panic pub fn udt_to_json(&self, name: &StringM<60>, sc_obj: &ScVal) -> Result { - let name = &name.to_string_lossy(); + let name = &name.to_utf8_string_lossy(); let udt = self.find(name)?; Ok(match (sc_obj, udt) { (ScVal::Map(Some(map)), ScSpecEntry::UdtStructV0(strukt)) => serde_json::Value::Object( @@ -593,7 +595,7 @@ impl Spec { .zip(map.iter()) .map(|(field, entry)| { let val = self.xdr_to_json(&entry.val, &field.type_)?; - Ok((field.name.to_string_lossy(), val)) + Ok((field.name.to_utf8_string_lossy(), val)) }) .collect::, Error>>()?, ), @@ -611,7 +613,7 @@ impl Spec { let (first, rest) = match v.split_at(1) { ([first], []) => (first, None), ([first], rest) => (first, Some(rest)), - _ => return Err(Error::IllFormedEnum(union.name.to_string_lossy())), + _ => return Err(Error::IllFormedEnum(union.name.to_utf8_string_lossy())), }; let ScVal::Symbol(case_name) = first else { @@ -627,14 +629,14 @@ impl Spec { }; name.as_vec() == case_name.as_vec() }) - .ok_or_else(|| Error::FailedToFindEnumCase(case_name.to_string_lossy()))?; + .ok_or_else(|| Error::FailedToFindEnumCase(case_name.to_utf8_string_lossy()))?; - let case_name = case_name.to_string_lossy(); + let case_name = case_name.to_utf8_string_lossy(); match case { ScSpecUdtUnionCaseV0::TupleV0(v) => { let rest = rest.ok_or_else(|| { Error::EnumMissingSecondValue( - union.name.to_string_lossy(), + union.name.to_utf8_string_lossy(), case_name.clone(), ) })?; @@ -1130,11 +1132,11 @@ impl Spec { } ScType::BytesN(t) => Some(format!("{}_hex_bytes", t.n)), ScType::Udt(ScSpecTypeUdt { name }) => { - match self.find(&name.to_string_lossy()).ok()? { + match self.find(&name.to_utf8_string_lossy()).ok()? { ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 { fields, .. }) if fields .get(0) - .map(|f| f.name.to_string_lossy() == "0") + .map(|f| f.name.to_utf8_string_lossy() == "0") .unwrap_or_default() => { let fields = fields @@ -1159,7 +1161,7 @@ impl Spec { let inner = strukt .fields .iter() - .map(|f| (f.name.to_string_lossy(), &f.type_)) + .map(|f| (f.name.to_utf8_string_lossy(), &f.type_)) .map(|(name, type_)| { let type_ = self.arg_value_name(type_, depth + 1)?; Some(format!("{name}: {type_}")) @@ -1176,7 +1178,7 @@ impl Spec { .map(|f| { Some(match f { ScSpecUdtUnionCaseV0::VoidV0(ScSpecUdtUnionCaseVoidV0 { name, .. }) => { - name.to_string_lossy() + name.to_utf8_string_lossy() } ScSpecUdtUnionCaseV0::TupleV0(ScSpecUdtUnionCaseTupleV0 { name, @@ -1184,7 +1186,7 @@ impl Spec { .. }) => format!( "{}({})", - name.to_string_lossy(), + name.to_utf8_string_lossy(), type_ .iter() .map(|type_| self.arg_value_name(type_, depth + 1)) @@ -1283,7 +1285,7 @@ impl Spec { Some(format!("\"{res}\"")) } ScType::Udt(ScSpecTypeUdt { name }) => { - self.example_udts(name.to_string_lossy().as_ref()) + self.example_udts(name.to_utf8_string_lossy().as_ref()) } // No specific value name for these yet. ScType::Val => None, @@ -1294,7 +1296,8 @@ impl Spec { match self.find(name).ok() { Some(ScSpecEntry::UdtStructV0(strukt)) => { // Check if a tuple strukt - if !strukt.fields.is_empty() && strukt.fields[0].name.to_string_lossy() == "0" { + if !strukt.fields.is_empty() && strukt.fields[0].name.to_utf8_string_lossy() == "0" + { let value_types = strukt .fields .iter() @@ -1307,7 +1310,7 @@ impl Spec { let inner = strukt .fields .iter() - .map(|f| (f.name.to_string_lossy(), &f.type_)) + .map(|f| (f.name.to_utf8_string_lossy(), &f.type_)) .map(|(name, type_)| { let type_ = self.example(type_)?; let name = format!(r#""{name}""#); @@ -1331,21 +1334,21 @@ impl Spec { .iter() .map(|case| match case { ScSpecUdtUnionCaseV0::VoidV0(ScSpecUdtUnionCaseVoidV0 { name, .. }) => { - Some(format!("\"{}\"", name.to_string_lossy())) + Some(format!("\"{}\"", name.to_utf8_string_lossy())) } ScSpecUdtUnionCaseV0::TupleV0(ScSpecUdtUnionCaseTupleV0 { name, type_, .. }) => { if type_.len() == 1 { let single = self.example(&type_[0])?; - Some(format!("{{\"{}\":{single}}}", name.to_string_lossy())) + Some(format!("{{\"{}\":{single}}}", name.to_utf8_string_lossy())) } else { let names = type_ .iter() .map(|t| self.example(t)) .collect::>>()? .join(", "); - Some(format!("{{\"{}\":[{names}]}}", name.to_string_lossy())) + Some(format!("{{\"{}\":[{names}]}}", name.to_utf8_string_lossy())) } } }) diff --git a/cmd/crates/soroban-spec-tools/src/utils.rs b/cmd/crates/soroban-spec-tools/src/utils.rs index 50cd5ee7a..66b153a11 100644 --- a/cmd/crates/soroban-spec-tools/src/utils.rs +++ b/cmd/crates/soroban-spec-tools/src/utils.rs @@ -6,9 +6,8 @@ use std::{ }; use stellar_xdr::curr::{ - DepthLimitedRead, ReadXdr, ScEnvMetaEntry, ScMetaEntry, ScMetaV0, ScSpecEntry, - ScSpecFunctionV0, ScSpecUdtEnumV0, ScSpecUdtErrorEnumV0, ScSpecUdtStructV0, ScSpecUdtUnionV0, - StringM, + Limited, Limits, ReadXdr, ScEnvMetaEntry, ScMetaEntry, ScMetaV0, ScSpecEntry, ScSpecFunctionV0, + ScSpecUdtEnumV0, ScSpecUdtErrorEnumV0, ScSpecUdtStructV0, ScSpecUdtUnionV0, StringM, }; pub struct ContractSpec { @@ -61,8 +60,8 @@ impl ContractSpec { let env_meta = if let Some(env_meta) = env_meta { env_meta_base64 = Some(base64.encode(env_meta)); let cursor = Cursor::new(env_meta); - let mut depth_limit_read = DepthLimitedRead::new(cursor, 100); - ScEnvMetaEntry::read_xdr_iter(&mut depth_limit_read).collect::, _>>()? + let mut read = Limited::new(cursor, Limits::none()); + ScEnvMetaEntry::read_xdr_iter(&mut read).collect::, _>>()? } else { vec![] }; @@ -71,8 +70,8 @@ impl ContractSpec { let meta = if let Some(meta) = meta { meta_base64 = Some(base64.encode(meta)); let cursor = Cursor::new(meta); - let mut depth_limit_read = DepthLimitedRead::new(cursor, 100); - ScMetaEntry::read_xdr_iter(&mut depth_limit_read).collect::, _>>()? + let mut read = Limited::new(cursor, Limits::none()); + ScMetaEntry::read_xdr_iter(&mut read).collect::, _>>()? } else { vec![] }; @@ -81,8 +80,8 @@ impl ContractSpec { let spec = if let Some(spec) = spec { spec_base64 = Some(base64.encode(spec)); let cursor = Cursor::new(spec); - let mut depth_limit_read = DepthLimitedRead::new(cursor, 100); - ScSpecEntry::read_xdr_iter(&mut depth_limit_read).collect::, _>>()? + let mut read = Limited::new(cursor, Limits::none()); + ScSpecEntry::read_xdr_iter(&mut read).collect::, _>>()? } else { vec![] }; @@ -147,12 +146,12 @@ impl Display for ContractSpec { } fn write_func(f: &mut std::fmt::Formatter<'_>, func: &ScSpecFunctionV0) -> std::fmt::Result { - writeln!(f, " • Function: {}", func.name.to_string_lossy())?; + writeln!(f, " • Function: {}", func.name.to_utf8_string_lossy())?; if func.doc.len() > 0 { writeln!( f, " Docs: {}", - &indent(&func.doc.to_string_lossy(), 11).trim() + &indent(&func.doc.to_utf8_string_lossy(), 11).trim() )?; } writeln!( @@ -175,7 +174,7 @@ fn write_union(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtUnionV0) -> std:: writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Cases:")?; @@ -192,7 +191,7 @@ fn write_struct(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtStructV0) -> std writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Fields:")?; @@ -200,7 +199,7 @@ fn write_struct(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtStructV0) -> std writeln!( f, " • {}: {}", - field.name.to_string_lossy(), + field.name.to_utf8_string_lossy(), indent(&format!("{:#?}", field.type_), 8).trim() )?; if field.doc.len() > 0 { @@ -217,7 +216,7 @@ fn write_enum(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtEnumV0) -> std::fm writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Cases:")?; @@ -234,7 +233,7 @@ fn write_error(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtErrorEnumV0) -> s writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Cases:")?; @@ -255,9 +254,13 @@ fn indent(s: &str, n: usize) -> String { fn format_name(lib: &StringM<80>, name: &StringM<60>) -> String { if lib.len() > 0 { - format!("{}::{}", lib.to_string_lossy(), name.to_string_lossy()) + format!( + "{}::{}", + lib.to_utf8_string_lossy(), + name.to_utf8_string_lossy() + ) } else { - name.to_string_lossy() + name.to_utf8_string_lossy() } } diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/assembled-tx.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/assembled-tx.d.ts new file mode 100644 index 000000000..8297cbf3c --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/assembled-tx.d.ts @@ -0,0 +1,184 @@ +import { Account, Address, Operation, SorobanRpc, xdr } from "stellar-sdk"; +import type { Memo, MemoType, Transaction } from "stellar-sdk"; +import type { ClassOptions, MethodOptions, Wallet, XDR_BASE64 } from "./method-options.js"; +export type Tx = Transaction, Operation[]>; +export declare class ExpiredStateError extends Error { +} +export declare class NeedsMoreSignaturesError extends Error { +} +export declare class WalletDisconnectedError extends Error { +} +export declare class SendResultOnlyError extends Error { +} +export declare class SendFailedError extends Error { +} +export declare class NoUnsignedNonInvokerAuthEntriesError extends Error { +} +type SendTx = SorobanRpc.Api.SendTransactionResponse; +type GetTx = SorobanRpc.Api.GetTransactionResponse; +export type u32 = number; +export type i32 = number; +export type u64 = bigint; +export type i64 = bigint; +export type u128 = bigint; +export type i128 = bigint; +export type u256 = bigint; +export type i256 = bigint; +export type Option = T | undefined; +export type Typepoint = bigint; +export type Duration = bigint; +export { Address }; +export interface Error_ { + message: string; +} +export interface Result { + unwrap(): T; + unwrapErr(): E; + isOk(): boolean; + isErr(): boolean; +} +export declare class Ok implements Result { + readonly value: T; + constructor(value: T); + unwrapErr(): E; + unwrap(): T; + isOk(): boolean; + isErr(): boolean; +} +export declare class Err implements Result { + readonly error: E; + constructor(error: E); + unwrapErr(): E; + unwrap(): never; + isOk(): boolean; + isErr(): boolean; +} +export declare const contractErrorPattern: RegExp; +type AssembledTransactionOptions = MethodOptions & ClassOptions & { + method: string; + args?: any[]; + parseResultXdr: (xdr: string | xdr.ScVal | Err) => T; +}; +export declare const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; +export declare class AssembledTransaction { + options: AssembledTransactionOptions; + raw: Tx; + private simulation?; + private simulationResult?; + private simulationTransactionData?; + private server; + toJSON(): string; + static fromJSON(options: Omit, 'args'>, { tx, simulationResult, simulationTransactionData }: { + tx: XDR_BASE64; + simulationResult: { + auth: XDR_BASE64[]; + retval: XDR_BASE64; + }; + simulationTransactionData: XDR_BASE64; + }): AssembledTransaction; + private constructor(); + static fromSimulation(options: AssembledTransactionOptions): Promise>; + simulate: () => Promise; + get simulationData(): { + result: SorobanRpc.Api.SimulateHostFunctionResult; + transactionData: xdr.SorobanTransactionData; + }; + get result(): T; + parseError(errorMessage: string): Err | undefined; + getWallet: () => Promise; + getPublicKey: () => Promise; + /** + * Get account details from the Soroban network for the publicKey currently + * selected in user's wallet. If not connected to Freighter, use placeholder + * null account. + */ + getAccount: () => Promise; + /** + * Sign the transaction with the `wallet` (default Freighter), then send to + * the network and return a `SentTransaction` that keeps track of all the + * attempts to send and fetch the transaction from the network. + */ + signAndSend: ({ secondsToWait, force }?: { + /** + * Wait `secondsToWait` seconds (default: 10) for both the transaction to SEND successfully (will keep trying if the server returns `TRY_AGAIN_LATER`), as well as for the transaction to COMPLETE (will keep checking if the server returns `PENDING`). + */ + secondsToWait?: number | undefined; + /** + * If `true`, sign and send the transaction even if it is a read call. + */ + force?: boolean | undefined; + }) => Promise>; + getStorageExpiration: () => Promise; + /** + * Get a list of accounts, other than the invoker of the simulation, that + * need to sign auth entries in this transaction. + * + * Soroban allows multiple people to sign a transaction. Someone needs to + * sign the final transaction envelope; this person/account is called the + * _invoker_, or _source_. Other accounts might need to sign individual auth + * entries in the transaction, if they're not also the invoker. + * + * This function returns a list of accounts that need to sign auth entries, + * assuming that the same invoker/source account will sign the final + * transaction envelope as signed the initial simulation. + * + * One at a time, for each public key in this array, you will need to + * serialize this transaction with `toJSON`, send to the owner of that key, + * deserialize the transaction with `txFromJson`, and call + * {@link signAuthEntries}. Then re-serialize and send to the next account + * in this list. + */ + needsNonInvokerSigningBy: ({ includeAlreadySigned, }?: { + /** + * Whether or not to include auth entries that have already been signed. Default: false + */ + includeAlreadySigned?: boolean | undefined; + }) => Promise; + preImageFor(entry: xdr.SorobanAuthorizationEntry, signatureExpirationLedger: number): xdr.HashIdPreimage; + /** + * If {@link needsNonInvokerSigningBy} returns a non-empty list, you can serialize + * the transaction with `toJSON`, send it to the owner of one of the public keys + * in the map, deserialize with `txFromJSON`, and call this method on their + * machine. Internally, this will use `signAuthEntry` function from connected + * `wallet` for each. + * + * Then, re-serialize the transaction and either send to the next + * `needsNonInvokerSigningBy` owner, or send it back to the original account + * who simulated the transaction so they can {@link sign} the transaction + * envelope and {@link send} it to the network. + * + * Sending to all `needsNonInvokerSigningBy` owners in parallel is not currently + * supported! + */ + signAuthEntries: (expiration?: number | Promise) => Promise; + get isReadCall(): boolean; + hasRealInvoker: () => Promise; +} +/** + * A transaction that has been sent to the Soroban network. This happens in two steps: + * + * 1. `sendTransaction`: initial submission of the transaction to the network. + * This step can run into problems, and will be retried with exponential + * backoff if it does. See all attempts in `sendTransactionResponseAll` and the + * most recent attempt in `sendTransactionResponse`. + * 2. `getTransaction`: once the transaction has been submitted to the network + * successfully, you need to wait for it to finalize to get the results of the + * transaction. This step can also run into problems, and will be retried with + * exponential backoff if it does. See all attempts in + * `getTransactionResponseAll` and the most recent attempt in + * `getTransactionResponse`. + */ +declare class SentTransaction { + options: AssembledTransactionOptions; + assembled: AssembledTransaction; + server: SorobanRpc.Server; + signed: Tx; + sendTransactionResponse?: SendTx; + sendTransactionResponseAll?: SendTx[]; + getTransactionResponse?: GetTx; + getTransactionResponseAll?: GetTx[]; + constructor(options: AssembledTransactionOptions, assembled: AssembledTransaction); + static init: (options: AssembledTransactionOptions, assembled: AssembledTransaction, secondsToWait?: number) => Promise>; + private send; + get result(): T; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/assembled-tx.js b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/assembled-tx.js new file mode 100644 index 000000000..5d2128f47 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/assembled-tx.js @@ -0,0 +1,462 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AssembledTransaction = exports.NULL_ACCOUNT = exports.contractErrorPattern = exports.Err = exports.Ok = exports.Address = exports.NoUnsignedNonInvokerAuthEntriesError = exports.SendFailedError = exports.SendResultOnlyError = exports.WalletDisconnectedError = exports.NeedsMoreSignaturesError = exports.ExpiredStateError = void 0; +const stellar_sdk_1 = require("stellar-sdk"); +Object.defineProperty(exports, "Address", { enumerable: true, get: function () { return stellar_sdk_1.Address; } }); +const buffer_1 = require("buffer"); +class ExpiredStateError extends Error { +} +exports.ExpiredStateError = ExpiredStateError; +class NeedsMoreSignaturesError extends Error { +} +exports.NeedsMoreSignaturesError = NeedsMoreSignaturesError; +class WalletDisconnectedError extends Error { +} +exports.WalletDisconnectedError = WalletDisconnectedError; +class SendResultOnlyError extends Error { +} +exports.SendResultOnlyError = SendResultOnlyError; +class SendFailedError extends Error { +} +exports.SendFailedError = SendFailedError; +class NoUnsignedNonInvokerAuthEntriesError extends Error { +} +exports.NoUnsignedNonInvokerAuthEntriesError = NoUnsignedNonInvokerAuthEntriesError; +; +; +class Ok { + value; + constructor(value) { + this.value = value; + } + unwrapErr() { + throw new Error('No error'); + } + unwrap() { + return this.value; + } + isOk() { + return true; + } + isErr() { + return !this.isOk(); + } +} +exports.Ok = Ok; +class Err { + error; + constructor(error) { + this.error = error; + } + unwrapErr() { + return this.error; + } + unwrap() { + throw new Error(this.error.message); + } + isOk() { + return false; + } + isErr() { + return !this.isOk(); + } +} +exports.Err = Err; +exports.contractErrorPattern = /Error\(Contract, #(\d+)\)/; +exports.NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; +class AssembledTransaction { + options; + raw; + simulation; + simulationResult; + simulationTransactionData; + server; + toJSON() { + return JSON.stringify({ + method: this.options.method, + tx: this.raw?.toXDR(), + simulationResult: { + auth: this.simulationData.result.auth.map(a => a.toXDR('base64')), + retval: this.simulationData.result.retval.toXDR('base64'), + }, + simulationTransactionData: this.simulationData.transactionData.toXDR('base64'), + }); + } + static fromJSON(options, { tx, simulationResult, simulationTransactionData }) { + const txn = new AssembledTransaction(options); + txn.raw = stellar_sdk_1.TransactionBuilder.fromXDR(tx, options.networkPassphrase); + txn.simulationResult = { + auth: simulationResult.auth.map(a => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64')), + retval: stellar_sdk_1.xdr.ScVal.fromXDR(simulationResult.retval, 'base64'), + }; + txn.simulationTransactionData = stellar_sdk_1.xdr.SorobanTransactionData.fromXDR(simulationTransactionData, 'base64'); + return txn; + } + constructor(options) { + this.options = options; + this.server = new stellar_sdk_1.SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + } + static async fromSimulation(options) { + const tx = new AssembledTransaction(options); + const contract = new stellar_sdk_1.Contract(options.contractId); + tx.raw = new stellar_sdk_1.TransactionBuilder(await tx.getAccount(), { + fee: options.fee?.toString(10) ?? stellar_sdk_1.BASE_FEE, + networkPassphrase: options.networkPassphrase, + }) + .addOperation(contract.call(options.method, ...(options.args ?? []))) + .setTimeout(stellar_sdk_1.TimeoutInfinite) + .build(); + return await tx.simulate(); + } + simulate = async () => { + if (!this.raw) + throw new Error('Transaction has not yet been assembled'); + this.simulation = await this.server.simulateTransaction(this.raw); + if (stellar_sdk_1.SorobanRpc.Api.isSimulationSuccess(this.simulation)) { + this.raw = stellar_sdk_1.SorobanRpc.assembleTransaction(this.raw, this.simulation).build(); + } + return this; + }; + get simulationData() { + if (this.simulationResult && this.simulationTransactionData) { + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData, + }; + } + // else, we know we just did the simulation on this machine + const simulation = this.simulation; + if (stellar_sdk_1.SorobanRpc.Api.isSimulationError(simulation)) { + throw new Error(`Transaction simulation failed: "${simulation.error}"`); + } + if (stellar_sdk_1.SorobanRpc.Api.isSimulationRestore(simulation)) { + throw new ExpiredStateError(`You need to restore some contract state before you can invoke this method. ${JSON.stringify(simulation, null, 2)}`); + } + if (!simulation.result) { + throw new Error(`Expected an invocation simulation, but got no 'result' field. Simulation: ${JSON.stringify(simulation, null, 2)}`); + } + // add to object for serialization & deserialization + this.simulationResult = simulation.result; + this.simulationTransactionData = simulation.transactionData.build(); + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData, + }; + } + get result() { + try { + return this.options.parseResultXdr(this.simulationData.result.retval); + } + catch (e) { + let err = this.parseError(e.toString()); + if (err) + return err; + throw e; + } + } + parseError(errorMessage) { + if (!this.options.errorTypes) + return; + const match = errorMessage.match(exports.contractErrorPattern); + if (!match) + return; + let i = parseInt(match[1], 10); + let err = this.options.errorTypes[i]; + if (err) + return new Err(err); + } + getWallet = async () => { + return this.options.wallet ?? (await Promise.resolve().then(() => require("@stellar/freighter-api"))).default; + }; + getPublicKey = async () => { + const wallet = await this.getWallet(); + if (await wallet.isConnected() && await wallet.isAllowed()) { + return (await wallet.getUserInfo()).publicKey; + } + }; + /** + * Get account details from the Soroban network for the publicKey currently + * selected in user's wallet. If not connected to Freighter, use placeholder + * null account. + */ + getAccount = async () => { + const publicKey = await this.getPublicKey(); + return publicKey + ? await this.server.getAccount(publicKey) + : new stellar_sdk_1.Account(exports.NULL_ACCOUNT, "0"); + }; + /** + * Sign the transaction with the `wallet` (default Freighter), then send to + * the network and return a `SentTransaction` that keeps track of all the + * attempts to send and fetch the transaction from the network. + */ + signAndSend = async ({ secondsToWait = 10, force = false } = {}) => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated'); + } + if (!force && this.isReadCall) { + throw new Error('This is a read call. It requires no signature or sending. Use `force: true` to sign and send anyway.'); + } + if (!await this.hasRealInvoker()) { + throw new WalletDisconnectedError('Wallet is not connected'); + } + if (this.raw.source !== (await this.getAccount()).accountId()) { + throw new Error(`You must submit the transaction with the account that originally created it. Please switch to the wallet with "${this.raw.source}" as its public key.`); + } + if ((await this.needsNonInvokerSigningBy()).length) { + throw new NeedsMoreSignaturesError('Transaction requires more signatures. See `needsNonInvokerSigningBy` for details.'); + } + return await SentTransaction.init(this.options, this, secondsToWait); + }; + getStorageExpiration = async () => { + const entryRes = await this.server.getLedgerEntries(new stellar_sdk_1.Contract(this.options.contractId).getFootprint()); + if (!entryRes.entries || + !entryRes.entries.length || + !entryRes.entries[0].liveUntilLedgerSeq) + throw new Error('failed to get ledger entry'); + return entryRes.entries[0].liveUntilLedgerSeq; + }; + /** + * Get a list of accounts, other than the invoker of the simulation, that + * need to sign auth entries in this transaction. + * + * Soroban allows multiple people to sign a transaction. Someone needs to + * sign the final transaction envelope; this person/account is called the + * _invoker_, or _source_. Other accounts might need to sign individual auth + * entries in the transaction, if they're not also the invoker. + * + * This function returns a list of accounts that need to sign auth entries, + * assuming that the same invoker/source account will sign the final + * transaction envelope as signed the initial simulation. + * + * One at a time, for each public key in this array, you will need to + * serialize this transaction with `toJSON`, send to the owner of that key, + * deserialize the transaction with `txFromJson`, and call + * {@link signAuthEntries}. Then re-serialize and send to the next account + * in this list. + */ + needsNonInvokerSigningBy = async ({ includeAlreadySigned = false, } = {}) => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated'); + } + // We expect that any transaction constructed by these libraries has a + // single operation, which is an InvokeHostFunction operation. The host + // function being invoked is the contract method call. + if (!("operations" in this.raw)) { + throw new Error(`Unexpected Transaction type; no operations: ${JSON.stringify(this.raw)}`); + } + const rawInvokeHostFunctionOp = this.raw + .operations[0]; + return [...new Set((rawInvokeHostFunctionOp.auth ?? []).filter(entry => entry.credentials().switch() === + stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsAddress() && + (includeAlreadySigned || + entry.credentials().address().signature().switch().name === 'scvVoid')).map(entry => stellar_sdk_1.StrKey.encodeEd25519PublicKey(entry.credentials().address().address().accountId().ed25519())))]; + }; + preImageFor(entry, signatureExpirationLedger) { + const addrAuth = entry.credentials().address(); + return stellar_sdk_1.xdr.HashIdPreimage.envelopeTypeSorobanAuthorization(new stellar_sdk_1.xdr.HashIdPreimageSorobanAuthorization({ + networkId: (0, stellar_sdk_1.hash)(buffer_1.Buffer.from(this.options.networkPassphrase)), + nonce: addrAuth.nonce(), + invocation: entry.rootInvocation(), + signatureExpirationLedger, + })); + } + /** + * If {@link needsNonInvokerSigningBy} returns a non-empty list, you can serialize + * the transaction with `toJSON`, send it to the owner of one of the public keys + * in the map, deserialize with `txFromJSON`, and call this method on their + * machine. Internally, this will use `signAuthEntry` function from connected + * `wallet` for each. + * + * Then, re-serialize the transaction and either send to the next + * `needsNonInvokerSigningBy` owner, or send it back to the original account + * who simulated the transaction so they can {@link sign} the transaction + * envelope and {@link send} it to the network. + * + * Sending to all `needsNonInvokerSigningBy` owners in parallel is not currently + * supported! + */ + signAuthEntries = async ( + /** + * When to set each auth entry to expire. Could be any number of blocks in + * the future. Can be supplied as a promise or a raw number. Default: + * contract's current `persistent` storage expiration date/ledger + * number/block. + */ + expiration = this.getStorageExpiration()) => { + if (!this.raw) + throw new Error('Transaction has not yet been assembled or simulated'); + const needsNonInvokerSigningBy = await this.needsNonInvokerSigningBy(); + if (!needsNonInvokerSigningBy) + throw new NoUnsignedNonInvokerAuthEntriesError('No unsigned non-invoker auth entries; maybe you already signed?'); + const publicKey = await this.getPublicKey(); + if (!publicKey) + throw new Error('Could not get public key from wallet; maybe Freighter is not signed in?'); + if (needsNonInvokerSigningBy.indexOf(publicKey) === -1) + throw new Error(`No auth entries for public key "${publicKey}"`); + const wallet = await this.getWallet(); + const rawInvokeHostFunctionOp = this.raw + .operations[0]; + const authEntries = rawInvokeHostFunctionOp.auth ?? []; + for (const [i, entry] of authEntries.entries()) { + if (entry.credentials().switch() !== + stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsAddress()) { + // if the invoker/source account, then the entry doesn't need explicit + // signature, since the tx envelope is already signed by the source + // account, so only check for sorobanCredentialsAddress + continue; + } + const pk = stellar_sdk_1.StrKey.encodeEd25519PublicKey(entry.credentials().address().address().accountId().ed25519()); + // this auth entry needs to be signed by a different account + // (or maybe already was!) + if (pk !== publicKey) + continue; + authEntries[i] = await (0, stellar_sdk_1.authorizeEntry)(entry, async (preimage) => buffer_1.Buffer.from(await wallet.signAuthEntry(preimage.toXDR('base64')), 'base64'), await expiration, this.options.networkPassphrase); + } + }; + get isReadCall() { + const authsCount = this.simulationData.result.auth.length; + const writeLength = this.simulationData.transactionData.resources().footprint().readWrite().length; + return (authsCount === 0) && (writeLength === 0); + } + hasRealInvoker = async () => { + const account = await this.getAccount(); + return account.accountId() !== exports.NULL_ACCOUNT; + }; +} +exports.AssembledTransaction = AssembledTransaction; +/** + * A transaction that has been sent to the Soroban network. This happens in two steps: + * + * 1. `sendTransaction`: initial submission of the transaction to the network. + * This step can run into problems, and will be retried with exponential + * backoff if it does. See all attempts in `sendTransactionResponseAll` and the + * most recent attempt in `sendTransactionResponse`. + * 2. `getTransaction`: once the transaction has been submitted to the network + * successfully, you need to wait for it to finalize to get the results of the + * transaction. This step can also run into problems, and will be retried with + * exponential backoff if it does. See all attempts in + * `getTransactionResponseAll` and the most recent attempt in + * `getTransactionResponse`. + */ +class SentTransaction { + options; + assembled; + server; + signed; + sendTransactionResponse; + sendTransactionResponseAll; + getTransactionResponse; + getTransactionResponseAll; + constructor(options, assembled) { + this.options = options; + this.assembled = assembled; + this.server = new stellar_sdk_1.SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + this.assembled = assembled; + } + static init = async (options, assembled, secondsToWait = 10) => { + const tx = new SentTransaction(options, assembled); + return await tx.send(secondsToWait); + }; + send = async (secondsToWait = 10) => { + const wallet = await this.assembled.getWallet(); + this.sendTransactionResponseAll = await withExponentialBackoff(async (previousFailure) => { + if (previousFailure) { + // Increment transaction sequence number and resimulate before trying again + // Soroban transaction can only have 1 operation + const op = this.assembled.raw.operations[0]; + this.assembled.raw = new stellar_sdk_1.TransactionBuilder(await this.assembled.getAccount(), { + fee: this.assembled.raw.fee, + networkPassphrase: this.options.networkPassphrase, + }) + .setTimeout(stellar_sdk_1.TimeoutInfinite) + .addOperation(stellar_sdk_1.Operation.invokeHostFunction({ ...op, auth: op.auth ?? [] })) + .build(); + await this.assembled.simulate(); + } + const signature = await wallet.signTransaction(this.assembled.raw.toXDR(), { + networkPassphrase: this.options.networkPassphrase, + }); + this.signed = stellar_sdk_1.TransactionBuilder.fromXDR(signature, this.options.networkPassphrase); + return this.server.sendTransaction(this.signed); + }, resp => resp.status !== "PENDING", secondsToWait); + this.sendTransactionResponse = this.sendTransactionResponseAll[this.sendTransactionResponseAll.length - 1]; + if (this.sendTransactionResponse.status !== "PENDING") { + throw new Error(`Tried to resubmit transaction for ${secondsToWait} seconds, but it's still failing. ` + + `All attempts: ${JSON.stringify(this.sendTransactionResponseAll, null, 2)}`); + } + const { hash } = this.sendTransactionResponse; + this.getTransactionResponseAll = await withExponentialBackoff(() => this.server.getTransaction(hash), resp => resp.status === stellar_sdk_1.SorobanRpc.Api.GetTransactionStatus.NOT_FOUND, secondsToWait); + this.getTransactionResponse = this.getTransactionResponseAll[this.getTransactionResponseAll.length - 1]; + if (this.getTransactionResponse.status === stellar_sdk_1.SorobanRpc.Api.GetTransactionStatus.NOT_FOUND) { + console.error(`Waited ${secondsToWait} seconds for transaction to complete, but it did not. ` + + `Returning anyway. Check the transaction status manually. ` + + `Sent transaction: ${JSON.stringify(this.sendTransactionResponse, null, 2)}\n` + + `All attempts to get the result: ${JSON.stringify(this.getTransactionResponseAll, null, 2)}`); + } + return this; + }; + get result() { + // 1. check if transaction was submitted and awaited with `getTransaction` + if ("getTransactionResponse" in this && + this.getTransactionResponse) { + // getTransactionResponse has a `returnValue` field unless it failed + if ("returnValue" in this.getTransactionResponse) { + return this.options.parseResultXdr(this.getTransactionResponse.returnValue); + } + // if "returnValue" not present, the transaction failed; return without parsing the result + throw new Error("Transaction failed! Cannot parse result."); + } + // 2. otherwise, maybe it was merely sent with `sendTransaction` + if (this.sendTransactionResponse) { + const errorResult = this.sendTransactionResponse.errorResult?.result(); + if (errorResult) { + throw new SendFailedError(`Transaction simulation looked correct, but attempting to send the transaction failed. Check \`simulation\` and \`sendTransactionResponseAll\` to troubleshoot. Decoded \`sendTransactionResponse.errorResultXdr\`: ${errorResult}`); + } + throw new SendResultOnlyError(`Transaction was sent to the network, but not yet awaited. No result to show. Await transaction completion with \`getTransaction(sendTransactionResponse.hash)\``); + } + // 3. finally, if neither of those are present, throw an error + throw new Error(`Sending transaction failed: ${JSON.stringify(this.assembled)}`); + } +} +/** + * Keep calling a `fn` for `secondsToWait` seconds, if `keepWaitingIf` is true. + * Returns an array of all attempts to call the function. + */ +async function withExponentialBackoff(fn, keepWaitingIf, secondsToWait, exponentialFactor = 1.5, verbose = false) { + const attempts = []; + let count = 0; + attempts.push(await fn()); + if (!keepWaitingIf(attempts[attempts.length - 1])) + return attempts; + const waitUntil = new Date(Date.now() + secondsToWait * 1000).valueOf(); + let waitTime = 1000; + let totalWaitTime = waitTime; + while (Date.now() < waitUntil && keepWaitingIf(attempts[attempts.length - 1])) { + count++; + // Wait a beat + if (verbose) { + console.info(`Waiting ${waitTime}ms before trying again (bringing the total wait time to ${totalWaitTime}ms so far, of total ${secondsToWait * 1000}ms)`); + } + await new Promise(res => setTimeout(res, waitTime)); + // Exponential backoff + waitTime = waitTime * exponentialFactor; + if (new Date(Date.now() + waitTime).valueOf() > waitUntil) { + waitTime = waitUntil - Date.now(); + if (verbose) { + console.info(`was gonna wait too long; new waitTime: ${waitTime}ms`); + } + } + totalWaitTime = waitTime + totalWaitTime; + // Try again + attempts.push(await fn(attempts[attempts.length - 1])); + if (verbose && keepWaitingIf(attempts[attempts.length - 1])) { + console.info(`${count}. Called ${fn}; ${attempts.length} prev attempts. Most recent: ${JSON.stringify(attempts[attempts.length - 1], null, 2)}`); + } + } + return attempts; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/index.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/index.d.ts new file mode 100644 index 000000000..d32b06f97 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/index.d.ts @@ -0,0 +1,424 @@ +import { ContractSpec } from 'stellar-sdk'; +import { Buffer } from "buffer"; +import { AssembledTransaction, Ok, Err } from './assembled-tx.js'; +import type { u32, i32, i64, i128, Option, Error_ } from './assembled-tx.js'; +import type { ClassOptions } from './method-options.js'; +export * from './assembled-tx.js'; +export * from './method-options.js'; +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: { + 1: { + message: string; + }; +}; +export declare class Contract { + readonly options: ClassOptions; + spec: ContractSpec; + constructor(options: ClassOptions); + private readonly parsers; + private txFromJSON; + readonly fromJSON: { + hello: (json: string) => AssembledTransaction; + woid: (json: string) => AssembledTransaction; + val: (json: string) => AssembledTransaction; + u32FailOnEven: (json: string) => AssembledTransaction | Ok>; + u32: (json: string) => AssembledTransaction; + i32: (json: string) => AssembledTransaction; + i64: (json: string) => AssembledTransaction; + struktHel: (json: string) => AssembledTransaction; + strukt: (json: string) => AssembledTransaction; + simple: (json: string) => AssembledTransaction; + complex: (json: string) => AssembledTransaction; + addresse: (json: string) => AssembledTransaction; + bytes: (json: string) => AssembledTransaction; + bytesN: (json: string) => AssembledTransaction; + card: (json: string) => AssembledTransaction; + boolean: (json: string) => AssembledTransaction; + not: (json: string) => AssembledTransaction; + i128: (json: string) => AssembledTransaction; + u128: (json: string) => AssembledTransaction; + multiArgs: (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; + tupleStrukt: (json: string) => AssembledTransaction; + }; + /** +* 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + u32FailOnEven: ({ u32_ }: { + u32_: u32; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => Promise | Ok>>; + /** +* 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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 +*/ + struktHel: ({ strukt }: { + strukt: Test; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + bytesN: ({ bytes_n }: { + bytes_n: Buffer; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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. +*/ + multiArgs: ({ a, b }: { + a: u32; + b: boolean; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + tupleStrukt: ({ tuple_strukt }: { + tuple_strukt: TupleStruct; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => Promise>; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/index.js b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/index.js new file mode 100644 index 000000000..735f2fa29 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/index.js @@ -0,0 +1,527 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Contract = exports.Errors = exports.RoyalCard = exports.networks = void 0; +const stellar_sdk_1 = require("stellar-sdk"); +const buffer_1 = require("buffer"); +const assembled_tx_js_1 = require("./assembled-tx.js"); +__exportStar(require("./assembled-tx.js"), exports); +__exportStar(require("./method-options.js"), exports); +if (typeof window !== 'undefined') { + //@ts-ignore Buffer exists + window.Buffer = window.Buffer || buffer_1.Buffer; +} +exports.networks = { + futurenet: { + networkPassphrase: "Test SDF Future Network ; October 2022", + contractId: "CBYMYMSDF6FBDNCFJCRC7KMO4REYFPOH2U4N7FXI3GJO6YXNCQ43CDSK", + } +}; +/** + + */ +var RoyalCard; +(function (RoyalCard) { + RoyalCard[RoyalCard["Jack"] = 11] = "Jack"; + RoyalCard[RoyalCard["Queen"] = 12] = "Queen"; + RoyalCard[RoyalCard["King"] = 13] = "King"; +})(RoyalCard || (exports.RoyalCard = RoyalCard = {})); +/** + + */ +exports.Errors = { + 1: { message: "Please provide an odd number" } +}; +class Contract { + options; + spec; + constructor(options) { + this.options = options; + this.spec = new stellar_sdk_1.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=" + ]); + } + parsers = { + hello: (result) => this.spec.funcResToNative("hello", result), + woid: () => { }, + val: (result) => this.spec.funcResToNative("val", result), + u32FailOnEven: (result) => { + if (result instanceof assembled_tx_js_1.Err) + return result; + return new assembled_tx_js_1.Ok(this.spec.funcResToNative("u32_fail_on_even", result)); + }, + u32: (result) => this.spec.funcResToNative("u32_", result), + i32: (result) => this.spec.funcResToNative("i32_", result), + i64: (result) => this.spec.funcResToNative("i64_", result), + struktHel: (result) => this.spec.funcResToNative("strukt_hel", result), + strukt: (result) => this.spec.funcResToNative("strukt", result), + simple: (result) => this.spec.funcResToNative("simple", result), + complex: (result) => this.spec.funcResToNative("complex", result), + addresse: (result) => this.spec.funcResToNative("addresse", result), + bytes: (result) => this.spec.funcResToNative("bytes", result), + bytesN: (result) => this.spec.funcResToNative("bytes_n", result), + card: (result) => this.spec.funcResToNative("card", result), + boolean: (result) => this.spec.funcResToNative("boolean", result), + not: (result) => this.spec.funcResToNative("not", result), + i128: (result) => this.spec.funcResToNative("i128", result), + u128: (result) => this.spec.funcResToNative("u128", result), + multiArgs: (result) => this.spec.funcResToNative("multi_args", result), + map: (result) => this.spec.funcResToNative("map", result), + vec: (result) => this.spec.funcResToNative("vec", result), + tuple: (result) => this.spec.funcResToNative("tuple", result), + option: (result) => this.spec.funcResToNative("option", result), + u256: (result) => this.spec.funcResToNative("u256", result), + i256: (result) => this.spec.funcResToNative("i256", result), + string: (result) => this.spec.funcResToNative("string", result), + tupleStrukt: (result) => this.spec.funcResToNative("tuple_strukt", result) + }; + txFromJSON = (json) => { + const { method, ...tx } = JSON.parse(json); + return assembled_tx_js_1.AssembledTransaction.fromJSON({ + ...this.options, + method, + parseResultXdr: this.parsers[method], + }, tx); + }; + fromJSON = { + hello: (this.txFromJSON), + woid: (this.txFromJSON), + val: (this.txFromJSON), + u32FailOnEven: (this.txFromJSON), + u32: (this.txFromJSON), + i32: (this.txFromJSON), + i64: (this.txFromJSON), + struktHel: (this.txFromJSON), + strukt: (this.txFromJSON), + simple: (this.txFromJSON), + complex: (this.txFromJSON), + addresse: (this.txFromJSON), + bytes: (this.txFromJSON), + bytesN: (this.txFromJSON), + card: (this.txFromJSON), + boolean: (this.txFromJSON), + not: (this.txFromJSON), + i128: (this.txFromJSON), + u128: (this.txFromJSON), + multiArgs: (this.txFromJSON), + map: (this.txFromJSON), + vec: (this.txFromJSON), + tuple: (this.txFromJSON), + option: (this.txFromJSON), + u256: (this.txFromJSON), + i256: (this.txFromJSON), + string: (this.txFromJSON), + tupleStrukt: (this.txFromJSON) + }; + /** +* 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 = async ({ hello }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'hello', + args: this.spec.funcArgsToScVals("hello", { hello }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['hello'], + }); + }; + /** +* 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 = async (options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'woid', + args: this.spec.funcArgsToScVals("woid", {}), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['woid'], + }); + }; + /** +* 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 = async (options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'val', + args: this.spec.funcArgsToScVals("val", {}), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['val'], + }); + }; + /** +* 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. +*/ + u32FailOnEven = async ({ u32_ }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'u32_fail_on_even', + args: this.spec.funcArgsToScVals("u32_fail_on_even", { u32_ }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['u32FailOnEven'], + }); + }; + /** +* 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 = async ({ u32_ }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'u32_', + args: this.spec.funcArgsToScVals("u32_", { u32_ }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['u32'], + }); + }; + /** +* 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 = async ({ i32_ }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'i32_', + args: this.spec.funcArgsToScVals("i32_", { i32_ }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['i32'], + }); + }; + /** +* 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 = async ({ i64_ }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'i64_', + args: this.spec.funcArgsToScVals("i64_", { i64_ }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['i64'], + }); + }; + /** +* 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 +*/ + struktHel = async ({ strukt }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'strukt_hel', + args: this.spec.funcArgsToScVals("strukt_hel", { strukt }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['struktHel'], + }); + }; + /** +* 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 = async ({ strukt }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'strukt', + args: this.spec.funcArgsToScVals("strukt", { strukt }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['strukt'], + }); + }; + /** +* 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 = async ({ simple }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'simple', + args: this.spec.funcArgsToScVals("simple", { simple }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['simple'], + }); + }; + /** +* 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 = async ({ complex }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'complex', + args: this.spec.funcArgsToScVals("complex", { complex }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['complex'], + }); + }; + /** +* 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 = async ({ addresse }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'addresse', + args: this.spec.funcArgsToScVals("addresse", { addresse: new stellar_sdk_1.Address(addresse) }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['addresse'], + }); + }; + /** +* 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 = async ({ bytes }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'bytes', + args: this.spec.funcArgsToScVals("bytes", { bytes }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['bytes'], + }); + }; + /** +* 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. +*/ + bytesN = async ({ bytes_n }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'bytes_n', + args: this.spec.funcArgsToScVals("bytes_n", { bytes_n }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['bytesN'], + }); + }; + /** +* 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 = async ({ card }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'card', + args: this.spec.funcArgsToScVals("card", { card }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['card'], + }); + }; + /** +* 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 = async ({ boolean }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'boolean', + args: this.spec.funcArgsToScVals("boolean", { boolean }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['boolean'], + }); + }; + /** +* 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 = async ({ boolean }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'not', + args: this.spec.funcArgsToScVals("not", { boolean }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['not'], + }); + }; + /** +* 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 = async ({ i128 }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'i128', + args: this.spec.funcArgsToScVals("i128", { i128 }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['i128'], + }); + }; + /** +* 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 = async ({ u128 }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'u128', + args: this.spec.funcArgsToScVals("u128", { u128 }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['u128'], + }); + }; + /** +* 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. +*/ + multiArgs = async ({ a, b }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'multi_args', + args: this.spec.funcArgsToScVals("multi_args", { a, b }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['multiArgs'], + }); + }; + /** +* 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 = async ({ map }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'map', + args: this.spec.funcArgsToScVals("map", { map }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['map'], + }); + }; + /** +* 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 = async ({ vec }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'vec', + args: this.spec.funcArgsToScVals("vec", { vec }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['vec'], + }); + }; + /** +* 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 = async ({ tuple }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'tuple', + args: this.spec.funcArgsToScVals("tuple", { tuple }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['tuple'], + }); + }; + /** +* 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 = async ({ option }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'option', + args: this.spec.funcArgsToScVals("option", { option }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['option'], + }); + }; + /** +* 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 = async ({ u256 }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'u256', + args: this.spec.funcArgsToScVals("u256", { u256 }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['u256'], + }); + }; + /** +* 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 = async ({ i256 }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'i256', + args: this.spec.funcArgsToScVals("i256", { i256 }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['i256'], + }); + }; + /** +* 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 = async ({ string }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'string', + args: this.spec.funcArgsToScVals("string", { string }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['string'], + }); + }; + /** +* 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. +*/ + tupleStrukt = async ({ tuple_strukt }, options = {}) => { + return await assembled_tx_js_1.AssembledTransaction.fromSimulation({ + method: 'tuple_strukt', + args: this.spec.funcArgsToScVals("tuple_strukt", { tuple_strukt }), + ...options, + ...this.options, + errorTypes: exports.Errors, + parseResultXdr: this.parsers['tupleStrukt'], + }); + }; +} +exports.Contract = Contract; diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/method-options.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/method-options.d.ts new file mode 100644 index 000000000..fc6b21d5d --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/method-options.d.ts @@ -0,0 +1,47 @@ +declare let responseTypes: 'simulated' | 'full' | undefined; +export type ResponseTypes = typeof responseTypes; +export type XDR_BASE64 = string; +export interface Wallet { + isConnected: () => Promise; + isAllowed: () => Promise; + getUserInfo: () => Promise<{ + publicKey?: string; + }>; + signTransaction: (tx: XDR_BASE64, opts?: { + network?: string; + networkPassphrase?: string; + accountToSign?: string; + }) => Promise; + signAuthEntry: (entryXdr: XDR_BASE64, opts?: { + accountToSign?: string; + }) => Promise; +} +export type ClassOptions = { + contractId: string; + networkPassphrase: string; + rpcUrl: string; + errorTypes?: Record; + /** + * A Wallet interface, such as Freighter, that has the methods `isConnected`, `isAllowed`, `getUserInfo`, and `signTransaction`. If not provided, will attempt to import and use Freighter. Example: + * + * @example + * ```ts + * import freighter from "@stellar/freighter-api"; + * import { Contract } from "test_custom_types"; + * const contract = new Contract({ + * …, + * wallet: freighter, + * }) + * ``` + */ + wallet?: Wallet; +}; +export type MethodOptions = { + /** + * The fee to pay for the transaction. Default: soroban-sdk's BASE_FEE ('100') + */ + fee?: number; +}; +export {}; diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/method-options.js b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/method-options.js new file mode 100644 index 000000000..6d483ac32 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/cjs/method-options.js @@ -0,0 +1,4 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// defined this way so typeahead shows full union, not named alias +let responseTypes; diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/assembled-tx.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/assembled-tx.d.ts new file mode 100644 index 000000000..8297cbf3c --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/assembled-tx.d.ts @@ -0,0 +1,184 @@ +import { Account, Address, Operation, SorobanRpc, xdr } from "stellar-sdk"; +import type { Memo, MemoType, Transaction } from "stellar-sdk"; +import type { ClassOptions, MethodOptions, Wallet, XDR_BASE64 } from "./method-options.js"; +export type Tx = Transaction, Operation[]>; +export declare class ExpiredStateError extends Error { +} +export declare class NeedsMoreSignaturesError extends Error { +} +export declare class WalletDisconnectedError extends Error { +} +export declare class SendResultOnlyError extends Error { +} +export declare class SendFailedError extends Error { +} +export declare class NoUnsignedNonInvokerAuthEntriesError extends Error { +} +type SendTx = SorobanRpc.Api.SendTransactionResponse; +type GetTx = SorobanRpc.Api.GetTransactionResponse; +export type u32 = number; +export type i32 = number; +export type u64 = bigint; +export type i64 = bigint; +export type u128 = bigint; +export type i128 = bigint; +export type u256 = bigint; +export type i256 = bigint; +export type Option = T | undefined; +export type Typepoint = bigint; +export type Duration = bigint; +export { Address }; +export interface Error_ { + message: string; +} +export interface Result { + unwrap(): T; + unwrapErr(): E; + isOk(): boolean; + isErr(): boolean; +} +export declare class Ok implements Result { + readonly value: T; + constructor(value: T); + unwrapErr(): E; + unwrap(): T; + isOk(): boolean; + isErr(): boolean; +} +export declare class Err implements Result { + readonly error: E; + constructor(error: E); + unwrapErr(): E; + unwrap(): never; + isOk(): boolean; + isErr(): boolean; +} +export declare const contractErrorPattern: RegExp; +type AssembledTransactionOptions = MethodOptions & ClassOptions & { + method: string; + args?: any[]; + parseResultXdr: (xdr: string | xdr.ScVal | Err) => T; +}; +export declare const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; +export declare class AssembledTransaction { + options: AssembledTransactionOptions; + raw: Tx; + private simulation?; + private simulationResult?; + private simulationTransactionData?; + private server; + toJSON(): string; + static fromJSON(options: Omit, 'args'>, { tx, simulationResult, simulationTransactionData }: { + tx: XDR_BASE64; + simulationResult: { + auth: XDR_BASE64[]; + retval: XDR_BASE64; + }; + simulationTransactionData: XDR_BASE64; + }): AssembledTransaction; + private constructor(); + static fromSimulation(options: AssembledTransactionOptions): Promise>; + simulate: () => Promise; + get simulationData(): { + result: SorobanRpc.Api.SimulateHostFunctionResult; + transactionData: xdr.SorobanTransactionData; + }; + get result(): T; + parseError(errorMessage: string): Err | undefined; + getWallet: () => Promise; + getPublicKey: () => Promise; + /** + * Get account details from the Soroban network for the publicKey currently + * selected in user's wallet. If not connected to Freighter, use placeholder + * null account. + */ + getAccount: () => Promise; + /** + * Sign the transaction with the `wallet` (default Freighter), then send to + * the network and return a `SentTransaction` that keeps track of all the + * attempts to send and fetch the transaction from the network. + */ + signAndSend: ({ secondsToWait, force }?: { + /** + * Wait `secondsToWait` seconds (default: 10) for both the transaction to SEND successfully (will keep trying if the server returns `TRY_AGAIN_LATER`), as well as for the transaction to COMPLETE (will keep checking if the server returns `PENDING`). + */ + secondsToWait?: number | undefined; + /** + * If `true`, sign and send the transaction even if it is a read call. + */ + force?: boolean | undefined; + }) => Promise>; + getStorageExpiration: () => Promise; + /** + * Get a list of accounts, other than the invoker of the simulation, that + * need to sign auth entries in this transaction. + * + * Soroban allows multiple people to sign a transaction. Someone needs to + * sign the final transaction envelope; this person/account is called the + * _invoker_, or _source_. Other accounts might need to sign individual auth + * entries in the transaction, if they're not also the invoker. + * + * This function returns a list of accounts that need to sign auth entries, + * assuming that the same invoker/source account will sign the final + * transaction envelope as signed the initial simulation. + * + * One at a time, for each public key in this array, you will need to + * serialize this transaction with `toJSON`, send to the owner of that key, + * deserialize the transaction with `txFromJson`, and call + * {@link signAuthEntries}. Then re-serialize and send to the next account + * in this list. + */ + needsNonInvokerSigningBy: ({ includeAlreadySigned, }?: { + /** + * Whether or not to include auth entries that have already been signed. Default: false + */ + includeAlreadySigned?: boolean | undefined; + }) => Promise; + preImageFor(entry: xdr.SorobanAuthorizationEntry, signatureExpirationLedger: number): xdr.HashIdPreimage; + /** + * If {@link needsNonInvokerSigningBy} returns a non-empty list, you can serialize + * the transaction with `toJSON`, send it to the owner of one of the public keys + * in the map, deserialize with `txFromJSON`, and call this method on their + * machine. Internally, this will use `signAuthEntry` function from connected + * `wallet` for each. + * + * Then, re-serialize the transaction and either send to the next + * `needsNonInvokerSigningBy` owner, or send it back to the original account + * who simulated the transaction so they can {@link sign} the transaction + * envelope and {@link send} it to the network. + * + * Sending to all `needsNonInvokerSigningBy` owners in parallel is not currently + * supported! + */ + signAuthEntries: (expiration?: number | Promise) => Promise; + get isReadCall(): boolean; + hasRealInvoker: () => Promise; +} +/** + * A transaction that has been sent to the Soroban network. This happens in two steps: + * + * 1. `sendTransaction`: initial submission of the transaction to the network. + * This step can run into problems, and will be retried with exponential + * backoff if it does. See all attempts in `sendTransactionResponseAll` and the + * most recent attempt in `sendTransactionResponse`. + * 2. `getTransaction`: once the transaction has been submitted to the network + * successfully, you need to wait for it to finalize to get the results of the + * transaction. This step can also run into problems, and will be retried with + * exponential backoff if it does. See all attempts in + * `getTransactionResponseAll` and the most recent attempt in + * `getTransactionResponse`. + */ +declare class SentTransaction { + options: AssembledTransactionOptions; + assembled: AssembledTransaction; + server: SorobanRpc.Server; + signed: Tx; + sendTransactionResponse?: SendTx; + sendTransactionResponseAll?: SendTx[]; + getTransactionResponse?: GetTx; + getTransactionResponseAll?: GetTx[]; + constructor(options: AssembledTransactionOptions, assembled: AssembledTransaction); + static init: (options: AssembledTransactionOptions, assembled: AssembledTransaction, secondsToWait?: number) => Promise>; + private send; + get result(): T; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/assembled-tx.js b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/assembled-tx.js new file mode 100644 index 000000000..24168acf4 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/assembled-tx.js @@ -0,0 +1,450 @@ +import { Account, Address, Contract, Operation, SorobanRpc, StrKey, TimeoutInfinite, TransactionBuilder, authorizeEntry, hash, xdr, BASE_FEE, } from "stellar-sdk"; +import { Buffer } from "buffer"; +export class ExpiredStateError extends Error { +} +export class NeedsMoreSignaturesError extends Error { +} +export class WalletDisconnectedError extends Error { +} +export class SendResultOnlyError extends Error { +} +export class SendFailedError extends Error { +} +export class NoUnsignedNonInvokerAuthEntriesError extends Error { +} +export { Address }; +; +; +export class Ok { + value; + constructor(value) { + this.value = value; + } + unwrapErr() { + throw new Error('No error'); + } + unwrap() { + return this.value; + } + isOk() { + return true; + } + isErr() { + return !this.isOk(); + } +} +export class Err { + error; + constructor(error) { + this.error = error; + } + unwrapErr() { + return this.error; + } + unwrap() { + throw new Error(this.error.message); + } + isOk() { + return false; + } + isErr() { + return !this.isOk(); + } +} +export const contractErrorPattern = /Error\(Contract, #(\d+)\)/; +export const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; +export class AssembledTransaction { + options; + raw; + simulation; + simulationResult; + simulationTransactionData; + server; + toJSON() { + return JSON.stringify({ + method: this.options.method, + tx: this.raw?.toXDR(), + simulationResult: { + auth: this.simulationData.result.auth.map(a => a.toXDR('base64')), + retval: this.simulationData.result.retval.toXDR('base64'), + }, + simulationTransactionData: this.simulationData.transactionData.toXDR('base64'), + }); + } + static fromJSON(options, { tx, simulationResult, simulationTransactionData }) { + const txn = new AssembledTransaction(options); + txn.raw = TransactionBuilder.fromXDR(tx, options.networkPassphrase); + txn.simulationResult = { + auth: simulationResult.auth.map(a => xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64')), + retval: xdr.ScVal.fromXDR(simulationResult.retval, 'base64'), + }; + txn.simulationTransactionData = xdr.SorobanTransactionData.fromXDR(simulationTransactionData, 'base64'); + return txn; + } + constructor(options) { + this.options = options; + this.server = new SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + } + static async fromSimulation(options) { + const tx = new AssembledTransaction(options); + const contract = new Contract(options.contractId); + tx.raw = new TransactionBuilder(await tx.getAccount(), { + fee: options.fee?.toString(10) ?? BASE_FEE, + networkPassphrase: options.networkPassphrase, + }) + .addOperation(contract.call(options.method, ...(options.args ?? []))) + .setTimeout(TimeoutInfinite) + .build(); + return await tx.simulate(); + } + simulate = async () => { + if (!this.raw) + throw new Error('Transaction has not yet been assembled'); + this.simulation = await this.server.simulateTransaction(this.raw); + if (SorobanRpc.Api.isSimulationSuccess(this.simulation)) { + this.raw = SorobanRpc.assembleTransaction(this.raw, this.simulation).build(); + } + return this; + }; + get simulationData() { + if (this.simulationResult && this.simulationTransactionData) { + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData, + }; + } + // else, we know we just did the simulation on this machine + const simulation = this.simulation; + if (SorobanRpc.Api.isSimulationError(simulation)) { + throw new Error(`Transaction simulation failed: "${simulation.error}"`); + } + if (SorobanRpc.Api.isSimulationRestore(simulation)) { + throw new ExpiredStateError(`You need to restore some contract state before you can invoke this method. ${JSON.stringify(simulation, null, 2)}`); + } + if (!simulation.result) { + throw new Error(`Expected an invocation simulation, but got no 'result' field. Simulation: ${JSON.stringify(simulation, null, 2)}`); + } + // add to object for serialization & deserialization + this.simulationResult = simulation.result; + this.simulationTransactionData = simulation.transactionData.build(); + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData, + }; + } + get result() { + try { + return this.options.parseResultXdr(this.simulationData.result.retval); + } + catch (e) { + let err = this.parseError(e.toString()); + if (err) + return err; + throw e; + } + } + parseError(errorMessage) { + if (!this.options.errorTypes) + return; + const match = errorMessage.match(contractErrorPattern); + if (!match) + return; + let i = parseInt(match[1], 10); + let err = this.options.errorTypes[i]; + if (err) + return new Err(err); + } + getWallet = async () => { + return this.options.wallet ?? (await import("@stellar/freighter-api")).default; + }; + getPublicKey = async () => { + const wallet = await this.getWallet(); + if (await wallet.isConnected() && await wallet.isAllowed()) { + return (await wallet.getUserInfo()).publicKey; + } + }; + /** + * Get account details from the Soroban network for the publicKey currently + * selected in user's wallet. If not connected to Freighter, use placeholder + * null account. + */ + getAccount = async () => { + const publicKey = await this.getPublicKey(); + return publicKey + ? await this.server.getAccount(publicKey) + : new Account(NULL_ACCOUNT, "0"); + }; + /** + * Sign the transaction with the `wallet` (default Freighter), then send to + * the network and return a `SentTransaction` that keeps track of all the + * attempts to send and fetch the transaction from the network. + */ + signAndSend = async ({ secondsToWait = 10, force = false } = {}) => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated'); + } + if (!force && this.isReadCall) { + throw new Error('This is a read call. It requires no signature or sending. Use `force: true` to sign and send anyway.'); + } + if (!await this.hasRealInvoker()) { + throw new WalletDisconnectedError('Wallet is not connected'); + } + if (this.raw.source !== (await this.getAccount()).accountId()) { + throw new Error(`You must submit the transaction with the account that originally created it. Please switch to the wallet with "${this.raw.source}" as its public key.`); + } + if ((await this.needsNonInvokerSigningBy()).length) { + throw new NeedsMoreSignaturesError('Transaction requires more signatures. See `needsNonInvokerSigningBy` for details.'); + } + return await SentTransaction.init(this.options, this, secondsToWait); + }; + getStorageExpiration = async () => { + const entryRes = await this.server.getLedgerEntries(new Contract(this.options.contractId).getFootprint()); + if (!entryRes.entries || + !entryRes.entries.length || + !entryRes.entries[0].liveUntilLedgerSeq) + throw new Error('failed to get ledger entry'); + return entryRes.entries[0].liveUntilLedgerSeq; + }; + /** + * Get a list of accounts, other than the invoker of the simulation, that + * need to sign auth entries in this transaction. + * + * Soroban allows multiple people to sign a transaction. Someone needs to + * sign the final transaction envelope; this person/account is called the + * _invoker_, or _source_. Other accounts might need to sign individual auth + * entries in the transaction, if they're not also the invoker. + * + * This function returns a list of accounts that need to sign auth entries, + * assuming that the same invoker/source account will sign the final + * transaction envelope as signed the initial simulation. + * + * One at a time, for each public key in this array, you will need to + * serialize this transaction with `toJSON`, send to the owner of that key, + * deserialize the transaction with `txFromJson`, and call + * {@link signAuthEntries}. Then re-serialize and send to the next account + * in this list. + */ + needsNonInvokerSigningBy = async ({ includeAlreadySigned = false, } = {}) => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated'); + } + // We expect that any transaction constructed by these libraries has a + // single operation, which is an InvokeHostFunction operation. The host + // function being invoked is the contract method call. + if (!("operations" in this.raw)) { + throw new Error(`Unexpected Transaction type; no operations: ${JSON.stringify(this.raw)}`); + } + const rawInvokeHostFunctionOp = this.raw + .operations[0]; + return [...new Set((rawInvokeHostFunctionOp.auth ?? []).filter(entry => entry.credentials().switch() === + xdr.SorobanCredentialsType.sorobanCredentialsAddress() && + (includeAlreadySigned || + entry.credentials().address().signature().switch().name === 'scvVoid')).map(entry => StrKey.encodeEd25519PublicKey(entry.credentials().address().address().accountId().ed25519())))]; + }; + preImageFor(entry, signatureExpirationLedger) { + const addrAuth = entry.credentials().address(); + return xdr.HashIdPreimage.envelopeTypeSorobanAuthorization(new xdr.HashIdPreimageSorobanAuthorization({ + networkId: hash(Buffer.from(this.options.networkPassphrase)), + nonce: addrAuth.nonce(), + invocation: entry.rootInvocation(), + signatureExpirationLedger, + })); + } + /** + * If {@link needsNonInvokerSigningBy} returns a non-empty list, you can serialize + * the transaction with `toJSON`, send it to the owner of one of the public keys + * in the map, deserialize with `txFromJSON`, and call this method on their + * machine. Internally, this will use `signAuthEntry` function from connected + * `wallet` for each. + * + * Then, re-serialize the transaction and either send to the next + * `needsNonInvokerSigningBy` owner, or send it back to the original account + * who simulated the transaction so they can {@link sign} the transaction + * envelope and {@link send} it to the network. + * + * Sending to all `needsNonInvokerSigningBy` owners in parallel is not currently + * supported! + */ + signAuthEntries = async ( + /** + * When to set each auth entry to expire. Could be any number of blocks in + * the future. Can be supplied as a promise or a raw number. Default: + * contract's current `persistent` storage expiration date/ledger + * number/block. + */ + expiration = this.getStorageExpiration()) => { + if (!this.raw) + throw new Error('Transaction has not yet been assembled or simulated'); + const needsNonInvokerSigningBy = await this.needsNonInvokerSigningBy(); + if (!needsNonInvokerSigningBy) + throw new NoUnsignedNonInvokerAuthEntriesError('No unsigned non-invoker auth entries; maybe you already signed?'); + const publicKey = await this.getPublicKey(); + if (!publicKey) + throw new Error('Could not get public key from wallet; maybe Freighter is not signed in?'); + if (needsNonInvokerSigningBy.indexOf(publicKey) === -1) + throw new Error(`No auth entries for public key "${publicKey}"`); + const wallet = await this.getWallet(); + const rawInvokeHostFunctionOp = this.raw + .operations[0]; + const authEntries = rawInvokeHostFunctionOp.auth ?? []; + for (const [i, entry] of authEntries.entries()) { + if (entry.credentials().switch() !== + xdr.SorobanCredentialsType.sorobanCredentialsAddress()) { + // if the invoker/source account, then the entry doesn't need explicit + // signature, since the tx envelope is already signed by the source + // account, so only check for sorobanCredentialsAddress + continue; + } + const pk = StrKey.encodeEd25519PublicKey(entry.credentials().address().address().accountId().ed25519()); + // this auth entry needs to be signed by a different account + // (or maybe already was!) + if (pk !== publicKey) + continue; + authEntries[i] = await authorizeEntry(entry, async (preimage) => Buffer.from(await wallet.signAuthEntry(preimage.toXDR('base64')), 'base64'), await expiration, this.options.networkPassphrase); + } + }; + get isReadCall() { + const authsCount = this.simulationData.result.auth.length; + const writeLength = this.simulationData.transactionData.resources().footprint().readWrite().length; + return (authsCount === 0) && (writeLength === 0); + } + hasRealInvoker = async () => { + const account = await this.getAccount(); + return account.accountId() !== NULL_ACCOUNT; + }; +} +/** + * A transaction that has been sent to the Soroban network. This happens in two steps: + * + * 1. `sendTransaction`: initial submission of the transaction to the network. + * This step can run into problems, and will be retried with exponential + * backoff if it does. See all attempts in `sendTransactionResponseAll` and the + * most recent attempt in `sendTransactionResponse`. + * 2. `getTransaction`: once the transaction has been submitted to the network + * successfully, you need to wait for it to finalize to get the results of the + * transaction. This step can also run into problems, and will be retried with + * exponential backoff if it does. See all attempts in + * `getTransactionResponseAll` and the most recent attempt in + * `getTransactionResponse`. + */ +class SentTransaction { + options; + assembled; + server; + signed; + sendTransactionResponse; + sendTransactionResponseAll; + getTransactionResponse; + getTransactionResponseAll; + constructor(options, assembled) { + this.options = options; + this.assembled = assembled; + this.server = new SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + this.assembled = assembled; + } + static init = async (options, assembled, secondsToWait = 10) => { + const tx = new SentTransaction(options, assembled); + return await tx.send(secondsToWait); + }; + send = async (secondsToWait = 10) => { + const wallet = await this.assembled.getWallet(); + this.sendTransactionResponseAll = await withExponentialBackoff(async (previousFailure) => { + if (previousFailure) { + // Increment transaction sequence number and resimulate before trying again + // Soroban transaction can only have 1 operation + const op = this.assembled.raw.operations[0]; + this.assembled.raw = new TransactionBuilder(await this.assembled.getAccount(), { + fee: this.assembled.raw.fee, + networkPassphrase: this.options.networkPassphrase, + }) + .setTimeout(TimeoutInfinite) + .addOperation(Operation.invokeHostFunction({ ...op, auth: op.auth ?? [] })) + .build(); + await this.assembled.simulate(); + } + const signature = await wallet.signTransaction(this.assembled.raw.toXDR(), { + networkPassphrase: this.options.networkPassphrase, + }); + this.signed = TransactionBuilder.fromXDR(signature, this.options.networkPassphrase); + return this.server.sendTransaction(this.signed); + }, resp => resp.status !== "PENDING", secondsToWait); + this.sendTransactionResponse = this.sendTransactionResponseAll[this.sendTransactionResponseAll.length - 1]; + if (this.sendTransactionResponse.status !== "PENDING") { + throw new Error(`Tried to resubmit transaction for ${secondsToWait} seconds, but it's still failing. ` + + `All attempts: ${JSON.stringify(this.sendTransactionResponseAll, null, 2)}`); + } + const { hash } = this.sendTransactionResponse; + this.getTransactionResponseAll = await withExponentialBackoff(() => this.server.getTransaction(hash), resp => resp.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND, secondsToWait); + this.getTransactionResponse = this.getTransactionResponseAll[this.getTransactionResponseAll.length - 1]; + if (this.getTransactionResponse.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND) { + console.error(`Waited ${secondsToWait} seconds for transaction to complete, but it did not. ` + + `Returning anyway. Check the transaction status manually. ` + + `Sent transaction: ${JSON.stringify(this.sendTransactionResponse, null, 2)}\n` + + `All attempts to get the result: ${JSON.stringify(this.getTransactionResponseAll, null, 2)}`); + } + return this; + }; + get result() { + // 1. check if transaction was submitted and awaited with `getTransaction` + if ("getTransactionResponse" in this && + this.getTransactionResponse) { + // getTransactionResponse has a `returnValue` field unless it failed + if ("returnValue" in this.getTransactionResponse) { + return this.options.parseResultXdr(this.getTransactionResponse.returnValue); + } + // if "returnValue" not present, the transaction failed; return without parsing the result + throw new Error("Transaction failed! Cannot parse result."); + } + // 2. otherwise, maybe it was merely sent with `sendTransaction` + if (this.sendTransactionResponse) { + const errorResult = this.sendTransactionResponse.errorResult?.result(); + if (errorResult) { + throw new SendFailedError(`Transaction simulation looked correct, but attempting to send the transaction failed. Check \`simulation\` and \`sendTransactionResponseAll\` to troubleshoot. Decoded \`sendTransactionResponse.errorResultXdr\`: ${errorResult}`); + } + throw new SendResultOnlyError(`Transaction was sent to the network, but not yet awaited. No result to show. Await transaction completion with \`getTransaction(sendTransactionResponse.hash)\``); + } + // 3. finally, if neither of those are present, throw an error + throw new Error(`Sending transaction failed: ${JSON.stringify(this.assembled)}`); + } +} +/** + * Keep calling a `fn` for `secondsToWait` seconds, if `keepWaitingIf` is true. + * Returns an array of all attempts to call the function. + */ +async function withExponentialBackoff(fn, keepWaitingIf, secondsToWait, exponentialFactor = 1.5, verbose = false) { + const attempts = []; + let count = 0; + attempts.push(await fn()); + if (!keepWaitingIf(attempts[attempts.length - 1])) + return attempts; + const waitUntil = new Date(Date.now() + secondsToWait * 1000).valueOf(); + let waitTime = 1000; + let totalWaitTime = waitTime; + while (Date.now() < waitUntil && keepWaitingIf(attempts[attempts.length - 1])) { + count++; + // Wait a beat + if (verbose) { + console.info(`Waiting ${waitTime}ms before trying again (bringing the total wait time to ${totalWaitTime}ms so far, of total ${secondsToWait * 1000}ms)`); + } + await new Promise(res => setTimeout(res, waitTime)); + // Exponential backoff + waitTime = waitTime * exponentialFactor; + if (new Date(Date.now() + waitTime).valueOf() > waitUntil) { + waitTime = waitUntil - Date.now(); + if (verbose) { + console.info(`was gonna wait too long; new waitTime: ${waitTime}ms`); + } + } + totalWaitTime = waitTime + totalWaitTime; + // Try again + attempts.push(await fn(attempts[attempts.length - 1])); + if (verbose && keepWaitingIf(attempts[attempts.length - 1])) { + console.info(`${count}. Called ${fn}; ${attempts.length} prev attempts. Most recent: ${JSON.stringify(attempts[attempts.length - 1], null, 2)}`); + } + } + return attempts; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/index.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/index.d.ts new file mode 100644 index 000000000..d32b06f97 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/index.d.ts @@ -0,0 +1,424 @@ +import { ContractSpec } from 'stellar-sdk'; +import { Buffer } from "buffer"; +import { AssembledTransaction, Ok, Err } from './assembled-tx.js'; +import type { u32, i32, i64, i128, Option, Error_ } from './assembled-tx.js'; +import type { ClassOptions } from './method-options.js'; +export * from './assembled-tx.js'; +export * from './method-options.js'; +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: { + 1: { + message: string; + }; +}; +export declare class Contract { + readonly options: ClassOptions; + spec: ContractSpec; + constructor(options: ClassOptions); + private readonly parsers; + private txFromJSON; + readonly fromJSON: { + hello: (json: string) => AssembledTransaction; + woid: (json: string) => AssembledTransaction; + val: (json: string) => AssembledTransaction; + u32FailOnEven: (json: string) => AssembledTransaction | Ok>; + u32: (json: string) => AssembledTransaction; + i32: (json: string) => AssembledTransaction; + i64: (json: string) => AssembledTransaction; + struktHel: (json: string) => AssembledTransaction; + strukt: (json: string) => AssembledTransaction; + simple: (json: string) => AssembledTransaction; + complex: (json: string) => AssembledTransaction; + addresse: (json: string) => AssembledTransaction; + bytes: (json: string) => AssembledTransaction; + bytesN: (json: string) => AssembledTransaction; + card: (json: string) => AssembledTransaction; + boolean: (json: string) => AssembledTransaction; + not: (json: string) => AssembledTransaction; + i128: (json: string) => AssembledTransaction; + u128: (json: string) => AssembledTransaction; + multiArgs: (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; + tupleStrukt: (json: string) => AssembledTransaction; + }; + /** +* 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + u32FailOnEven: ({ u32_ }: { + u32_: u32; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => Promise | Ok>>; + /** +* 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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 +*/ + struktHel: ({ strukt }: { + strukt: Test; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + bytesN: ({ bytes_n }: { + bytes_n: Buffer; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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. +*/ + multiArgs: ({ a, b }: { + a: u32; + b: boolean; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + tupleStrukt: ({ tuple_strukt }: { + tuple_strukt: TupleStruct; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => Promise>; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/index.js b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/index.js new file mode 100644 index 000000000..bfd8b1823 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/index.js @@ -0,0 +1,509 @@ +import { ContractSpec, Address } from 'stellar-sdk'; +import { Buffer } from "buffer"; +import { AssembledTransaction, Ok, Err } from './assembled-tx.js'; +export * from './assembled-tx.js'; +export * from './method-options.js'; +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 = { + 1: { message: "Please provide an odd number" } +}; +export class Contract { + options; + spec; + constructor(options) { + this.options = options; + this.spec = 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=" + ]); + } + parsers = { + hello: (result) => this.spec.funcResToNative("hello", result), + woid: () => { }, + val: (result) => this.spec.funcResToNative("val", result), + u32FailOnEven: (result) => { + if (result instanceof Err) + return result; + return new Ok(this.spec.funcResToNative("u32_fail_on_even", result)); + }, + u32: (result) => this.spec.funcResToNative("u32_", result), + i32: (result) => this.spec.funcResToNative("i32_", result), + i64: (result) => this.spec.funcResToNative("i64_", result), + struktHel: (result) => this.spec.funcResToNative("strukt_hel", result), + strukt: (result) => this.spec.funcResToNative("strukt", result), + simple: (result) => this.spec.funcResToNative("simple", result), + complex: (result) => this.spec.funcResToNative("complex", result), + addresse: (result) => this.spec.funcResToNative("addresse", result), + bytes: (result) => this.spec.funcResToNative("bytes", result), + bytesN: (result) => this.spec.funcResToNative("bytes_n", result), + card: (result) => this.spec.funcResToNative("card", result), + boolean: (result) => this.spec.funcResToNative("boolean", result), + not: (result) => this.spec.funcResToNative("not", result), + i128: (result) => this.spec.funcResToNative("i128", result), + u128: (result) => this.spec.funcResToNative("u128", result), + multiArgs: (result) => this.spec.funcResToNative("multi_args", result), + map: (result) => this.spec.funcResToNative("map", result), + vec: (result) => this.spec.funcResToNative("vec", result), + tuple: (result) => this.spec.funcResToNative("tuple", result), + option: (result) => this.spec.funcResToNative("option", result), + u256: (result) => this.spec.funcResToNative("u256", result), + i256: (result) => this.spec.funcResToNative("i256", result), + string: (result) => this.spec.funcResToNative("string", result), + tupleStrukt: (result) => this.spec.funcResToNative("tuple_strukt", result) + }; + txFromJSON = (json) => { + const { method, ...tx } = JSON.parse(json); + return AssembledTransaction.fromJSON({ + ...this.options, + method, + parseResultXdr: this.parsers[method], + }, tx); + }; + fromJSON = { + hello: (this.txFromJSON), + woid: (this.txFromJSON), + val: (this.txFromJSON), + u32FailOnEven: (this.txFromJSON), + u32: (this.txFromJSON), + i32: (this.txFromJSON), + i64: (this.txFromJSON), + struktHel: (this.txFromJSON), + strukt: (this.txFromJSON), + simple: (this.txFromJSON), + complex: (this.txFromJSON), + addresse: (this.txFromJSON), + bytes: (this.txFromJSON), + bytesN: (this.txFromJSON), + card: (this.txFromJSON), + boolean: (this.txFromJSON), + not: (this.txFromJSON), + i128: (this.txFromJSON), + u128: (this.txFromJSON), + multiArgs: (this.txFromJSON), + map: (this.txFromJSON), + vec: (this.txFromJSON), + tuple: (this.txFromJSON), + option: (this.txFromJSON), + u256: (this.txFromJSON), + i256: (this.txFromJSON), + string: (this.txFromJSON), + tupleStrukt: (this.txFromJSON) + }; + /** +* 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 = async ({ hello }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'hello', + args: this.spec.funcArgsToScVals("hello", { hello }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['hello'], + }); + }; + /** +* 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 = async (options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'woid', + args: this.spec.funcArgsToScVals("woid", {}), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['woid'], + }); + }; + /** +* 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 = async (options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'val', + args: this.spec.funcArgsToScVals("val", {}), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['val'], + }); + }; + /** +* 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. +*/ + u32FailOnEven = async ({ u32_ }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'u32_fail_on_even', + args: this.spec.funcArgsToScVals("u32_fail_on_even", { u32_ }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['u32FailOnEven'], + }); + }; + /** +* 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 = async ({ u32_ }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'u32_', + args: this.spec.funcArgsToScVals("u32_", { u32_ }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['u32'], + }); + }; + /** +* 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 = async ({ i32_ }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'i32_', + args: this.spec.funcArgsToScVals("i32_", { i32_ }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['i32'], + }); + }; + /** +* 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 = async ({ i64_ }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'i64_', + args: this.spec.funcArgsToScVals("i64_", { i64_ }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['i64'], + }); + }; + /** +* 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 +*/ + struktHel = async ({ strukt }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'strukt_hel', + args: this.spec.funcArgsToScVals("strukt_hel", { strukt }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['struktHel'], + }); + }; + /** +* 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 = async ({ strukt }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'strukt', + args: this.spec.funcArgsToScVals("strukt", { strukt }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['strukt'], + }); + }; + /** +* 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 = async ({ simple }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'simple', + args: this.spec.funcArgsToScVals("simple", { simple }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['simple'], + }); + }; + /** +* 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 = async ({ complex }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'complex', + args: this.spec.funcArgsToScVals("complex", { complex }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['complex'], + }); + }; + /** +* 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 = async ({ addresse }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'addresse', + args: this.spec.funcArgsToScVals("addresse", { addresse: new Address(addresse) }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['addresse'], + }); + }; + /** +* 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 = async ({ bytes }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'bytes', + args: this.spec.funcArgsToScVals("bytes", { bytes }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['bytes'], + }); + }; + /** +* 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. +*/ + bytesN = async ({ bytes_n }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'bytes_n', + args: this.spec.funcArgsToScVals("bytes_n", { bytes_n }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['bytesN'], + }); + }; + /** +* 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 = async ({ card }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'card', + args: this.spec.funcArgsToScVals("card", { card }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['card'], + }); + }; + /** +* 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 = async ({ boolean }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'boolean', + args: this.spec.funcArgsToScVals("boolean", { boolean }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['boolean'], + }); + }; + /** +* 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 = async ({ boolean }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'not', + args: this.spec.funcArgsToScVals("not", { boolean }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['not'], + }); + }; + /** +* 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 = async ({ i128 }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'i128', + args: this.spec.funcArgsToScVals("i128", { i128 }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['i128'], + }); + }; + /** +* 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 = async ({ u128 }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'u128', + args: this.spec.funcArgsToScVals("u128", { u128 }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['u128'], + }); + }; + /** +* 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. +*/ + multiArgs = async ({ a, b }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'multi_args', + args: this.spec.funcArgsToScVals("multi_args", { a, b }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['multiArgs'], + }); + }; + /** +* 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 = async ({ map }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'map', + args: this.spec.funcArgsToScVals("map", { map }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['map'], + }); + }; + /** +* 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 = async ({ vec }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'vec', + args: this.spec.funcArgsToScVals("vec", { vec }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['vec'], + }); + }; + /** +* 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 = async ({ tuple }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'tuple', + args: this.spec.funcArgsToScVals("tuple", { tuple }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['tuple'], + }); + }; + /** +* 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 = async ({ option }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'option', + args: this.spec.funcArgsToScVals("option", { option }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['option'], + }); + }; + /** +* 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 = async ({ u256 }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'u256', + args: this.spec.funcArgsToScVals("u256", { u256 }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['u256'], + }); + }; + /** +* 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 = async ({ i256 }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'i256', + args: this.spec.funcArgsToScVals("i256", { i256 }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['i256'], + }); + }; + /** +* 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 = async ({ string }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'string', + args: this.spec.funcArgsToScVals("string", { string }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['string'], + }); + }; + /** +* 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. +*/ + tupleStrukt = async ({ tuple_strukt }, options = {}) => { + return await AssembledTransaction.fromSimulation({ + method: 'tuple_strukt', + args: this.spec.funcArgsToScVals("tuple_strukt", { tuple_strukt }), + ...options, + ...this.options, + errorTypes: Errors, + parseResultXdr: this.parsers['tupleStrukt'], + }); + }; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/method-options.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/method-options.d.ts new file mode 100644 index 000000000..fc6b21d5d --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/method-options.d.ts @@ -0,0 +1,47 @@ +declare let responseTypes: 'simulated' | 'full' | undefined; +export type ResponseTypes = typeof responseTypes; +export type XDR_BASE64 = string; +export interface Wallet { + isConnected: () => Promise; + isAllowed: () => Promise; + getUserInfo: () => Promise<{ + publicKey?: string; + }>; + signTransaction: (tx: XDR_BASE64, opts?: { + network?: string; + networkPassphrase?: string; + accountToSign?: string; + }) => Promise; + signAuthEntry: (entryXdr: XDR_BASE64, opts?: { + accountToSign?: string; + }) => Promise; +} +export type ClassOptions = { + contractId: string; + networkPassphrase: string; + rpcUrl: string; + errorTypes?: Record; + /** + * A Wallet interface, such as Freighter, that has the methods `isConnected`, `isAllowed`, `getUserInfo`, and `signTransaction`. If not provided, will attempt to import and use Freighter. Example: + * + * @example + * ```ts + * import freighter from "@stellar/freighter-api"; + * import { Contract } from "test_custom_types"; + * const contract = new Contract({ + * …, + * wallet: freighter, + * }) + * ``` + */ + wallet?: Wallet; +}; +export type MethodOptions = { + /** + * The fee to pay for the transaction. Default: soroban-sdk's BASE_FEE ('100') + */ + fee?: number; +}; +export {}; diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/method-options.js b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/method-options.js new file mode 100644 index 000000000..00ad9d3cf --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/method-options.js @@ -0,0 +1,3 @@ +// defined this way so typeahead shows full union, not named alias +let responseTypes; +export {}; diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/package.json b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/package.json new file mode 100644 index 000000000..1632c2c4d --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/esm/package.json @@ -0,0 +1 @@ +{"type": "module"} \ No newline at end of file diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/assembled-tx.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/assembled-tx.d.ts new file mode 100644 index 000000000..8297cbf3c --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/assembled-tx.d.ts @@ -0,0 +1,184 @@ +import { Account, Address, Operation, SorobanRpc, xdr } from "stellar-sdk"; +import type { Memo, MemoType, Transaction } from "stellar-sdk"; +import type { ClassOptions, MethodOptions, Wallet, XDR_BASE64 } from "./method-options.js"; +export type Tx = Transaction, Operation[]>; +export declare class ExpiredStateError extends Error { +} +export declare class NeedsMoreSignaturesError extends Error { +} +export declare class WalletDisconnectedError extends Error { +} +export declare class SendResultOnlyError extends Error { +} +export declare class SendFailedError extends Error { +} +export declare class NoUnsignedNonInvokerAuthEntriesError extends Error { +} +type SendTx = SorobanRpc.Api.SendTransactionResponse; +type GetTx = SorobanRpc.Api.GetTransactionResponse; +export type u32 = number; +export type i32 = number; +export type u64 = bigint; +export type i64 = bigint; +export type u128 = bigint; +export type i128 = bigint; +export type u256 = bigint; +export type i256 = bigint; +export type Option = T | undefined; +export type Typepoint = bigint; +export type Duration = bigint; +export { Address }; +export interface Error_ { + message: string; +} +export interface Result { + unwrap(): T; + unwrapErr(): E; + isOk(): boolean; + isErr(): boolean; +} +export declare class Ok implements Result { + readonly value: T; + constructor(value: T); + unwrapErr(): E; + unwrap(): T; + isOk(): boolean; + isErr(): boolean; +} +export declare class Err implements Result { + readonly error: E; + constructor(error: E); + unwrapErr(): E; + unwrap(): never; + isOk(): boolean; + isErr(): boolean; +} +export declare const contractErrorPattern: RegExp; +type AssembledTransactionOptions = MethodOptions & ClassOptions & { + method: string; + args?: any[]; + parseResultXdr: (xdr: string | xdr.ScVal | Err) => T; +}; +export declare const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; +export declare class AssembledTransaction { + options: AssembledTransactionOptions; + raw: Tx; + private simulation?; + private simulationResult?; + private simulationTransactionData?; + private server; + toJSON(): string; + static fromJSON(options: Omit, 'args'>, { tx, simulationResult, simulationTransactionData }: { + tx: XDR_BASE64; + simulationResult: { + auth: XDR_BASE64[]; + retval: XDR_BASE64; + }; + simulationTransactionData: XDR_BASE64; + }): AssembledTransaction; + private constructor(); + static fromSimulation(options: AssembledTransactionOptions): Promise>; + simulate: () => Promise; + get simulationData(): { + result: SorobanRpc.Api.SimulateHostFunctionResult; + transactionData: xdr.SorobanTransactionData; + }; + get result(): T; + parseError(errorMessage: string): Err | undefined; + getWallet: () => Promise; + getPublicKey: () => Promise; + /** + * Get account details from the Soroban network for the publicKey currently + * selected in user's wallet. If not connected to Freighter, use placeholder + * null account. + */ + getAccount: () => Promise; + /** + * Sign the transaction with the `wallet` (default Freighter), then send to + * the network and return a `SentTransaction` that keeps track of all the + * attempts to send and fetch the transaction from the network. + */ + signAndSend: ({ secondsToWait, force }?: { + /** + * Wait `secondsToWait` seconds (default: 10) for both the transaction to SEND successfully (will keep trying if the server returns `TRY_AGAIN_LATER`), as well as for the transaction to COMPLETE (will keep checking if the server returns `PENDING`). + */ + secondsToWait?: number | undefined; + /** + * If `true`, sign and send the transaction even if it is a read call. + */ + force?: boolean | undefined; + }) => Promise>; + getStorageExpiration: () => Promise; + /** + * Get a list of accounts, other than the invoker of the simulation, that + * need to sign auth entries in this transaction. + * + * Soroban allows multiple people to sign a transaction. Someone needs to + * sign the final transaction envelope; this person/account is called the + * _invoker_, or _source_. Other accounts might need to sign individual auth + * entries in the transaction, if they're not also the invoker. + * + * This function returns a list of accounts that need to sign auth entries, + * assuming that the same invoker/source account will sign the final + * transaction envelope as signed the initial simulation. + * + * One at a time, for each public key in this array, you will need to + * serialize this transaction with `toJSON`, send to the owner of that key, + * deserialize the transaction with `txFromJson`, and call + * {@link signAuthEntries}. Then re-serialize and send to the next account + * in this list. + */ + needsNonInvokerSigningBy: ({ includeAlreadySigned, }?: { + /** + * Whether or not to include auth entries that have already been signed. Default: false + */ + includeAlreadySigned?: boolean | undefined; + }) => Promise; + preImageFor(entry: xdr.SorobanAuthorizationEntry, signatureExpirationLedger: number): xdr.HashIdPreimage; + /** + * If {@link needsNonInvokerSigningBy} returns a non-empty list, you can serialize + * the transaction with `toJSON`, send it to the owner of one of the public keys + * in the map, deserialize with `txFromJSON`, and call this method on their + * machine. Internally, this will use `signAuthEntry` function from connected + * `wallet` for each. + * + * Then, re-serialize the transaction and either send to the next + * `needsNonInvokerSigningBy` owner, or send it back to the original account + * who simulated the transaction so they can {@link sign} the transaction + * envelope and {@link send} it to the network. + * + * Sending to all `needsNonInvokerSigningBy` owners in parallel is not currently + * supported! + */ + signAuthEntries: (expiration?: number | Promise) => Promise; + get isReadCall(): boolean; + hasRealInvoker: () => Promise; +} +/** + * A transaction that has been sent to the Soroban network. This happens in two steps: + * + * 1. `sendTransaction`: initial submission of the transaction to the network. + * This step can run into problems, and will be retried with exponential + * backoff if it does. See all attempts in `sendTransactionResponseAll` and the + * most recent attempt in `sendTransactionResponse`. + * 2. `getTransaction`: once the transaction has been submitted to the network + * successfully, you need to wait for it to finalize to get the results of the + * transaction. This step can also run into problems, and will be retried with + * exponential backoff if it does. See all attempts in + * `getTransactionResponseAll` and the most recent attempt in + * `getTransactionResponse`. + */ +declare class SentTransaction { + options: AssembledTransactionOptions; + assembled: AssembledTransaction; + server: SorobanRpc.Server; + signed: Tx; + sendTransactionResponse?: SendTx; + sendTransactionResponseAll?: SendTx[]; + getTransactionResponse?: GetTx; + getTransactionResponseAll?: GetTx[]; + constructor(options: AssembledTransactionOptions, assembled: AssembledTransaction); + static init: (options: AssembledTransactionOptions, assembled: AssembledTransaction, secondsToWait?: number) => Promise>; + private send; + get result(): T; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/index.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/index.d.ts new file mode 100644 index 000000000..d32b06f97 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/index.d.ts @@ -0,0 +1,424 @@ +import { ContractSpec } from 'stellar-sdk'; +import { Buffer } from "buffer"; +import { AssembledTransaction, Ok, Err } from './assembled-tx.js'; +import type { u32, i32, i64, i128, Option, Error_ } from './assembled-tx.js'; +import type { ClassOptions } from './method-options.js'; +export * from './assembled-tx.js'; +export * from './method-options.js'; +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: { + 1: { + message: string; + }; +}; +export declare class Contract { + readonly options: ClassOptions; + spec: ContractSpec; + constructor(options: ClassOptions); + private readonly parsers; + private txFromJSON; + readonly fromJSON: { + hello: (json: string) => AssembledTransaction; + woid: (json: string) => AssembledTransaction; + val: (json: string) => AssembledTransaction; + u32FailOnEven: (json: string) => AssembledTransaction | Ok>; + u32: (json: string) => AssembledTransaction; + i32: (json: string) => AssembledTransaction; + i64: (json: string) => AssembledTransaction; + struktHel: (json: string) => AssembledTransaction; + strukt: (json: string) => AssembledTransaction; + simple: (json: string) => AssembledTransaction; + complex: (json: string) => AssembledTransaction; + addresse: (json: string) => AssembledTransaction; + bytes: (json: string) => AssembledTransaction; + bytesN: (json: string) => AssembledTransaction; + card: (json: string) => AssembledTransaction; + boolean: (json: string) => AssembledTransaction; + not: (json: string) => AssembledTransaction; + i128: (json: string) => AssembledTransaction; + u128: (json: string) => AssembledTransaction; + multiArgs: (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; + tupleStrukt: (json: string) => AssembledTransaction; + }; + /** +* 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + u32FailOnEven: ({ u32_ }: { + u32_: u32; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => Promise | Ok>>; + /** +* 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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 +*/ + struktHel: ({ strukt }: { + strukt: Test; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + bytesN: ({ bytes_n }: { + bytes_n: Buffer; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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. +*/ + multiArgs: ({ a, b }: { + a: u32; + b: boolean; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: bigint; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => 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: 100. + */ + fee?: number; + }) => 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. +*/ + tupleStrukt: ({ tuple_strukt }: { + tuple_strukt: TupleStruct; + }, options?: { + /** + * The fee to pay for the transaction. Default: 100. + */ + fee?: number; + }) => Promise>; +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/method-options.d.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/method-options.d.ts new file mode 100644 index 000000000..fc6b21d5d --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/dist/types/method-options.d.ts @@ -0,0 +1,47 @@ +declare let responseTypes: 'simulated' | 'full' | undefined; +export type ResponseTypes = typeof responseTypes; +export type XDR_BASE64 = string; +export interface Wallet { + isConnected: () => Promise; + isAllowed: () => Promise; + getUserInfo: () => Promise<{ + publicKey?: string; + }>; + signTransaction: (tx: XDR_BASE64, opts?: { + network?: string; + networkPassphrase?: string; + accountToSign?: string; + }) => Promise; + signAuthEntry: (entryXdr: XDR_BASE64, opts?: { + accountToSign?: string; + }) => Promise; +} +export type ClassOptions = { + contractId: string; + networkPassphrase: string; + rpcUrl: string; + errorTypes?: Record; + /** + * A Wallet interface, such as Freighter, that has the methods `isConnected`, `isAllowed`, `getUserInfo`, and `signTransaction`. If not provided, will attempt to import and use Freighter. Example: + * + * @example + * ```ts + * import freighter from "@stellar/freighter-api"; + * import { Contract } from "test_custom_types"; + * const contract = new Contract({ + * …, + * wallet: freighter, + * }) + * ``` + */ + wallet?: Wallet; +}; +export type MethodOptions = { + /** + * The fee to pay for the transaction. Default: soroban-sdk's BASE_FEE ('100') + */ + fee?: number; +}; +export {}; 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 index ea6452d89..bd71e5951 100644 --- 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 @@ -8,25 +8,49 @@ "name": "test_custom_types", "version": "0.0.0", "dependencies": { - "@stellar/freighter-api": "1.5.1", + "@stellar/freighter-api": "1.7.1", "buffer": "6.0.3", - "soroban-client": "1.0.0-beta.2" + "stellar-sdk": "11.1.0" }, "devDependencies": { "typescript": "5.1.6" } }, "node_modules/@stellar/freighter-api": { - "version": "1.5.1", - "license": "Apache-2.0" + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-1.7.1.tgz", + "integrity": "sha512-XvPO+XgEbkeP0VhP0U1edOkds+rGS28+y8GRGbCVXeZ9ZslbWqRFQoETAdX8IXGuykk2ib/aPokiLc5ZaWYP7w==" + }, + "node_modules/@stellar/js-xdr": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.0.1.tgz", + "integrity": "sha512-dp5Eh7Nr1YjiIeqpdkj2cQYxfoPudDAH3ck8MWggp48Htw66Z/hUssNYUQG/OftLjEmHT90Z/dtey2Y77DOxIw==" + }, + "node_modules/@stellar/stellar-base": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-10.0.1.tgz", + "integrity": "sha512-BDbx7VHOEQh+4J3Q+gStNXgPaNckVFmD4aOlBBGwxlF6vPFmVnW8IoJdkX7T58zpX55eWI6DXvEhDBlrqTlhAQ==", + "dependencies": { + "@stellar/js-xdr": "^3.0.1", + "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.0.1" + } }, "node_modules/asynckit": { "version": "0.4.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.5.1", - "license": "MIT", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -35,13 +59,16 @@ }, "node_modules/base32.js": { "version": "0.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", + "integrity": "sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==", "engines": { "node": ">=0.12.0" } }, "node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -55,18 +82,20 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/bignumber.js": { "version": "9.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", "engines": { "node": "*" } }, "node_modules/buffer": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -81,7 +110,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -89,7 +117,8 @@ }, "node_modules/combined-stream": { "version": "1.0.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -99,20 +128,30 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "engines": { "node": ">=0.4.0" } }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -124,7 +163,8 @@ }, "node_modules/form-data": { "version": "4.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -136,6 +176,8 @@ }, "node_modules/ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -149,27 +191,25 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "BSD-3-Clause" + ] }, "node_modules/inherits": { "version": "2.0.4", - "license": "ISC" - }, - "node_modules/js-xdr": { - "version": "3.0.0", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/mime-db": { "version": "1.52.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "2.1.35", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { "mime-db": "1.52.0" }, @@ -178,8 +218,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.6.1", - "license": "MIT", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz", + "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -189,10 +230,21 @@ }, "node_modules/proxy-from-env": { "version": "1.1.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -206,12 +258,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/sha.js": { "version": "2.4.11", - "license": "(MIT AND BSD-3-Clause)", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -222,47 +274,43 @@ }, "node_modules/sodium-native": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.0.4.tgz", + "integrity": "sha512-faqOKw4WQKK7r/ybn6Lqo1F9+L5T6NlBJJYvpxbZPetpWylUVqz449mvlwIBKBqxEHbWakWuOlUt8J3Qpc4sWw==", "hasInstallScript": true, - "license": "MIT", "optional": true, "dependencies": { "node-gyp-build": "^4.6.0" } }, - "node_modules/soroban-client": { - "version": "1.0.0-beta.2", - "license": "Apache-2.0", + "node_modules/stellar-sdk": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/stellar-sdk/-/stellar-sdk-11.1.0.tgz", + "integrity": "sha512-fIdo77ogpU+ecHgs59pk9velpXd4F/ch0DzOI4QZw8zVZApc3oeNWP3+X6ui7BWpeRHAGsP2CHQzBLxm0JTIgg==", "dependencies": { - "axios": "^1.4.0", - "bignumber.js": "^9.1.1", - "buffer": "^6.0.3", - "stellar-base": "v10.0.0-beta.1", + "@stellar/stellar-base": "10.0.1", + "axios": "^1.6.0", + "bignumber.js": "^9.1.2", + "eventsource": "^2.0.2", + "randombytes": "^2.1.0", + "toml": "^3.0.0", "urijs": "^1.19.1" } }, - "node_modules/stellar-base": { - "version": "10.0.0-beta.1", - "license": "Apache-2.0", - "dependencies": { - "base32.js": "^0.1.0", - "bignumber.js": "^9.1.2", - "buffer": "^6.0.3", - "js-xdr": "^3.0.0", - "sha.js": "^2.3.6", - "tweetnacl": "^1.0.3" - }, - "optionalDependencies": { - "sodium-native": "^4.0.1" - } + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" }, "node_modules/tweetnacl": { "version": "1.0.3", - "license": "Unlicense" + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" }, "node_modules/typescript": { "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -273,7 +321,8 @@ }, "node_modules/urijs": { "version": "1.19.11", - "license": "MIT" + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" } } } diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/package.json b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/package.json index efb3acfe2..557c8b364 100644 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/package.json +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/package.json @@ -2,9 +2,9 @@ "version": "0.0.0", "name": "test_custom_types", "dependencies": { - "@stellar/freighter-api": "1.5.1", + "@stellar/freighter-api": "1.7.1", "buffer": "6.0.3", - "soroban-client": "1.0.0-beta.2" + "stellar-sdk": "11.1.0" }, "scripts": { "build": "node ./scripts/build.mjs" diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/assembled-tx.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/assembled-tx.ts new file mode 100644 index 000000000..58476807f --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/assembled-tx.ts @@ -0,0 +1,664 @@ +import { + Account, + Address, + Contract, + Operation, + SorobanRpc, + StrKey, + TimeoutInfinite, + TransactionBuilder, + authorizeEntry, + hash, + nativeToScVal, + xdr, + BASE_FEE, +} from "stellar-sdk"; +import type { Memo, MemoType, Transaction } from "stellar-sdk"; +import { Buffer } from "buffer"; +import type { + ClassOptions, + MethodOptions, + Wallet, + XDR_BASE64, +} from "./method-options.js"; + +export type Tx = Transaction, Operation[]> + +export class ExpiredStateError extends Error { } +export class NeedsMoreSignaturesError extends Error { } +export class WalletDisconnectedError extends Error { } +export class SendResultOnlyError extends Error { } +export class SendFailedError extends Error { } +export class NoUnsignedNonInvokerAuthEntriesError extends Error { } + +type SendTx = SorobanRpc.Api.SendTransactionResponse; +type GetTx = SorobanRpc.Api.GetTransactionResponse; + +export type u32 = number; +export type i32 = number; +export type u64 = bigint; +export type i64 = bigint; +export type u128 = bigint; +export type i128 = bigint; +export type u256 = bigint; +export type i256 = bigint; +export type Option = T | undefined; +export type Typepoint = bigint; +export type Duration = bigint; +export {Address}; + +/// Error interface containing the error message +export interface Error_ { message: string }; + +export interface Result { + unwrap(): T, + unwrapErr(): E, + isOk(): boolean, + isErr(): boolean, +}; + +export class Ok implements Result { + constructor(readonly value: T) { } + unwrapErr(): E { + throw new Error('No error'); + } + unwrap(): T { + return this.value; + } + + isOk(): boolean { + return true; + } + + isErr(): boolean { + return !this.isOk() + } +} + +export class Err implements Result { + constructor(readonly error: E) { } + unwrapErr(): E { + return this.error; + } + unwrap(): never { + throw new Error(this.error.message); + } + + isOk(): boolean { + return false; + } + + isErr(): boolean { + return !this.isOk() + } +} + +export const contractErrorPattern = /Error\(Contract, #(\d+)\)/; + +type AssembledTransactionOptions = MethodOptions & + ClassOptions & { + method: string; + args?: any[]; + parseResultXdr: (xdr: string | xdr.ScVal | Err) => T; + }; + +export const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF" + +export class AssembledTransaction { + public raw: Tx + private simulation?: SorobanRpc.Api.SimulateTransactionResponse + private simulationResult?: SorobanRpc.Api.SimulateHostFunctionResult + private simulationTransactionData?: xdr.SorobanTransactionData + private server: SorobanRpc.Server + + toJSON() { + return JSON.stringify({ + method: this.options.method, + tx: this.raw?.toXDR(), + simulationResult: { + auth: this.simulationData.result.auth.map(a => a.toXDR('base64')), + retval: this.simulationData.result.retval.toXDR('base64'), + }, + simulationTransactionData: this.simulationData.transactionData.toXDR('base64'), + }) + } + + static fromJSON( + options: Omit, 'args'>, + { tx, simulationResult, simulationTransactionData }: + { + tx: XDR_BASE64, + simulationResult: { + auth: XDR_BASE64[], + retval: XDR_BASE64, + }, + simulationTransactionData: XDR_BASE64, + } + ): AssembledTransaction { + const txn = new AssembledTransaction(options) + txn.raw = TransactionBuilder.fromXDR(tx, options.networkPassphrase) as Tx + txn.simulationResult = { + auth: simulationResult.auth.map(a => xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64')), + retval: xdr.ScVal.fromXDR(simulationResult.retval, 'base64'), + } + txn.simulationTransactionData = xdr.SorobanTransactionData.fromXDR(simulationTransactionData, 'base64') + return txn + } + + private constructor(public options: AssembledTransactionOptions) { + this.server = new SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + } + + static async fromSimulation(options: AssembledTransactionOptions): Promise> { + const tx = new AssembledTransaction(options) + const contract = new Contract(options.contractId); + + tx.raw = new TransactionBuilder(await tx.getAccount(), { + fee: options.fee?.toString(10) ?? BASE_FEE, + networkPassphrase: options.networkPassphrase, + }) + .addOperation(contract.call(options.method, ...(options.args ?? []))) + .setTimeout(TimeoutInfinite) + .build(); + + return await tx.simulate() + } + + simulate = async (): Promise => { + if (!this.raw) throw new Error('Transaction has not yet been assembled') + this.simulation = await this.server.simulateTransaction(this.raw); + + if (SorobanRpc.Api.isSimulationSuccess(this.simulation)) { + this.raw = SorobanRpc.assembleTransaction( + this.raw, + this.simulation + ).build() + } + + return this + } + + get simulationData(): { + result: SorobanRpc.Api.SimulateHostFunctionResult + transactionData: xdr.SorobanTransactionData + } { + if (this.simulationResult && this.simulationTransactionData) { + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData, + } + } + // else, we know we just did the simulation on this machine + const simulation = this.simulation! + if (SorobanRpc.Api.isSimulationError(simulation)) { + throw new Error(`Transaction simulation failed: "${simulation.error}"`) + } + + if (SorobanRpc.Api.isSimulationRestore(simulation)) { + throw new ExpiredStateError(`You need to restore some contract state before you can invoke this method. ${JSON.stringify(simulation, null, 2)}`) + } + + if (!simulation.result) { + throw new Error(`Expected an invocation simulation, but got no 'result' field. Simulation: ${JSON.stringify(simulation, null, 2)}`) + } + + // add to object for serialization & deserialization + this.simulationResult = simulation.result + this.simulationTransactionData = simulation.transactionData.build() + + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData!, + } + } + + get result(): T { + try { + return this.options.parseResultXdr(this.simulationData.result.retval) + } catch (e) { + let err = this.parseError(e.toString()) + if (err) return err as T + throw e + } + } + + parseError(errorMessage: string): Err | undefined { + if (!this.options.errorTypes) return + const match = errorMessage.match(contractErrorPattern) + if (!match) return + let i = parseInt(match[1], 10) + let err = this.options.errorTypes[i] + if (err) return new Err(err) + } + + getWallet = async (): Promise => { + return this.options.wallet ?? (await import("@stellar/freighter-api")).default + } + + getPublicKey = async (): Promise => { + const wallet = await this.getWallet() + if (await wallet.isConnected() && await wallet.isAllowed()) { + return (await wallet.getUserInfo()).publicKey + } + } + + /** + * Get account details from the Soroban network for the publicKey currently + * selected in user's wallet. If not connected to Freighter, use placeholder + * null account. + */ + getAccount = async (): Promise => { + const publicKey = await this.getPublicKey() + return publicKey + ? await this.server.getAccount(publicKey) + : new Account(NULL_ACCOUNT, "0") + } + + /** + * Sign the transaction with the `wallet` (default Freighter), then send to + * the network and return a `SentTransaction` that keeps track of all the + * attempts to send and fetch the transaction from the network. + */ + signAndSend = async ({ secondsToWait = 10, force = false }: { + /** + * Wait `secondsToWait` seconds (default: 10) for both the transaction to SEND successfully (will keep trying if the server returns `TRY_AGAIN_LATER`), as well as for the transaction to COMPLETE (will keep checking if the server returns `PENDING`). + */ + secondsToWait?: number + /** + * If `true`, sign and send the transaction even if it is a read call. + */ + force?: boolean + } = {}): Promise> => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated') + } + + if (!force && this.isReadCall) { + throw new Error('This is a read call. It requires no signature or sending. Use `force: true` to sign and send anyway.') + } + + if (!await this.hasRealInvoker()) { + throw new WalletDisconnectedError('Wallet is not connected') + } + + if (this.raw.source !== (await this.getAccount()).accountId()) { + throw new Error(`You must submit the transaction with the account that originally created it. Please switch to the wallet with "${this.raw.source}" as its public key.`) + } + + if ((await this.needsNonInvokerSigningBy()).length) { + throw new NeedsMoreSignaturesError( + 'Transaction requires more signatures. See `needsNonInvokerSigningBy` for details.' + ) + } + + return await SentTransaction.init(this.options, this, secondsToWait); + } + + getStorageExpiration = async () => { + const entryRes = await this.server.getLedgerEntries( + new Contract(this.options.contractId).getFootprint() + ) + if ( + !entryRes.entries || + !entryRes.entries.length || + !entryRes.entries[0].liveUntilLedgerSeq + ) throw new Error('failed to get ledger entry') + return entryRes.entries[0].liveUntilLedgerSeq + } + + /** + * Get a list of accounts, other than the invoker of the simulation, that + * need to sign auth entries in this transaction. + * + * Soroban allows multiple people to sign a transaction. Someone needs to + * sign the final transaction envelope; this person/account is called the + * _invoker_, or _source_. Other accounts might need to sign individual auth + * entries in the transaction, if they're not also the invoker. + * + * This function returns a list of accounts that need to sign auth entries, + * assuming that the same invoker/source account will sign the final + * transaction envelope as signed the initial simulation. + * + * One at a time, for each public key in this array, you will need to + * serialize this transaction with `toJSON`, send to the owner of that key, + * deserialize the transaction with `txFromJson`, and call + * {@link signAuthEntries}. Then re-serialize and send to the next account + * in this list. + */ + needsNonInvokerSigningBy = async ({ + includeAlreadySigned = false, + }: { + /** + * Whether or not to include auth entries that have already been signed. Default: false + */ + includeAlreadySigned?: boolean + } = {}): Promise => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated') + } + + // We expect that any transaction constructed by these libraries has a + // single operation, which is an InvokeHostFunction operation. The host + // function being invoked is the contract method call. + if (!("operations" in this.raw)) { + throw new Error( + `Unexpected Transaction type; no operations: ${JSON.stringify(this.raw) + }` + ) + } + const rawInvokeHostFunctionOp = this.raw + .operations[0] as Operation.InvokeHostFunction + + return [...new Set((rawInvokeHostFunctionOp.auth ?? []).filter(entry => + entry.credentials().switch() === + xdr.SorobanCredentialsType.sorobanCredentialsAddress() && + ( + includeAlreadySigned || + entry.credentials().address().signature().switch().name === 'scvVoid' + ) + ).map(entry => StrKey.encodeEd25519PublicKey( + entry.credentials().address().address().accountId().ed25519() + )))] + } + + preImageFor( + entry: xdr.SorobanAuthorizationEntry, + signatureExpirationLedger: number + ): xdr.HashIdPreimage { + const addrAuth = entry.credentials().address() + return xdr.HashIdPreimage.envelopeTypeSorobanAuthorization( + new xdr.HashIdPreimageSorobanAuthorization({ + networkId: hash(Buffer.from(this.options.networkPassphrase)), + nonce: addrAuth.nonce(), + invocation: entry.rootInvocation(), + signatureExpirationLedger, + }), + ) + } + + /** + * If {@link needsNonInvokerSigningBy} returns a non-empty list, you can serialize + * the transaction with `toJSON`, send it to the owner of one of the public keys + * in the map, deserialize with `txFromJSON`, and call this method on their + * machine. Internally, this will use `signAuthEntry` function from connected + * `wallet` for each. + * + * Then, re-serialize the transaction and either send to the next + * `needsNonInvokerSigningBy` owner, or send it back to the original account + * who simulated the transaction so they can {@link sign} the transaction + * envelope and {@link send} it to the network. + * + * Sending to all `needsNonInvokerSigningBy` owners in parallel is not currently + * supported! + */ + signAuthEntries = async ( + /** + * When to set each auth entry to expire. Could be any number of blocks in + * the future. Can be supplied as a promise or a raw number. Default: + * contract's current `persistent` storage expiration date/ledger + * number/block. + */ + expiration: number | Promise = this.getStorageExpiration() + ): Promise => { + if (!this.raw) throw new Error('Transaction has not yet been assembled or simulated') + const needsNonInvokerSigningBy = await this.needsNonInvokerSigningBy() + + if (!needsNonInvokerSigningBy) throw new NoUnsignedNonInvokerAuthEntriesError('No unsigned non-invoker auth entries; maybe you already signed?') + const publicKey = await this.getPublicKey() + if (!publicKey) throw new Error('Could not get public key from wallet; maybe Freighter is not signed in?') + if (needsNonInvokerSigningBy.indexOf(publicKey) === -1) throw new Error(`No auth entries for public key "${publicKey}"`) + const wallet = await this.getWallet() + + const rawInvokeHostFunctionOp = this.raw + .operations[0] as Operation.InvokeHostFunction + + const authEntries = rawInvokeHostFunctionOp.auth ?? [] + + for (const [i, entry] of authEntries.entries()) { + if ( + entry.credentials().switch() !== + xdr.SorobanCredentialsType.sorobanCredentialsAddress() + ) { + // if the invoker/source account, then the entry doesn't need explicit + // signature, since the tx envelope is already signed by the source + // account, so only check for sorobanCredentialsAddress + continue + } + const pk = StrKey.encodeEd25519PublicKey( + entry.credentials().address().address().accountId().ed25519() + ) + + // this auth entry needs to be signed by a different account + // (or maybe already was!) + if (pk !== publicKey) continue + + authEntries[i] = await authorizeEntry( + entry, + async preimage => Buffer.from( + await wallet.signAuthEntry(preimage.toXDR('base64')), + 'base64' + ), + await expiration, + this.options.networkPassphrase + ) + } + } + + get isReadCall(): boolean { + const authsCount = this.simulationData.result.auth.length; + const writeLength = this.simulationData.transactionData.resources().footprint().readWrite().length + return (authsCount === 0) && (writeLength === 0); + } + + hasRealInvoker = async (): Promise => { + const account = await this.getAccount() + return account.accountId() !== NULL_ACCOUNT + } +} + +/** + * A transaction that has been sent to the Soroban network. This happens in two steps: + * + * 1. `sendTransaction`: initial submission of the transaction to the network. + * This step can run into problems, and will be retried with exponential + * backoff if it does. See all attempts in `sendTransactionResponseAll` and the + * most recent attempt in `sendTransactionResponse`. + * 2. `getTransaction`: once the transaction has been submitted to the network + * successfully, you need to wait for it to finalize to get the results of the + * transaction. This step can also run into problems, and will be retried with + * exponential backoff if it does. See all attempts in + * `getTransactionResponseAll` and the most recent attempt in + * `getTransactionResponse`. + */ +class SentTransaction { + public server: SorobanRpc.Server + public signed: Tx + public sendTransactionResponse?: SendTx + public sendTransactionResponseAll?: SendTx[] + public getTransactionResponse?: GetTx + public getTransactionResponseAll?: GetTx[] + + constructor(public options: AssembledTransactionOptions, public assembled: AssembledTransaction) { + this.server = new SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + this.assembled = assembled + } + + static init = async ( + options: AssembledTransactionOptions, + assembled: AssembledTransaction, + secondsToWait: number = 10 + ): Promise> => { + const tx = new SentTransaction(options, assembled) + return await tx.send(secondsToWait) + } + + private send = async (secondsToWait: number = 10): Promise => { + const wallet = await this.assembled.getWallet() + + this.sendTransactionResponseAll = await withExponentialBackoff( + async (previousFailure) => { + if (previousFailure) { + // Increment transaction sequence number and resimulate before trying again + + // Soroban transaction can only have 1 operation + const op = this.assembled.raw.operations[0] as Operation.InvokeHostFunction; + + this.assembled.raw = new TransactionBuilder(await this.assembled.getAccount(), { + fee: this.assembled.raw.fee, + networkPassphrase: this.options.networkPassphrase, + }) + .setTimeout(TimeoutInfinite) + .addOperation( + Operation.invokeHostFunction({ ...op, auth: op.auth ?? [] }), + ) + .build() + + await this.assembled.simulate() + } + + const signature = await wallet.signTransaction(this.assembled.raw.toXDR(), { + networkPassphrase: this.options.networkPassphrase, + }); + + this.signed = TransactionBuilder.fromXDR( + signature, + this.options.networkPassphrase + ) as Tx + + return this.server.sendTransaction(this.signed) + }, + resp => resp.status !== "PENDING", + secondsToWait + ) + + this.sendTransactionResponse = this.sendTransactionResponseAll[this.sendTransactionResponseAll.length - 1] + + if (this.sendTransactionResponse.status !== "PENDING") { + throw new Error( + `Tried to resubmit transaction for ${secondsToWait + } seconds, but it's still failing. ` + + `All attempts: ${JSON.stringify( + this.sendTransactionResponseAll, + null, + 2 + )}` + ); + } + + const { hash } = this.sendTransactionResponse + + this.getTransactionResponseAll = await withExponentialBackoff( + () => this.server.getTransaction(hash), + resp => resp.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND, + secondsToWait + ) + + this.getTransactionResponse = this.getTransactionResponseAll[this.getTransactionResponseAll.length - 1] + if (this.getTransactionResponse.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND) { + console.error( + `Waited ${secondsToWait + } seconds for transaction to complete, but it did not. ` + + `Returning anyway. Check the transaction status manually. ` + + `Sent transaction: ${JSON.stringify( + this.sendTransactionResponse, + null, + 2 + )}\n` + + `All attempts to get the result: ${JSON.stringify( + this.getTransactionResponseAll, + null, + 2 + )}` + ); + } + + return this; + } + + get result(): T { + // 1. check if transaction was submitted and awaited with `getTransaction` + if ( + "getTransactionResponse" in this && + this.getTransactionResponse + ) { + // getTransactionResponse has a `returnValue` field unless it failed + if ("returnValue" in this.getTransactionResponse) { + return this.options.parseResultXdr(this.getTransactionResponse.returnValue!) + } + + // if "returnValue" not present, the transaction failed; return without parsing the result + throw new Error("Transaction failed! Cannot parse result.") + } + + // 2. otherwise, maybe it was merely sent with `sendTransaction` + if (this.sendTransactionResponse) { + const errorResult = this.sendTransactionResponse.errorResult?.result() + if (errorResult) { + throw new SendFailedError( + `Transaction simulation looked correct, but attempting to send the transaction failed. Check \`simulation\` and \`sendTransactionResponseAll\` to troubleshoot. Decoded \`sendTransactionResponse.errorResultXdr\`: ${errorResult}` + ) + } + throw new SendResultOnlyError( + `Transaction was sent to the network, but not yet awaited. No result to show. Await transaction completion with \`getTransaction(sendTransactionResponse.hash)\`` + ) + } + + // 3. finally, if neither of those are present, throw an error + throw new Error(`Sending transaction failed: ${JSON.stringify(this.assembled)}`) + } +} + +/** + * Keep calling a `fn` for `secondsToWait` seconds, if `keepWaitingIf` is true. + * Returns an array of all attempts to call the function. + */ +async function withExponentialBackoff( + fn: (previousFailure?: T) => Promise, + keepWaitingIf: (result: T) => boolean, + secondsToWait: number, + exponentialFactor = 1.5, + verbose = false, +): Promise { + const attempts: T[] = [] + + let count = 0 + attempts.push(await fn()) + if (!keepWaitingIf(attempts[attempts.length - 1])) return attempts + + const waitUntil = new Date(Date.now() + secondsToWait * 1000).valueOf() + let waitTime = 1000 + let totalWaitTime = waitTime + + while (Date.now() < waitUntil && keepWaitingIf(attempts[attempts.length - 1])) { + count++ + // Wait a beat + if (verbose) { + console.info(`Waiting ${waitTime}ms before trying again (bringing the total wait time to ${totalWaitTime}ms so far, of total ${secondsToWait * 1000}ms)`) + } + await new Promise(res => setTimeout(res, waitTime)) + // Exponential backoff + waitTime = waitTime * exponentialFactor; + if (new Date(Date.now() + waitTime).valueOf() > waitUntil) { + waitTime = waitUntil - Date.now() + if (verbose) { + console.info(`was gonna wait too long; new waitTime: ${waitTime}ms`) + } + } + totalWaitTime = waitTime + totalWaitTime + // Try again + attempts.push(await fn(attempts[attempts.length - 1])) + if (verbose && keepWaitingIf(attempts[attempts.length - 1])) { + console.info( + `${count}. Called ${fn}; ${attempts.length + } prev attempts. Most recent: ${JSON.stringify(attempts[attempts.length - 1], null, 2) + }` + ) + } + } + + return attempts +} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/convert.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/convert.ts deleted file mode 100644 index 12d7044aa..000000000 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/convert.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { - xdr, - Address, - nativeToScVal, - scValToBigInt, - ScInt -} from 'soroban-client'; - -export function strToScVal(base64Xdr: string): xdr.ScVal { - return xdr.ScVal.fromXDR(base64Xdr, 'base64'); -} - -export function scValStrToJs(base64Xdr: string): T { - return scValToJs(strToScVal(base64Xdr)); -} - -export function scValToJs(val: xdr.ScVal): T { - switch (val?.switch()) { - case xdr.ScValType.scvBool(): { - return val.b() as unknown as T; - } - case xdr.ScValType.scvVoid(): - case undefined: { - return 0 as unknown as T; - } - case xdr.ScValType.scvU32(): { - return val.u32() as unknown as T; - } - case xdr.ScValType.scvI32(): { - return val.i32() as unknown as T; - } - case xdr.ScValType.scvU64(): - case xdr.ScValType.scvI64(): - case xdr.ScValType.scvU128(): - case xdr.ScValType.scvI128(): - case xdr.ScValType.scvU256(): - case xdr.ScValType.scvI256(): { - return scValToBigInt(val) as unknown as T; - } - case xdr.ScValType.scvAddress(): { - return Address.fromScVal(val).toString() as unknown as T; - } - case xdr.ScValType.scvString(): { - return val.str().toString() as unknown as T; - } - case xdr.ScValType.scvSymbol(): { - return val.sym().toString() as unknown as T; - } - case xdr.ScValType.scvBytes(): { - return val.bytes() as unknown as T; - } - case xdr.ScValType.scvVec(): { - type Element = ElementType; - return val.vec()!.map(v => scValToJs(v)) as unknown as T; - } - case xdr.ScValType.scvMap(): { - type Key = KeyType; - type Value = ValueType; - let res: any = {}; - val.map()!.forEach((e) => { - let key = scValToJs(e.key()); - let value; - let v: xdr.ScVal = e.val(); - // For now we assume second level maps are real maps. Not perfect but better. - switch (v?.switch()) { - case xdr.ScValType.scvMap(): { - let inner_map = new Map() as Map; - v.map()!.forEach((e) => { - let key = scValToJs(e.key()); - let value = scValToJs(e.val()); - inner_map.set(key, value); - }); - value = inner_map; - break; - } - default: { - value = scValToJs(e.val()); - } - } - //@ts-ignore - res[key as Key] = value as Value; - }); - return res as unknown as T - } - case xdr.ScValType.scvContractInstance(): - case xdr.ScValType.scvLedgerKeyNonce(): - case xdr.ScValType.scvTimepoint(): - case xdr.ScValType.scvDuration(): - return val.value() as unknown as T; - // TODO: Add this case when merged - // case xdr.ScValType.scvError(): - default: { - throw new Error(`type not implemented yet: ${val?.switch().name}`); - } - }; -} - -type ElementType = T extends Array ? U : never; -type KeyType = T extends Map ? K : never; -type ValueType = T extends Map ? V : never; - -export function addressToScVal(addr: string): xdr.ScVal { - return nativeToScVal(addr, { type: 'address' } as any /* bug workaround */); -} - -export function i128ToScVal(i: bigint): xdr.ScVal { - return new ScInt(i).toI128(); -} - -export function u128ToScVal(i: bigint): xdr.ScVal { - return new ScInt(i).toU128(); -} 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 d0e4e0349..5dee944fa 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 @@ -1,93 +1,31 @@ -import * as SorobanClient from 'soroban-client'; -import { ContractSpec, Address } from 'soroban-client'; +import { ContractSpec, Address } from 'stellar-sdk'; import { Buffer } from "buffer"; -import { invoke } from './invoke.js'; -import type { ResponseTypes, Wallet, ClassOptions } from './method-options.js' - -export * from './invoke.js' -export * from './method-options.js' - -export type u32 = number; -export type i32 = number; -export type u64 = bigint; -export type i64 = bigint; -export type u128 = bigint; -export type i128 = bigint; -export type u256 = bigint; -export type i256 = bigint; -export type Option = T | undefined; -export type Typepoint = bigint; -export type Duration = bigint; -export {Address}; - -/// Error interface containing the error message -export interface Error_ { message: string }; - -export interface Result { - unwrap(): T, - unwrapErr(): E, - isOk(): boolean, - isErr(): boolean, -}; - -export class Ok implements Result { - constructor(readonly value: T) { } - unwrapErr(): E { - throw new Error('No error'); - } - unwrap(): T { - return this.value; - } - - isOk(): boolean { - return true; - } - - isErr(): boolean { - return !this.isOk() - } -} - -export class Err implements Result { - constructor(readonly error: E) { } - unwrapErr(): E { - return this.error; - } - unwrap(): never { - throw new Error(this.error.message); - } - - isOk(): boolean { - return false; - } - - isErr(): boolean { - return !this.isOk() - } -} +import { AssembledTransaction, Ok, Err } from './assembled-tx.js'; +import type { + u32, + i32, + u64, + i64, + u128, + i128, + u256, + i256, + Option, + Typepoint, + Duration, + Error_, + Result, +} from './assembled-tx.js'; +import type { ClassOptions, XDR_BASE64 } from './method-options.js'; + +export * from './assembled-tx.js'; +export * from './method-options.js'; if (typeof window !== 'undefined') { //@ts-ignore Buffer exists window.Buffer = window.Buffer || Buffer; } -const regex = /Error\(Contract, #(\d+)\)/; - -function parseError(message: string): Err | undefined { - const match = message.match(regex); - if (!match) { - return undefined; - } - if (Errors === undefined) { - return undefined; - } - let i = parseInt(match[1], 10); - let err = Errors[i]; - if (err) { - return new Err(err); - } - return undefined; -} export const networks = { futurenet: { @@ -97,31 +35,55 @@ export const networks = { } as const /** - * This is from the rust doc above the struct Test - */ + This is from the rust doc above the struct Test + */ export interface Test { - a: u32; - b: boolean; - c: string; + /** + + */ +a: u32; + /** + + */ +b: boolean; + /** + + */ +c: string; } +/** + + */ export type SimpleEnum = {tag: "First", values: void} | {tag: "Second", values: void} | {tag: "Third", values: void}; +/** + + */ export 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}; -const Errors = { +/** + + */ +export const Errors = { 1: {message:"Please provide an odd number"} } export class Contract { - spec: ContractSpec; + spec: ContractSpec; constructor(public readonly options: ClassOptions) { this.spec = new ContractSpec([ "AAAAAQAAAC9UaGlzIGlzIGZyb20gdGhlIHJ1c3QgZG9jIGFib3ZlIHRoZSBzdHJ1Y3QgVGVzdAAAAAAAAAAABFRlc3QAAAADAAAAAAAAAAFhAAAAAAAABAAAAAAAAAABYgAAAAAAAAEAAAAAAAAAAWMAAAAAAAAR", @@ -158,857 +120,638 @@ export class Contract { "AAAAAAAAAAAAAAAEaTI1NgAAAAEAAAAAAAAABGkyNTYAAAANAAAAAQAAAA0=", "AAAAAAAAAAAAAAAGc3RyaW5nAAAAAAABAAAAAAAAAAZzdHJpbmcAAAAAABAAAAABAAAAEA==", "AAAAAAAAAAAAAAAMdHVwbGVfc3RydWt0AAAAAQAAAAAAAAAMdHVwbGVfc3RydWt0AAAH0AAAAAtUdXBsZVN0cnVjdAAAAAABAAAH0AAAAAtUdXBsZVN0cnVjdAA=" - ]); - } - hello = async ({hello}: {hello: string}, options: { + ]); + } + private readonly parsers = { + hello: (result: XDR_BASE64): string => this.spec.funcResToNative("hello", result), + woid: () => {}, + val: (result: XDR_BASE64): any => this.spec.funcResToNative("val", result), + u32FailOnEven: (result: XDR_BASE64 | Err): Ok | Err => { + if (result instanceof Err) return result + return new Ok(this.spec.funcResToNative("u32_fail_on_even", result)) + }, + u32: (result: XDR_BASE64): u32 => this.spec.funcResToNative("u32_", result), + i32: (result: XDR_BASE64): i32 => this.spec.funcResToNative("i32_", result), + i64: (result: XDR_BASE64): i64 => this.spec.funcResToNative("i64_", result), + struktHel: (result: XDR_BASE64): Array => this.spec.funcResToNative("strukt_hel", result), + strukt: (result: XDR_BASE64): Test => this.spec.funcResToNative("strukt", result), + simple: (result: XDR_BASE64): SimpleEnum => this.spec.funcResToNative("simple", result), + complex: (result: XDR_BASE64): ComplexEnum => this.spec.funcResToNative("complex", result), + addresse: (result: XDR_BASE64): string => this.spec.funcResToNative("addresse", result), + bytes: (result: XDR_BASE64): Buffer => this.spec.funcResToNative("bytes", result), + bytesN: (result: XDR_BASE64): Buffer => this.spec.funcResToNative("bytes_n", result), + card: (result: XDR_BASE64): RoyalCard => this.spec.funcResToNative("card", result), + boolean: (result: XDR_BASE64): boolean => this.spec.funcResToNative("boolean", result), + not: (result: XDR_BASE64): boolean => this.spec.funcResToNative("not", result), + i128: (result: XDR_BASE64): i128 => this.spec.funcResToNative("i128", result), + u128: (result: XDR_BASE64): u128 => this.spec.funcResToNative("u128", result), + multiArgs: (result: XDR_BASE64): u32 => this.spec.funcResToNative("multi_args", result), + map: (result: XDR_BASE64): Map => this.spec.funcResToNative("map", result), + vec: (result: XDR_BASE64): Array => this.spec.funcResToNative("vec", result), + tuple: (result: XDR_BASE64): readonly [string, u32] => this.spec.funcResToNative("tuple", result), + option: (result: XDR_BASE64): Option => this.spec.funcResToNative("option", result), + u256: (result: XDR_BASE64): u256 => this.spec.funcResToNative("u256", result), + i256: (result: XDR_BASE64): i256 => this.spec.funcResToNative("i256", result), + string: (result: XDR_BASE64): string => this.spec.funcResToNative("string", result), + tupleStrukt: (result: XDR_BASE64): TupleStruct => this.spec.funcResToNative("tuple_strukt", result) + }; + private txFromJSON = (json: string): AssembledTransaction => { + const { method, ...tx } = JSON.parse(json) + return AssembledTransaction.fromJSON( + { + ...this.options, + method, + parseResultXdr: this.parsers[method], + }, + tx, + ); + } + public readonly fromJSON = { + hello: this.txFromJSON>, + woid: this.txFromJSON>, + val: this.txFromJSON>, + u32FailOnEven: this.txFromJSON>, + u32: this.txFromJSON>, + i32: this.txFromJSON>, + i64: this.txFromJSON>, + struktHel: this.txFromJSON>, + strukt: this.txFromJSON>, + simple: this.txFromJSON>, + complex: this.txFromJSON>, + addresse: this.txFromJSON>, + bytes: this.txFromJSON>, + bytesN: this.txFromJSON>, + card: this.txFromJSON>, + boolean: this.txFromJSON>, + not: this.txFromJSON>, + i128: this.txFromJSON>, + u128: this.txFromJSON>, + multiArgs: this.txFromJSON>, + map: this.txFromJSON>, + vec: this.txFromJSON>, + tuple: this.txFromJSON>, + option: this.txFromJSON>, + u256: this.txFromJSON>, + i256: this.txFromJSON>, + string: this.txFromJSON>, + tupleStrukt: this.txFromJSON> + } + /** + * 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 = async ({hello}: {hello: string}, options: { /** * The fee to pay for the transaction. Default: 100. */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `string`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. - */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'hello', args: this.spec.funcArgsToScVals("hello", {hello}), ...options, ...this.options, - parseResultXdr: (xdr): string => { - return this.spec.funcResToNative("hello", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['hello'], }); } - woid = async (options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `void`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async (options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'woid', args: this.spec.funcArgsToScVals("woid", {}), ...options, ...this.options, - parseResultXdr: () => {}, + errorTypes: Errors, + parseResultXdr: this.parsers['woid'], }); } - val = async (options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `any`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async (options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'val', args: this.spec.funcArgsToScVals("val", {}), ...options, ...this.options, - parseResultXdr: (xdr): any => { - return this.spec.funcResToNative("val", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['val'], }); } - u32FailOnEven = async ({u32_}: {u32_: u32}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number + * 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. + */ + u32FailOnEven = async ({u32_}: {u32_: u32}, options: { /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Ok | Err | undefined`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - try { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'u32_fail_on_even', args: this.spec.funcArgsToScVals("u32_fail_on_even", {u32_}), ...options, ...this.options, - parseResultXdr: (xdr): Ok | Err | undefined => { - return new Ok(this.spec.funcResToNative("u32_fail_on_even", xdr)); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['u32FailOnEven'], }); - } catch (e) { - let err = parseError(e.toString()); - if (err) return err; - throw e; - } } - u32 = async ({u32_}: {u32_: u32}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number + * 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 = async ({u32_}: {u32_: u32}, options: { /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `u32`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'u32_', args: this.spec.funcArgsToScVals("u32_", {u32_}), ...options, ...this.options, - parseResultXdr: (xdr): u32 => { - return this.spec.funcResToNative("u32_", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['u32'], }); } - i32 = async ({i32_}: {i32_: i32}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number + * 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 = async ({i32_}: {i32_: i32}, options: { /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `i32`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'i32_', args: this.spec.funcArgsToScVals("i32_", {i32_}), ...options, ...this.options, - parseResultXdr: (xdr): i32 => { - return this.spec.funcResToNative("i32_", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['i32'], }); } - i64 = async ({i64_}: {i64_: i64}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `i64`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({i64_}: {i64_: i64}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'i64_', args: this.spec.funcArgsToScVals("i64_", {i64_}), ...options, ...this.options, - parseResultXdr: (xdr): i64 => { - return this.spec.funcResToNative("i64_", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['i64'], }); } - /** - * Example contract method which takes a struct - */ -struktHel = async ({strukt}: {strukt: Test}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number + * 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 + */ + struktHel = async ({strukt}: {strukt: Test}, options: { /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Array`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'strukt_hel', args: this.spec.funcArgsToScVals("strukt_hel", {strukt}), ...options, ...this.options, - parseResultXdr: (xdr): Array => { - return this.spec.funcResToNative("strukt_hel", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['struktHel'], }); } - strukt = async ({strukt}: {strukt: Test}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Test`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({strukt}: {strukt: Test}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'strukt', args: this.spec.funcArgsToScVals("strukt", {strukt}), ...options, ...this.options, - parseResultXdr: (xdr): Test => { - return this.spec.funcResToNative("strukt", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['strukt'], }); } - simple = async ({simple}: {simple: SimpleEnum}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `SimpleEnum`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({simple}: {simple: SimpleEnum}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'simple', args: this.spec.funcArgsToScVals("simple", {simple}), ...options, ...this.options, - parseResultXdr: (xdr): SimpleEnum => { - return this.spec.funcResToNative("simple", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['simple'], }); } - complex = async ({complex}: {complex: ComplexEnum}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `ComplexEnum`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({complex}: {complex: ComplexEnum}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'complex', args: this.spec.funcArgsToScVals("complex", {complex}), ...options, ...this.options, - parseResultXdr: (xdr): ComplexEnum => { - return this.spec.funcResToNative("complex", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['complex'], }); } - addresse = async ({addresse}: {addresse: string}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `string`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({addresse}: {addresse: string}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'addresse', args: this.spec.funcArgsToScVals("addresse", {addresse: new Address(addresse)}), ...options, ...this.options, - parseResultXdr: (xdr): string => { - return this.spec.funcResToNative("addresse", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['addresse'], }); } - bytes = async ({bytes}: {bytes: Buffer}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Buffer`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({bytes}: {bytes: Buffer}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'bytes', args: this.spec.funcArgsToScVals("bytes", {bytes}), ...options, ...this.options, - parseResultXdr: (xdr): Buffer => { - return this.spec.funcResToNative("bytes", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['bytes'], }); } - bytesN = async ({bytes_n}: {bytes_n: Buffer}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Buffer`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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. + */ + bytesN = async ({bytes_n}: {bytes_n: Buffer}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'bytes_n', args: this.spec.funcArgsToScVals("bytes_n", {bytes_n}), ...options, ...this.options, - parseResultXdr: (xdr): Buffer => { - return this.spec.funcResToNative("bytes_n", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['bytesN'], }); } - card = async ({card}: {card: RoyalCard}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `RoyalCard`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({card}: {card: RoyalCard}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'card', args: this.spec.funcArgsToScVals("card", {card}), ...options, ...this.options, - parseResultXdr: (xdr): RoyalCard => { - return this.spec.funcResToNative("card", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['card'], }); } - boolean = async ({boolean}: {boolean: boolean}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `boolean`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({boolean}: {boolean: boolean}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'boolean', args: this.spec.funcArgsToScVals("boolean", {boolean}), ...options, ...this.options, - parseResultXdr: (xdr): boolean => { - return this.spec.funcResToNative("boolean", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['boolean'], }); } - /** - * Negates a boolean value - */ -not = async ({boolean}: {boolean: boolean}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number + * 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 = async ({boolean}: {boolean: boolean}, options: { /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `boolean`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'not', args: this.spec.funcArgsToScVals("not", {boolean}), ...options, ...this.options, - parseResultXdr: (xdr): boolean => { - return this.spec.funcResToNative("not", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['not'], }); } - i128 = async ({i128}: {i128: i128}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `i128`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({i128}: {i128: i128}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'i128', args: this.spec.funcArgsToScVals("i128", {i128}), ...options, ...this.options, - parseResultXdr: (xdr): i128 => { - return this.spec.funcResToNative("i128", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['i128'], }); } - u128 = async ({u128}: {u128: u128}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `u128`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({u128}: {u128: u128}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'u128', args: this.spec.funcArgsToScVals("u128", {u128}), ...options, ...this.options, - parseResultXdr: (xdr): u128 => { - return this.spec.funcResToNative("u128", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['u128'], }); } - multiArgs = async ({a, b}: {a: u32, b: boolean}, options: { - /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `u32`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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. + */ + multiArgs = async ({a, b}: {a: u32, b: boolean}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'multi_args', args: this.spec.funcArgsToScVals("multi_args", {a, b}), ...options, ...this.options, - parseResultXdr: (xdr): u32 => { - return this.spec.funcResToNative("multi_args", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['multiArgs'], }); } - map = async ({map}: {map: Map}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number + * 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 = async ({map}: {map: Map}, options: { /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Map`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'map', args: this.spec.funcArgsToScVals("map", {map}), ...options, ...this.options, - parseResultXdr: (xdr): Map => { - return this.spec.funcResToNative("map", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['map'], }); } - vec = async ({vec}: {vec: Array}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Array`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({vec}: {vec: Array}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'vec', args: this.spec.funcArgsToScVals("vec", {vec}), ...options, ...this.options, - parseResultXdr: (xdr): Array => { - return this.spec.funcResToNative("vec", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['vec'], }); } - tuple = async ({tuple}: {tuple: readonly [string, u32]}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `readonly [string, u32]`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({tuple}: {tuple: readonly [string, u32]}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'tuple', args: this.spec.funcArgsToScVals("tuple", {tuple}), ...options, ...this.options, - parseResultXdr: (xdr): readonly [string, u32] => { - return this.spec.funcResToNative("tuple", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['tuple'], }); } - /** - * Example of an optional argument - */ -option = async ({option}: {option: Option}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `Option`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({option}: {option: Option}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'option', args: this.spec.funcArgsToScVals("option", {option}), ...options, ...this.options, - parseResultXdr: (xdr): Option => { - return this.spec.funcResToNative("option", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['option'], }); } - u256 = async ({u256}: {u256: u256}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `u256`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({u256}: {u256: u256}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'u256', args: this.spec.funcArgsToScVals("u256", {u256}), ...options, ...this.options, - parseResultXdr: (xdr): u256 => { - return this.spec.funcResToNative("u256", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['u256'], }); } - i256 = async ({i256}: {i256: i256}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `i256`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({i256}: {i256: i256}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'i256', args: this.spec.funcArgsToScVals("i256", {i256}), ...options, ...this.options, - parseResultXdr: (xdr): i256 => { - return this.spec.funcResToNative("i256", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['i256'], }); } - string = async ({string}: {string: string}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `string`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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 = async ({string}: {string: string}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'string', args: this.spec.funcArgsToScVals("string", {string}), ...options, ...this.options, - parseResultXdr: (xdr): string => { - return this.spec.funcResToNative("string", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['string'], }); } - tupleStrukt = async ({tuple_strukt}: {tuple_strukt: TupleStruct}, options: { /** - * The fee to pay for the transaction. Default: 100. - */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `TupleStruct`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R + * 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. + */ + tupleStrukt = async ({tuple_strukt}: {tuple_strukt: TupleStruct}, options: { /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. + * The fee to pay for the transaction. Default: 100. */ - secondsToWait?: number + fee?: number, } = {}) => { - return await invoke({ + return await AssembledTransaction.fromSimulation({ method: 'tuple_strukt', args: this.spec.funcArgsToScVals("tuple_strukt", {tuple_strukt}), ...options, ...this.options, - parseResultXdr: (xdr): TupleStruct => { - return this.spec.funcResToNative("tuple_strukt", xdr); - }, + errorTypes: Errors, + parseResultXdr: this.parsers['tupleStrukt'], }); } diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/invoke.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/invoke.ts deleted file mode 100644 index d69166ce1..000000000 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/invoke.ts +++ /dev/null @@ -1,254 +0,0 @@ -import * as SorobanClient from "soroban-client"; -import { SorobanRpc } from "soroban-client"; -import type { - Account, - Memo, - MemoType, - Operation, - Transaction, - xdr, -} from "soroban-client"; -import type { - ClassOptions, - MethodOptions, - ResponseTypes, - Wallet, -} from "./method-options.js"; - -export type Tx = Transaction, Operation[]>; - -/** - * Get account details from the Soroban network for the publicKey currently - * selected in Freighter. If not connected to Freighter, return null. - */ -async function getAccount( - wallet: Wallet, - server: SorobanClient.Server -): Promise { - if (!(await wallet.isConnected()) || !(await wallet.isAllowed())) { - return null; - } - const { publicKey } = await wallet.getUserInfo(); - if (!publicKey) { - return null; - } - return await server.getAccount(publicKey); -} - -export class NotImplementedError extends Error {} - -type Simulation = SorobanRpc.SimulateTransactionResponse; -type SendTx = SorobanRpc.SendTransactionResponse; -type GetTx = SorobanRpc.GetTransactionResponse; - -// defined this way so typeahead shows full union, not named alias -let someRpcResponse: Simulation | SendTx | GetTx; -type SomeRpcResponse = typeof someRpcResponse; - -type InvokeArgs = MethodOptions & - ClassOptions & { - method: string; - args?: any[]; - parseResultXdr: (xdr: string | xdr.ScVal) => T; - }; - -/** - * Invoke a method on the test_custom_types contract. - * - * Uses Freighter to determine the current user and if necessary sign the transaction. - * - * @returns {T}, by default, the parsed XDR from either the simulation or the full transaction. If `simulateOnly` or `fullRpcResponse` are true, returns either the full simulation or the result of sending/getting the transaction to/from the ledger. - */ -export async function invoke( - args: InvokeArgs -): Promise< - R extends undefined - ? T - : R extends "simulated" - ? Simulation - : R extends "full" - ? SomeRpcResponse - : T ->; -export async function invoke({ - method, - args = [], - fee = 100, - responseType, - parseResultXdr, - secondsToWait = 10, - rpcUrl, - networkPassphrase, - contractId, - wallet, -}: InvokeArgs): Promise { - wallet = wallet ?? (await import("@stellar/freighter-api")); - let parse = parseResultXdr; - const server = new SorobanClient.Server(rpcUrl, { - allowHttp: rpcUrl.startsWith("http://"), - }); - const walletAccount = await getAccount(wallet, server); - - // use a placeholder null account if not yet connected to Freighter so that view calls can still work - const account = - walletAccount ?? - new SorobanClient.Account( - "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", - "0" - ); - - const contract = new SorobanClient.Contract(contractId); - - let tx = new SorobanClient.TransactionBuilder(account, { - fee: fee.toString(10), - networkPassphrase, - }) - .addOperation(contract.call(method, ...args)) - .setTimeout(SorobanClient.TimeoutInfinite) - .build(); - const simulated = await server.simulateTransaction(tx); - - if (SorobanRpc.isSimulationError(simulated)) { - throw new Error(simulated.error); - } else if (responseType === "simulated") { - return simulated; - } else if (!simulated.result) { - throw new Error(`invalid simulation: no result in ${simulated}`); - } - - let authsCount = simulated.result.auth.length; - const writeLength = simulated.transactionData.getReadWrite().length; - const isViewCall = (authsCount === 0) && (writeLength === 0); - - if (isViewCall) { - if (responseType === "full") { - return simulated; - } - - return parseResultXdr(simulated.result.retval); - } - - if (authsCount > 1) { - throw new NotImplementedError("Multiple auths not yet supported"); - } - if (authsCount === 1) { - // TODO: figure out how to fix with new SorobanClient - // const auth = SorobanClient.xdr.SorobanAuthorizationEntry.fromXDR(auths![0]!, 'base64') - // if (auth.addressWithNonce() !== undefined) { - // throw new NotImplementedError( - // `This transaction needs to be signed by ${auth.addressWithNonce() - // }; Not yet supported` - // ) - // } - } - - if (!walletAccount) { - throw new Error("Not connected to Freighter"); - } - - tx = await signTx( - wallet, - SorobanClient.assembleTransaction(tx, networkPassphrase, simulated).build(), - networkPassphrase - ); - - const raw = await sendTx(tx, secondsToWait, server); - if (responseType === "full") { - return raw; - } - - // if `sendTx` awaited the inclusion of the tx in the ledger, it used - // `getTransaction`, which has a `returnValue` field - if ("returnValue" in raw) return parse(raw.returnValue!); - - // otherwise, it returned the result of `sendTransaction` - if ("errorResultXdr" in raw) return parse(raw.errorResultXdr!); - - // if neither of these are present, something went wrong - console.error("Don't know how to parse result! Returning full RPC response."); - return raw; -} - -/** - * Sign a transaction with Freighter and return the fully-reconstructed - * transaction ready to send with {@link sendTx}. - * - * If you need to construct a transaction yourself rather than using `invoke` - * or one of the exported contract methods, you may want to use this function - * to sign the transaction with Freighter. - */ -export async function signTx( - wallet: Wallet, - tx: Tx, - networkPassphrase: string -): Promise { - const signed = await wallet.signTransaction(tx.toXDR(), { - networkPassphrase, - }); - - return SorobanClient.TransactionBuilder.fromXDR( - signed, - networkPassphrase - ) as Tx; -} - -/** - * Send a transaction to the Soroban network. - * - * Wait `secondsToWait` seconds for the transaction to complete (default: 10). - * - * If you need to construct or sign a transaction yourself rather than using - * `invoke` or one of the exported contract methods, you may want to use this - * function for its timeout/`secondsToWait` logic, rather than implementing - * your own. - */ -export async function sendTx( - tx: Tx, - secondsToWait: number, - server: SorobanClient.Server -): Promise { - const sendTransactionResponse = await server.sendTransaction(tx); - - if (sendTransactionResponse.status !== "PENDING" || secondsToWait === 0) { - return sendTransactionResponse; - } - - let getTransactionResponse = await server.getTransaction( - sendTransactionResponse.hash - ); - - const waitUntil = new Date(Date.now() + secondsToWait * 1000).valueOf(); - - let waitTime = 1000; - let exponentialFactor = 1.5; - - while ( - Date.now() < waitUntil && - getTransactionResponse.status === SorobanRpc.GetTransactionStatus.NOT_FOUND - ) { - // Wait a beat - await new Promise((resolve) => setTimeout(resolve, waitTime)); - /// Exponential backoff - waitTime = waitTime * exponentialFactor; - // See if the transaction is complete - getTransactionResponse = await server.getTransaction( - sendTransactionResponse.hash - ); - } - - if (getTransactionResponse.status === SorobanRpc.GetTransactionStatus.NOT_FOUND) { - console.error( - `Waited ${ - secondsToWait - } seconds for transaction to complete, but it did not. ` + - `Returning anyway. Check the transaction status manually. ` + - `Info: ${JSON.stringify( - sendTransactionResponse, - null, - 2 - )}` - ); - } - - return getTransactionResponse; -} diff --git a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/method-options.ts b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/method-options.ts index 05c4c46ca..737ae0a05 100644 --- a/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/method-options.ts +++ b/cmd/crates/soroban-spec-typescript/fixtures/test_custom_types/src/method-options.ts @@ -13,12 +13,19 @@ export interface Wallet { networkPassphrase?: string, accountToSign?: string, }) => Promise, + signAuthEntry: ( + entryXdr: XDR_BASE64, + opts?: { + accountToSign?: string; + } + ) => Promise } export type ClassOptions = { contractId: string networkPassphrase: string rpcUrl: string + errorTypes?: Record /** * A Wallet interface, such as Freighter, that has the methods `isConnected`, `isAllowed`, `getUserInfo`, and `signTransaction`. If not provided, will attempt to import and use Freighter. Example: * @@ -35,21 +42,9 @@ export type ClassOptions = { wallet?: Wallet } -export type MethodOptions = { +export type MethodOptions = { /** - * The fee to pay for the transaction. Default: 100. + * The fee to pay for the transaction. Default: soroban-sdk's BASE_FEE ('100') */ fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `{RETURN_TYPE}`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. - */ - secondsToWait?: number } diff --git a/cmd/crates/soroban-spec-typescript/src/boilerplate.rs b/cmd/crates/soroban-spec-typescript/src/boilerplate.rs index 95b690591..7ffe64189 100644 --- a/cmd/crates/soroban-spec-typescript/src/boilerplate.rs +++ b/cmd/crates/soroban-spec-typescript/src/boilerplate.rs @@ -81,8 +81,8 @@ impl Project { [ "package.json", "README.md", + "src/assembled-tx.ts", "src/index.ts", - "src/invoke.ts", "src/method-options.ts", ] .into_iter() diff --git a/cmd/crates/soroban-spec-typescript/src/lib.rs b/cmd/crates/soroban-spec-typescript/src/lib.rs index 7dff04756..4225b8aab 100644 --- a/cmd/crates/soroban-spec-typescript/src/lib.rs +++ b/cmd/crates/soroban-spec-typescript/src/lib.rs @@ -10,7 +10,7 @@ use crate::types::Type; use heck::ToLowerCamelCase; use itertools::Itertools; use sha2::{Digest, Sha256}; -use stellar_xdr::curr::{ScSpecEntry, WriteXdr}; +use stellar_xdr::curr::{Limits, ScSpecEntry, WriteXdr}; use types::Entry; @@ -61,18 +61,47 @@ pub fn generate_from_wasm(wasm: &[u8]) -> Result { } fn generate_class(fns: &[Entry], spec: &[ScSpecEntry]) -> String { - let methods = fns.iter().map(entry_to_ts).join("\n\n "); + let methods = fns.iter().map(entry_to_method).join("\n\n "); + let parsers = fns + .iter() + .filter_map(entry_to_parser) + .map(|(method, parser)| format!("{method}: {parser}")) + .join(",\n "); + let from_jsons = fns + .iter() + .filter_map(entry_to_parser) + .map(|(method, _)| { + format!("{method}: this.txFromJSON>") + }) + .join(",\n "); let spec = spec .iter() - .map(|s| format!("\"{}\"", s.to_xdr_base64().unwrap())) + .map(|s| format!("\"{}\"", s.to_xdr_base64(Limits::none()).unwrap())) .join(",\n "); format!( r#"export class Contract {{ - spec: ContractSpec; + spec: ContractSpec; constructor(public readonly options: ClassOptions) {{ this.spec = new ContractSpec([ {spec} - ]); + ]); + }} + private readonly parsers = {{ + {parsers} + }}; + private txFromJSON = (json: string): AssembledTransaction => {{ + const {{ method, ...tx }} = JSON.parse(json) + return AssembledTransaction.fromJSON( + {{ + ...this.options, + method, + parseResultXdr: this.parsers[method], + }}, + tx, + ); + }} + public readonly fromJSON = {{ + {from_jsons} }} {methods} }}"#, @@ -91,64 +120,95 @@ pub fn generate(spec: &[ScSpecEntry]) -> String { let (fns, other): (Vec<_>, Vec<_>) = collected .into_iter() .partition(|entry| matches!(entry, Entry::Function { .. })); - let top = other.iter().map(entry_to_ts).join("\n"); + let top = other.iter().map(entry_to_method).join("\n"); let bottom = generate_class(&fns, spec); format!("{top}\n\n{bottom}") } -fn doc_to_ts_doc(doc: &str) -> String { - if doc.is_empty() { - String::new() - } else { - let doc = doc.split('\n').join("\n * "); +fn doc_to_ts_doc(doc: &str, method: Option<&str>) -> String { + let header = if let Some(method) = method { format!( r#"/** - * {doc} - */ -"#, + * Construct and simulate a {method} 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."# ) - } + } else { + "/**\n ".to_string() + }; + let footer = "\n */\n"; + let body = if doc.is_empty() { + String::new() + } else { + doc.split('\n').join("\n * ") + }; + format!(r#"{header}{body}{footer}"#) } fn is_error_enum(entry: &ScSpecEntry) -> bool { matches!(entry, ScSpecEntry::UdtErrorEnumV0(_)) } -fn method_options(return_type: &String) -> String { - format!( - r#"{{ +const METHOD_OPTIONS: &str = r"{ /** * The fee to pay for the transaction. Default: 100. */ - fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `{return_type}`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {{@link SorobanClient.SorobanRpc.GetTransactionResponse}} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {{@link SorobanClient.SorobanRpc.SendTransactionResponse}} more quickly, before the transaction has time to be included in the ledger. Default: 10. - */ - secondsToWait?: number - }}"# - ) -} + fee?: number, + }"; fn jsify_name(name: &String) -> String { name.to_lower_camel_case() } +pub fn entry_to_parser(entry: &Entry) -> Option<(String, String)> { + if let Entry::Function { name, outputs, .. } = entry { + let mut is_result = false; + let mut return_type: String; + if outputs.is_empty() { + return_type = "void".to_owned(); + } else if outputs.len() == 1 { + return_type = type_to_ts(&outputs[0]); + is_result = return_type.starts_with("Result<"); + } else { + return_type = format!("readonly [{}]", outputs.iter().map(type_to_ts).join(", ")); + }; + + if is_result { + return_type = return_type + .strip_prefix("Result<") + .unwrap() + .strip_suffix('>') + .unwrap() + .to_owned(); + return_type = format!("Ok<{return_type}> | Err"); + } + + let output = outputs + .get(0) + .map(|_| format!("this.spec.funcResToNative(\"{name}\", result)")) + .unwrap_or_default(); + let parse_result_xdr = if return_type == "void" { + r"() => {}".to_owned() + } else if is_result { + format!( + r"(result: XDR_BASE64 | Err): {return_type} => {{ + if (result instanceof Err) return result + return new Ok({output}) + }}" + ) + } else { + format!(r"(result: XDR_BASE64): {return_type} => {output}") + }; + let js_name = jsify_name(name); + Some((js_name, parse_result_xdr)) + } else { + None + } +} + #[allow(clippy::too_many_lines)] -pub fn entry_to_ts(entry: &Entry) -> String { +pub fn entry_to_method(entry: &Entry) -> String { match entry { Entry::Function { - doc, - name, - inputs, - outputs, + doc, name, inputs, .. } => { let input_vals = inputs.iter().map(func_input_to_arg_name).join(", "); let input = (!inputs.is_empty()) @@ -159,81 +219,30 @@ pub fn entry_to_ts(entry: &Entry) -> String { ) }) .unwrap_or_default(); - let mut is_result = false; - let mut return_type: String; - if outputs.is_empty() { - return_type = "void".to_owned(); - } else if outputs.len() == 1 { - return_type = type_to_ts(&outputs[0]); - is_result = return_type.starts_with("Result<"); - } else { - return_type = format!("readonly [{}]", outputs.iter().map(type_to_ts).join(", ")); - }; - let ts_doc = doc_to_ts_doc(doc); - - if is_result { - return_type = return_type - .strip_prefix("Result<") - .unwrap() - .strip_suffix('>') - .unwrap() - .to_owned(); - return_type = format!("Ok<{return_type}> | Err | undefined"); - } - - let mut output = outputs - .get(0) - .map(|_| format!("this.spec.funcResToNative(\"{name}\", xdr)")) - .unwrap_or_default(); - if is_result { - output = format!("new Ok({output})"); - } - if return_type != "void" { - output = format!(r#"return {output};"#); - }; - let parse_result_xdr = if return_type == "void" { - r#"parseResultXdr: () => {}"#.to_owned() - } else { - format!( - r#"parseResultXdr: (xdr): {return_type} => {{ - {output} - }}"# - ) - }; - let js_name = jsify_name(name); - let options = method_options(&return_type); + let ts_doc = doc_to_ts_doc(doc, Some(name)); + let (js_name, _) = entry_to_parser(entry).unwrap(); let parsed_scvals = inputs.iter().map(parse_arg_to_scval).join(", "); let args = format!("args: this.spec.funcArgsToScVals(\"{name}\", {{{parsed_scvals}}}),"); - let mut body = format!( - r#"return await invoke({{ + let body = format!( + r#"return await AssembledTransaction.fromSimulation({{ method: '{name}', {args} ...options, ...this.options, - {parse_result_xdr}, + errorTypes: Errors, + parseResultXdr: this.parsers['{js_name}'], }});"# ); - if is_result { - body = format!( - r#"try {{ - {body} - }} catch (e) {{ - let err = parseError(e.toString()); - if (err) return err; - throw e; - }}"# - ); - } format!( - r#"{ts_doc}{js_name} = async ({input}options: {options} = {{}}) => {{ - {body} + r#" {ts_doc} {js_name} = async ({input}options: {METHOD_OPTIONS} = {{}}) => {{ + {body} }} "# ) } Entry::Struct { doc, name, fields } => { - let docs = doc_to_ts_doc(doc); + let docs = doc_to_ts_doc(doc, None); let fields = fields.iter().map(field_to_ts).join("\n "); format!( r#"{docs}export interface {name} {{ @@ -244,13 +253,13 @@ pub fn entry_to_ts(entry: &Entry) -> String { } Entry::TupleStruct { doc, name, fields } => { - let docs = doc_to_ts_doc(doc); + let docs = doc_to_ts_doc(doc, None); let fields = fields.iter().map(type_to_ts).join(", "); format!("{docs}export type {name} = readonly [{fields}];") } Entry::Union { name, doc, cases } => { - let doc = doc_to_ts_doc(doc); + let doc = doc_to_ts_doc(doc, None); let cases = cases.iter().map(case_to_ts).join(" | "); format!( @@ -259,7 +268,7 @@ pub fn entry_to_ts(entry: &Entry) -> String { ) } Entry::Enum { doc, name, cases } => { - let doc = doc_to_ts_doc(doc); + let doc = doc_to_ts_doc(doc, None); let cases = cases.iter().map(enum_case_to_ts).join("\n "); let name = (name == "Error") .then(|| format!("{name}s")) @@ -272,13 +281,13 @@ pub fn entry_to_ts(entry: &Entry) -> String { ) } Entry::ErrorEnum { doc, cases, .. } => { - let doc = doc_to_ts_doc(doc); + let doc = doc_to_ts_doc(doc, None); let cases = cases .iter() .map(|c| format!("{}: {{message:\"{}\"}}", c.value, c.doc)) .join(",\n "); format!( - r#"{doc}const Errors = {{ + r#"{doc}export const Errors = {{ {cases} }}"# ) @@ -303,7 +312,7 @@ fn case_to_ts(case: &types::UnionCase) -> String { fn field_to_ts(field: &types::StructField) -> String { let types::StructField { doc, name, value } = field; - let doc = doc_to_ts_doc(doc); + let doc = doc_to_ts_doc(doc, None); let type_ = type_to_ts(value); format!("{doc}{name}: {type_};") } diff --git a/cmd/crates/soroban-spec-typescript/src/project_template/package.json b/cmd/crates/soroban-spec-typescript/src/project_template/package.json index d75b89c74..3c6b89642 100644 --- a/cmd/crates/soroban-spec-typescript/src/project_template/package.json +++ b/cmd/crates/soroban-spec-typescript/src/project_template/package.json @@ -2,9 +2,9 @@ "version": "0.0.0", "name": "INSERT_CONTRACT_NAME_HERE", "dependencies": { - "@stellar/freighter-api": "1.5.1", + "@stellar/freighter-api": "1.7.1", "buffer": "6.0.3", - "soroban-client": "1.0.0-beta.3" + "stellar-sdk": "11.1.0" }, "scripts": { "build": "node ./scripts/build.mjs" diff --git a/cmd/crates/soroban-spec-typescript/src/project_template/src/assembled-tx.ts b/cmd/crates/soroban-spec-typescript/src/project_template/src/assembled-tx.ts new file mode 100644 index 000000000..58476807f --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/src/project_template/src/assembled-tx.ts @@ -0,0 +1,664 @@ +import { + Account, + Address, + Contract, + Operation, + SorobanRpc, + StrKey, + TimeoutInfinite, + TransactionBuilder, + authorizeEntry, + hash, + nativeToScVal, + xdr, + BASE_FEE, +} from "stellar-sdk"; +import type { Memo, MemoType, Transaction } from "stellar-sdk"; +import { Buffer } from "buffer"; +import type { + ClassOptions, + MethodOptions, + Wallet, + XDR_BASE64, +} from "./method-options.js"; + +export type Tx = Transaction, Operation[]> + +export class ExpiredStateError extends Error { } +export class NeedsMoreSignaturesError extends Error { } +export class WalletDisconnectedError extends Error { } +export class SendResultOnlyError extends Error { } +export class SendFailedError extends Error { } +export class NoUnsignedNonInvokerAuthEntriesError extends Error { } + +type SendTx = SorobanRpc.Api.SendTransactionResponse; +type GetTx = SorobanRpc.Api.GetTransactionResponse; + +export type u32 = number; +export type i32 = number; +export type u64 = bigint; +export type i64 = bigint; +export type u128 = bigint; +export type i128 = bigint; +export type u256 = bigint; +export type i256 = bigint; +export type Option = T | undefined; +export type Typepoint = bigint; +export type Duration = bigint; +export {Address}; + +/// Error interface containing the error message +export interface Error_ { message: string }; + +export interface Result { + unwrap(): T, + unwrapErr(): E, + isOk(): boolean, + isErr(): boolean, +}; + +export class Ok implements Result { + constructor(readonly value: T) { } + unwrapErr(): E { + throw new Error('No error'); + } + unwrap(): T { + return this.value; + } + + isOk(): boolean { + return true; + } + + isErr(): boolean { + return !this.isOk() + } +} + +export class Err implements Result { + constructor(readonly error: E) { } + unwrapErr(): E { + return this.error; + } + unwrap(): never { + throw new Error(this.error.message); + } + + isOk(): boolean { + return false; + } + + isErr(): boolean { + return !this.isOk() + } +} + +export const contractErrorPattern = /Error\(Contract, #(\d+)\)/; + +type AssembledTransactionOptions = MethodOptions & + ClassOptions & { + method: string; + args?: any[]; + parseResultXdr: (xdr: string | xdr.ScVal | Err) => T; + }; + +export const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF" + +export class AssembledTransaction { + public raw: Tx + private simulation?: SorobanRpc.Api.SimulateTransactionResponse + private simulationResult?: SorobanRpc.Api.SimulateHostFunctionResult + private simulationTransactionData?: xdr.SorobanTransactionData + private server: SorobanRpc.Server + + toJSON() { + return JSON.stringify({ + method: this.options.method, + tx: this.raw?.toXDR(), + simulationResult: { + auth: this.simulationData.result.auth.map(a => a.toXDR('base64')), + retval: this.simulationData.result.retval.toXDR('base64'), + }, + simulationTransactionData: this.simulationData.transactionData.toXDR('base64'), + }) + } + + static fromJSON( + options: Omit, 'args'>, + { tx, simulationResult, simulationTransactionData }: + { + tx: XDR_BASE64, + simulationResult: { + auth: XDR_BASE64[], + retval: XDR_BASE64, + }, + simulationTransactionData: XDR_BASE64, + } + ): AssembledTransaction { + const txn = new AssembledTransaction(options) + txn.raw = TransactionBuilder.fromXDR(tx, options.networkPassphrase) as Tx + txn.simulationResult = { + auth: simulationResult.auth.map(a => xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64')), + retval: xdr.ScVal.fromXDR(simulationResult.retval, 'base64'), + } + txn.simulationTransactionData = xdr.SorobanTransactionData.fromXDR(simulationTransactionData, 'base64') + return txn + } + + private constructor(public options: AssembledTransactionOptions) { + this.server = new SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + } + + static async fromSimulation(options: AssembledTransactionOptions): Promise> { + const tx = new AssembledTransaction(options) + const contract = new Contract(options.contractId); + + tx.raw = new TransactionBuilder(await tx.getAccount(), { + fee: options.fee?.toString(10) ?? BASE_FEE, + networkPassphrase: options.networkPassphrase, + }) + .addOperation(contract.call(options.method, ...(options.args ?? []))) + .setTimeout(TimeoutInfinite) + .build(); + + return await tx.simulate() + } + + simulate = async (): Promise => { + if (!this.raw) throw new Error('Transaction has not yet been assembled') + this.simulation = await this.server.simulateTransaction(this.raw); + + if (SorobanRpc.Api.isSimulationSuccess(this.simulation)) { + this.raw = SorobanRpc.assembleTransaction( + this.raw, + this.simulation + ).build() + } + + return this + } + + get simulationData(): { + result: SorobanRpc.Api.SimulateHostFunctionResult + transactionData: xdr.SorobanTransactionData + } { + if (this.simulationResult && this.simulationTransactionData) { + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData, + } + } + // else, we know we just did the simulation on this machine + const simulation = this.simulation! + if (SorobanRpc.Api.isSimulationError(simulation)) { + throw new Error(`Transaction simulation failed: "${simulation.error}"`) + } + + if (SorobanRpc.Api.isSimulationRestore(simulation)) { + throw new ExpiredStateError(`You need to restore some contract state before you can invoke this method. ${JSON.stringify(simulation, null, 2)}`) + } + + if (!simulation.result) { + throw new Error(`Expected an invocation simulation, but got no 'result' field. Simulation: ${JSON.stringify(simulation, null, 2)}`) + } + + // add to object for serialization & deserialization + this.simulationResult = simulation.result + this.simulationTransactionData = simulation.transactionData.build() + + return { + result: this.simulationResult, + transactionData: this.simulationTransactionData!, + } + } + + get result(): T { + try { + return this.options.parseResultXdr(this.simulationData.result.retval) + } catch (e) { + let err = this.parseError(e.toString()) + if (err) return err as T + throw e + } + } + + parseError(errorMessage: string): Err | undefined { + if (!this.options.errorTypes) return + const match = errorMessage.match(contractErrorPattern) + if (!match) return + let i = parseInt(match[1], 10) + let err = this.options.errorTypes[i] + if (err) return new Err(err) + } + + getWallet = async (): Promise => { + return this.options.wallet ?? (await import("@stellar/freighter-api")).default + } + + getPublicKey = async (): Promise => { + const wallet = await this.getWallet() + if (await wallet.isConnected() && await wallet.isAllowed()) { + return (await wallet.getUserInfo()).publicKey + } + } + + /** + * Get account details from the Soroban network for the publicKey currently + * selected in user's wallet. If not connected to Freighter, use placeholder + * null account. + */ + getAccount = async (): Promise => { + const publicKey = await this.getPublicKey() + return publicKey + ? await this.server.getAccount(publicKey) + : new Account(NULL_ACCOUNT, "0") + } + + /** + * Sign the transaction with the `wallet` (default Freighter), then send to + * the network and return a `SentTransaction` that keeps track of all the + * attempts to send and fetch the transaction from the network. + */ + signAndSend = async ({ secondsToWait = 10, force = false }: { + /** + * Wait `secondsToWait` seconds (default: 10) for both the transaction to SEND successfully (will keep trying if the server returns `TRY_AGAIN_LATER`), as well as for the transaction to COMPLETE (will keep checking if the server returns `PENDING`). + */ + secondsToWait?: number + /** + * If `true`, sign and send the transaction even if it is a read call. + */ + force?: boolean + } = {}): Promise> => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated') + } + + if (!force && this.isReadCall) { + throw new Error('This is a read call. It requires no signature or sending. Use `force: true` to sign and send anyway.') + } + + if (!await this.hasRealInvoker()) { + throw new WalletDisconnectedError('Wallet is not connected') + } + + if (this.raw.source !== (await this.getAccount()).accountId()) { + throw new Error(`You must submit the transaction with the account that originally created it. Please switch to the wallet with "${this.raw.source}" as its public key.`) + } + + if ((await this.needsNonInvokerSigningBy()).length) { + throw new NeedsMoreSignaturesError( + 'Transaction requires more signatures. See `needsNonInvokerSigningBy` for details.' + ) + } + + return await SentTransaction.init(this.options, this, secondsToWait); + } + + getStorageExpiration = async () => { + const entryRes = await this.server.getLedgerEntries( + new Contract(this.options.contractId).getFootprint() + ) + if ( + !entryRes.entries || + !entryRes.entries.length || + !entryRes.entries[0].liveUntilLedgerSeq + ) throw new Error('failed to get ledger entry') + return entryRes.entries[0].liveUntilLedgerSeq + } + + /** + * Get a list of accounts, other than the invoker of the simulation, that + * need to sign auth entries in this transaction. + * + * Soroban allows multiple people to sign a transaction. Someone needs to + * sign the final transaction envelope; this person/account is called the + * _invoker_, or _source_. Other accounts might need to sign individual auth + * entries in the transaction, if they're not also the invoker. + * + * This function returns a list of accounts that need to sign auth entries, + * assuming that the same invoker/source account will sign the final + * transaction envelope as signed the initial simulation. + * + * One at a time, for each public key in this array, you will need to + * serialize this transaction with `toJSON`, send to the owner of that key, + * deserialize the transaction with `txFromJson`, and call + * {@link signAuthEntries}. Then re-serialize and send to the next account + * in this list. + */ + needsNonInvokerSigningBy = async ({ + includeAlreadySigned = false, + }: { + /** + * Whether or not to include auth entries that have already been signed. Default: false + */ + includeAlreadySigned?: boolean + } = {}): Promise => { + if (!this.raw) { + throw new Error('Transaction has not yet been simulated') + } + + // We expect that any transaction constructed by these libraries has a + // single operation, which is an InvokeHostFunction operation. The host + // function being invoked is the contract method call. + if (!("operations" in this.raw)) { + throw new Error( + `Unexpected Transaction type; no operations: ${JSON.stringify(this.raw) + }` + ) + } + const rawInvokeHostFunctionOp = this.raw + .operations[0] as Operation.InvokeHostFunction + + return [...new Set((rawInvokeHostFunctionOp.auth ?? []).filter(entry => + entry.credentials().switch() === + xdr.SorobanCredentialsType.sorobanCredentialsAddress() && + ( + includeAlreadySigned || + entry.credentials().address().signature().switch().name === 'scvVoid' + ) + ).map(entry => StrKey.encodeEd25519PublicKey( + entry.credentials().address().address().accountId().ed25519() + )))] + } + + preImageFor( + entry: xdr.SorobanAuthorizationEntry, + signatureExpirationLedger: number + ): xdr.HashIdPreimage { + const addrAuth = entry.credentials().address() + return xdr.HashIdPreimage.envelopeTypeSorobanAuthorization( + new xdr.HashIdPreimageSorobanAuthorization({ + networkId: hash(Buffer.from(this.options.networkPassphrase)), + nonce: addrAuth.nonce(), + invocation: entry.rootInvocation(), + signatureExpirationLedger, + }), + ) + } + + /** + * If {@link needsNonInvokerSigningBy} returns a non-empty list, you can serialize + * the transaction with `toJSON`, send it to the owner of one of the public keys + * in the map, deserialize with `txFromJSON`, and call this method on their + * machine. Internally, this will use `signAuthEntry` function from connected + * `wallet` for each. + * + * Then, re-serialize the transaction and either send to the next + * `needsNonInvokerSigningBy` owner, or send it back to the original account + * who simulated the transaction so they can {@link sign} the transaction + * envelope and {@link send} it to the network. + * + * Sending to all `needsNonInvokerSigningBy` owners in parallel is not currently + * supported! + */ + signAuthEntries = async ( + /** + * When to set each auth entry to expire. Could be any number of blocks in + * the future. Can be supplied as a promise or a raw number. Default: + * contract's current `persistent` storage expiration date/ledger + * number/block. + */ + expiration: number | Promise = this.getStorageExpiration() + ): Promise => { + if (!this.raw) throw new Error('Transaction has not yet been assembled or simulated') + const needsNonInvokerSigningBy = await this.needsNonInvokerSigningBy() + + if (!needsNonInvokerSigningBy) throw new NoUnsignedNonInvokerAuthEntriesError('No unsigned non-invoker auth entries; maybe you already signed?') + const publicKey = await this.getPublicKey() + if (!publicKey) throw new Error('Could not get public key from wallet; maybe Freighter is not signed in?') + if (needsNonInvokerSigningBy.indexOf(publicKey) === -1) throw new Error(`No auth entries for public key "${publicKey}"`) + const wallet = await this.getWallet() + + const rawInvokeHostFunctionOp = this.raw + .operations[0] as Operation.InvokeHostFunction + + const authEntries = rawInvokeHostFunctionOp.auth ?? [] + + for (const [i, entry] of authEntries.entries()) { + if ( + entry.credentials().switch() !== + xdr.SorobanCredentialsType.sorobanCredentialsAddress() + ) { + // if the invoker/source account, then the entry doesn't need explicit + // signature, since the tx envelope is already signed by the source + // account, so only check for sorobanCredentialsAddress + continue + } + const pk = StrKey.encodeEd25519PublicKey( + entry.credentials().address().address().accountId().ed25519() + ) + + // this auth entry needs to be signed by a different account + // (or maybe already was!) + if (pk !== publicKey) continue + + authEntries[i] = await authorizeEntry( + entry, + async preimage => Buffer.from( + await wallet.signAuthEntry(preimage.toXDR('base64')), + 'base64' + ), + await expiration, + this.options.networkPassphrase + ) + } + } + + get isReadCall(): boolean { + const authsCount = this.simulationData.result.auth.length; + const writeLength = this.simulationData.transactionData.resources().footprint().readWrite().length + return (authsCount === 0) && (writeLength === 0); + } + + hasRealInvoker = async (): Promise => { + const account = await this.getAccount() + return account.accountId() !== NULL_ACCOUNT + } +} + +/** + * A transaction that has been sent to the Soroban network. This happens in two steps: + * + * 1. `sendTransaction`: initial submission of the transaction to the network. + * This step can run into problems, and will be retried with exponential + * backoff if it does. See all attempts in `sendTransactionResponseAll` and the + * most recent attempt in `sendTransactionResponse`. + * 2. `getTransaction`: once the transaction has been submitted to the network + * successfully, you need to wait for it to finalize to get the results of the + * transaction. This step can also run into problems, and will be retried with + * exponential backoff if it does. See all attempts in + * `getTransactionResponseAll` and the most recent attempt in + * `getTransactionResponse`. + */ +class SentTransaction { + public server: SorobanRpc.Server + public signed: Tx + public sendTransactionResponse?: SendTx + public sendTransactionResponseAll?: SendTx[] + public getTransactionResponse?: GetTx + public getTransactionResponseAll?: GetTx[] + + constructor(public options: AssembledTransactionOptions, public assembled: AssembledTransaction) { + this.server = new SorobanRpc.Server(this.options.rpcUrl, { + allowHttp: this.options.rpcUrl.startsWith("http://"), + }); + this.assembled = assembled + } + + static init = async ( + options: AssembledTransactionOptions, + assembled: AssembledTransaction, + secondsToWait: number = 10 + ): Promise> => { + const tx = new SentTransaction(options, assembled) + return await tx.send(secondsToWait) + } + + private send = async (secondsToWait: number = 10): Promise => { + const wallet = await this.assembled.getWallet() + + this.sendTransactionResponseAll = await withExponentialBackoff( + async (previousFailure) => { + if (previousFailure) { + // Increment transaction sequence number and resimulate before trying again + + // Soroban transaction can only have 1 operation + const op = this.assembled.raw.operations[0] as Operation.InvokeHostFunction; + + this.assembled.raw = new TransactionBuilder(await this.assembled.getAccount(), { + fee: this.assembled.raw.fee, + networkPassphrase: this.options.networkPassphrase, + }) + .setTimeout(TimeoutInfinite) + .addOperation( + Operation.invokeHostFunction({ ...op, auth: op.auth ?? [] }), + ) + .build() + + await this.assembled.simulate() + } + + const signature = await wallet.signTransaction(this.assembled.raw.toXDR(), { + networkPassphrase: this.options.networkPassphrase, + }); + + this.signed = TransactionBuilder.fromXDR( + signature, + this.options.networkPassphrase + ) as Tx + + return this.server.sendTransaction(this.signed) + }, + resp => resp.status !== "PENDING", + secondsToWait + ) + + this.sendTransactionResponse = this.sendTransactionResponseAll[this.sendTransactionResponseAll.length - 1] + + if (this.sendTransactionResponse.status !== "PENDING") { + throw new Error( + `Tried to resubmit transaction for ${secondsToWait + } seconds, but it's still failing. ` + + `All attempts: ${JSON.stringify( + this.sendTransactionResponseAll, + null, + 2 + )}` + ); + } + + const { hash } = this.sendTransactionResponse + + this.getTransactionResponseAll = await withExponentialBackoff( + () => this.server.getTransaction(hash), + resp => resp.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND, + secondsToWait + ) + + this.getTransactionResponse = this.getTransactionResponseAll[this.getTransactionResponseAll.length - 1] + if (this.getTransactionResponse.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND) { + console.error( + `Waited ${secondsToWait + } seconds for transaction to complete, but it did not. ` + + `Returning anyway. Check the transaction status manually. ` + + `Sent transaction: ${JSON.stringify( + this.sendTransactionResponse, + null, + 2 + )}\n` + + `All attempts to get the result: ${JSON.stringify( + this.getTransactionResponseAll, + null, + 2 + )}` + ); + } + + return this; + } + + get result(): T { + // 1. check if transaction was submitted and awaited with `getTransaction` + if ( + "getTransactionResponse" in this && + this.getTransactionResponse + ) { + // getTransactionResponse has a `returnValue` field unless it failed + if ("returnValue" in this.getTransactionResponse) { + return this.options.parseResultXdr(this.getTransactionResponse.returnValue!) + } + + // if "returnValue" not present, the transaction failed; return without parsing the result + throw new Error("Transaction failed! Cannot parse result.") + } + + // 2. otherwise, maybe it was merely sent with `sendTransaction` + if (this.sendTransactionResponse) { + const errorResult = this.sendTransactionResponse.errorResult?.result() + if (errorResult) { + throw new SendFailedError( + `Transaction simulation looked correct, but attempting to send the transaction failed. Check \`simulation\` and \`sendTransactionResponseAll\` to troubleshoot. Decoded \`sendTransactionResponse.errorResultXdr\`: ${errorResult}` + ) + } + throw new SendResultOnlyError( + `Transaction was sent to the network, but not yet awaited. No result to show. Await transaction completion with \`getTransaction(sendTransactionResponse.hash)\`` + ) + } + + // 3. finally, if neither of those are present, throw an error + throw new Error(`Sending transaction failed: ${JSON.stringify(this.assembled)}`) + } +} + +/** + * Keep calling a `fn` for `secondsToWait` seconds, if `keepWaitingIf` is true. + * Returns an array of all attempts to call the function. + */ +async function withExponentialBackoff( + fn: (previousFailure?: T) => Promise, + keepWaitingIf: (result: T) => boolean, + secondsToWait: number, + exponentialFactor = 1.5, + verbose = false, +): Promise { + const attempts: T[] = [] + + let count = 0 + attempts.push(await fn()) + if (!keepWaitingIf(attempts[attempts.length - 1])) return attempts + + const waitUntil = new Date(Date.now() + secondsToWait * 1000).valueOf() + let waitTime = 1000 + let totalWaitTime = waitTime + + while (Date.now() < waitUntil && keepWaitingIf(attempts[attempts.length - 1])) { + count++ + // Wait a beat + if (verbose) { + console.info(`Waiting ${waitTime}ms before trying again (bringing the total wait time to ${totalWaitTime}ms so far, of total ${secondsToWait * 1000}ms)`) + } + await new Promise(res => setTimeout(res, waitTime)) + // Exponential backoff + waitTime = waitTime * exponentialFactor; + if (new Date(Date.now() + waitTime).valueOf() > waitUntil) { + waitTime = waitUntil - Date.now() + if (verbose) { + console.info(`was gonna wait too long; new waitTime: ${waitTime}ms`) + } + } + totalWaitTime = waitTime + totalWaitTime + // Try again + attempts.push(await fn(attempts[attempts.length - 1])) + if (verbose && keepWaitingIf(attempts[attempts.length - 1])) { + console.info( + `${count}. Called ${fn}; ${attempts.length + } prev attempts. Most recent: ${JSON.stringify(attempts[attempts.length - 1], null, 2) + }` + ) + } + } + + return attempts +} diff --git a/cmd/crates/soroban-spec-typescript/src/project_template/src/convert.ts b/cmd/crates/soroban-spec-typescript/src/project_template/src/convert.ts deleted file mode 100644 index 12d7044aa..000000000 --- a/cmd/crates/soroban-spec-typescript/src/project_template/src/convert.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { - xdr, - Address, - nativeToScVal, - scValToBigInt, - ScInt -} from 'soroban-client'; - -export function strToScVal(base64Xdr: string): xdr.ScVal { - return xdr.ScVal.fromXDR(base64Xdr, 'base64'); -} - -export function scValStrToJs(base64Xdr: string): T { - return scValToJs(strToScVal(base64Xdr)); -} - -export function scValToJs(val: xdr.ScVal): T { - switch (val?.switch()) { - case xdr.ScValType.scvBool(): { - return val.b() as unknown as T; - } - case xdr.ScValType.scvVoid(): - case undefined: { - return 0 as unknown as T; - } - case xdr.ScValType.scvU32(): { - return val.u32() as unknown as T; - } - case xdr.ScValType.scvI32(): { - return val.i32() as unknown as T; - } - case xdr.ScValType.scvU64(): - case xdr.ScValType.scvI64(): - case xdr.ScValType.scvU128(): - case xdr.ScValType.scvI128(): - case xdr.ScValType.scvU256(): - case xdr.ScValType.scvI256(): { - return scValToBigInt(val) as unknown as T; - } - case xdr.ScValType.scvAddress(): { - return Address.fromScVal(val).toString() as unknown as T; - } - case xdr.ScValType.scvString(): { - return val.str().toString() as unknown as T; - } - case xdr.ScValType.scvSymbol(): { - return val.sym().toString() as unknown as T; - } - case xdr.ScValType.scvBytes(): { - return val.bytes() as unknown as T; - } - case xdr.ScValType.scvVec(): { - type Element = ElementType; - return val.vec()!.map(v => scValToJs(v)) as unknown as T; - } - case xdr.ScValType.scvMap(): { - type Key = KeyType; - type Value = ValueType; - let res: any = {}; - val.map()!.forEach((e) => { - let key = scValToJs(e.key()); - let value; - let v: xdr.ScVal = e.val(); - // For now we assume second level maps are real maps. Not perfect but better. - switch (v?.switch()) { - case xdr.ScValType.scvMap(): { - let inner_map = new Map() as Map; - v.map()!.forEach((e) => { - let key = scValToJs(e.key()); - let value = scValToJs(e.val()); - inner_map.set(key, value); - }); - value = inner_map; - break; - } - default: { - value = scValToJs(e.val()); - } - } - //@ts-ignore - res[key as Key] = value as Value; - }); - return res as unknown as T - } - case xdr.ScValType.scvContractInstance(): - case xdr.ScValType.scvLedgerKeyNonce(): - case xdr.ScValType.scvTimepoint(): - case xdr.ScValType.scvDuration(): - return val.value() as unknown as T; - // TODO: Add this case when merged - // case xdr.ScValType.scvError(): - default: { - throw new Error(`type not implemented yet: ${val?.switch().name}`); - } - }; -} - -type ElementType = T extends Array ? U : never; -type KeyType = T extends Map ? K : never; -type ValueType = T extends Map ? V : never; - -export function addressToScVal(addr: string): xdr.ScVal { - return nativeToScVal(addr, { type: 'address' } as any /* bug workaround */); -} - -export function i128ToScVal(i: bigint): xdr.ScVal { - return new ScInt(i).toI128(); -} - -export function u128ToScVal(i: bigint): xdr.ScVal { - return new ScInt(i).toU128(); -} 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 2b7c15d24..271f25e63 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 @@ -1,90 +1,27 @@ -import * as SorobanClient from 'soroban-client'; -import { ContractSpec, Address } from 'soroban-client'; +import { ContractSpec, Address } from 'stellar-sdk'; import { Buffer } from "buffer"; -import { invoke } from './invoke.js'; -import type { ResponseTypes, Wallet, ClassOptions } from './method-options.js' - -export * from './invoke.js' -export * from './method-options.js' - -export type u32 = number; -export type i32 = number; -export type u64 = bigint; -export type i64 = bigint; -export type u128 = bigint; -export type i128 = bigint; -export type u256 = bigint; -export type i256 = bigint; -export type Option = T | undefined; -export type Typepoint = bigint; -export type Duration = bigint; -export {Address}; - -/// Error interface containing the error message -export interface Error_ { message: string }; - -export interface Result { - unwrap(): T, - unwrapErr(): E, - isOk(): boolean, - isErr(): boolean, -}; - -export class Ok implements Result { - constructor(readonly value: T) { } - unwrapErr(): E { - throw new Error('No error'); - } - unwrap(): T { - return this.value; - } - - isOk(): boolean { - return true; - } - - isErr(): boolean { - return !this.isOk() - } -} - -export class Err implements Result { - constructor(readonly error: E) { } - unwrapErr(): E { - return this.error; - } - unwrap(): never { - throw new Error(this.error.message); - } - - isOk(): boolean { - return false; - } - - isErr(): boolean { - return !this.isOk() - } -} +import { AssembledTransaction, Ok, Err } from './assembled-tx.js'; +import type { + u32, + i32, + u64, + i64, + u128, + i128, + u256, + i256, + Option, + Typepoint, + Duration, + Error_, + Result, +} from './assembled-tx.js'; +import type { ClassOptions, XDR_BASE64 } from './method-options.js'; + +export * from './assembled-tx.js'; +export * from './method-options.js'; if (typeof window !== 'undefined') { //@ts-ignore Buffer exists window.Buffer = window.Buffer || Buffer; } - -const regex = /Error\(Contract, #(\d+)\)/; - -function parseError(message: string): Err | undefined { - const match = message.match(regex); - if (!match) { - return undefined; - } - if (Errors === undefined) { - return undefined; - } - let i = parseInt(match[1], 10); - let err = Errors[i]; - if (err) { - return new Err(err); - } - return undefined; -} \ No newline at end of file diff --git a/cmd/crates/soroban-spec-typescript/src/project_template/src/invoke.ts b/cmd/crates/soroban-spec-typescript/src/project_template/src/invoke.ts deleted file mode 100644 index 27a85c0ac..000000000 --- a/cmd/crates/soroban-spec-typescript/src/project_template/src/invoke.ts +++ /dev/null @@ -1,259 +0,0 @@ -import * as SorobanClient from "soroban-client"; -import { SorobanRpc } from "soroban-client"; -import type { - Account, - Memo, - MemoType, - Operation, - Transaction, - xdr, -} from "soroban-client"; -import type { - ClassOptions, - MethodOptions, - ResponseTypes, - Wallet, -} from "./method-options.js"; - -export type Tx = Transaction, Operation[]>; - -export class SendFailedError extends Error { } -/** - * Get account details from the Soroban network for the publicKey currently - * selected in Freighter. If not connected to Freighter, return null. - */ -async function getAccount( - wallet: Wallet, - server: SorobanClient.Server -): Promise { - if (!(await wallet.isConnected()) || !(await wallet.isAllowed())) { - return null; - } - const { publicKey } = await wallet.getUserInfo(); - if (!publicKey) { - return null; - } - return await server.getAccount(publicKey); -} - -export class NotImplementedError extends Error {} - -type Simulation = SorobanRpc.SimulateTransactionResponse; -type SendTx = SorobanRpc.SendTransactionResponse; -type GetTx = SorobanRpc.GetTransactionResponse; - -// defined this way so typeahead shows full union, not named alias -let someRpcResponse: Simulation | SendTx | GetTx; -type SomeRpcResponse = typeof someRpcResponse; - -type InvokeArgs = MethodOptions & - ClassOptions & { - method: string; - args?: any[]; - parseResultXdr: (xdr: string | xdr.ScVal) => T; - }; - -/** - * Invoke a method on the test_custom_types contract. - * - * Uses Freighter to determine the current user and if necessary sign the transaction. - * - * @returns {T}, by default, the parsed XDR from either the simulation or the full transaction. If `simulateOnly` or `fullRpcResponse` are true, returns either the full simulation or the result of sending/getting the transaction to/from the ledger. - */ -export async function invoke( - args: InvokeArgs -): Promise< - R extends undefined - ? T - : R extends "simulated" - ? Simulation - : R extends "full" - ? SomeRpcResponse - : T ->; -export async function invoke({ - method, - args = [], - fee = 100, - responseType, - parseResultXdr, - secondsToWait = 10, - rpcUrl, - networkPassphrase, - contractId, - wallet, -}: InvokeArgs): Promise { - wallet = wallet ?? (await import("@stellar/freighter-api")).default; - let parse = parseResultXdr; - const server = new SorobanClient.Server(rpcUrl, { - allowHttp: rpcUrl.startsWith("http://"), - }); - const walletAccount = await getAccount(wallet, server); - - // use a placeholder null account if not yet connected to Freighter so that view calls can still work - const account = - walletAccount ?? - new SorobanClient.Account( - "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", - "0" - ); - - const contract = new SorobanClient.Contract(contractId); - - let tx = new SorobanClient.TransactionBuilder(account, { - fee: fee.toString(10), - networkPassphrase, - }) - .addOperation(contract.call(method, ...args)) - .setTimeout(SorobanClient.TimeoutInfinite) - .build(); - const simulated = await server.simulateTransaction(tx); - - if (SorobanRpc.isSimulationError(simulated)) { - throw new Error(simulated.error); - } else if (responseType === "simulated") { - return simulated; - } else if (!simulated.result) { - throw new Error(`invalid simulation: no result in ${simulated}`); - } - - let authsCount = simulated.result.auth.length; - const writeLength = simulated.transactionData.getReadWrite().length; - const isViewCall = (authsCount === 0) && (writeLength === 0); - - if (isViewCall) { - if (responseType === "full") { - return simulated; - } - - return parseResultXdr(simulated.result.retval); - } - - if (authsCount > 1) { - throw new NotImplementedError("Multiple auths not yet supported"); - } - if (authsCount === 1) { - // TODO: figure out how to fix with new SorobanClient - // const auth = SorobanClient.xdr.SorobanAuthorizationEntry.fromXDR(auths![0]!, 'base64') - // if (auth.addressWithNonce() !== undefined) { - // throw new NotImplementedError( - // `This transaction needs to be signed by ${auth.addressWithNonce() - // }; Not yet supported` - // ) - // } - } - - if (!walletAccount) { - throw new Error("Not connected to Freighter"); - } - - tx = await signTx( - wallet, - SorobanClient.assembleTransaction(tx, networkPassphrase, simulated).build(), - networkPassphrase - ); - - const raw = await sendTx(tx, secondsToWait, server); - if (responseType === "full") { - return raw; - } - - // if `sendTx` awaited the inclusion of the tx in the ledger, it used - // `getTransaction`, which has a `returnValue` field - if ("returnValue" in raw) return parse(raw.returnValue!); - - // otherwise, it returned the result of `sendTransaction` - if ("errorResult" in raw) { - throw new SendFailedError( - `errorResult.result(): ${JSON.stringify(raw.errorResult?.result())}` - ) - } - - // if neither of these are present, something went wrong - console.error("Don't know how to parse result! Returning full RPC response."); - return raw; -} - -/** - * Sign a transaction with Freighter and return the fully-reconstructed - * transaction ready to send with {@link sendTx}. - * - * If you need to construct a transaction yourself rather than using `invoke` - * or one of the exported contract methods, you may want to use this function - * to sign the transaction with Freighter. - */ -export async function signTx( - wallet: Wallet, - tx: Tx, - networkPassphrase: string -): Promise { - const signed = await wallet.signTransaction(tx.toXDR(), { - networkPassphrase, - }); - - return SorobanClient.TransactionBuilder.fromXDR( - signed, - networkPassphrase - ) as Tx; -} - -/** - * Send a transaction to the Soroban network. - * - * Wait `secondsToWait` seconds for the transaction to complete (default: 10). - * - * If you need to construct or sign a transaction yourself rather than using - * `invoke` or one of the exported contract methods, you may want to use this - * function for its timeout/`secondsToWait` logic, rather than implementing - * your own. - */ -export async function sendTx( - tx: Tx, - secondsToWait: number, - server: SorobanClient.Server -): Promise { - const sendTransactionResponse = await server.sendTransaction(tx); - - if (sendTransactionResponse.status !== "PENDING" || secondsToWait === 0) { - return sendTransactionResponse; - } - - let getTransactionResponse = await server.getTransaction( - sendTransactionResponse.hash - ); - - const waitUntil = new Date(Date.now() + secondsToWait * 1000).valueOf(); - - let waitTime = 1000; - let exponentialFactor = 1.5; - - while ( - Date.now() < waitUntil && - getTransactionResponse.status === SorobanRpc.GetTransactionStatus.NOT_FOUND - ) { - // Wait a beat - await new Promise((resolve) => setTimeout(resolve, waitTime)); - /// Exponential backoff - waitTime = waitTime * exponentialFactor; - // See if the transaction is complete - getTransactionResponse = await server.getTransaction( - sendTransactionResponse.hash - ); - } - - if (getTransactionResponse.status === SorobanRpc.GetTransactionStatus.NOT_FOUND) { - console.error( - `Waited ${ - secondsToWait - } seconds for transaction to complete, but it did not. ` + - `Returning anyway. Check the transaction status manually. ` + - `Info: ${JSON.stringify( - sendTransactionResponse, - null, - 2 - )}` - ); - } - - return getTransactionResponse; -} diff --git a/cmd/crates/soroban-spec-typescript/src/project_template/src/method-options.ts b/cmd/crates/soroban-spec-typescript/src/project_template/src/method-options.ts index d55991bf8..d1ff142f9 100644 --- a/cmd/crates/soroban-spec-typescript/src/project_template/src/method-options.ts +++ b/cmd/crates/soroban-spec-typescript/src/project_template/src/method-options.ts @@ -13,12 +13,19 @@ export interface Wallet { networkPassphrase?: string, accountToSign?: string, }) => Promise, + signAuthEntry: ( + entryXdr: XDR_BASE64, + opts?: { + accountToSign?: string; + } + ) => Promise } export type ClassOptions = { contractId: string networkPassphrase: string rpcUrl: string + errorTypes?: Record /** * A Wallet interface, such as Freighter, that has the methods `isConnected`, `isAllowed`, `getUserInfo`, and `signTransaction`. If not provided, will attempt to import and use Freighter. Example: * @@ -35,21 +42,9 @@ export type ClassOptions = { wallet?: Wallet } -export type MethodOptions = { +export type MethodOptions = { /** - * The fee to pay for the transaction. Default: 100. + * The fee to pay for the transaction. Default: soroban-sdk's BASE_FEE ('100') */ fee?: number - /** - * What type of response to return. - * - * - `undefined`, the default, parses the returned XDR as `{RETURN_TYPE}`. Runs preflight, checks to see if auth/signing is required, and sends the transaction if so. If there's no error and `secondsToWait` is positive, awaits the finalized transaction. - * - `'simulated'` will only simulate/preflight the transaction, even if it's a change/set method that requires auth/signing. Returns full preflight info. - * - `'full'` return the full RPC response, meaning either 1. the preflight info, if it's a view/read method that doesn't require auth/signing, or 2. the `sendTransaction` response, if there's a problem with sending the transaction or if you set `secondsToWait` to 0, or 3. the `getTransaction` response, if it's a change method with no `sendTransaction` errors and a positive `secondsToWait`. - */ - responseType?: R - /** - * If the simulation shows that this invocation requires auth/signing, `invoke` will wait `secondsToWait` seconds for the transaction to complete before giving up and returning the incomplete {@link SorobanClient.SorobanRpc.GetTransactionResponse} results (or attempting to parse their probably-missing XDR with `parseResultXdr`, depending on `responseType`). Set this to `0` to skip waiting altogether, which will return you {@link SorobanClient.SorobanRpc.SendTransactionResponse} more quickly, before the transaction has time to be included in the ledger. Default: 10. - */ - secondsToWait?: number } diff --git a/cmd/crates/soroban-spec-typescript/src/types.rs b/cmd/crates/soroban-spec-typescript/src/types.rs index 350d41296..025118431 100644 --- a/cmd/crates/soroban-spec-typescript/src/types.rs +++ b/cmd/crates/soroban-spec-typescript/src/types.rs @@ -15,8 +15,8 @@ pub struct StructField { impl From<&ScSpecUdtStructFieldV0> for StructField { fn from(f: &ScSpecUdtStructFieldV0) -> Self { StructField { - doc: f.doc.to_string_lossy(), - name: f.name.to_string_lossy(), + doc: f.doc.to_utf8_string_lossy(), + name: f.name.to_utf8_string_lossy(), value: (&f.type_).into(), } } @@ -33,8 +33,8 @@ pub struct FunctionInput { impl From<&ScSpecFunctionInputV0> for FunctionInput { fn from(f: &ScSpecFunctionInputV0) -> Self { FunctionInput { - doc: f.doc.to_string_lossy(), - name: f.name.to_string_lossy(), + doc: f.doc.to_utf8_string_lossy(), + name: f.name.to_utf8_string_lossy(), value: (&f.type_).into(), } } @@ -51,12 +51,14 @@ pub struct UnionCase { impl From<&ScSpecUdtUnionCaseV0> for UnionCase { fn from(c: &ScSpecUdtUnionCaseV0) -> Self { let (doc, name, values) = match c { - ScSpecUdtUnionCaseV0::VoidV0(v) => { - (v.doc.to_string_lossy(), v.name.to_string_lossy(), vec![]) - } + ScSpecUdtUnionCaseV0::VoidV0(v) => ( + v.doc.to_utf8_string_lossy(), + v.name.to_utf8_string_lossy(), + vec![], + ), ScSpecUdtUnionCaseV0::TupleV0(t) => ( - t.doc.to_string_lossy(), - t.name.to_string_lossy(), + t.doc.to_utf8_string_lossy(), + t.name.to_utf8_string_lossy(), t.type_.iter().map(Type::from).collect(), ), }; @@ -75,8 +77,8 @@ pub struct EnumCase { impl From<&ScSpecUdtEnumCaseV0> for EnumCase { fn from(c: &ScSpecUdtEnumCaseV0) -> Self { EnumCase { - doc: c.doc.to_string_lossy(), - name: c.name.to_string_lossy(), + doc: c.doc.to_utf8_string_lossy(), + name: c.name.to_utf8_string_lossy(), value: c.value, } } @@ -93,8 +95,8 @@ pub struct ErrorEnumCase { impl From<&ScSpecUdtErrorEnumCaseV0> for ErrorEnumCase { fn from(c: &ScSpecUdtErrorEnumCaseV0) -> Self { ErrorEnumCase { - doc: c.doc.to_string_lossy(), - name: c.name.to_string_lossy(), + doc: c.doc.to_utf8_string_lossy(), + name: c.name.to_utf8_string_lossy(), value: c.value, } } @@ -189,7 +191,7 @@ impl From<&ScSpecTypeDef> for Type { element: Box::new(Type::from(vec.element_type.as_ref())), }, ScSpecTypeDef::Udt(udt) => Type::Custom { - name: udt.name.to_string_lossy(), + name: udt.name.to_utf8_string_lossy(), }, ScSpecTypeDef::BytesN(b) => Type::BytesN { n: b.n }, ScSpecTypeDef::Val => Type::Val, @@ -218,34 +220,34 @@ impl From<&ScSpecEntry> for Entry { fn from(spec: &ScSpecEntry) -> Self { match spec { ScSpecEntry::FunctionV0(f) => Entry::Function { - doc: f.doc.to_string_lossy(), - name: f.name.to_string_lossy(), + doc: f.doc.to_utf8_string_lossy(), + name: f.name.to_utf8_string_lossy(), inputs: f.inputs.iter().map(Into::into).collect(), outputs: f.outputs.iter().map(Into::into).collect(), }, ScSpecEntry::UdtStructV0(s) if is_tuple_strukt(s) => Entry::TupleStruct { - doc: s.doc.to_string_lossy(), - name: s.name.to_string_lossy(), + doc: s.doc.to_utf8_string_lossy(), + name: s.name.to_utf8_string_lossy(), fields: s.fields.iter().map(|f| &f.type_).map(Into::into).collect(), }, ScSpecEntry::UdtStructV0(s) => Entry::Struct { - doc: s.doc.to_string_lossy(), - name: s.name.to_string_lossy(), + doc: s.doc.to_utf8_string_lossy(), + name: s.name.to_utf8_string_lossy(), fields: s.fields.iter().map(Into::into).collect(), }, ScSpecEntry::UdtUnionV0(u) => Entry::Union { - doc: u.doc.to_string_lossy(), - name: u.name.to_string_lossy(), + doc: u.doc.to_utf8_string_lossy(), + name: u.name.to_utf8_string_lossy(), cases: u.cases.iter().map(Into::into).collect(), }, ScSpecEntry::UdtEnumV0(e) => Entry::Enum { - doc: e.doc.to_string_lossy(), - name: e.name.to_string_lossy(), + doc: e.doc.to_utf8_string_lossy(), + name: e.name.to_utf8_string_lossy(), cases: e.cases.iter().map(Into::into).collect(), }, ScSpecEntry::UdtErrorEnumV0(e) => Entry::ErrorEnum { - doc: e.doc.to_string_lossy(), - name: e.name.to_string_lossy(), + doc: e.doc.to_utf8_string_lossy(), + name: e.name.to_utf8_string_lossy(), cases: e.cases.iter().map(Into::into).collect(), }, } @@ -253,5 +255,5 @@ impl From<&ScSpecEntry> for Entry { } fn is_tuple_strukt(s: &ScSpecUdtStructV0) -> bool { - !s.fields.is_empty() && s.fields[0].name.to_string_lossy() == "0" + !s.fields.is_empty() && s.fields[0].name.to_utf8_string_lossy() == "0" } diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/.env b/cmd/crates/soroban-spec-typescript/ts-tests/.env index e69de29bb..39b245482 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/.env +++ b/cmd/crates/soroban-spec-typescript/ts-tests/.env @@ -0,0 +1,2 @@ +SOROBAN_NETWORK_PASSPHRASE="Standalone Network ; February 2017" +SOROBAN_RPC_URL="http://localhost:8000/soroban/rpc" diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/.eslintrc.cjs b/cmd/crates/soroban-spec-typescript/ts-tests/.eslintrc.cjs new file mode 100644 index 000000000..90af706bb --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/ts-tests/.eslintrc.cjs @@ -0,0 +1,11 @@ +/* eslint-env node */ +module.exports = { + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + parser: '@typescript-eslint/parser', + parserOptions: { project: './tsconfig.json' }, + plugins: ['@typescript-eslint'], + root: true, + rules: { + "@typescript-eslint/no-floating-promises": ["error"] + }, +}; diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/.gitignore b/cmd/crates/soroban-spec-typescript/ts-tests/.gitignore index dda1cd312..878823de0 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/.gitignore +++ b/cmd/crates/soroban-spec-typescript/ts-tests/.gitignore @@ -1,4 +1,4 @@ build node_modules yarn.lock -contract-id-*.txt +contract-*.txt diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh b/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh new file mode 100755 index 000000000..9a2a83b63 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/ts-tests/initialize.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# read .env file, but prefer explicitly set environment variables +IFS=$'\n' +for l in $(cat .env); do + IFS='=' read -ra VARVAL <<< "$l" + # If variable with such name already exists, preserves its value + eval "export ${VARVAL[0]}=\${${VARVAL[0]}:-${VARVAL[1]}}" +done +unset IFS + +echo Network +echo " RPC: $SOROBAN_RPC_URL" +echo " Passphrase: \"$SOROBAN_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; } +echo " Status: $NETWORK_STATUS" + +# Print command before executing, from https://stackoverflow.com/a/23342259/249801 +# Discussion: https://github.com/stellar/soroban-tools/pull/1034#pullrequestreview-1690667116 +exe() { echo"${@/eval/}" ; "$@" ; } + +function fund_all() { + exe eval "./soroban config identity fund" + exe eval "./soroban config identity generate alice" + exe eval "./soroban config identity fund alice" + exe eval "./soroban config identity generate bob" + exe eval "./soroban config identity fund bob" +} +function upload() { + exe eval "(./soroban contract $1 --wasm $2 --ignore-checks) > $3" +} +function deploy() { + exe eval "(./soroban contract deploy --wasm-hash $(cat $1) --ignore-checks) > $2" +} +function deploy_all() { + upload 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_hello_world.wasm contract-id-hello-world.txt + upload deploy ../../../../target/wasm32-unknown-unknown/test-wasms/test_swap.wasm contract-id-swap.txt + upload install ../../../../target/wasm32-unknown-unknown/test-wasms/test_token.wasm contract-token-hash.txt + deploy contract-token-hash.txt contract-id-token-a.txt + deploy contract-token-hash.txt contract-id-token-b.txt +} +function initialize() { + exe eval "./soroban contract invoke --id $(cat $1) -- initialize --admin $(./soroban config identity address) --decimal 0 --name 'Token $2' --symbol '$2'" +} +function initialize_all() { + initialize contract-id-token-a.txt A + initialize contract-id-token-b.txt B +} +function bind() { + exe eval "./soroban contract bindings typescript --contract-id $(cat $1) --output-dir ./node_modules/$2 --overwrite" +} +function bind_all() { + bind contract-id-custom-types.txt test-custom-types + bind contract-id-hello-world.txt test-hello-world + bind contract-id-swap.txt test-swap + bind contract-id-token-a.txt token +} + +function mint() { + exe eval "./soroban contract invoke --id $(cat $1) -- mint --amount 2000000 --to $(./soroban config identity address $2)" +} +function mint_all() { + mint contract-id-token-a.txt alice + mint contract-id-token-b.txt bob +} + +curl -X POST "http://localhost:8000/soroban/rpc" || { echo "Make sure you're running standalone RPC network on localhost:8000" && exit 1; } +fund_all +deploy_all +initialize_all +mint_all +bind_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 20622f5c9..1ed2de71f 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/package-lock.json +++ b/cmd/crates/soroban-spec-typescript/ts-tests/package-lock.json @@ -1,2257 +1,3405 @@ { - "name": "ts-tests", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "hasInstallScript": true, - "devDependencies": { - "@ava/typescript": "^4.1.0", - "@types/node": "^20.4.9", - "ava": "^5.3.1", - "soroban-client": "1.0.0-beta.2", - "typescript": "^5.1.6" - }, - "engines": { - "node": ">=20.0.0", - "npm": ">=9.8.1" - } - }, - "node_modules/@ava/typescript": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ava/typescript/-/typescript-4.1.0.tgz", - "integrity": "sha512-1iWZQ/nr9iflhLK9VN8H+1oDZqe93qxNnyYUz+jTzkYPAHc5fdZXBrqmNIgIfFhWYXK5OaQ5YtC7OmLeTNhVEg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0", - "execa": "^7.1.1" - }, - "engines": { - "node": "^14.19 || ^16.15 || ^18 || ^20" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/node": { - "version": "20.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", - "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/aggregate-error": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", - "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", - "dev": true, - "dependencies": { - "clean-stack": "^4.0.0", - "indent-string": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arrgv": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", - "integrity": "sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/arrify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", - "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/ava": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ava/-/ava-5.3.1.tgz", - "integrity": "sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.2", - "acorn-walk": "^8.2.0", - "ansi-styles": "^6.2.1", - "arrgv": "^1.0.2", - "arrify": "^3.0.0", - "callsites": "^4.0.0", - "cbor": "^8.1.0", - "chalk": "^5.2.0", - "chokidar": "^3.5.3", - "chunkd": "^2.0.1", - "ci-info": "^3.8.0", - "ci-parallel-vars": "^1.0.1", - "clean-yaml-object": "^0.1.0", - "cli-truncate": "^3.1.0", - "code-excerpt": "^4.0.0", - "common-path-prefix": "^3.0.0", - "concordance": "^5.0.4", - "currently-unhandled": "^0.4.1", - "debug": "^4.3.4", - "emittery": "^1.0.1", - "figures": "^5.0.0", - "globby": "^13.1.4", - "ignore-by-default": "^2.1.0", - "indent-string": "^5.0.0", - "is-error": "^2.2.2", - "is-plain-object": "^5.0.0", - "is-promise": "^4.0.0", - "matcher": "^5.0.0", - "mem": "^9.0.2", - "ms": "^2.1.3", - "p-event": "^5.0.1", - "p-map": "^5.5.0", - "picomatch": "^2.3.1", - "pkg-conf": "^4.0.0", - "plur": "^5.1.0", - "pretty-ms": "^8.0.0", - "resolve-cwd": "^3.0.0", - "stack-utils": "^2.0.6", - "strip-ansi": "^7.0.1", - "supertap": "^3.0.1", - "temp-dir": "^3.0.0", - "write-file-atomic": "^5.0.1", - "yargs": "^17.7.2" - }, - "bin": { - "ava": "entrypoints/cli.mjs" - }, - "engines": { - "node": ">=14.19 <15 || >=16.15 <17 || >=18" - }, - "peerDependencies": { - "@ava/typescript": "*" - }, - "peerDependenciesMeta": { - "@ava/typescript": { - "optional": true - } - } - }, - "node_modules/axios": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", - "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.0", - "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==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "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==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/blueimp-md5": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", - "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", - "dev": true - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/callsites": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.1.0.tgz", - "integrity": "sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cbor": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", - "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", - "dev": true, - "dependencies": { - "nofilter": "^3.1.0" - }, - "engines": { - "node": ">=12.19" - } - }, - "node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chunkd": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chunkd/-/chunkd-2.0.1.tgz", - "integrity": "sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==", - "dev": true - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/ci-parallel-vars": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ci-parallel-vars/-/ci-parallel-vars-1.0.1.tgz", - "integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==", - "dev": true - }, - "node_modules/clean-stack": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", - "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clean-yaml-object": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", - "integrity": "sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", - "dev": true, - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/code-excerpt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", - "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", - "dev": true, - "dependencies": { - "convert-to-spaces": "^2.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "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==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "node_modules/concordance": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", - "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", - "dev": true, - "dependencies": { - "date-time": "^3.1.0", - "esutils": "^2.0.3", - "fast-diff": "^1.2.0", - "js-string-escape": "^1.0.1", - "lodash": "^4.17.15", - "md5-hex": "^3.0.1", - "semver": "^7.3.2", - "well-known-symbols": "^2.0.0" - }, - "engines": { - "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" - } - }, - "node_modules/convert-to-spaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", - "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", - "dev": true, - "dependencies": { - "array-find-index": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/date-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", - "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", - "dev": true, - "dependencies": { - "time-zone": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/emittery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-1.0.1.tgz", - "integrity": "sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "dev": true, - "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz", - "integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==", - "dev": true, - "engines": { - "node": ">=10 <11 || >=12 <13 || >=14" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/irregular-plurals": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", - "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-error": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", - "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", - "dev": true - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-string-escape": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/js-xdr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/js-xdr/-/js-xdr-3.0.0.tgz", - "integrity": "sha512-tSt6UKJ2L7t+yaQURGkHo9kop9qnVbChTlCu62zNiDbDZQoZb/YjUj2iFJ3lgelhfg9p5bhO2o/QX+g36TPsSQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/load-json-file": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", - "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "dependencies": { - "p-defer": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/matcher": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", - "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/md5-hex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", - "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", - "dev": true, - "dependencies": { - "blueimp-md5": "^2.10.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mem": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz", - "integrity": "sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==", - "dev": true, - "dependencies": { - "map-age-cleaner": "^0.1.3", - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sindresorhus/mem?sponsor=1" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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==", - "dev": true, - "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==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/node-gyp-build": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", - "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", - "dev": true, - "optional": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/nofilter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", - "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", - "dev": true, - "engines": { - "node": ">=12.19" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-event": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz", - "integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==", - "dev": true, - "dependencies": { - "p-timeout": "^5.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", - "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", - "dev": true, - "dependencies": { - "aggregate-error": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-timeout": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", - "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-ms": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", - "integrity": "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-conf": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz", - "integrity": "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==", - "dev": true, - "dependencies": { - "find-up": "^6.0.0", - "load-json-file": "^7.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/plur": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", - "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==", - "dev": true, - "dependencies": { - "irregular-plurals": "^3.3.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-ms": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-8.0.0.tgz", - "integrity": "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==", - "dev": true, - "dependencies": { - "parse-ms": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/sodium-native": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.0.4.tgz", - "integrity": "sha512-faqOKw4WQKK7r/ybn6Lqo1F9+L5T6NlBJJYvpxbZPetpWylUVqz449mvlwIBKBqxEHbWakWuOlUt8J3Qpc4sWw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.6.0" - } - }, - "node_modules/soroban-client": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/soroban-client/-/soroban-client-1.0.0-beta.2.tgz", - "integrity": "sha512-v5h3yvef7HkUD3H26w33NUEgRXcPiOSDWEsVzMloaxsprs3N002tXJHvFF+Uw1eYt50Uk6bvqBgvkLwX10VENw==", - "dev": true, - "dependencies": { - "axios": "^1.4.0", - "bignumber.js": "^9.1.1", - "buffer": "^6.0.3", - "stellar-base": "v10.0.0-beta.1", - "urijs": "^1.19.1" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/stellar-base": { - "version": "10.0.0-beta.1", - "resolved": "https://registry.npmjs.org/stellar-base/-/stellar-base-10.0.0-beta.1.tgz", - "integrity": "sha512-zXC5AsbUsLi57JruyeIMv23s3iUxq/P2ZFrSJ+FerLIZjSAjY8EDs4zwY4LCuu7swUu46Lm8GK6sqxUZCPekHw==", - "dev": true, - "dependencies": { - "base32.js": "^0.1.0", - "bignumber.js": "^9.1.2", - "buffer": "^6.0.3", - "js-xdr": "^3.0.0", - "sha.js": "^2.3.6", - "tweetnacl": "^1.0.3" - }, - "optionalDependencies": { - "sodium-native": "^4.0.1" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supertap": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", - "integrity": "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==", - "dev": true, - "dependencies": { - "indent-string": "^5.0.0", - "js-yaml": "^3.14.1", - "serialize-error": "^7.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/temp-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", - "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", - "dev": true, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/time-zone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", - "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/urijs": { - "version": "1.19.11", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "dev": true - }, - "node_modules/well-known-symbols": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", - "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } + "name": "ts-tests", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "hasInstallScript": true, + "devDependencies": { + "@ava/typescript": "^4.1.0", + "@types/node": "^20.4.9", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "ava": "^5.3.1", + "dotenv": "^16.3.1", + "eslint": "^8.53.0", + "stellar-sdk": "11.1.0", + "typescript": "^5.1.6" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ava/typescript": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ava/typescript/-/typescript-4.1.0.tgz", + "integrity": "sha512-1iWZQ/nr9iflhLK9VN8H+1oDZqe93qxNnyYUz+jTzkYPAHc5fdZXBrqmNIgIfFhWYXK5OaQ5YtC7OmLeTNhVEg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^5.0.0", + "execa": "^7.1.1" + }, + "engines": { + "node": "^14.19 || ^16.15 || ^18 || ^20" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@stellar/js-xdr": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.0.1.tgz", + "integrity": "sha512-dp5Eh7Nr1YjiIeqpdkj2cQYxfoPudDAH3ck8MWggp48Htw66Z/hUssNYUQG/OftLjEmHT90Z/dtey2Y77DOxIw==", + "dev": true + }, + "node_modules/@stellar/stellar-base": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-10.0.1.tgz", + "integrity": "sha512-BDbx7VHOEQh+4J3Q+gStNXgPaNckVFmD4aOlBBGwxlF6vPFmVnW8IoJdkX7T58zpX55eWI6DXvEhDBlrqTlhAQ==", + "dev": true, + "dependencies": { + "@stellar/js-xdr": "^3.0.1", + "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.0.1" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", + "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.14.0.tgz", + "integrity": "sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/type-utils": "6.14.0", + "@typescript-eslint/utils": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.14.0.tgz", + "integrity": "sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.14.0.tgz", + "integrity": "sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.14.0.tgz", + "integrity": "sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/utils": "6.14.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.14.0.tgz", + "integrity": "sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.14.0.tgz", + "integrity": "sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.14.0.tgz", + "integrity": "sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.14.0.tgz", + "integrity": "sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.14.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "dependencies": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrgv": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", + "integrity": "sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/arrify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", + "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/ava": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ava/-/ava-5.3.1.tgz", + "integrity": "sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.2", + "acorn-walk": "^8.2.0", + "ansi-styles": "^6.2.1", + "arrgv": "^1.0.2", + "arrify": "^3.0.0", + "callsites": "^4.0.0", + "cbor": "^8.1.0", + "chalk": "^5.2.0", + "chokidar": "^3.5.3", + "chunkd": "^2.0.1", + "ci-info": "^3.8.0", + "ci-parallel-vars": "^1.0.1", + "clean-yaml-object": "^0.1.0", + "cli-truncate": "^3.1.0", + "code-excerpt": "^4.0.0", + "common-path-prefix": "^3.0.0", + "concordance": "^5.0.4", + "currently-unhandled": "^0.4.1", + "debug": "^4.3.4", + "emittery": "^1.0.1", + "figures": "^5.0.0", + "globby": "^13.1.4", + "ignore-by-default": "^2.1.0", + "indent-string": "^5.0.0", + "is-error": "^2.2.2", + "is-plain-object": "^5.0.0", + "is-promise": "^4.0.0", + "matcher": "^5.0.0", + "mem": "^9.0.2", + "ms": "^2.1.3", + "p-event": "^5.0.1", + "p-map": "^5.5.0", + "picomatch": "^2.3.1", + "pkg-conf": "^4.0.0", + "plur": "^5.1.0", + "pretty-ms": "^8.0.0", + "resolve-cwd": "^3.0.0", + "stack-utils": "^2.0.6", + "strip-ansi": "^7.0.1", + "supertap": "^3.0.1", + "temp-dir": "^3.0.0", + "write-file-atomic": "^5.0.1", + "yargs": "^17.7.2" + }, + "bin": { + "ava": "entrypoints/cli.mjs" + }, + "engines": { + "node": ">=14.19 <15 || >=16.15 <17 || >=18" + }, + "peerDependencies": { + "@ava/typescript": "*" + }, + "peerDependenciesMeta": { + "@ava/typescript": { + "optional": true + } + } + }, + "node_modules/ava/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ava/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "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==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blueimp-md5": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", + "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/callsites": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.1.0.tgz", + "integrity": "sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chunkd": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chunkd/-/chunkd-2.0.1.tgz", + "integrity": "sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==", + "dev": true + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/ci-parallel-vars": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ci-parallel-vars/-/ci-parallel-vars-1.0.1.tgz", + "integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==", + "dev": true + }, + "node_modules/clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clean-yaml-object": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", + "integrity": "sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/code-excerpt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", + "dev": true, + "dependencies": { + "convert-to-spaces": "^2.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concordance": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", + "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", + "dev": true, + "dependencies": { + "date-time": "^3.1.0", + "esutils": "^2.0.3", + "fast-diff": "^1.2.0", + "js-string-escape": "^1.0.1", + "lodash": "^4.17.15", + "md5-hex": "^3.0.1", + "semver": "^7.3.2", + "well-known-symbols": "^2.0.0" + }, + "engines": { + "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" + } + }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/date-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", + "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", + "dev": true, + "dependencies": { + "time-zone": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emittery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-1.0.1.tgz", + "integrity": "sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz", + "integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==", + "dev": true, + "engines": { + "node": ">=10 <11 || >=12 <13 || >=14" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/irregular-plurals": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", + "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-error": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", + "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/load-json-file": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", + "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/matcher": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", + "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/md5-hex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", + "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "dev": true, + "dependencies": { + "blueimp-md5": "^2.10.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mem": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz", + "integrity": "sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==", + "dev": true, + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sindresorhus/mem?sponsor=1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-gyp-build": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz", + "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-event": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz", + "integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==", + "dev": true, + "dependencies": { + "p-timeout": "^5.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "dependencies": { + "aggregate-error": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", + "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module/node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-ms": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", + "integrity": "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-conf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz", + "integrity": "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==", + "dev": true, + "dependencies": { + "find-up": "^6.0.0", + "load-json-file": "^7.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-conf/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-conf/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-conf/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-conf/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-conf/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-conf/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/plur": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", + "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==", + "dev": true, + "dependencies": { + "irregular-plurals": "^3.3.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-8.0.0.tgz", + "integrity": "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==", + "dev": true, + "dependencies": { + "parse-ms": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sodium-native": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.0.4.tgz", + "integrity": "sha512-faqOKw4WQKK7r/ybn6Lqo1F9+L5T6NlBJJYvpxbZPetpWylUVqz449mvlwIBKBqxEHbWakWuOlUt8J3Qpc4sWw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stellar-sdk": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/stellar-sdk/-/stellar-sdk-11.1.0.tgz", + "integrity": "sha512-fIdo77ogpU+ecHgs59pk9velpXd4F/ch0DzOI4QZw8zVZApc3oeNWP3+X6ui7BWpeRHAGsP2CHQzBLxm0JTIgg==", + "dev": true, + "dependencies": { + "@stellar/stellar-base": "10.0.1", + "axios": "^1.6.0", + "bignumber.js": "^9.1.2", + "eventsource": "^2.0.2", + "randombytes": "^2.1.0", + "toml": "^3.0.0", + "urijs": "^1.19.1" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supertap": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", + "integrity": "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==", + "dev": true, + "dependencies": { + "indent-string": "^5.0.0", + "js-yaml": "^3.14.1", + "serialize-error": "^7.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/supertap/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/supertap/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "dev": true + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "dev": true + }, + "node_modules/well-known-symbols": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", + "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } } diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/package.json b/cmd/crates/soroban-spec-typescript/ts-tests/package.json index 7ad7212ae..37633c7d4 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/package.json +++ b/cmd/crates/soroban-spec-typescript/ts-tests/package.json @@ -1,34 +1,31 @@ { - "private": true, - "type": "module", - "scripts": { - "postinstall": "npm run deploy && npm run bindings || { echo \"Make sure you're running standalone RPC network on localhost:8000\" && exit 1; }", - "fund": "./soroban config identity fund", - "bindings:custom-types": "./soroban contract bindings typescript --contract-id $(cat contract-id-custom-types.txt) --output-dir ./node_modules/test-custom-types --overwrite", - "bindings:hello-world": "./soroban contract bindings typescript --contract-id $(cat contract-id-hello-world.txt) --output-dir ./node_modules/test-hello-world --overwrite", - "bindings": "npm run bindings:custom-types && npm run bindings:hello-world", - "deploy:custom-types": "(./soroban contract deploy --wasm ../../../../target/wasm32-unknown-unknown/test-wasms/test_custom_types.wasm) > contract-id-custom-types.txt", - "deploy:hello-world": "(./soroban contract deploy --wasm ../../../../target/wasm32-unknown-unknown/test-wasms/test_hello_world.wasm) > contract-id-hello-world.txt", - "deploy": "npm run deploy:custom-types && npm run deploy:hello-world", - "test": "ava" - }, - "devDependencies": { - "@ava/typescript": "^4.1.0", - "@types/node": "^20.4.9", - "ava": "^5.3.1", - "soroban-client": "1.0.0-beta.2", - "typescript": "^5.1.6" - }, - "ava": { - "typescript": { - "rewritePaths": { - "src/": "build/" - }, - "compile": "tsc" - } - }, - "engines": { - "node": ">=20.0.0", - "npm": ">=9.8.1" + "private": true, + "type": "module", + "scripts": { + "lint": "eslint src/*", + "postinstall": "./initialize.sh", + "test": "npm run lint && ava" + }, + "devDependencies": { + "@ava/typescript": "^4.1.0", + "@types/node": "^20.4.9", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "ava": "^5.3.1", + "dotenv": "^16.3.1", + "eslint": "^8.53.0", + "stellar-sdk": "11.1.0", + "typescript": "^5.1.6" + }, + "ava": { + "typescript": { + "rewritePaths": { + "src/": "build/" + }, + "compile": "tsc" + }, + "require": [ + "dotenv/config" + ] } } diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-custom-types.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-custom-types.ts index 1c5d04706..75f261d94 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-custom-types.ts +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-custom-types.ts @@ -1,126 +1,136 @@ import test from 'ava' -import { publicKey, rpcUrl, wallet } from './util.js' -import { Contract, Ok, Err, networks, Address } from 'test-custom-types' +import { root, rpcUrl, wallet } from './util.js' +import { Contract, Ok, Err, networks } from 'test-custom-types' -const contract = new Contract({ ...networks.standalone, rpcUrl, wallet}); +const addr = root.address; +const publicKey = root.keypair.publicKey(); + +const contract = new Contract({ ...networks.standalone, rpcUrl, wallet }); test('hello', async t => { - t.is(await contract.hello({ hello: 'tests' }), 'tests') + const { result } = await contract.hello({ hello: 'tests' }) + t.is(result, 'tests') }) test('woid', async t => { - t.is(await contract.woid(), undefined) + t.is((await contract.woid()).result, undefined) }) test('u32_fail_on_even', async t => { - t.deepEqual(await contract.u32FailOnEven({ u32_: 1 }), new Ok(1)) - t.deepEqual(await contract.u32FailOnEven({ u32_: 0 }), new Err({ message: "Please provide an odd number" })) + t.deepEqual( + (await contract.u32FailOnEven({ u32_: 1 })).result, + new Ok(1) + ) + t.deepEqual( + (await contract.u32FailOnEven({ u32_: 0 })).result, + new Err({ message: "Please provide an odd number" }) + ) }) test('u32', async t => { - t.is(await contract.u32({ u32_: 1 }), 1) + t.is((await contract.u32({ u32_: 1 })).result, 1) }) test('i32', async t => { - t.is(await contract.i32({ i32_: 1 }), 1) + t.is((await contract.i32({ i32_: 1 })).result, 1) }) test('i64', async t => { - t.is(await contract.i64({ i64_: 1n }), 1n) + t.is((await contract.i64({ i64_: 1n })).result, 1n) }) test("strukt_hel", async (t) => { - let test = { a: 0, b: true, c: "world" } - t.deepEqual(await contract.struktHel({ strukt: test }), ["Hello", "world"]) + const test = { a: 0, b: true, c: "world" } + t.deepEqual((await contract.struktHel({ strukt: test })).result, ["Hello", "world"]) }) test("strukt", async (t) => { - let test = { a: 0, b: true, c: "hello" } - t.deepEqual(await contract.strukt({ strukt: test }), test) + const test = { a: 0, b: true, c: "hello" } + t.deepEqual((await contract.strukt({ strukt: test })).result, test) }) test('simple first', async t => { const simple = { tag: 'First', values: undefined } as const - t.deepEqual(await contract.simple({ simple }), simple) + t.deepEqual((await contract.simple({ simple })).result, simple) }) test('simple second', async t => { const simple = { tag: 'Second', values: undefined } as const - t.deepEqual(await contract.simple({ simple }), simple) + t.deepEqual((await contract.simple({ simple })).result, simple) }) test('simple third', async t => { const simple = { tag: 'Third', values: undefined } as const - t.deepEqual(await contract.simple({ simple }), simple) + t.deepEqual((await contract.simple({ simple })).result, simple) }) test('complex with struct', async t => { const arg = { tag: 'Struct', values: [{ a: 0, b: true, c: 'hello' }] } as const const ret = { tag: 'Struct', values: [{ a: 0, b: true, c: 'hello' }] } - t.deepEqual(await contract.complex({ complex: arg }), ret) + t.deepEqual((await contract.complex({ complex: arg })).result, ret) }) test('complex with tuple', async t => { const arg = { tag: 'Tuple', values: [[{ a: 0, b: true, c: 'hello' }, { tag: 'First', values: undefined }]] } as const const ret = { tag: 'Tuple', values: [[{ a: 0, b: true, c: 'hello' }, { tag: 'First', values: undefined }]] } - t.deepEqual(await contract.complex({ complex: arg }), ret) + t.deepEqual((await contract.complex({ complex: arg })).result, ret) }) test('complex with enum', async t => { const arg = { tag: 'Enum', values: [{ tag: 'First', values: undefined }] } as const const ret = { tag: 'Enum', values: [{ tag: 'First', values: undefined }] } - t.deepEqual(await contract.complex({ complex: arg }), ret) + t.deepEqual((await contract.complex({ complex: arg })).result, ret) }) test('complex with asset', async t => { const arg = { tag: 'Asset', values: [publicKey, 1n] } as const - const ret = { tag: 'Asset', values: [new Address(publicKey), 1n] } - t.deepEqual(await contract.complex({ complex: arg }), ret) + const ret = { tag: 'Asset', values: [addr, 1n] } + t.deepEqual((await contract.complex({ complex: arg })).result, ret) }) test('complex with void', async t => { const complex = { tag: 'Void', values: undefined } as const - t.deepEqual(await contract.complex({ complex }), complex) + t.deepEqual((await contract.complex({ complex })).result, complex) }) test('addresse', async t => { - t.deepEqual(await contract.addresse({ addresse: publicKey }), Address.fromString(publicKey)) + t.deepEqual((await contract.addresse({ addresse: publicKey })).result, addr) }) test('bytes', async t => { const bytes = Buffer.from('hello') - t.deepEqual(await contract.bytes({ bytes }), bytes) + t.deepEqual((await contract.bytes({ bytes })).result, bytes) }) test('bytes_n', async t => { const bytes_n = Buffer.from('123456789') // what's the correct way to construct bytes_n? - t.deepEqual(await contract.bytesN({ bytes_n }), bytes_n) + t.deepEqual((await contract.bytesN({ bytes_n })).result, bytes_n) }) test('card', async t => { const card = 11 - t.is(await contract.card({ card }), card) + t.is((await contract.card({ card })).result, card) }) test('boolean', async t => { - t.is(await contract.boolean({ boolean: true }), true) + t.is((await contract.boolean({ boolean: true })).result, true) }) test('not', async t => { - t.is(await contract.not({ boolean: true }), false) + t.is((await contract.not({ boolean: true })).result, false) }) test('i128', async t => { - t.is(await contract.i128({ i128: -1n }), -1n) + t.is((await contract.i128({ i128: -1n })).result, -1n) }) test('u128', async t => { - t.is(await contract.u128({ u128: 1n }), 1n) + t.is((await contract.u128({ u128: 1n })).result, 1n) }) test('multi_args', async t => { - t.is(await contract.multiArgs({ a: 1, b: true }), 1) - t.is(await contract.multiArgs({ a: 1, b: false }), 0) + t.is((await contract.multiArgs({ a: 1, b: true })).result, 1) + t.is((await contract.multiArgs({ a: 1, b: false })).result, 0) }) test('map', async t => { @@ -128,46 +138,46 @@ test('map', async t => { map.set(1, true) map.set(2, false) // map.set(3, 'hahaha') // should throw an error - t.deepEqual(await contract.map({ map }), map) + t.deepEqual((await contract.map({ map })).result, map) }) test('vec', async t => { const vec = [1, 2, 3] - t.deepEqual(await contract.vec({ vec }), vec) + t.deepEqual((await contract.vec({ vec })).result, vec) }) test('tuple', async t => { const tuple = ['hello', 1] as const - t.deepEqual(await contract.tuple({ tuple }), tuple) + t.deepEqual((await contract.tuple({ tuple })).result, tuple) }) test('option', async t => { // this makes sense - t.deepEqual(await contract.option({ option: 1 }), 1) + t.deepEqual((await contract.option({ option: 1 })).result, 1) // this passes but shouldn't - t.deepEqual(await contract.option({ option: undefined }), undefined) + t.deepEqual((await contract.option({ option: undefined })).result, undefined) // this is the behavior we probably want, but fails // t.deepEqual(await contract.option(), undefined) // typing and implementation require the object - // t.deepEqual(await contract.option({}), undefined) // typing requires argument; implementation would be fine with this - // t.deepEqual(await contract.option({ option: undefined }), undefined) + // t.deepEqual((await contract.option({})).result, undefined) // typing requires argument; implementation would be fine with this + // t.deepEqual((await contract.option({ option: undefined })).result, undefined) }) test('u256', async t => { - t.is(await contract.u256({ u256: 1n }), 1n) + t.is((await contract.u256({ u256: 1n })).result, 1n) }) test('i256', async t => { - t.is(await contract.i256({ i256: -1n }), -1n) + t.is((await contract.i256({ i256: -1n })).result, -1n) }) test('string', async t => { - t.is(await contract.string({ string: 'hello' }), 'hello') + t.is((await contract.string({ string: 'hello' })).result, 'hello') }) test('tuple_strukt', async t => { const arg = [{ a: 0, b: true, c: 'hello' }, { tag: 'First', values: undefined }] as const const res = [{ a: 0, b: true, c: 'hello' }, { tag: 'First', values: undefined }] - t.deepEqual(await contract.tupleStrukt({ tuple_strukt: arg }), res) + t.deepEqual((await contract.tupleStrukt({ tuple_strukt: arg })).result, res) }) diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-deserialized-transaction.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-deserialized-transaction.ts new file mode 100644 index 000000000..f6152d2c1 --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-deserialized-transaction.ts @@ -0,0 +1,16 @@ +import test from "ava" +import { wallet, rpcUrl } from "./util.js" +import { Contract, networks } from "test-hello-world" + +const contract = new Contract({ ...networks.standalone, rpcUrl, wallet }) + +test("has correctly-typed result", async (t) => { + const initial = await contract.hello({ world: "tests" }) + t.is(initial.result[0], "Hello") + t.is(initial.result[1], "tests") + + const serialized = initial.toJSON() + const deserialized = contract.fromJSON.hello(serialized) + t.is(deserialized.result[0], "Hello") // throws TS error if `result` is of type `unknown` + t.is(deserialized.result[1], "tests") // throws TS error if `result` is of type `unknown` +}); diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-hello-world.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-hello-world.ts index dc8367931..5ccdde788 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-hello-world.ts +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-hello-world.ts @@ -1,20 +1,26 @@ import test from "ava"; -import { wallet, publicKey, rpcUrl } from "./util.js"; -import { Address, Contract, networks } from "test-hello-world"; +import { root, wallet, rpcUrl } from "./util.js"; +import { Contract, networks } from "test-hello-world"; -const contract = new Contract({...networks.standalone, rpcUrl, wallet}); +const contract = new Contract({ ...networks.standalone, rpcUrl, wallet }); test("hello", async (t) => { - t.deepEqual(await contract.hello({ world: "tests" }), ["Hello", "tests"]); + t.deepEqual((await contract.hello({ world: "tests" })).result, ["Hello", "tests"]); }); -// Currently must run tests in serial because nonce logic not smart enough to handle concurrent calls. -test.serial.failing("auth", async (t) => { - t.deepEqual(await contract.auth({ addr: publicKey, world: 'lol' }), Address.fromString(publicKey)) +test("auth", async (t) => { + t.deepEqual( + (await contract.auth({ + addr: root.keypair.publicKey(), + world: 'lol' + })).result, + root.address + ) }); -test.serial.failing("inc", async (t) => { - t.is(await contract.getCount(), 0); - t.is(await contract.inc(), 1) - t.is(await contract.getCount(), 1); +test("inc", async (t) => { + const { result: startingBalance } = await contract.getCount() + const inc = await contract.inc() + t.is((await inc.signAndSend()).result, startingBalance + 1) + t.is((await contract.getCount()).result, startingBalance + 1) }); diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-methods-as-args.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-methods-as-args.ts index dfa7c4724..afa3b6512 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-methods-as-args.ts +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-methods-as-args.ts @@ -2,11 +2,11 @@ import test from "ava"; import { wallet, rpcUrl } from "./util.js"; import { Contract, networks } from "test-hello-world"; -const contract = new Contract({...networks.standalone, rpcUrl, wallet}); +const contract = new Contract({ ...networks.standalone, rpcUrl, wallet }); // this test checks that apps can pass methods as arguments to other methods and have them still work const hello = contract.hello test("hello", async (t) => { - t.deepEqual(await hello({ world: "tests" }), ["Hello", "tests"]); + t.deepEqual((await hello({ world: "tests" })).result, ["Hello", "tests"]); }); diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/test-swap.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-swap.ts new file mode 100644 index 000000000..41871839c --- /dev/null +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/test-swap.ts @@ -0,0 +1,134 @@ +import test from "ava" +import { SorobanRpc, xdr } from 'stellar-sdk' +import { wallet, rpcUrl, alice, bob, networkPassphrase, root, Wallet } from "./util.js" +import { Contract as Token } from "token" +import { Contract as Swap, networks, NeedsMoreSignaturesError } from "test-swap" +import fs from "node:fs" + +const tokenAId = fs.readFileSync(new URL("../contract-id-token-a.txt", import.meta.url), "utf8").trim() +const tokenBId = fs.readFileSync(new URL("../contract-id-token-b.txt", import.meta.url), "utf8").trim() + +// `root` is the invoker of all contracts +const tokenA = new Token({ + contractId: tokenAId, + networkPassphrase, + rpcUrl, + wallet, +}) +const tokenB = new Token({ + contractId: tokenBId, + networkPassphrase, + rpcUrl, + wallet, +}) +function swapContractAs(invoker: typeof root | typeof alice | typeof bob) { + return new Swap({ + ...networks.standalone, + rpcUrl, + wallet: new Wallet(invoker.keypair.publicKey()), + }) +} + +const amountAToSwap = 2n +const amountBToSwap = 1n +const alicePk = alice.keypair.publicKey() +const bobPk = bob.keypair.publicKey() + +test('calling `signAndSend()` too soon throws descriptive error', async t => { + const swapContract = swapContractAs(root) + const tx = await swapContract.swap({ + a: alicePk, + b: bobPk, + token_a: tokenAId, + token_b: tokenBId, + amount_a: amountAToSwap, + min_a_for_b: amountAToSwap, + amount_b: amountBToSwap, + min_b_for_a: amountBToSwap, + }) + const error = await t.throwsAsync(tx.signAndSend()) + t.true(error instanceof NeedsMoreSignaturesError, `error is not of type 'NeedsMoreSignaturesError'; instead it is of type '${error?.constructor.name}'`) + if (error) t.regex(error.message, /needsNonInvokerSigningBy/) +}) + +test('alice swaps bob 10 A for 1 B', async t => { + const swapContractAsRoot = swapContractAs(root) + const [ + { result: aliceStartingABalance }, + { result: aliceStartingBBalance }, + { result: bobStartingABalance }, + { result: bobStartingBBalance }, + ] = await Promise.all([ + tokenA.balance({ id: alicePk }), + tokenB.balance({ id: alicePk }), + tokenA.balance({ id: bobPk }), + tokenB.balance({ id: bobPk }), + ]) + t.true(aliceStartingABalance >= amountAToSwap, `alice does not have enough Token A! aliceStartingABalance: ${aliceStartingABalance}`) + t.true(bobStartingBBalance >= amountBToSwap, `bob does not have enough Token B! bobStartingBBalance: ${bobStartingBBalance}`) + + const tx = await swapContractAsRoot.swap({ + a: alicePk, + b: bobPk, + token_a: tokenAId, + token_b: tokenBId, + amount_a: amountAToSwap, + min_a_for_b: amountAToSwap, + amount_b: amountBToSwap, + min_b_for_a: amountBToSwap, + }) + + const needsNonInvokerSigningBy = await tx.needsNonInvokerSigningBy() + t.is(needsNonInvokerSigningBy.length, 2) + t.is(needsNonInvokerSigningBy.indexOf(alicePk), 0, 'needsNonInvokerSigningBy does not have alice\'s public key!') + t.is(needsNonInvokerSigningBy.indexOf(bobPk), 1, 'needsNonInvokerSigningBy does not have bob\'s public key!') + + + // root serializes & sends to alice + const jsonFromRoot = tx.toJSON() + const txAlice = swapContractAs(alice).fromJSON.swap(jsonFromRoot) + await txAlice.signAuthEntries() + + // alice serializes & sends to bob + const jsonFromAlice = txAlice.toJSON() + const txBob = swapContractAs(bob).fromJSON.swap(jsonFromAlice) + await txBob.signAuthEntries() + + // bob serializes & sends back to root + const jsonFromBob = txBob.toJSON() + const txRoot = swapContractAsRoot.fromJSON.swap(jsonFromBob) + const result = await txRoot.signAndSend() + + t.truthy(result.sendTransactionResponse, `tx failed: ${JSON.stringify(result, null, 2)}`) + t.is(result.sendTransactionResponse!.status, 'PENDING', `tx failed: ${JSON.stringify(result, null, 2)}`) + t.truthy(result.getTransactionResponseAll?.length, `tx failed: ${JSON.stringify(result.getTransactionResponseAll, null, 2)}`) + t.not(result.getTransactionResponse!.status, 'FAILED', `tx failed: ${JSON.stringify( + ((result.getTransactionResponse as SorobanRpc.Api.GetFailedTransactionResponse) + .resultXdr.result().value() as xdr.OperationResult[] + ).map(op => + op.value()?.value().switch() + ), null, 2)}` + ) + t.is( + result.getTransactionResponse!.status, + SorobanRpc.Api.GetTransactionStatus.SUCCESS, + `tx failed: ${JSON.stringify(result.getTransactionResponse, null, 2)}` + ) + + t.is( + (await tokenA.balance({ id: alicePk })).result, + aliceStartingABalance - amountAToSwap + ) + t.is( + (await tokenB.balance({ id: alicePk })).result, + aliceStartingBBalance + amountBToSwap + ) + t.is( + (await tokenA.balance({ id: bobPk })).result, + bobStartingABalance + amountAToSwap + ) + t.is( + (await tokenB.balance({ id: bobPk })).result, + bobStartingBBalance - amountBToSwap + ) +}) 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 81517944f..69c15350e 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts @@ -1,27 +1,57 @@ -import { Keypair, TransactionBuilder } from "soroban-client"; +import { spawnSync } from "node:child_process"; +import { Keypair, TransactionBuilder, hash } from "stellar-sdk"; +import { Address } from 'test-custom-types' + +const rootKeypair = Keypair.fromSecret(spawnSync("./soroban", ["config", "identity", "show"], { shell: true, encoding: "utf8" }).stdout.trim()); +const aliceKeypair = Keypair.fromSecret(spawnSync("./soroban", ["config", "identity", "show", "alice"], { shell: true, encoding: "utf8" }).stdout.trim()); +const bobKeypair = Keypair.fromSecret(spawnSync("./soroban", ["config", "identity", "show", "bob"], { shell: true, encoding: "utf8" }).stdout.trim()); + +export const root = { + keypair: rootKeypair, + address: Address.fromString(rootKeypair.publicKey()), +} + +export const alice = { + keypair: aliceKeypair, + address: Address.fromString(aliceKeypair.publicKey()), +} + +export const bob = { + keypair: bobKeypair, + address: Address.fromString(bobKeypair.publicKey()), +} + +function getKeypair(pk: string): Keypair { + return Keypair.fromSecret({ + [root.keypair.publicKey()]: root.keypair.secret(), + [alice.keypair.publicKey()]: alice.keypair.secret(), + [bob.keypair.publicKey()]: bob.keypair.secret(), + }[pk]) +} export const rpcUrl = process.env.SOROBAN_RPC_URL ?? "http://localhost:8000/"; -export const secretKey = - "SC36BWNUOCZAO7DMEJNNKFV6BOTPJP7IG5PSHLUOLT6DZFRU3D3XGIXW"; - -const keypair = Keypair.fromSecret(secretKey); -export const publicKey = keypair.publicKey(); -const networkPassphrase = "Standalone Network ; February 2017"; - -export const wallet = { - isConnected: () => Promise.resolve(true), - isAllowed: () => Promise.resolve(true), - getUserInfo: () => Promise.resolve({ publicKey }), - signTransaction: async ( - tx: string, - _opts?: { - network?: string; - networkPassphrase?: string; - accountToSign?: string; - } - ) => { +export const networkPassphrase = process.env.SOROBAN_NETWORK_PASSPHRASE ?? "Standalone Network ; February 2017"; + +export class Wallet { + constructor(private publicKey: string) {} + isConnected = () => Promise.resolve(true) + isAllowed = () => Promise.resolve(true) + getUserInfo = () => Promise.resolve({ publicKey: this.publicKey }) + signTransaction = async (tx: string) => { const t = TransactionBuilder.fromXDR(tx, networkPassphrase); - t.sign(keypair); + t.sign(getKeypair(this.publicKey)); return t.toXDR(); - }, -}; + } + signAuthEntry = async ( + entryXdr: string, + opts?: { + accountToSign?: string, + } + ): Promise => { + return getKeypair(opts?.accountToSign ?? this.publicKey) + .sign(hash(Buffer.from(entryXdr, "base64"))) + .toString('base64') + } +} + +export const wallet = new Wallet(root.keypair.publicKey()) diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/tsconfig.json b/cmd/crates/soroban-spec-typescript/ts-tests/tsconfig.json index b90870f4e..119437bc5 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/tsconfig.json +++ b/cmd/crates/soroban-spec-typescript/ts-tests/tsconfig.json @@ -22,9 +22,9 @@ // "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. */ + "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. */ + "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. */ diff --git a/cmd/crates/soroban-test/Cargo.toml b/cmd/crates/soroban-test/Cargo.toml index e2a4d4d87..7780409ec 100644 --- a/cmd/crates/soroban-test/Cargo.toml +++ b/cmd/crates/soroban-test/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/stellar/soroban-test" authors = ["Stellar Development Foundation "] license = "Apache-2.0" readme = "README.md" -version = "20.0.0-rc4" +version = "20.1.1" edition = "2021" rust-version = "1.70" autobins = false @@ -39,4 +39,4 @@ which = { workspace = true } tokio = "1.28.1" [features] -integration = [] \ No newline at end of file +integration = [] diff --git a/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/hello/Cargo.toml index e6df599f7..8b08d0076 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 = "20.0.0-rc4" +version = "20.1.1" edition = "2021" publish = false 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 3540ecb51..baa76473b 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 = "20.0.0-rc4" +version = "20.1.1" 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 db1778c3b..64780d47a 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 = "20.0.0-rc4" +version = "20.1.1" authors = ["Stellar Development Foundation "] license = "Apache-2.0" edition = "2021" diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/src/lib.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/src/lib.rs index 03077ad57..40006a1b7 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/src/lib.rs +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/hello_world/src/lib.rs @@ -49,7 +49,7 @@ impl Contract { } pub fn prng_u64_in_range(env: Env, low: u64, high: u64) -> u64 { - env.prng().u64_in_range(low..=high) + env.prng().gen_range(low..=high) } pub fn upgrade_contract(env: Env, hash: BytesN<32>) { 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 new file mode 100644 index 000000000..27aede50d --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "test_swap" +version.workspace = true +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +edition = "2021" +publish = false +rust-version = "1.70" + +[lib] +crate-type = ["cdylib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } + +[dev_dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/lib.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/lib.rs new file mode 100644 index 000000000..528b84227 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/lib.rs @@ -0,0 +1,77 @@ +//! This contract performs an atomic token swap between two parties. +//! Parties don't need to know each other and their signatures may be matched +//! off-chain. +//! This example demonstrates how multi-party authorization can be implemented. +#![no_std] + +use soroban_sdk::{contract, contractimpl, token, Address, Env, IntoVal}; + +#[contract] +pub struct AtomicSwapContract; + +#[contractimpl] +impl AtomicSwapContract { + // Swap token A for token B atomically. Settle for the minimum requested price + // for each party (this is an arbitrary choice; both parties could have + // received the full amount as well). + pub fn swap( + env: Env, + a: Address, + b: Address, + token_a: Address, + token_b: Address, + amount_a: i128, + min_b_for_a: i128, + amount_b: i128, + min_a_for_b: i128, + ) { + // Verify preconditions on the minimum price for both parties. + if amount_b < min_b_for_a { + panic!("not enough token B for token A"); + } + if amount_a < min_a_for_b { + panic!("not enough token A for token B"); + } + // Require authorization for a subset of arguments specific to a party. + // Notice, that arguments are symmetric - there is no difference between + // `a` and `b` in the call and hence their signatures can be used + // either for `a` or for `b` role. + a.require_auth_for_args( + (token_a.clone(), token_b.clone(), amount_a, min_b_for_a).into_val(&env), + ); + b.require_auth_for_args( + (token_b.clone(), token_a.clone(), amount_b, min_a_for_b).into_val(&env), + ); + + // Perform the swap by moving tokens from a to b and from b to a. + move_token(&env, &token_a, &a, &b, amount_a, min_a_for_b); + move_token(&env, &token_b, &b, &a, amount_b, min_b_for_a); + } +} + +fn move_token( + env: &Env, + token: &Address, + from: &Address, + to: &Address, + max_spend_amount: i128, + transfer_amount: i128, +) { + let token = token::Client::new(env, token); + let contract_address = env.current_contract_address(); + // This call needs to be authorized by `from` address. It transfers the + // maximum spend amount to the swap contract's address in order to decouple + // the signature from `to` address (so that parties don't need to know each + // other). + token.transfer(from, &contract_address, &max_spend_amount); + // Transfer the necessary amount to `to`. + token.transfer(&contract_address, to, &transfer_amount); + // Refund the remaining balance to `from`. + token.transfer( + &contract_address, + from, + &(&max_spend_amount - &transfer_amount), + ); +} + +mod test; diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/test.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/test.rs new file mode 100644 index 000000000..4f3845331 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/test.rs @@ -0,0 +1,112 @@ +#![cfg(test)] +extern crate std; + +use super::*; +use soroban_sdk::{ + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + token, Address, Env, IntoVal, +}; +use token::Client as TokenClient; +use token::StellarAssetClient as TokenAdminClient; + +fn create_token_contract<'a>(e: &Env, admin: &Address) -> (TokenClient<'a>, TokenAdminClient<'a>) { + let contract_address = e.register_stellar_asset_contract(admin.clone()); + ( + TokenClient::new(e, &contract_address), + TokenAdminClient::new(e, &contract_address), + ) +} + +fn create_atomic_swap_contract(e: &Env) -> AtomicSwapContractClient { + AtomicSwapContractClient::new(e, &e.register_contract(None, AtomicSwapContract {})) +} + +#[test] +fn test_atomic_swap() { + let env = Env::default(); + env.mock_all_auths(); + + let a = Address::random(&env); + let b = Address::random(&env); + + let token_admin = Address::random(&env); + + let (token_a, token_a_admin) = create_token_contract(&env, &token_admin); + let (token_b, token_b_admin) = create_token_contract(&env, &token_admin); + token_a_admin.mint(&a, &1000); + token_b_admin.mint(&b, &5000); + + let contract = create_atomic_swap_contract(&env); + + contract.swap( + &a, + &b, + &token_a.address, + &token_b.address, + &1000, + &4500, + &5000, + &950, + ); + + assert_eq!( + env.auths(), + std::vec![ + ( + a.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + contract.address.clone(), + symbol_short!("swap"), + ( + token_a.address.clone(), + token_b.address.clone(), + 1000_i128, + 4500_i128 + ) + .into_val(&env), + )), + sub_invocations: std::vec![AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token_a.address.clone(), + symbol_short!("transfer"), + (a.clone(), contract.address.clone(), 1000_i128,).into_val(&env), + )), + sub_invocations: std::vec![] + }] + } + ), + ( + b.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + contract.address.clone(), + symbol_short!("swap"), + ( + token_b.address.clone(), + token_a.address.clone(), + 5000_i128, + 950_i128 + ) + .into_val(&env), + )), + sub_invocations: std::vec![AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token_b.address.clone(), + symbol_short!("transfer"), + (b.clone(), contract.address.clone(), 5000_i128,).into_val(&env), + )), + sub_invocations: std::vec![] + }] + } + ), + ] + ); + + assert_eq!(token_a.balance(&a), 50); + assert_eq!(token_a.balance(&b), 950); + + assert_eq!(token_b.balance(&a), 4500); + assert_eq!(token_b.balance(&b), 500); +} 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 new file mode 100644 index 000000000..7a81bee77 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "test_token" +version.workspace = true +description = "Soroban standard token contract" +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +edition = "2021" +publish = false +rust-version = "1.70" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +soroban-sdk = { workspace = true } +soroban-token-sdk = { workspace = true } + +[dev_dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/admin.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/admin.rs new file mode 100644 index 000000000..a820bf040 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/admin.rs @@ -0,0 +1,18 @@ +use soroban_sdk::{Address, Env}; + +use crate::storage_types::DataKey; + +pub fn has_administrator(e: &Env) -> bool { + let key = DataKey::Admin; + e.storage().instance().has(&key) +} + +pub fn read_administrator(e: &Env) -> Address { + let key = DataKey::Admin; + e.storage().instance().get(&key).unwrap() +} + +pub fn write_administrator(e: &Env, id: &Address) { + let key = DataKey::Admin; + e.storage().instance().set(&key, id); +} diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/allowance.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/allowance.rs new file mode 100644 index 000000000..ad7468716 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/allowance.rs @@ -0,0 +1,63 @@ +use crate::storage_types::{AllowanceDataKey, AllowanceValue, DataKey}; +use soroban_sdk::{Address, Env}; + +pub fn read_allowance(e: &Env, from: Address, spender: Address) -> AllowanceValue { + let key = DataKey::Allowance(AllowanceDataKey { from, spender }); + if let Some(allowance) = e.storage().temporary().get::<_, AllowanceValue>(&key) { + if allowance.expiration_ledger < e.ledger().sequence() { + AllowanceValue { + amount: 0, + expiration_ledger: allowance.expiration_ledger, + } + } else { + allowance + } + } else { + AllowanceValue { + amount: 0, + expiration_ledger: 0, + } + } +} + +pub fn write_allowance( + e: &Env, + from: Address, + spender: Address, + amount: i128, + expiration_ledger: u32, +) { + let allowance = AllowanceValue { + amount, + expiration_ledger, + }; + + if amount > 0 && expiration_ledger < e.ledger().sequence() { + panic!("expiration_ledger is less than ledger seq when amount > 0") + } + + let key = DataKey::Allowance(AllowanceDataKey { from, spender }); + e.storage().temporary().set(&key.clone(), &allowance); + + if amount > 0 { + let live_for = expiration_ledger + .checked_sub(e.ledger().sequence()) + .unwrap(); + + e.storage().temporary().extend_ttl(&key, live_for, live_for) + } +} + +pub fn spend_allowance(e: &Env, from: Address, spender: Address, amount: i128) { + let allowance = read_allowance(e, from.clone(), spender.clone()); + if allowance.amount < amount { + panic!("insufficient allowance"); + } + write_allowance( + e, + from, + spender, + allowance.amount - amount, + allowance.expiration_ledger, + ); +} diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/balance.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/balance.rs new file mode 100644 index 000000000..76134e8d8 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/balance.rs @@ -0,0 +1,35 @@ +use crate::storage_types::{DataKey, BALANCE_BUMP_AMOUNT, BALANCE_LIFETIME_THRESHOLD}; +use soroban_sdk::{Address, Env}; + +pub fn read_balance(e: &Env, addr: Address) -> i128 { + let key = DataKey::Balance(addr); + if let Some(balance) = e.storage().persistent().get::(&key) { + e.storage() + .persistent() + .extend_ttl(&key, BALANCE_LIFETIME_THRESHOLD, BALANCE_BUMP_AMOUNT); + balance + } else { + 0 + } +} + +fn write_balance(e: &Env, addr: Address, amount: i128) { + let key = DataKey::Balance(addr); + e.storage().persistent().set(&key, &amount); + e.storage() + .persistent() + .extend_ttl(&key, BALANCE_LIFETIME_THRESHOLD, BALANCE_BUMP_AMOUNT); +} + +pub fn receive_balance(e: &Env, addr: Address, amount: i128) { + let balance = read_balance(e, addr.clone()); + write_balance(e, addr, balance + amount); +} + +pub fn spend_balance(e: &Env, addr: Address, amount: i128) { + let balance = read_balance(e, addr.clone()); + if balance < amount { + panic!("insufficient balance"); + } + write_balance(e, addr, balance - amount); +} diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/contract.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/contract.rs new file mode 100644 index 000000000..cc5690c6c --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/contract.rs @@ -0,0 +1,167 @@ +//! This contract demonstrates a sample implementation of the Soroban token +//! interface. +use crate::admin::{has_administrator, read_administrator, write_administrator}; +use crate::allowance::{read_allowance, spend_allowance, write_allowance}; +use crate::balance::{read_balance, receive_balance, spend_balance}; +use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; +use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; +use soroban_sdk::token::{self, Interface as _}; +use soroban_sdk::{contract, contractimpl, Address, Env, String}; +use soroban_token_sdk::metadata::TokenMetadata; +use soroban_token_sdk::TokenUtils; + +fn check_nonnegative_amount(amount: i128) { + if amount < 0 { + panic!("negative amount is not allowed: {}", amount) + } +} + +#[contract] +pub struct Token; + +#[contractimpl] +impl Token { + pub fn initialize(e: Env, admin: Address, decimal: u32, name: String, symbol: String) { + if has_administrator(&e) { + panic!("already initialized") + } + write_administrator(&e, &admin); + if decimal > u8::MAX.into() { + panic!("Decimal must fit in a u8"); + } + + write_metadata( + &e, + TokenMetadata { + decimal, + name, + symbol, + }, + ) + } + + pub fn mint(e: Env, to: Address, amount: i128) { + check_nonnegative_amount(amount); + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + receive_balance(&e, to.clone(), amount); + TokenUtils::new(&e).events().mint(admin, to, amount); + } + + pub fn set_admin(e: Env, new_admin: Address) { + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_administrator(&e, &new_admin); + TokenUtils::new(&e).events().set_admin(admin, new_admin); + } +} + +#[contractimpl] +impl token::Interface for Token { + fn allowance(e: Env, from: Address, spender: Address) -> i128 { + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + read_allowance(&e, from, spender).amount + } + + fn approve(e: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32) { + from.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_allowance(&e, from.clone(), spender.clone(), amount, expiration_ledger); + TokenUtils::new(&e) + .events() + .approve(from, spender, amount, expiration_ledger); + } + + fn balance(e: Env, id: Address) -> i128 { + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + read_balance(&e, id) + } + + fn transfer(e: Env, from: Address, to: Address, amount: i128) { + from.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_balance(&e, from.clone(), amount); + receive_balance(&e, to.clone(), amount); + TokenUtils::new(&e).events().transfer(from, to, amount); + } + + fn transfer_from(e: Env, spender: Address, from: Address, to: Address, amount: i128) { + spender.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_allowance(&e, from.clone(), spender, amount); + spend_balance(&e, from.clone(), amount); + receive_balance(&e, to.clone(), amount); + TokenUtils::new(&e).events().transfer(from, to, amount) + } + + fn burn(e: Env, from: Address, amount: i128) { + from.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_balance(&e, from.clone(), amount); + TokenUtils::new(&e).events().burn(from, amount); + } + + fn burn_from(e: Env, spender: Address, from: Address, amount: i128) { + spender.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_allowance(&e, from.clone(), spender, amount); + spend_balance(&e, from.clone(), amount); + TokenUtils::new(&e).events().burn(from, amount) + } + + fn decimals(e: Env) -> u32 { + read_decimal(&e) + } + + fn name(e: Env) -> String { + read_name(&e) + } + + fn symbol(e: Env) -> String { + read_symbol(&e) + } +} diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/lib.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/lib.rs new file mode 100644 index 000000000..b5f04e4dc --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] + +mod admin; +mod allowance; +mod balance; +mod contract; +mod metadata; +mod storage_types; +mod test; + +pub use crate::contract::TokenClient; diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/metadata.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/metadata.rs new file mode 100644 index 000000000..715feeeaa --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/metadata.rs @@ -0,0 +1,22 @@ +use soroban_sdk::{Env, String}; +use soroban_token_sdk::{metadata::TokenMetadata, TokenUtils}; + +pub fn read_decimal(e: &Env) -> u32 { + let util = TokenUtils::new(e); + util.metadata().get_metadata().decimal +} + +pub fn read_name(e: &Env) -> String { + let util = TokenUtils::new(e); + util.metadata().get_metadata().name +} + +pub fn read_symbol(e: &Env) -> String { + let util = TokenUtils::new(e); + util.metadata().get_metadata().symbol +} + +pub fn write_metadata(e: &Env, metadata: TokenMetadata) { + let util = TokenUtils::new(e); + util.metadata().set_metadata(&metadata); +} diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/storage_types.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/storage_types.rs new file mode 100644 index 000000000..5710c0574 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/storage_types.rs @@ -0,0 +1,31 @@ +use soroban_sdk::{contracttype, Address}; + +pub(crate) const DAY_IN_LEDGERS: u32 = 17280; +pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; +pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; +pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +#[derive(Clone)] +#[contracttype] +pub struct AllowanceDataKey { + pub from: Address, + pub spender: Address, +} + +#[contracttype] +pub struct AllowanceValue { + pub amount: i128, + pub expiration_ledger: u32, +} + +#[derive(Clone)] +#[contracttype] +pub enum DataKey { + Allowance(AllowanceDataKey), + Balance(Address), + Nonce(Address), + State(Address), + Admin, +} diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/test.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/test.rs new file mode 100644 index 000000000..9aae46eba --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/test.rs @@ -0,0 +1,256 @@ +#![cfg(test)] +extern crate std; + +use crate::{contract::Token, TokenClient}; +use soroban_sdk::{ + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + Address, Env, IntoVal, Symbol, +}; + +fn create_token<'a>(e: &Env, admin: &Address) -> TokenClient<'a> { + let token = TokenClient::new(e, &e.register_contract(None, Token {})); + token.initialize(admin, &7, &"name".into_val(e), &"symbol".into_val(e)); + token +} + +#[test] +fn test() { + let e = Env::default(); + e.mock_all_auths(); + + let admin1 = Address::random(&e); + let admin2 = Address::random(&e); + let user1 = Address::random(&e); + let user2 = Address::random(&e); + let user3 = Address::random(&e); + let token = create_token(&e, &admin1); + + token.mint(&user1, &1000); + assert_eq!( + e.auths(), + std::vec![( + admin1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("mint"), + (&user1, 1000_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.balance(&user1), 1000); + + token.approve(&user2, &user3, &500, &200); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("approve"), + (&user2, &user3, 500_i128, 200_u32).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.allowance(&user2, &user3), 500); + + token.transfer(&user1, &user2, &600); + assert_eq!( + e.auths(), + std::vec![( + user1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("transfer"), + (&user1, &user2, 600_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.balance(&user1), 400); + assert_eq!(token.balance(&user2), 600); + + token.transfer_from(&user3, &user2, &user1, &400); + assert_eq!( + e.auths(), + std::vec![( + user3.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + Symbol::new(&e, "transfer_from"), + (&user3, &user2, &user1, 400_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.balance(&user1), 800); + assert_eq!(token.balance(&user2), 200); + + token.transfer(&user1, &user3, &300); + assert_eq!(token.balance(&user1), 500); + assert_eq!(token.balance(&user3), 300); + + token.set_admin(&admin2); + assert_eq!( + e.auths(), + std::vec![( + admin1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("set_admin"), + (&admin2,).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + + // Increase to 500 + token.approve(&user2, &user3, &500, &200); + assert_eq!(token.allowance(&user2, &user3), 500); + token.approve(&user2, &user3, &0, &200); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("approve"), + (&user2, &user3, 0_i128, 200_u32).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.allowance(&user2, &user3), 0); +} + +#[test] +fn test_burn() { + let e = Env::default(); + e.mock_all_auths(); + + let admin = Address::random(&e); + let user1 = Address::random(&e); + let user2 = Address::random(&e); + let token = create_token(&e, &admin); + + token.mint(&user1, &1000); + assert_eq!(token.balance(&user1), 1000); + + token.approve(&user1, &user2, &500, &200); + assert_eq!(token.allowance(&user1, &user2), 500); + + token.burn_from(&user2, &user1, &500); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("burn_from"), + (&user2, &user1, 500_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + + assert_eq!(token.allowance(&user1, &user2), 0); + assert_eq!(token.balance(&user1), 500); + assert_eq!(token.balance(&user2), 0); + + token.burn(&user1, &500); + assert_eq!( + e.auths(), + std::vec![( + user1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("burn"), + (&user1, 500_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + + assert_eq!(token.balance(&user1), 0); + assert_eq!(token.balance(&user2), 0); +} + +#[test] +#[should_panic(expected = "insufficient balance")] +fn transfer_insufficient_balance() { + let e = Env::default(); + e.mock_all_auths(); + + let admin = Address::random(&e); + let user1 = Address::random(&e); + let user2 = Address::random(&e); + let token = create_token(&e, &admin); + + token.mint(&user1, &1000); + assert_eq!(token.balance(&user1), 1000); + + token.transfer(&user1, &user2, &1001); +} + +#[test] +#[should_panic(expected = "insufficient allowance")] +fn transfer_from_insufficient_allowance() { + let e = Env::default(); + e.mock_all_auths(); + + let admin = Address::random(&e); + let user1 = Address::random(&e); + let user2 = Address::random(&e); + let user3 = Address::random(&e); + let token = create_token(&e, &admin); + + token.mint(&user1, &1000); + assert_eq!(token.balance(&user1), 1000); + + token.approve(&user1, &user3, &100, &200); + assert_eq!(token.allowance(&user1, &user3), 100); + + token.transfer_from(&user3, &user1, &user2, &101); +} + +#[test] +#[should_panic(expected = "already initialized")] +fn initialize_already_initialized() { + let e = Env::default(); + let admin = Address::random(&e); + let token = create_token(&e, &admin); + + token.initialize(&admin, &10, &"name".into_val(&e), &"symbol".into_val(&e)); +} + +#[test] +#[should_panic(expected = "Decimal must fit in a u8")] +fn decimal_is_over_max() { + let e = Env::default(); + let admin = Address::random(&e); + let token = TokenClient::new(&e, &e.register_contract(None, Token {})); + token.initialize( + &admin, + &(u32::from(u8::MAX) + 1), + &"name".into_val(&e), + &"symbol".into_val(&e), + ); +} diff --git a/cmd/crates/soroban-test/tests/it/arg_parsing.rs b/cmd/crates/soroban-test/tests/it/arg_parsing.rs index fd685b5a9..c245fd8c9 100644 --- a/cmd/crates/soroban-test/tests/it/arg_parsing.rs +++ b/cmd/crates/soroban-test/tests/it/arg_parsing.rs @@ -90,7 +90,7 @@ fn parse_i256() { #[test] fn parse_bytes() { - let b = from_string_primitive(r#"beefface"#, &ScSpecTypeDef::Bytes).unwrap(); + let b = from_string_primitive(r"beefface", &ScSpecTypeDef::Bytes).unwrap(); assert_eq!( b, ScVal::Bytes(ScBytes(vec![0xbe, 0xef, 0xfa, 0xce].try_into().unwrap())) @@ -100,7 +100,7 @@ fn parse_bytes() { #[test] fn parse_bytes_when_hex_is_all_numbers() { - let b = from_string_primitive(r#"4554"#, &ScSpecTypeDef::Bytes).unwrap(); + let b = from_string_primitive(r"4554", &ScSpecTypeDef::Bytes).unwrap(); assert_eq!( b, ScVal::Bytes(ScBytes(vec![0x45, 0x54].try_into().unwrap())) @@ -111,7 +111,7 @@ fn parse_bytes_when_hex_is_all_numbers() { #[test] fn parse_bytesn() { let b = from_string_primitive( - r#"beefface"#, + r"beefface", &ScSpecTypeDef::BytesN(ScSpecTypeBytesN { n: 4 }), ) .unwrap(); @@ -124,8 +124,8 @@ fn parse_bytesn() { #[test] fn parse_bytesn_when_hex_is_all_numbers() { - let b = from_string_primitive(r#"4554"#, &ScSpecTypeDef::BytesN(ScSpecTypeBytesN { n: 2 })) - .unwrap(); + let b = + from_string_primitive(r"4554", &ScSpecTypeDef::BytesN(ScSpecTypeBytesN { n: 2 })).unwrap(); assert_eq!( b, ScVal::Bytes(ScBytes(vec![0x45, 0x54].try_into().unwrap())) diff --git a/cmd/soroban-cli/Cargo.toml b/cmd/soroban-cli/Cargo.toml index f6f6c757e..9f4fa2897 100644 --- a/cmd/soroban-cli/Cargo.toml +++ b/cmd/soroban-cli/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/stellar/soroban-cli" authors = ["Stellar Development Foundation "] license = "Apache-2.0" readme = "README.md" -version = "20.0.0-rc4" +version = "20.1.1" edition = "2021" rust-version = "1.72" autobins = false @@ -35,6 +35,7 @@ default = [] opt = ["dep:wasm-opt"] [dependencies] +stellar-xdr = { workspace = true, features = ["cli"] } soroban-env-host = { workspace = true } soroban-spec = { workspace = true } soroban-spec-json = { workspace = true } @@ -66,7 +67,7 @@ rand = "0.8.5" wasmparser = { workspace = true } sha2 = { workspace = true } csv = "1.1.6" -ed25519-dalek = "2.0.0" +ed25519-dalek = "=2.0.0" jsonrpsee-http-client = "0.20.1" jsonrpsee-core = "0.20.1" hyper = "0.14.27" diff --git a/cmd/soroban-cli/src/commands/contract/deploy.rs b/cmd/soroban-cli/src/commands/contract/deploy.rs index 5467b992a..1be8a3f54 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy.rs @@ -5,6 +5,7 @@ use std::num::ParseIntError; use clap::{arg, command, Parser}; use rand::Rng; use sha2::{Digest, Sha256}; +use soroban_env_host::xdr::Limits; use soroban_env_host::{ xdr::{ AccountId, ContractExecutable, ContractIdPreimage, ContractIdPreimageFromAddress, @@ -211,7 +212,7 @@ fn get_contract_id( network_id, contract_id_preimage, }); - let preimage_xdr = preimage.to_xdr()?; + let preimage_xdr = preimage.to_xdr(Limits::none())?; Ok(Hash(Sha256::digest(preimage_xdr).into())) } diff --git a/cmd/soroban-cli/src/commands/contract/install.rs b/cmd/soroban-cli/src/commands/contract/install.rs index ea5719140..905775298 100644 --- a/cmd/soroban-cli/src/commands/contract/install.rs +++ b/cmd/soroban-cli/src/commands/contract/install.rs @@ -15,6 +15,7 @@ use crate::rpc::{self, Client}; use crate::{commands::config, utils, wasm}; const CONTRACT_META_SDK_KEY: &str = "rssdkver"; +const PUBLIC_NETWORK_PASSPHRASE: &str = "Public Global Stellar Network ; September 2015"; #[derive(Parser, Debug, Clone)] #[group(skip)] @@ -70,29 +71,35 @@ impl Cmd { } pub async fn run_and_get_hash(&self) -> Result { + self.run_against_rpc_server(&self.wasm.read()?).await + } + + async fn run_against_rpc_server(&self, contract: &[u8]) -> Result { + let network = self.config.get_network()?; + let client = Client::new(&network.rpc_url)?; + client + .verify_network_passphrase(Some(&network.network_passphrase)) + .await?; let wasm_spec = &self.wasm.parse().map_err(|e| Error::CannotParseWasm { wasm: self.wasm.wasm.clone(), error: e, })?; + // Check Rust SDK version if using the public network. if let Some(rs_sdk_ver) = get_contract_meta_sdk_version(wasm_spec) { - if rs_sdk_ver.contains("rc") && !self.ignore_checks { + if rs_sdk_ver.contains("rc") + && !self.ignore_checks + && network.network_passphrase == PUBLIC_NETWORK_PASSPHRASE + { return Err(Error::ContractCompiledWithReleaseCandidateSdk { wasm: self.wasm.wasm.clone(), version: rs_sdk_ver, }); - } else if rs_sdk_ver.contains("rc") { + } else if rs_sdk_ver.contains("rc") + && network.network_passphrase == PUBLIC_NETWORK_PASSPHRASE + { tracing::warn!("the deployed smart contract {path} was built with Soroban Rust SDK v{rs_sdk_ver}, a release candidate version not intended for use with the Stellar Public Network", path = self.wasm.wasm.display()); } } - self.run_against_rpc_server(&self.wasm.read()?).await - } - - async fn run_against_rpc_server(&self, contract: &[u8]) -> Result { - let network = self.config.get_network()?; - let client = Client::new(&network.rpc_url)?; - client - .verify_network_passphrase(Some(&network.network_passphrase)) - .await?; let key = self.config.key_pair()?; // Get the account sequence number @@ -150,7 +157,7 @@ fn get_contract_meta_sdk_version(wasm_spec: &utils::contract_spec::ContractSpec) let rs_sdk_version_option = if let Some(_meta) = &wasm_spec.meta_base64 { wasm_spec.meta.iter().find(|entry| match entry { ScMetaEntry::ScMetaV0(ScMetaV0 { key, .. }) => { - key.to_string_lossy().contains(CONTRACT_META_SDK_KEY) + key.to_utf8_string_lossy().contains(CONTRACT_META_SDK_KEY) } }) } else { @@ -159,7 +166,7 @@ fn get_contract_meta_sdk_version(wasm_spec: &utils::contract_spec::ContractSpec) if let Some(rs_sdk_version_entry) = &rs_sdk_version_option { match rs_sdk_version_entry { ScMetaEntry::ScMetaV0(ScMetaV0 { val, .. }) => { - return Some(val.to_string_lossy()); + return Some(val.to_utf8_string_lossy()); } } } diff --git a/cmd/soroban-cli/src/commands/contract/invoke.rs b/cmd/soroban-cli/src/commands/contract/invoke.rs index 2d4c77c61..78be7b381 100644 --- a/cmd/soroban-cli/src/commands/contract/invoke.rs +++ b/cmd/soroban-cli/src/commands/contract/invoke.rs @@ -164,7 +164,7 @@ impl Cmd { .max_term_width(300); for ScSpecFunctionV0 { name, .. } in spec.find_functions()? { - cmd = cmd.subcommand(build_custom_cmd(&name.to_string_lossy(), &spec)?); + cmd = cmd.subcommand(build_custom_cmd(&name.to_utf8_string_lossy(), &spec)?); } cmd.build(); let long_help = cmd.render_long_help(); @@ -181,7 +181,7 @@ impl Cmd { .inputs .iter() .map(|i| { - let name = i.name.to_string()?; + 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(); if matches!(i.type_, ScSpecTypeDef::Address) { @@ -410,7 +410,7 @@ fn build_custom_cmd(name: &str, spec: &Spec) -> Result { let inputs_map = &func .inputs .iter() - .map(|i| (i.name.to_string().unwrap(), i.type_.clone())) + .map(|i| (i.name.to_utf8_string().unwrap(), i.type_.clone())) .collect::>(); let name: &'static str = Box::leak(name.to_string().into_boxed_str()); let mut cmd = clap::Command::new(name) @@ -421,7 +421,7 @@ fn build_custom_cmd(name: &str, spec: &Spec) -> Result { if kebab_name != name { cmd = cmd.alias(kebab_name); } - let doc: &'static str = Box::leak(func.doc.to_string_lossy().into_boxed_str()); + let doc: &'static str = Box::leak(func.doc.to_utf8_string_lossy().into_boxed_str()); let long_doc: &'static str = Box::leak(arg_file_help(doc).into_boxed_str()); cmd = cmd.about(Some(doc)).long_about(long_doc); diff --git a/cmd/soroban-cli/src/commands/contract/read.rs b/cmd/soroban-cli/src/commands/contract/read.rs index 8fa943273..842832d5f 100644 --- a/cmd/soroban-cli/src/commands/contract/read.rs +++ b/cmd/soroban-cli/src/commands/contract/read.rs @@ -11,6 +11,7 @@ use soroban_env_host::{ }, HostError, }; +use soroban_sdk::xdr::Limits; use crate::{ commands::config, @@ -163,10 +164,10 @@ impl Cmd { })?, ], Output::Xdr => [ - key.to_xdr_base64()?, - val.to_xdr_base64()?, - last_modified_ledger.to_xdr_base64()?, - live_until_ledger_seq.to_xdr_base64()?, + key.to_xdr_base64(Limits::none())?, + val.to_xdr_base64(Limits::none())?, + last_modified_ledger.to_xdr_base64(Limits::none())?, + live_until_ledger_seq.to_xdr_base64(Limits::none())?, ], }; out.write_record(output) diff --git a/cmd/soroban-cli/src/commands/events.rs b/cmd/soroban-cli/src/commands/events.rs index 002920de2..676052053 100644 --- a/cmd/soroban-cli/src/commands/events.rs +++ b/cmd/soroban-cli/src/commands/events.rs @@ -1,7 +1,7 @@ use clap::{arg, command, Parser}; use std::io; -use soroban_env_host::xdr::{self, ReadXdr}; +use soroban_env_host::xdr::{self, Limits, ReadXdr}; use super::config::{locator, network}; use crate::{rpc, utils}; @@ -143,7 +143,7 @@ impl Cmd { } if segment != "*" { - if let Err(e) = xdr::ScVal::from_xdr_base64(segment) { + if let Err(e) = xdr::ScVal::from_xdr_base64(segment, Limits::none()) { return Err(Error::InvalidSegment { topic: topic.to_string(), segment: segment.to_string(), diff --git a/cmd/soroban-cli/src/commands/lab/mod.rs b/cmd/soroban-cli/src/commands/lab/mod.rs index 7e33d7d97..96d64094d 100644 --- a/cmd/soroban-cli/src/commands/lab/mod.rs +++ b/cmd/soroban-cli/src/commands/lab/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; pub mod token; -pub mod xdr; #[derive(Debug, Subcommand)] pub enum Cmd { @@ -9,7 +8,7 @@ pub enum Cmd { Token(token::Root), /// Decode xdr - Xdr(xdr::Cmd), + Xdr(stellar_xdr::cli::Root), } #[derive(thiserror::Error, Debug)] @@ -17,7 +16,7 @@ pub enum Error { #[error(transparent)] Token(#[from] token::Error), #[error(transparent)] - Xdr(#[from] xdr::Error), + Xdr(#[from] stellar_xdr::cli::Error), } impl Cmd { diff --git a/cmd/soroban-cli/src/commands/lab/xdr.rs b/cmd/soroban-cli/src/commands/lab/xdr.rs deleted file mode 100644 index 014ccf7be..000000000 --- a/cmd/soroban-cli/src/commands/lab/xdr.rs +++ /dev/null @@ -1,34 +0,0 @@ -mod decode; - -use std::fmt::Debug; - -use clap::{Parser, Subcommand}; - -#[derive(Parser, Debug, Clone)] -#[group(skip)] -pub struct Cmd { - #[clap(subcommand)] - sub: SubCmd, -} - -#[derive(Subcommand, Debug, Clone)] -enum SubCmd { - /// Decode XDR - Dec(decode::Cmd), -} - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("decode: {0}")] - Decode(#[from] decode::Error), -} - -impl Cmd { - #[allow(clippy::too_many_lines)] - pub fn run(&self) -> Result<(), Error> { - match &self.sub { - SubCmd::Dec(d) => d.run()?, - }; - Ok(()) - } -} diff --git a/cmd/soroban-cli/src/commands/lab/xdr/decode.rs b/cmd/soroban-cli/src/commands/lab/xdr/decode.rs deleted file mode 100644 index 47f640cc5..000000000 --- a/cmd/soroban-cli/src/commands/lab/xdr/decode.rs +++ /dev/null @@ -1,65 +0,0 @@ -use clap::{ - arg, - builder::{PossibleValuesParser, TypedValueParser}, - Parser, ValueEnum, -}; -use core::str::FromStr; -use soroban_env_host::xdr; - -#[derive(Parser, Debug, Clone)] -#[group(skip)] -pub struct Cmd { - /// XDR type to decode to - #[arg( - long, - value_parser = - PossibleValuesParser::new(xdr::TypeVariant::VARIANTS_STR) - .try_map(|s| xdr::TypeVariant::from_str(&s)) - )] - r#type: xdr::TypeVariant, - /// XDR (base64 encoded) to decode - #[arg(long)] - xdr: String, - /// Type of output - #[arg(long, value_enum, default_value_t)] - output: Output, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)] -pub enum Output { - // Default structured output - Default, - /// Json representation - Json, -} - -impl Default for Output { - fn default() -> Self { - Self::Default - } -} - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("parsing xdr: {0}")] - Xdr(#[from] xdr::Error), - #[error("generating json: {0}")] - Json(#[from] serde_json::Error), -} - -impl Cmd { - pub fn run(&self) -> Result<(), Error> { - let value = - xdr::Type::from_xdr_base64(self.r#type, self.xdr.clone()).map_err(Error::Xdr)?; - - match self.output { - Output::Default => println!("{value:#?}"), - Output::Json => println!( - "{}", - serde_json::to_string_pretty(&value).map_err(Error::Json)? - ), - } - - Ok(()) - } -} diff --git a/cmd/soroban-cli/src/commands/mod.rs b/cmd/soroban-cli/src/commands/mod.rs index a9f668082..76152261d 100644 --- a/cmd/soroban-cli/src/commands/mod.rs +++ b/cmd/soroban-cli/src/commands/mod.rs @@ -45,9 +45,8 @@ Full CLI reference: https://github.com/stellar/soroban-tools/tree/main/docs/soro #[derive(Parser, Debug)] #[command( name = "soroban", - version = version::short(), - long_version = version::long(), about = ABOUT, + version = version::long(), long_about = ABOUT.to_string() + LONG_ABOUT, disable_help_subcommand = true, )] diff --git a/cmd/soroban-cli/src/commands/version.rs b/cmd/soroban-cli/src/commands/version.rs index e1c7204d7..d9fc091b2 100644 --- a/cmd/soroban-cli/src/commands/version.rs +++ b/cmd/soroban-cli/src/commands/version.rs @@ -15,15 +15,11 @@ impl Cmd { } } -pub fn short() -> String { - format!("{} ({GIT_REVISION})", env!("CARGO_PKG_VERSION")) -} - pub fn long() -> String { let env = soroban_env_host::VERSION; let xdr = soroban_env_host::VERSION.xdr; [ - short(), + format!("{} ({GIT_REVISION})", env!("CARGO_PKG_VERSION")), format!("soroban-env {} ({})", env.pkg, env.rev), format!("soroban-env interface version {}", meta::INTERFACE_VERSION), format!( diff --git a/cmd/soroban-cli/src/key.rs b/cmd/soroban-cli/src/key.rs index ae3086f54..e9901abd2 100644 --- a/cmd/soroban-cli/src/key.rs +++ b/cmd/soroban-cli/src/key.rs @@ -1,6 +1,7 @@ use clap::arg; use soroban_env_host::xdr::{ - self, LedgerKey, LedgerKeyContractCode, LedgerKeyContractData, ReadXdr, ScAddress, ScVal, + self, LedgerKey, LedgerKeyContractCode, LedgerKeyContractData, Limits, ReadXdr, ScAddress, + ScVal, }; use std::path::PathBuf; @@ -75,7 +76,7 @@ impl Args { .collect::, Error>>()? } else if let Some(keys) = &self.key_xdr { keys.iter() - .map(|s| Ok(ScVal::from_xdr_base64(s)?)) + .map(|s| Ok(ScVal::from_xdr_base64(s, Limits::none())?)) .collect::, Error>>()? } else if let Some(wasm) = &self.wasm { return Ok(vec![crate::wasm::Args { wasm: wasm.clone() }.try_into()?]); diff --git a/cmd/soroban-cli/src/rpc/mod.rs b/cmd/soroban-cli/src/rpc/mod.rs index d9fe541a3..535426292 100644 --- a/cmd/soroban-cli/src/rpc/mod.rs +++ b/cmd/soroban-cli/src/rpc/mod.rs @@ -7,15 +7,15 @@ use serde_aux::prelude::{ deserialize_default_from_null, deserialize_number_from_string, deserialize_option_number_from_string, }; -use soroban_env_host::xdr::DepthLimitedRead; use soroban_env_host::xdr::{ self, AccountEntry, AccountId, ContractDataEntry, DiagnosticEvent, Error as XdrError, - LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount, PublicKey, ReadXdr, + LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount, Limited, PublicKey, ReadXdr, SorobanAuthorizationEntry, SorobanResources, SorobanTransactionData, Transaction, TransactionEnvelope, TransactionMeta, TransactionMetaV3, TransactionResult, Uint256, VecM, WriteXdr, }; use soroban_sdk::token; +use soroban_sdk::xdr::Limits; use std::{ fmt::Display, str::FromStr, @@ -111,10 +111,7 @@ pub struct SendTransactionResponse { default )] pub error_result_xdr: Option, - #[serde( - rename = "latestLedger", - deserialize_with = "deserialize_number_from_string" - )] + #[serde(rename = "latestLedger")] pub latest_ledger: u32, #[serde( rename = "latestLedgerCloseTime", @@ -159,12 +156,15 @@ impl TryInto for GetTransactionResponseRaw { status: self.status, envelope: self .envelope_xdr - .map(ReadXdr::from_xdr_base64) + .map(|v| ReadXdr::from_xdr_base64(v, Limits::none())) + .transpose()?, + result: self + .result_xdr + .map(|v| ReadXdr::from_xdr_base64(v, Limits::none())) .transpose()?, - result: self.result_xdr.map(ReadXdr::from_xdr_base64).transpose()?, result_meta: self .result_meta_xdr - .map(ReadXdr::from_xdr_base64) + .map(|v| ReadXdr::from_xdr_base64(v, Limits::none())) .transpose()?, }) } @@ -174,10 +174,7 @@ impl TryInto for GetTransactionResponseRaw { pub struct LedgerEntryResult { pub key: String, pub xdr: String, - #[serde( - rename = "lastModifiedLedgerSeq", - deserialize_with = "deserialize_number_from_string" - )] + #[serde(rename = "lastModifiedLedgerSeq")] pub last_modified_ledger: u32, #[serde( rename = "liveUntilLedgerSeq", @@ -191,10 +188,7 @@ pub struct LedgerEntryResult { #[derive(serde::Deserialize, serde::Serialize, Debug)] pub struct GetLedgerEntriesResponse { pub entries: Option>, - #[serde( - rename = "latestLedger", - deserialize_with = "deserialize_number_from_string" - )] + #[serde(rename = "latestLedger")] pub latest_ledger: i64, } @@ -207,20 +201,14 @@ pub struct GetNetworkResponse { )] pub friendbot_url: Option, pub passphrase: String, - #[serde( - rename = "protocolVersion", - deserialize_with = "deserialize_number_from_string" - )] + #[serde(rename = "protocolVersion")] pub protocol_version: u32, } #[derive(serde::Deserialize, serde::Serialize, Debug)] pub struct GetLatestLedgerResponse { pub id: String, - #[serde( - rename = "protocolVersion", - deserialize_with = "deserialize_number_from_string" - )] + #[serde(rename = "protocolVersion")] pub protocol_version: u32, pub sequence: u32, } @@ -278,10 +266,7 @@ pub struct SimulateTransactionResponse { default )] pub restore_preamble: Option, - #[serde( - rename = "latestLedger", - deserialize_with = "deserialize_number_from_string" - )] + #[serde(rename = "latestLedger")] pub latest_ledger: u32, #[serde(skip_serializing_if = "Option::is_none", default)] pub error: Option, @@ -296,9 +281,14 @@ impl SimulateTransactionResponse { auth: r .auth .iter() - .map(|a| Ok(SorobanAuthorizationEntry::from_xdr_base64(a)?)) + .map(|a| { + Ok(SorobanAuthorizationEntry::from_xdr_base64( + a, + Limits::none(), + )?) + }) .collect::>()?, - xdr: xdr::ScVal::from_xdr_base64(&r.xdr)?, + xdr: xdr::ScVal::from_xdr_base64(&r.xdr, Limits::none())?, }) }) .collect() @@ -307,13 +297,14 @@ impl SimulateTransactionResponse { pub fn events(&self) -> Result, Error> { self.events .iter() - .map(|e| Ok(DiagnosticEvent::from_xdr_base64(e)?)) + .map(|e| Ok(DiagnosticEvent::from_xdr_base64(e, Limits::none())?)) .collect() } pub fn transaction_data(&self) -> Result { Ok(SorobanTransactionData::from_xdr_base64( &self.transaction_data, + Limits::none(), )?) } } @@ -333,10 +324,7 @@ pub struct RestorePreamble { pub struct GetEventsResponse { #[serde(deserialize_with = "deserialize_default_from_null")] pub events: Vec, - #[serde( - rename = "latestLedger", - deserialize_with = "deserialize_number_from_string" - )] + #[serde(rename = "latestLedger")] pub latest_ledger: u32, } @@ -368,7 +356,7 @@ pub struct Event { #[serde(rename = "type")] pub event_type: String, - pub ledger: String, + pub ledger: u32, #[serde(rename = "ledgerClosedAt")] pub ledger_closed_at: String, @@ -398,10 +386,12 @@ impl Display for Event { writeln!(f, " Contract: {}", self.contract_id)?; writeln!(f, " Topics:")?; for topic in &self.topic { - let scval = xdr::ScVal::from_xdr_base64(topic).map_err(|_| std::fmt::Error)?; + let scval = + xdr::ScVal::from_xdr_base64(topic, Limits::none()).map_err(|_| std::fmt::Error)?; writeln!(f, " {scval:?}")?; } - let scval = xdr::ScVal::from_xdr_base64(&self.value).map_err(|_| std::fmt::Error)?; + let scval = xdr::ScVal::from_xdr_base64(&self.value, Limits::none()) + .map_err(|_| std::fmt::Error)?; writeln!(f, " Value: {scval:?}") } } @@ -457,7 +447,7 @@ impl Event { colored!(stdout, " Topics:\n")?; for topic in &self.topic { - let scval = xdr::ScVal::from_xdr_base64(topic)?; + let scval = xdr::ScVal::from_xdr_base64(topic, Limits::none())?; colored!( stdout, " {}{:?}{}\n", @@ -467,7 +457,7 @@ impl Event { )?; } - let scval = xdr::ScVal::from_xdr_base64(&self.value)?; + let scval = xdr::ScVal::from_xdr_base64(&self.value, Limits::none())?; colored!( stdout, " Value: {}{:?}{}\n", @@ -612,10 +602,8 @@ soroban config identity fund {address} --helper-url "# )); } let ledger_entry = &entries[0]; - let mut depth_limit_read = DepthLimitedRead::new(ledger_entry.xdr.as_bytes(), 100); - if let LedgerEntryData::Account(entry) = - LedgerEntryData::read_xdr_base64(&mut depth_limit_read)? - { + let mut read = Limited::new(ledger_entry.xdr.as_bytes(), Limits::none()); + if let LedgerEntryData::Account(entry) = LedgerEntryData::read_xdr_base64(&mut read)? { tracing::trace!(account=?entry); Ok(entry) } else { @@ -635,7 +623,10 @@ soroban config identity fund {address} --helper-url "# status, .. } = client - .request("sendTransaction", rpc_params![tx.to_xdr_base64()?]) + .request( + "sendTransaction", + rpc_params![tx.to_xdr_base64(Limits::none())?], + ) .await .map_err(|err| { Error::TransactionSubmissionFailed(format!("No status yet:\n {err:#?}")) @@ -645,9 +636,9 @@ soroban config identity fund {address} --helper-url "# let error = error_result_xdr .ok_or(Error::MissingError) .and_then(|x| { - TransactionResult::read_xdr_base64(&mut DepthLimitedRead::new( + TransactionResult::read_xdr_base64(&mut Limited::new( x.as_bytes(), - 100, + Limits::none(), )) .map_err(|_| Error::InvalidResponse) }) @@ -701,10 +692,12 @@ soroban config identity fund {address} --helper-url "# tx: &TransactionEnvelope, ) -> Result { tracing::trace!("Simulating:\n{tx:#?}"); - let base64_tx = tx.to_xdr_base64()?; + let base64_tx = tx.to_xdr_base64(Limits::none())?; + let mut builder = ObjectParams::new(); + builder.insert("transaction", base64_tx)?; let response: SimulateTransactionResponse = self .client()? - .request("simulateTransaction", rpc_params![base64_tx]) + .request("simulateTransaction", builder) .await?; tracing::trace!("Simulation response:\n {response:#?}"); match response.error { @@ -750,11 +743,11 @@ soroban config identity fund {address} --helper-url "# ) -> Result { let mut base64_keys: Vec = vec![]; for k in keys { - let base64_result = k.to_xdr_base64(); + let base64_result = k.to_xdr_base64(Limits::none()); if base64_result.is_err() { return Err(Error::Xdr(XdrError::Invalid)); } - base64_keys.push(k.to_xdr_base64().unwrap()); + base64_keys.push(k.to_xdr_base64(Limits::none()).unwrap()); } Ok(self .client()? @@ -788,8 +781,8 @@ soroban config identity fund {address} --helper-url "# live_until_ledger_seq_ledger_seq, }| { Ok(FullLedgerEntry { - key: LedgerKey::from_xdr_base64(key)?, - val: LedgerEntryData::from_xdr_base64(xdr)?, + key: LedgerKey::from_xdr_base64(key, Limits::none())?, + val: LedgerEntryData::from_xdr_base64(xdr, Limits::none())?, live_until_ledger_seq: live_until_ledger_seq_ledger_seq.unwrap_or_default(), last_modified_ledger: *last_modified_ledger, }) @@ -831,7 +824,7 @@ soroban config identity fund {address} --helper-url "# let mut oparams = ObjectParams::new(); match start { - EventStart::Ledger(l) => oparams.insert("startLedger", l.to_string())?, + EventStart::Ledger(l) => oparams.insert("startLedger", l)?, EventStart::Cursor(c) => { pagination.insert("cursor".to_string(), c.into()); } @@ -859,7 +852,7 @@ soroban config identity fund {address} --helper-url "# return Err(Error::NotFound("Contract".to_string(), contract_address)); } let contract_ref_entry = &entries[0]; - match LedgerEntryData::from_xdr_base64(&contract_ref_entry.xdr)? { + match LedgerEntryData::from_xdr_base64(&contract_ref_entry.xdr, Limits::none())? { LedgerEntryData::ContractData(contract_data) => Ok(contract_data), scval => Err(Error::UnexpectedContractCodeDataType(scval)), } @@ -890,7 +883,7 @@ soroban config identity fund {address} --helper-url "# )); } let contract_data_entry = &entries[0]; - match LedgerEntryData::from_xdr_base64(&contract_data_entry.xdr)? { + match LedgerEntryData::from_xdr_base64(&contract_data_entry.xdr, Limits::none())? { LedgerEntryData::ContractCode(xdr::ContractCodeEntry { code, .. }) => Ok(code.into()), scval => Err(Error::UnexpectedContractCodeDataType(scval)), } @@ -963,7 +956,7 @@ mod tests { "minResourceFee": "100000000", "cost": { "cpuInsns": "1000", "memBytes": "1000" }, "transactionData": "", - "latestLedger": "1234" + "latestLedger": 1234 }"#; let resp: SimulateTransactionResponse = serde_json::from_str(s).unwrap(); @@ -973,7 +966,7 @@ mod tests { #[test] fn simulation_transaction_response_parsing_mostly_empty() { let s = r#"{ - "latestLedger": "1234" + "latestLedger": 1234 }"#; let resp: SimulateTransactionResponse = serde_json::from_str(s).unwrap(); diff --git a/cmd/soroban-cli/src/rpc/txn.rs b/cmd/soroban-cli/src/rpc/txn.rs index 32cda0633..cda5a3857 100644 --- a/cmd/soroban-cli/src/rpc/txn.rs +++ b/cmd/soroban-cli/src/rpc/txn.rs @@ -2,12 +2,13 @@ use ed25519_dalek::Signer; use sha2::{Digest, Sha256}; use soroban_env_host::xdr::{ self, AccountId, DecoratedSignature, ExtensionPoint, Hash, HashIdPreimage, - HashIdPreimageSorobanAuthorization, InvokeHostFunctionOp, Memo, Operation, OperationBody, - Preconditions, PublicKey, ReadXdr, RestoreFootprintOp, ScAddress, ScMap, ScSymbol, ScVal, - Signature, SignatureHint, SorobanAddressCredentials, SorobanAuthorizationEntry, - SorobanAuthorizedFunction, SorobanCredentials, SorobanResources, SorobanTransactionData, - Transaction, TransactionEnvelope, TransactionExt, TransactionSignaturePayload, - TransactionSignaturePayloadTaggedTransaction, TransactionV1Envelope, Uint256, VecM, WriteXdr, + HashIdPreimageSorobanAuthorization, InvokeHostFunctionOp, Limits, Memo, Operation, + OperationBody, Preconditions, PublicKey, ReadXdr, RestoreFootprintOp, ScAddress, ScMap, + ScSymbol, ScVal, Signature, SignatureHint, SorobanAddressCredentials, + SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanCredentials, SorobanResources, + SorobanTransactionData, Transaction, TransactionEnvelope, TransactionExt, + TransactionSignaturePayload, TransactionSignaturePayloadTaggedTransaction, + TransactionV1Envelope, Uint256, VecM, WriteXdr, }; use crate::rpc::{Client, Error, RestorePreamble, SimulateTransactionResponse}; @@ -31,7 +32,7 @@ impl Assembled { network_id: Hash(Sha256::digest(network_passphrase).into()), tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(self.txn.clone()), }; - Ok(Sha256::digest(signature_payload.to_xdr()?).into()) + Ok(Sha256::digest(signature_payload.to_xdr(Limits::none())?).into()) } pub fn sign( @@ -193,7 +194,7 @@ pub fn assemble( VecM::try_from( r.auth .iter() - .map(SorobanAuthorizationEntry::from_xdr_base64) + .map(|v| SorobanAuthorizationEntry::from_xdr_base64(v, Limits::none())) .collect::, _>>()?, ) }) @@ -340,7 +341,7 @@ fn sign_soroban_authorization_entry( nonce: *nonce, signature_expiration_ledger, }) - .to_xdr()?; + .to_xdr(Limits::none())?; let payload = Sha256::digest(preimage); let signature = signer.sign(&payload); @@ -378,7 +379,8 @@ fn sign_soroban_authorization_entry( } pub fn restore(parent: &Transaction, restore: &RestorePreamble) -> Result { - let transaction_data = SorobanTransactionData::from_xdr_base64(&restore.transaction_data)?; + let transaction_data = + SorobanTransactionData::from_xdr_base64(&restore.transaction_data, Limits::none())?; let fee = u32::try_from(restore.min_resource_fee) .map_err(|_| Error::LargeFee(restore.min_resource_fee))?; Ok(Transaction { @@ -459,10 +461,10 @@ mod tests { min_resource_fee: 115, latest_ledger: 3, results: vec![SimulateHostFunctionResultRaw { - auth: vec![fn_auth.to_xdr_base64().unwrap()], - xdr: ScVal::U32(0).to_xdr_base64().unwrap(), + auth: vec![fn_auth.to_xdr_base64(Limits::none()).unwrap()], + xdr: ScVal::U32(0).to_xdr_base64(Limits::none()).unwrap(), }], - transaction_data: transaction_data().to_xdr_base64().unwrap(), + transaction_data: transaction_data().to_xdr_base64(Limits::none()).unwrap(), ..Default::default() } } @@ -572,7 +574,7 @@ mod tests { &txn, &SimulateTransactionResponse { min_resource_fee: 115, - transaction_data: transaction_data().to_xdr_base64().unwrap(), + transaction_data: transaction_data().to_xdr_base64(Limits::none()).unwrap(), latest_ledger: 3, ..Default::default() }, @@ -592,7 +594,7 @@ mod tests { &txn, &SimulateTransactionResponse { min_resource_fee: 115, - transaction_data: transaction_data().to_xdr_base64().unwrap(), + transaction_data: transaction_data().to_xdr_base64(Limits::none()).unwrap(), latest_ledger: 3, ..Default::default() }, diff --git a/cmd/soroban-cli/src/utils.rs b/cmd/soroban-cli/src/utils.rs index 27faee733..ab0382b48 100644 --- a/cmd/soroban-cli/src/utils.rs +++ b/cmd/soroban-cli/src/utils.rs @@ -4,7 +4,7 @@ use stellar_strkey::ed25519::PrivateKey; use soroban_env_host::xdr::{ Asset, ContractIdPreimage, DecoratedSignature, Error as XdrError, Hash, HashIdPreimage, - HashIdPreimageContractId, Signature, SignatureHint, Transaction, TransactionEnvelope, + HashIdPreimageContractId, Limits, Signature, SignatureHint, Transaction, TransactionEnvelope, TransactionSignaturePayload, TransactionSignaturePayloadTaggedTransaction, TransactionV1Envelope, WriteXdr, }; @@ -26,7 +26,7 @@ pub fn transaction_hash(tx: &Transaction, network_passphrase: &str) -> Result<[u network_id: Hash(Sha256::digest(network_passphrase).into()), tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(tx.clone()), }; - Ok(Sha256::digest(signature_payload.to_xdr()?).into()) + Ok(Sha256::digest(signature_payload.to_xdr(Limits::none())?).into()) } /// # Errors @@ -112,7 +112,7 @@ pub fn contract_id_hash_from_asset( network_id, contract_id_preimage: ContractIdPreimage::Asset(asset.clone()), }); - let preimage_xdr = preimage.to_xdr()?; + let preimage_xdr = preimage.to_xdr(Limits::none())?; Ok(Hash(Sha256::digest(preimage_xdr).into())) } diff --git a/cmd/soroban-cli/src/utils/contract_spec.rs b/cmd/soroban-cli/src/utils/contract_spec.rs index da67bedc4..b4f24abec 100644 --- a/cmd/soroban-cli/src/utils/contract_spec.rs +++ b/cmd/soroban-cli/src/utils/contract_spec.rs @@ -5,7 +5,7 @@ use std::{ }; use soroban_env_host::xdr::{ - self, DepthLimitedRead, ReadXdr, ScEnvMetaEntry, ScMetaEntry, ScMetaV0, ScSpecEntry, + self, Limited, Limits, ReadXdr, ScEnvMetaEntry, ScMetaEntry, ScMetaV0, ScSpecEntry, ScSpecFunctionV0, ScSpecUdtEnumV0, ScSpecUdtErrorEnumV0, ScSpecUdtStructV0, ScSpecUdtUnionV0, StringM, WriteXdr, }; @@ -60,9 +60,8 @@ impl ContractSpec { let env_meta = if let Some(env_meta) = env_meta { env_meta_base64 = Some(base64.encode(env_meta)); let cursor = Cursor::new(env_meta); - let mut depth_limit_read = DepthLimitedRead::new(cursor, 100); - ScEnvMetaEntry::read_xdr_iter(&mut depth_limit_read) - .collect::, xdr::Error>>()? + let mut read = Limited::new(cursor, Limits::none()); + ScEnvMetaEntry::read_xdr_iter(&mut read).collect::, xdr::Error>>()? } else { vec![] }; @@ -71,7 +70,7 @@ impl ContractSpec { let meta = if let Some(meta) = meta { meta_base64 = Some(base64.encode(meta)); let cursor = Cursor::new(meta); - let mut depth_limit_read = DepthLimitedRead::new(cursor, 100); + let mut depth_limit_read = Limited::new(cursor, Limits::none()); ScMetaEntry::read_xdr_iter(&mut depth_limit_read) .collect::, xdr::Error>>()? } else { @@ -82,9 +81,8 @@ impl ContractSpec { let spec = if let Some(spec) = spec { spec_base64 = Some(base64.encode(spec)); let cursor = Cursor::new(spec); - let mut depth_limit_read = DepthLimitedRead::new(cursor, 100); - ScSpecEntry::read_xdr_iter(&mut depth_limit_read) - .collect::, xdr::Error>>()? + let mut read = Limited::new(cursor, Limits::none()); + ScSpecEntry::read_xdr_iter(&mut read).collect::, xdr::Error>>()? } else { vec![] }; @@ -103,7 +101,7 @@ impl ContractSpec { let spec = self .spec .iter() - .map(|e| Ok(format!("\"{}\"", e.to_xdr_base64()?))) + .map(|e| Ok(format!("\"{}\"", e.to_xdr_base64(Limits::none())?))) .collect::, Error>>()? .join(",\n"); Ok(format!("[{spec}]")) @@ -159,12 +157,12 @@ impl Display for ContractSpec { } fn write_func(f: &mut std::fmt::Formatter<'_>, func: &ScSpecFunctionV0) -> std::fmt::Result { - writeln!(f, " • Function: {}", func.name.to_string_lossy())?; + writeln!(f, " • Function: {}", func.name.to_utf8_string_lossy())?; if func.doc.len() > 0 { writeln!( f, " Docs: {}", - &indent(&func.doc.to_string_lossy(), 11).trim() + &indent(&func.doc.to_utf8_string_lossy(), 11).trim() )?; } writeln!( @@ -187,7 +185,7 @@ fn write_union(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtUnionV0) -> std:: writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Cases:")?; @@ -204,7 +202,7 @@ fn write_struct(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtStructV0) -> std writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Fields:")?; @@ -212,7 +210,7 @@ fn write_struct(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtStructV0) -> std writeln!( f, " • {}: {}", - field.name.to_string_lossy(), + field.name.to_utf8_string_lossy(), indent(&format!("{:#?}", field.type_), 8).trim() )?; if field.doc.len() > 0 { @@ -229,7 +227,7 @@ fn write_enum(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtEnumV0) -> std::fm writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Cases:")?; @@ -246,7 +244,7 @@ fn write_error(f: &mut std::fmt::Formatter<'_>, udt: &ScSpecUdtErrorEnumV0) -> s writeln!( f, " Docs: {}", - indent(&udt.doc.to_string_lossy(), 10).trim() + indent(&udt.doc.to_utf8_string_lossy(), 10).trim() )?; } writeln!(f, " Cases:")?; @@ -267,8 +265,12 @@ fn indent(s: &str, n: usize) -> String { fn format_name(lib: &StringM<80>, name: &StringM<60>) -> String { if lib.len() > 0 { - format!("{}::{}", lib.to_string_lossy(), name.to_string_lossy()) + format!( + "{}::{}", + lib.to_utf8_string_lossy(), + name.to_utf8_string_lossy() + ) } else { - name.to_string_lossy() + name.to_utf8_string_lossy() } } diff --git a/cmd/soroban-rpc/internal/config/config.go b/cmd/soroban-rpc/internal/config/config.go index b16d02bb6..1f89ab2b5 100644 --- a/cmd/soroban-rpc/internal/config/config.go +++ b/cmd/soroban-rpc/internal/config/config.go @@ -15,7 +15,6 @@ type Config struct { Strict bool StellarCoreURL string - CaptiveCoreUseDB bool CaptiveCoreStoragePath string StellarCoreBinaryPath string CaptiveCoreConfigPath string diff --git a/cmd/soroban-rpc/internal/config/options.go b/cmd/soroban-rpc/internal/config/options.go index c3b4f2eda..cecfb2e7d 100644 --- a/cmd/soroban-rpc/internal/config/options.go +++ b/cmd/soroban-rpc/internal/config/options.go @@ -174,12 +174,6 @@ func (cfg *Config) options() ConfigOptions { } }, }, - { - Name: "captive-core-use-db", - Usage: "informs captive core to use on disk mode. the db will by default be created in current runtime directory of soroban-rpc, unless DATABASE= setting is present in captive core config file.", - ConfigKey: &cfg.CaptiveCoreUseDB, - DefaultValue: false, - }, { Name: "history-archive-urls", Usage: "comma-separated list of stellar history archives to connect with", diff --git a/cmd/soroban-rpc/internal/config/test.soroban.rpc.config b/cmd/soroban-rpc/internal/config/test.soroban.rpc.config index 96d924743..c28a9c17b 100644 --- a/cmd/soroban-rpc/internal/config/test.soroban.rpc.config +++ b/cmd/soroban-rpc/internal/config/test.soroban.rpc.config @@ -4,7 +4,6 @@ NETWORK_PASSPHRASE="Standalone Network ; February 2017" STELLAR_CORE_URL="http://localhost:11626" CAPTIVE_CORE_CONFIG_PATH="/opt/stellar/soroban-rpc/etc/stellar-captive-core.cfg" CAPTIVE_CORE_STORAGE_PATH="/opt/stellar/soroban-rpc/captive-core" -CAPTIVE_CORE_USE_DB=true STELLAR_CORE_BINARY_PATH="/usr/bin/stellar-core" HISTORY_ARCHIVE_URLS=["http://localhost:1570"] DB_PATH="/opt/stellar/soroban-rpc/rpc_db.sqlite" diff --git a/cmd/soroban-rpc/internal/config/toml_test.go b/cmd/soroban-rpc/internal/config/toml_test.go index 603151a31..93fa1809b 100644 --- a/cmd/soroban-rpc/internal/config/toml_test.go +++ b/cmd/soroban-rpc/internal/config/toml_test.go @@ -19,7 +19,6 @@ NETWORK_PASSPHRASE = "Test SDF Future Network ; October 2022" # testing comments work ok STELLAR_CORE_BINARY_PATH = "/usr/bin/stellar-core" -CAPTIVE_CORE_USE_DB = true CAPTIVE_CORE_STORAGE_PATH = "/etc/stellar/soroban-rpc" CAPTIVE_CORE_CONFIG_PATH = "/etc/stellar/soroban-rpc/captive-core.cfg" ` @@ -31,7 +30,6 @@ func TestBasicTomlReading(t *testing.T) { // Check the fields got read correctly assert.Equal(t, []string{"http://history-futurenet.stellar.org"}, cfg.HistoryArchiveURLs) assert.Equal(t, network.FutureNetworkPassphrase, cfg.NetworkPassphrase) - assert.Equal(t, true, cfg.CaptiveCoreUseDB) assert.Equal(t, "/etc/stellar/soroban-rpc", cfg.CaptiveCoreStoragePath) assert.Equal(t, "/etc/stellar/soroban-rpc/captive-core.cfg", cfg.CaptiveCoreConfigPath) } diff --git a/cmd/soroban-rpc/internal/daemon/daemon.go b/cmd/soroban-rpc/internal/daemon/daemon.go index 0f0ab80f8..63afb9a71 100644 --- a/cmd/soroban-rpc/internal/daemon/daemon.go +++ b/cmd/soroban-rpc/internal/daemon/daemon.go @@ -105,7 +105,7 @@ func newCaptiveCore(cfg *config.Config, logger *supportlog.Entry) (*ledgerbacken HistoryArchiveURLs: cfg.HistoryArchiveURLs, NetworkPassphrase: cfg.NetworkPassphrase, Strict: true, - UseDB: cfg.CaptiveCoreUseDB, + UseDB: true, EnforceSorobanDiagnosticEvents: true, } captiveCoreToml, err := ledgerbackend.NewCaptiveCoreTomlFromFile(cfg.CaptiveCoreConfigPath, captiveCoreTomlParams) @@ -122,7 +122,7 @@ func newCaptiveCore(cfg *config.Config, logger *supportlog.Entry) (*ledgerbacken Log: logger.WithField("subservice", "stellar-core"), Toml: captiveCoreToml, UserAgent: "captivecore", - UseDB: cfg.CaptiveCoreUseDB, + UseDB: true, } return ledgerbackend.NewCaptive(captiveConfig) diff --git a/cmd/soroban-rpc/internal/db/ledgerentry.go b/cmd/soroban-rpc/internal/db/ledgerentry.go index 2e22cbc7a..1553ecf59 100644 --- a/cmd/soroban-rpc/internal/db/ledgerentry.go +++ b/cmd/soroban-rpc/internal/db/ledgerentry.go @@ -260,16 +260,22 @@ func entryKeyToTTLEntryKey(key xdr.LedgerKey) (xdr.LedgerKey, error) { } func (l *ledgerEntryReadTx) GetLedgerEntries(keys ...xdr.LedgerKey) ([]LedgerKeyAndEntry, error) { - encodedKeys := make([]string, len(keys), 2*len(keys)) - encodedKeyToKey := make(map[string]xdr.LedgerKey, len(keys)) - encodedKeyToEncodedTTLLedgerKey := make(map[string]string, len(keys)) - for _, k := range keys { + encodedKeys := make([]string, 0, 2*len(keys)) + type keyToEncoded struct { + key xdr.LedgerKey + encodedKey string + encodedTTLKey *string + } + keysToEncoded := make([]keyToEncoded, len(keys)) + for i, k := range keys { + k2 := k + keysToEncoded[i].key = k2 encodedKey, err := encodeLedgerKey(l.buffer, k) if err != nil { return nil, err } + keysToEncoded[i].encodedKey = encodedKey encodedKeys = append(encodedKeys, encodedKey) - encodedKeyToKey[encodedKey] = k if !hasTTLKey(k) { continue } @@ -281,7 +287,7 @@ func (l *ledgerEntryReadTx) GetLedgerEntries(keys ...xdr.LedgerKey) ([]LedgerKey if err != nil { return nil, err } - encodedKeyToEncodedTTLLedgerKey[encodedKey] = encodedTTLKey + keysToEncoded[i].encodedTTLKey = &encodedTTLKey encodedKeys = append(encodedKeys, encodedTTLKey) } @@ -290,9 +296,9 @@ func (l *ledgerEntryReadTx) GetLedgerEntries(keys ...xdr.LedgerKey) ([]LedgerKey return nil, err } - result := make([]LedgerKeyAndEntry, 0, len(rawResult)) - for encodedKey, key := range encodedKeyToKey { - encodedEntry, ok := rawResult[encodedKey] + result := make([]LedgerKeyAndEntry, 0, len(keys)) + for _, k2e := range keysToEncoded { + encodedEntry, ok := rawResult[k2e.encodedKey] if !ok { continue } @@ -300,22 +306,21 @@ func (l *ledgerEntryReadTx) GetLedgerEntries(keys ...xdr.LedgerKey) ([]LedgerKey if err := xdr.SafeUnmarshal([]byte(encodedEntry), &entry); err != nil { return nil, errors.Wrap(err, "cannot decode ledger entry from DB") } - encodedExpKey, has := encodedKeyToEncodedTTLLedgerKey[encodedKey] - if !has { - result = append(result, LedgerKeyAndEntry{key, entry, nil}) + if k2e.encodedTTLKey == nil { + result = append(result, LedgerKeyAndEntry{k2e.key, entry, nil}) continue } - encodedExpEntry, ok := rawResult[encodedExpKey] + encodedTTLEntry, ok := rawResult[*k2e.encodedTTLKey] if !ok { // missing ttl key. This should not happen. return nil, errors.New("missing ttl key entry") } - var expEntry xdr.LedgerEntry - if err := xdr.SafeUnmarshal([]byte(encodedExpEntry), &expEntry); err != nil { + var ttlEntry xdr.LedgerEntry + if err := xdr.SafeUnmarshal([]byte(encodedTTLEntry), &ttlEntry); err != nil { return nil, errors.Wrap(err, "cannot decode TTL ledger entry from DB") } - liveUntilSeq := uint32(expEntry.Data.Ttl.LiveUntilLedgerSeq) - result = append(result, LedgerKeyAndEntry{key, entry, &liveUntilSeq}) + liveUntilSeq := uint32(ttlEntry.Data.Ttl.LiveUntilLedgerSeq) + result = append(result, LedgerKeyAndEntry{k2e.key, entry, &liveUntilSeq}) } return result, nil diff --git a/cmd/soroban-rpc/internal/methods/get_events.go b/cmd/soroban-rpc/internal/methods/get_events.go index b16da281b..e5bf36281 100644 --- a/cmd/soroban-rpc/internal/methods/get_events.go +++ b/cmd/soroban-rpc/internal/methods/get_events.go @@ -68,7 +68,7 @@ func (e eventTypeSet) matches(event xdr.ContractEvent) bool { type EventInfo struct { EventType string `json:"type"` - Ledger int32 `json:"ledger,string"` + Ledger int32 `json:"ledger"` LedgerClosedAt string `json:"ledgerClosedAt"` ContractID string `json:"contractId"` ID string `json:"id"` @@ -79,7 +79,7 @@ type EventInfo struct { } type GetEventsRequest struct { - StartLedger int32 `json:"startLedger,string,omitempty"` + StartLedger uint32 `json:"startLedger,omitempty"` Filters []EventFilter `json:"filters"` Pagination *PaginationOptions `json:"pagination,omitempty"` } @@ -295,7 +295,7 @@ type PaginationOptions struct { type GetEventsResponse struct { Events []EventInfo `json:"events"` - LatestLedger int64 `json:"latestLedger,string"` + LatestLedger int64 `json:"latestLedger"` } type eventScanner interface { diff --git a/cmd/soroban-rpc/internal/methods/get_events_test.go b/cmd/soroban-rpc/internal/methods/get_events_test.go index dcaa5b306..4d15e2c0a 100644 --- a/cmd/soroban-rpc/internal/methods/get_events_test.go +++ b/cmd/soroban-rpc/internal/methods/get_events_test.go @@ -404,7 +404,7 @@ func TestGetEventsRequestValid(t *testing.T) { []byte("{ \"filters\": [], \"pagination\": { \"cursor\": \"0000000021474840576-0000000000\"} }"), &request, )) - assert.Equal(t, int32(0), request.StartLedger) + assert.Equal(t, uint32(0), request.StartLedger) assert.NoError(t, request.Valid(1000)) assert.EqualError(t, (&GetEventsRequest{ @@ -431,12 +431,6 @@ func TestGetEventsRequestValid(t *testing.T) { Pagination: nil, }).Valid(1000), "startLedger must be positive") - assert.EqualError(t, (&GetEventsRequest{ - StartLedger: -100, - Filters: []EventFilter{}, - Pagination: nil, - }).Valid(1000), "startLedger must be positive") - assert.EqualError(t, (&GetEventsRequest{ StartLedger: 1, Filters: []EventFilter{ diff --git a/cmd/soroban-rpc/internal/methods/get_latest_ledger.go b/cmd/soroban-rpc/internal/methods/get_latest_ledger.go index 96d0d11ed..11bd997ac 100644 --- a/cmd/soroban-rpc/internal/methods/get_latest_ledger.go +++ b/cmd/soroban-rpc/internal/methods/get_latest_ledger.go @@ -13,7 +13,7 @@ type GetLatestLedgerResponse struct { // Hash of the latest ledger as a hex-encoded string Hash string `json:"id"` // Stellar Core protocol version associated with the ledger. - ProtocolVersion uint32 `json:"protocolVersion,string"` + ProtocolVersion uint32 `json:"protocolVersion"` // Sequence number of the latest ledger. Sequence uint32 `json:"sequence"` } diff --git a/cmd/soroban-rpc/internal/methods/get_ledger_entries.go b/cmd/soroban-rpc/internal/methods/get_ledger_entries.go index b7c9c326b..4063858c2 100644 --- a/cmd/soroban-rpc/internal/methods/get_ledger_entries.go +++ b/cmd/soroban-rpc/internal/methods/get_ledger_entries.go @@ -6,7 +6,6 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" - "github.com/stellar/go/gxdr" "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" @@ -25,16 +24,16 @@ type LedgerEntryResult struct { // Ledger entry data encoded in base 64. XDR string `json:"xdr"` // Last modified ledger for this entry. - LastModifiedLedger int64 `json:"lastModifiedLedgerSeq,string"` + LastModifiedLedger uint32 `json:"lastModifiedLedgerSeq"` // The ledger sequence until the entry is live, available for entries that have associated ttl ledger entries. - LiveUntilLedgerSeq *uint32 `json:"liveUntilLedgerSeq,string,omitempty"` + LiveUntilLedgerSeq *uint32 `json:"liveUntilLedgerSeq,omitempty"` } type GetLedgerEntriesResponse struct { // All found ledger entries. Entries []LedgerEntryResult `json:"entries"` // Sequence number of the latest ledger at time of request. - LatestLedger int64 `json:"latestLedger,string"` + LatestLedger uint32 `json:"latestLedger"` } const getLedgerEntriesMaxKeys = 200 @@ -51,14 +50,6 @@ func NewGetLedgerEntriesHandler(logger *log.Entry, ledgerEntryReader db.LedgerEn var ledgerKeys []xdr.LedgerKey for i, requestKey := range request.Keys { var ledgerKey xdr.LedgerKey - if err := gxdr.ValidateLedgerKey(requestKey, gxdr.DefaultMaxDepth); err != nil { - logger.WithError(err).WithField("request", request). - Infof("could not validate ledgerKey at index %d from getLedgerEntries request", i) - return GetLedgerEntriesResponse{}, &jrpc2.Error{ - Code: jrpc2.InvalidParams, - Message: fmt.Sprintf("cannot unmarshal key value %s at index %d", requestKey, i), - } - } if err := xdr.SafeUnmarshalBase64(requestKey, &ledgerKey); err != nil { logger.WithError(err).WithField("request", request). Infof("could not unmarshal requestKey %s at index %d from getLedgerEntries request", requestKey, i) @@ -108,8 +99,18 @@ func NewGetLedgerEntriesHandler(logger *log.Entry, ledgerEntryReader db.LedgerEn } } - for i, ledgerKeyAndEntry := range ledgerKeysAndEntries { - ledgerXDR, err := xdr.MarshalBase64(ledgerKeyAndEntry.Entry.Data) + for _, ledgerKeyAndEntry := range ledgerKeysAndEntries { + keyXDR, err := xdr.MarshalBase64(ledgerKeyAndEntry.Key) + if err != nil { + logger.WithError(err).WithField("request", request). + Infof("could not serialize ledger key %v", ledgerKeyAndEntry.Key) + return GetLedgerEntriesResponse{}, &jrpc2.Error{ + Code: jrpc2.InternalError, + Message: fmt.Sprintf("could not serialize ledger key %v", ledgerKeyAndEntry.Key), + } + } + + entryXDR, err := xdr.MarshalBase64(ledgerKeyAndEntry.Entry.Data) if err != nil { logger.WithError(err).WithField("request", request). Infof("could not serialize ledger entry data for ledger entry %v", ledgerKeyAndEntry.Entry) @@ -120,16 +121,16 @@ func NewGetLedgerEntriesHandler(logger *log.Entry, ledgerEntryReader db.LedgerEn } ledgerEntryResults = append(ledgerEntryResults, LedgerEntryResult{ - Key: request.Keys[i], - XDR: ledgerXDR, - LastModifiedLedger: int64(ledgerKeyAndEntry.Entry.LastModifiedLedgerSeq), + Key: keyXDR, + XDR: entryXDR, + LastModifiedLedger: uint32(ledgerKeyAndEntry.Entry.LastModifiedLedgerSeq), LiveUntilLedgerSeq: ledgerKeyAndEntry.LiveUntilLedgerSeq, }) } response := GetLedgerEntriesResponse{ Entries: ledgerEntryResults, - LatestLedger: int64(latestLedger), + LatestLedger: uint32(latestLedger), } return response, nil }) diff --git a/cmd/soroban-rpc/internal/methods/get_ledger_entry.go b/cmd/soroban-rpc/internal/methods/get_ledger_entry.go index 614c6e634..b78d10996 100644 --- a/cmd/soroban-rpc/internal/methods/get_ledger_entry.go +++ b/cmd/soroban-rpc/internal/methods/get_ledger_entry.go @@ -6,7 +6,6 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" - "github.com/stellar/go/gxdr" "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" @@ -24,15 +23,10 @@ type GetLedgerEntryRequest struct { // TODO(https://github.com/stellar/soroban-tools/issues/374) remove after getLedgerEntries is deployed. type GetLedgerEntryResponse struct { XDR string `json:"xdr"` - LastModifiedLedger int64 `json:"lastModifiedLedgerSeq,string"` - LatestLedger int64 `json:"latestLedger,string"` + LastModifiedLedger uint32 `json:"lastModifiedLedgerSeq"` + LatestLedger uint32 `json:"latestLedger"` // The ledger sequence until the entry is live, available for entries that have associated ttl ledger entries. - LiveUntilLedgerSeq *uint32 `json:"LiveUntilLedgerSeq,string,omitempty"` -} - -var invalidLedgerKeyXdrError = &jrpc2.Error{ - Code: jrpc2.InvalidParams, - Message: "cannot unmarshal key value", + LiveUntilLedgerSeq *uint32 `json:"LiveUntilLedgerSeq,omitempty"` } // NewGetLedgerEntryHandler returns a json rpc handler to retrieve the specified ledger entry from stellar core @@ -40,16 +34,14 @@ var invalidLedgerKeyXdrError = &jrpc2.Error{ // TODO(https://github.com/stellar/soroban-tools/issues/374) remove after getLedgerEntries is deployed. func NewGetLedgerEntryHandler(logger *log.Entry, ledgerEntryReader db.LedgerEntryReader) jrpc2.Handler { return handler.New(func(ctx context.Context, request GetLedgerEntryRequest) (GetLedgerEntryResponse, error) { - if err := gxdr.ValidateLedgerKey(request.Key, gxdr.DefaultMaxDepth); err != nil { - logger.WithError(err).WithField("request", request). - Info("could not validate ledgerKey from getLedgerEntry request") - return GetLedgerEntryResponse{}, invalidLedgerKeyXdrError - } var key xdr.LedgerKey if err := xdr.SafeUnmarshalBase64(request.Key, &key); err != nil { logger.WithError(err).WithField("request", request). Info("could not unmarshal ledgerKey from getLedgerEntry request") - return GetLedgerEntryResponse{}, invalidLedgerKeyXdrError + return GetLedgerEntryResponse{}, &jrpc2.Error{ + Code: jrpc2.InvalidParams, + Message: "cannot unmarshal key value", + } } if key.Type == xdr.LedgerEntryTypeTtl { @@ -96,8 +88,8 @@ func NewGetLedgerEntryHandler(logger *log.Entry, ledgerEntryReader db.LedgerEntr } response := GetLedgerEntryResponse{ - LastModifiedLedger: int64(ledgerEntry.LastModifiedLedgerSeq), - LatestLedger: int64(latestLedger), + LastModifiedLedger: uint32(ledgerEntry.LastModifiedLedgerSeq), + LatestLedger: latestLedger, LiveUntilLedgerSeq: liveUntilLedgerSeq, } if response.XDR, err = xdr.MarshalBase64(ledgerEntry.Data); err != nil { diff --git a/cmd/soroban-rpc/internal/methods/get_network.go b/cmd/soroban-rpc/internal/methods/get_network.go index a421b7152..be2e0305f 100644 --- a/cmd/soroban-rpc/internal/methods/get_network.go +++ b/cmd/soroban-rpc/internal/methods/get_network.go @@ -14,7 +14,7 @@ type GetNetworkRequest struct{} type GetNetworkResponse struct { FriendbotURL string `json:"friendbotUrl,omitempty"` Passphrase string `json:"passphrase"` - ProtocolVersion int `json:"protocolVersion,string"` + ProtocolVersion int `json:"protocolVersion"` } // NewGetNetworkHandler returns a json rpc handler to for the getNetwork method diff --git a/cmd/soroban-rpc/internal/methods/get_transaction.go b/cmd/soroban-rpc/internal/methods/get_transaction.go index 257d435f3..7a2fe6575 100644 --- a/cmd/soroban-rpc/internal/methods/get_transaction.go +++ b/cmd/soroban-rpc/internal/methods/get_transaction.go @@ -30,11 +30,11 @@ type GetTransactionResponse struct { // Status is one of: TransactionSuccess, TransactionNotFound, or TransactionFailed. Status string `json:"status"` // LatestLedger is the latest ledger stored in Soroban-RPC. - LatestLedger int64 `json:"latestLedger,string"` + LatestLedger uint32 `json:"latestLedger"` // LatestLedgerCloseTime is the unix timestamp of when the latest ledger was closed. LatestLedgerCloseTime int64 `json:"latestLedgerCloseTime,string"` // LatestLedger is the oldest ledger stored in Soroban-RPC. - OldestLedger int64 `json:"oldestLedger,string"` + OldestLedger uint32 `json:"oldestLedger"` // LatestLedgerCloseTime is the unix timestamp of when the oldest ledger was closed. OldestLedgerCloseTime int64 `json:"oldestLedgerCloseTime,string"` @@ -53,7 +53,7 @@ type GetTransactionResponse struct { ResultMetaXdr string `json:"resultMetaXdr,omitempty"` // Ledger is the sequence of the ledger which included the transaction. - Ledger int64 `json:"ledger,string,omitempty"` + Ledger uint32 `json:"ledger,omitempty"` // LedgerCloseTime is the unix timestamp of when the transaction was included in the ledger. LedgerCloseTime int64 `json:"createdAt,string,omitempty"` } @@ -86,9 +86,9 @@ func GetTransaction(getter transactionGetter, request GetTransactionRequest) (Ge tx, found, storeRange := getter.GetTransaction(txHash) response := GetTransactionResponse{ - LatestLedger: int64(storeRange.LastLedger.Sequence), + LatestLedger: storeRange.LastLedger.Sequence, LatestLedgerCloseTime: storeRange.LastLedger.CloseTime, - OldestLedger: int64(storeRange.FirstLedger.Sequence), + OldestLedger: storeRange.FirstLedger.Sequence, OldestLedgerCloseTime: storeRange.FirstLedger.CloseTime, } if !found { @@ -98,7 +98,7 @@ func GetTransaction(getter transactionGetter, request GetTransactionRequest) (Ge response.ApplicationOrder = tx.ApplicationOrder response.FeeBump = tx.FeeBump - response.Ledger = int64(tx.Ledger.Sequence) + response.Ledger = tx.Ledger.Sequence response.LedgerCloseTime = tx.Ledger.CloseTime response.ResultXdr = base64.StdEncoding.EncodeToString(tx.Result) diff --git a/cmd/soroban-rpc/internal/methods/send_transaction.go b/cmd/soroban-rpc/internal/methods/send_transaction.go index 3651d7e68..d19c2658c 100644 --- a/cmd/soroban-rpc/internal/methods/send_transaction.go +++ b/cmd/soroban-rpc/internal/methods/send_transaction.go @@ -6,7 +6,6 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" - "github.com/stellar/go/gxdr" "github.com/stellar/go/network" proto "github.com/stellar/go/protocols/stellarcore" "github.com/stellar/go/support/log" @@ -31,7 +30,7 @@ type SendTransactionResponse struct { Hash string `json:"hash"` // LatestLedger is the latest ledger known to Soroban-RPC at the time it handled // the transaction submission request. - LatestLedger int64 `json:"latestLedger,string"` + LatestLedger uint32 `json:"latestLedger"` // LatestLedgerCloseTime is the unix timestamp of the close time of the latest ledger known to // Soroban-RPC at the time it handled the transaction submission request. LatestLedgerCloseTime int64 `json:"latestLedgerCloseTime,string"` @@ -49,24 +48,17 @@ type LatestLedgerStore interface { GetLatestLedger() transactions.LedgerInfo } -var invalidTransactionXdrError = &jrpc2.Error{ - Code: jrpc2.InvalidParams, - Message: "invalid_xdr", -} - // NewSendTransactionHandler returns a submit transaction json rpc handler func NewSendTransactionHandler(daemon interfaces.Daemon, logger *log.Entry, store LatestLedgerStore, passphrase string) jrpc2.Handler { submitter := daemon.CoreClient() return handler.New(func(ctx context.Context, request SendTransactionRequest) (SendTransactionResponse, error) { - if err := gxdr.ValidateTransactionEnvelope(request.Transaction, gxdr.DefaultMaxDepth); err != nil { - logger.WithError(err).WithField("request", request). - Info("could not validate send transaction envelope") - return SendTransactionResponse{}, invalidTransactionXdrError - } var envelope xdr.TransactionEnvelope err := xdr.SafeUnmarshalBase64(request.Transaction, &envelope) if err != nil { - return SendTransactionResponse{}, invalidTransactionXdrError + return SendTransactionResponse{}, &jrpc2.Error{ + Code: jrpc2.InvalidParams, + Message: "invalid_xdr", + } } var hash [32]byte @@ -106,14 +98,14 @@ func NewSendTransactionHandler(daemon interfaces.Daemon, logger *log.Entry, stor ErrorResultXDR: resp.Error, Status: resp.Status, Hash: txHash, - LatestLedger: int64(ledgerInfo.Sequence), + LatestLedger: ledgerInfo.Sequence, LatestLedgerCloseTime: ledgerInfo.CloseTime, }, nil case proto.TXStatusPending, proto.TXStatusDuplicate, proto.TXStatusTryAgainLater: return SendTransactionResponse{ Status: resp.Status, Hash: txHash, - LatestLedger: int64(ledgerInfo.Sequence), + LatestLedger: ledgerInfo.Sequence, LatestLedgerCloseTime: ledgerInfo.CloseTime, }, nil default: diff --git a/cmd/soroban-rpc/internal/methods/simulate_transaction.go b/cmd/soroban-rpc/internal/methods/simulate_transaction.go index cd6a8bae1..a278c9c23 100644 --- a/cmd/soroban-rpc/internal/methods/simulate_transaction.go +++ b/cmd/soroban-rpc/internal/methods/simulate_transaction.go @@ -7,7 +7,6 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" - "github.com/stellar/go/gxdr" "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" @@ -16,7 +15,8 @@ import ( ) type SimulateTransactionRequest struct { - Transaction string `json:"transaction"` + Transaction string `json:"transaction"` + ResourceConfig *preflight.ResourceConfig `json:"resourceConfig,omitempty"` } type SimulateTransactionCost struct { @@ -43,24 +43,17 @@ type SimulateTransactionResponse struct { Results []SimulateHostFunctionResult `json:"results,omitempty"` // an array of the individual host function call results Cost SimulateTransactionCost `json:"cost,omitempty"` // the effective cpu and memory cost of the invoked transaction execution. RestorePreamble *RestorePreamble `json:"restorePreamble,omitempty"` // If present, it indicates that a prior RestoreFootprint is required - LatestLedger int64 `json:"latestLedger,string"` + LatestLedger uint32 `json:"latestLedger"` } type PreflightGetter interface { - GetPreflight(ctx context.Context, readTx db.LedgerEntryReadTx, bucketListSize uint64, sourceAccount xdr.AccountId, opBody xdr.OperationBody, footprint xdr.LedgerFootprint) (preflight.Preflight, error) + GetPreflight(ctx context.Context, params preflight.PreflightGetterParameters) (preflight.Preflight, error) } // NewSimulateTransactionHandler returns a json rpc handler to run preflight simulations func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.LedgerEntryReader, ledgerReader db.LedgerReader, getter PreflightGetter) jrpc2.Handler { return handler.New(func(ctx context.Context, request SimulateTransactionRequest) SimulateTransactionResponse { - if err := gxdr.ValidateTransactionEnvelope(request.Transaction, gxdr.DefaultMaxDepth); err != nil { - logger.WithError(err).WithField("request", request). - Info("could not validate simulate transaction envelope") - return SimulateTransactionResponse{ - Error: "Could not unmarshal transaction", - } - } var txEnvelope xdr.TransactionEnvelope if err := xdr.SafeUnmarshalBase64(request.Transaction, &txEnvelope); err != nil { logger.WithError(err).WithField("request", request). @@ -121,11 +114,23 @@ func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.Ledge } } - result, err := getter.GetPreflight(ctx, readTx, bucketListSize, sourceAccount, op.Body, footprint) + resource_config := preflight.DefaultResourceConfig() + if request.ResourceConfig != nil { + resource_config = *request.ResourceConfig + } + params := preflight.PreflightGetterParameters{ + LedgerEntryReadTx: readTx, + BucketListSize: bucketListSize, + SourceAccount: sourceAccount, + OperationBody: op.Body, + Footprint: footprint, + ResourceConfig: resource_config, + } + result, err := getter.GetPreflight(ctx, params) if err != nil { return SimulateTransactionResponse{ Error: err.Error(), - LatestLedger: int64(latestLedger), + LatestLedger: latestLedger, } } @@ -154,7 +159,7 @@ func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.Ledge CPUInstructions: result.CPUInstructions, MemoryBytes: result.MemoryBytes, }, - LatestLedger: int64(latestLedger), + LatestLedger: latestLedger, RestorePreamble: restorePreamble, } }) diff --git a/cmd/soroban-rpc/internal/preflight/pool.go b/cmd/soroban-rpc/internal/preflight/pool.go index da391b576..1d1824115 100644 --- a/cmd/soroban-rpc/internal/preflight/pool.go +++ b/cmd/soroban-rpc/internal/preflight/pool.go @@ -139,26 +139,27 @@ func (m *metricsLedgerEntryWrapper) GetLedgerEntries(keys ...xdr.LedgerKey) ([]d return entries, err } -func (pwp *PreflightWorkerPool) GetPreflight(ctx context.Context, readTx db.LedgerEntryReadTx, bucketListSize uint64, sourceAccount xdr.AccountId, opBody xdr.OperationBody, footprint xdr.LedgerFootprint) (Preflight, error) { +func (pwp *PreflightWorkerPool) GetPreflight(ctx context.Context, params PreflightGetterParameters) (Preflight, error) { if pwp.isClosed.Load() { return Preflight{}, errors.New("preflight worker pool is closed") } wrappedTx := metricsLedgerEntryWrapper{ - LedgerEntryReadTx: readTx, + LedgerEntryReadTx: params.LedgerEntryReadTx, } - params := PreflightParameters{ + preflightParams := PreflightParameters{ Logger: pwp.logger, - SourceAccount: sourceAccount, - OpBody: opBody, + SourceAccount: params.SourceAccount, + OpBody: params.OperationBody, NetworkPassphrase: pwp.networkPassphrase, LedgerEntryReadTx: &wrappedTx, - BucketListSize: bucketListSize, - Footprint: footprint, + BucketListSize: params.BucketListSize, + Footprint: params.Footprint, + ResourceConfig: params.ResourceConfig, EnableDebug: pwp.enableDebug, } resultC := make(chan workerResult) select { - case pwp.requestChan <- workerRequest{ctx, params, resultC}: + case pwp.requestChan <- workerRequest{ctx, preflightParams, resultC}: result := <-resultC if wrappedTx.ledgerEntriesFetched > 0 { status := "ok" diff --git a/cmd/soroban-rpc/internal/preflight/preflight.go b/cmd/soroban-rpc/internal/preflight/preflight.go index 20ddcb4bc..e342ab434 100644 --- a/cmd/soroban-rpc/internal/preflight/preflight.go +++ b/cmd/soroban-rpc/internal/preflight/preflight.go @@ -35,6 +35,10 @@ type snapshotSourceHandle struct { logger *log.Entry } +const ( + defaultInstructionLeeway uint64 = 3000000 +) + // SnapshotSourceGet takes a LedgerKey XDR in base64 string and returns its matching LedgerEntry XDR in base64 string // It's used by the Rust preflight code to obtain ledger entries. // @@ -71,6 +75,25 @@ func FreeGoXDR(xdr C.xdr_t) { C.free(unsafe.Pointer(xdr.xdr)) } +type ResourceConfig struct { + InstructionLeeway uint64 `json:"instructionLeeway"` +} + +func DefaultResourceConfig() ResourceConfig { + return ResourceConfig{ + InstructionLeeway: defaultInstructionLeeway, + } +} + +type PreflightGetterParameters struct { + LedgerEntryReadTx db.LedgerEntryReadTx + BucketListSize uint64 + SourceAccount xdr.AccountId + OperationBody xdr.OperationBody + Footprint xdr.LedgerFootprint + ResourceConfig ResourceConfig +} + type PreflightParameters struct { Logger *log.Entry SourceAccount xdr.AccountId @@ -79,6 +102,7 @@ type PreflightParameters struct { NetworkPassphrase string LedgerEntryReadTx db.LedgerEntryReadTx BucketListSize uint64 + ResourceConfig ResourceConfig EnableDebug bool } @@ -216,12 +240,16 @@ func getInvokeHostFunctionPreflight(params PreflightParameters) (Preflight, erro handle := cgo.NewHandle(snapshotSourceHandle{params.LedgerEntryReadTx, params.Logger}) defer handle.Delete() + resourceConfig := C.resource_config_t{ + instruction_leeway: C.uint64_t(params.ResourceConfig.InstructionLeeway), + } res := C.preflight_invoke_hf_op( C.uintptr_t(handle), C.uint64_t(params.BucketListSize), invokeHostFunctionCXDR, sourceAccountCXDR, li, + resourceConfig, C.bool(params.EnableDebug), ) FreeGoXDR(invokeHostFunctionCXDR) diff --git a/cmd/soroban-rpc/internal/preflight/preflight_test.go b/cmd/soroban-rpc/internal/preflight/preflight_test.go index 1dca591b4..57a2e82b0 100644 --- a/cmd/soroban-rpc/internal/preflight/preflight_test.go +++ b/cmd/soroban-rpc/internal/preflight/preflight_test.go @@ -21,7 +21,7 @@ var mockContractHash = xdr.Hash{0xd, 0xe, 0xf} var contractCostParams = func() *xdr.ContractCostParams { var result xdr.ContractCostParams - for i := 0; i < 22; i++ { + for i := 0; i < 23; i++ { result = append(result, xdr.ContractCostParamEntry{ Ext: xdr.ExtensionPoint{}, ConstTerm: 0, diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index de33f0721..1cef8e8e9 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -48,11 +48,18 @@ func TestCLICargoTest(t *testing.T) { } func TestCLIWrapCustom(t *testing.T) { - NewCLITest(t) - testAccount := getCLIDefaultAccount(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("lab token wrap --asset=deadbeef:%s", testAccount)) - require.Equal(t, "true", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- authorized --id=%s", strkeyContractID, testAccount))) - runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- mint --to=%s --amount 1", strkeyContractID, testAccount)) + it := NewCLITest(t) + assetCode := "deadbeef" + issuerAccount := getCLIDefaultAccount(t) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("lab token wrap --asset=%s:%s", assetCode, issuerAccount)) + require.Equal(t, "true", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- authorized --id=%s", strkeyContractID, issuerAccount))) + asset := txnbuild.CreditAsset{ + Code: assetCode, + Issuer: issuerAccount, + } + establishAccountTrustline(t, it, it.MasterKey(), it.MasterAccount(), asset) + masterAccount := keypair.Root(StandaloneNetworkPassphrase).Address() + runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- mint --to=%s --amount 1", strkeyContractID, masterAccount)) } func TestCLIWrapNative(t *testing.T) { @@ -296,14 +303,9 @@ func fundAccount(t *testing.T, test *Test, account string, amount string) { ch := jhttp.NewChannel(test.sorobanRPCURL(), nil) client := jrpc2.NewClient(ch, nil) - sourceAccount := keypair.Root(StandaloneNetworkPassphrase) - tx, err := txnbuild.NewTransaction(txnbuild.TransactionParams{ - SourceAccount: &txnbuild.SimpleAccount{ - AccountID: keypair.Root(StandaloneNetworkPassphrase).Address(), - Sequence: 1, - }, - IncrementSequenceNum: false, + SourceAccount: test.MasterAccount(), + IncrementSequenceNum: true, Operations: []txnbuild.Operation{&txnbuild.CreateAccount{ Destination: account, Amount: amount, @@ -315,7 +317,29 @@ func fundAccount(t *testing.T, test *Test, account string, amount string) { }, }) require.NoError(t, err) - sendSuccessfulTransaction(t, client, sourceAccount, tx) + sendSuccessfulTransaction(t, client, test.MasterKey(), tx) +} + +func establishAccountTrustline(t *testing.T, test *Test, kp *keypair.Full, account txnbuild.Account, asset txnbuild.Asset) { + ch := jhttp.NewChannel(test.sorobanRPCURL(), nil) + client := jrpc2.NewClient(ch, nil) + + line := asset.MustToChangeTrustAsset() + tx, err := txnbuild.NewTransaction(txnbuild.TransactionParams{ + SourceAccount: account, + IncrementSequenceNum: true, + Operations: []txnbuild.Operation{&txnbuild.ChangeTrust{ + Line: line, + Limit: "2000", + }}, + BaseFee: txnbuild.MinBaseFee, + Memo: nil, + Preconditions: txnbuild.Preconditions{ + TimeBounds: txnbuild.NewInfiniteTimeout(), + }, + }) + require.NoError(t, err) + sendSuccessfulTransaction(t, client, kp, tx) } func parseInt(t *testing.T, s string) uint64 { diff --git a/cmd/soroban-rpc/internal/test/docker-compose.yml b/cmd/soroban-rpc/internal/test/docker-compose.yml index 39e3f7ed6..aaee8a8ac 100644 --- a/cmd/soroban-rpc/internal/test/docker-compose.yml +++ b/cmd/soroban-rpc/internal/test/docker-compose.yml @@ -15,7 +15,7 @@ services: # Note: Please keep the image pinned to an immutable tag matching the Captive Core version. # This avoids implicit updates which break compatibility between # the Core container and captive core. - image: ${CORE_IMAGE:-stellar/stellar-core:19.14.1-1553.f4c4e2fca.focal} + image: ${CORE_IMAGE:-stellar/unsafe-stellar-core:20.0.2-1633.669916b56.focal} depends_on: - core-postgres restart: on-failure diff --git a/cmd/soroban-rpc/internal/test/get_ledger_entries_test.go b/cmd/soroban-rpc/internal/test/get_ledger_entries_test.go index 74e6dce30..46b0b25dd 100644 --- a/cmd/soroban-rpc/internal/test/get_ledger_entries_test.go +++ b/cmd/soroban-rpc/internal/test/get_ledger_entries_test.go @@ -11,7 +11,6 @@ import ( "github.com/stretchr/testify/require" "github.com/stellar/go/keypair" - proto "github.com/stellar/go/protocols/stellarcore" "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" @@ -53,7 +52,7 @@ func TestGetLedgerEntriesNotFound(t *testing.T) { require.NoError(t, err) assert.Equal(t, 0, len(result.Entries)) - assert.Greater(t, result.LatestLedger, int64(0)) + assert.Greater(t, result.LatestLedger, uint32(0)) } func TestGetLedgerEntriesInvalidParams(t *testing.T) { @@ -80,8 +79,9 @@ func TestGetLedgerEntriesSucceeds(t *testing.T) { ch := jhttp.NewChannel(test.sorobanRPCURL(), nil) client := jrpc2.NewClient(ch, nil) - kp := keypair.Root(StandaloneNetworkPassphrase) - account := txnbuild.NewSimpleAccount(kp.Address(), 0) + sourceAccount := keypair.Root(StandaloneNetworkPassphrase) + address := sourceAccount.Address() + account := txnbuild.NewSimpleAccount(address, 0) contractBinary := getHelloWorldContract(t) params := preflightTransactionParams(t, client, txnbuild.TransactionParams{ @@ -96,35 +96,40 @@ func TestGetLedgerEntriesSucceeds(t *testing.T) { }, }) tx, err := txnbuild.NewTransaction(params) - require.NoError(t, err) - tx, err = tx.Sign(StandaloneNetworkPassphrase, kp) - require.NoError(t, err) - b64, err := tx.Base64() - require.NoError(t, err) + assert.NoError(t, err) + sendSuccessfulTransaction(t, client, sourceAccount, tx) - sendTxRequest := methods.SendTransactionRequest{Transaction: b64} - var sendTxResponse methods.SendTransactionResponse - err = client.CallResult(context.Background(), "sendTransaction", sendTxRequest, &sendTxResponse) - require.NoError(t, err) - require.Equal(t, proto.TXStatusPending, sendTxResponse.Status) + params = preflightTransactionParams(t, client, txnbuild.TransactionParams{ + SourceAccount: &account, + IncrementSequenceNum: true, + Operations: []txnbuild.Operation{ + createCreateContractOperation(address, contractBinary), + }, + BaseFee: txnbuild.MinBaseFee, + Preconditions: txnbuild.Preconditions{ + TimeBounds: txnbuild.NewInfiniteTimeout(), + }, + }) + tx, err = txnbuild.NewTransaction(params) + assert.NoError(t, err) + sendSuccessfulTransaction(t, client, sourceAccount, tx) - txStatusResponse := getTransaction(t, client, sendTxResponse.Hash) - require.Equal(t, methods.TransactionStatusSuccess, txStatusResponse.Status) + contractID := getContractID(t, address, testSalt, StandaloneNetworkPassphrase) contractHash := sha256.Sum256(contractBinary) - contractKeyB64, err := xdr.MarshalBase64(xdr.LedgerKey{ + contractCodeKeyB64, err := xdr.MarshalBase64(xdr.LedgerKey{ Type: xdr.LedgerEntryTypeContractCode, ContractCode: &xdr.LedgerKeyContractCode{ Hash: contractHash, }, }) - require.NoError(t, err) // Doesn't exist. - sourceAccount := keypair.Root(StandaloneNetworkPassphrase).Address() - contractID := getContractID(t, sourceAccount, testSalt, StandaloneNetworkPassphrase) + notFoundKeyB64, err := xdr.MarshalBase64(getCounterLedgerKey(contractID)) + require.NoError(t, err) + contractIDHash := xdr.Hash(contractID) - notFoundKeyB64, err := xdr.MarshalBase64(xdr.LedgerKey{ + contractInstanceKeyB64, err := xdr.MarshalBase64(xdr.LedgerKey{ Type: xdr.LedgerEntryTypeContractData, ContractData: &xdr.LedgerKeyContractData{ Contract: xdr.ScAddress{ @@ -139,9 +144,7 @@ func TestGetLedgerEntriesSucceeds(t *testing.T) { }) require.NoError(t, err) - var keys []string - keys = append(keys, contractKeyB64) - keys = append(keys, notFoundKeyB64) + keys := []string{contractCodeKeyB64, notFoundKeyB64, contractInstanceKeyB64} request := methods.GetLedgerEntriesRequest{ Keys: keys, } @@ -149,11 +152,28 @@ func TestGetLedgerEntriesSucceeds(t *testing.T) { var result methods.GetLedgerEntriesResponse err = client.CallResult(context.Background(), "getLedgerEntries", request, &result) require.NoError(t, err) - require.Equal(t, 1, len(result.Entries)) - require.Greater(t, result.LatestLedger, int64(0)) - + require.Equal(t, 2, len(result.Entries)) + require.Greater(t, result.LatestLedger, uint32(0)) + + require.Greater(t, result.Entries[0].LastModifiedLedger, uint32(0)) + require.LessOrEqual(t, result.Entries[0].LastModifiedLedger, result.LatestLedger) + require.NotNil(t, result.Entries[0].LiveUntilLedgerSeq) + require.Greater(t, *result.Entries[0].LiveUntilLedgerSeq, result.LatestLedger) + require.Equal(t, contractCodeKeyB64, result.Entries[0].Key) var firstEntry xdr.LedgerEntryData require.NoError(t, xdr.SafeUnmarshalBase64(result.Entries[0].XDR, &firstEntry)) + require.Equal(t, xdr.LedgerEntryTypeContractCode, firstEntry.Type) require.Equal(t, contractBinary, firstEntry.MustContractCode().Code) - require.Equal(t, contractKeyB64, result.Entries[0].Key) + + require.Greater(t, result.Entries[1].LastModifiedLedger, uint32(0)) + require.LessOrEqual(t, result.Entries[1].LastModifiedLedger, result.LatestLedger) + require.NotNil(t, result.Entries[1].LiveUntilLedgerSeq) + require.Greater(t, *result.Entries[1].LiveUntilLedgerSeq, result.LatestLedger) + require.Equal(t, contractInstanceKeyB64, result.Entries[1].Key) + var secondEntry xdr.LedgerEntryData + require.NoError(t, xdr.SafeUnmarshalBase64(result.Entries[1].XDR, &secondEntry)) + require.Equal(t, xdr.LedgerEntryTypeContractData, secondEntry.Type) + require.True(t, secondEntry.MustContractData().Key.Equals(xdr.ScVal{ + Type: xdr.ScValTypeScvLedgerKeyContractInstance, + })) } diff --git a/cmd/soroban-rpc/internal/test/get_ledger_entry_test.go b/cmd/soroban-rpc/internal/test/get_ledger_entry_test.go index f30af115f..dd4879d53 100644 --- a/cmd/soroban-rpc/internal/test/get_ledger_entry_test.go +++ b/cmd/soroban-rpc/internal/test/get_ledger_entry_test.go @@ -107,7 +107,7 @@ func TestGetLedgerEntrySucceeds(t *testing.T) { var result methods.GetLedgerEntryResponse err = client.CallResult(context.Background(), "getLedgerEntry", request, &result) assert.NoError(t, err) - assert.Greater(t, result.LatestLedger, int64(0)) + assert.Greater(t, result.LatestLedger, uint32(0)) assert.GreaterOrEqual(t, result.LatestLedger, result.LastModifiedLedger) var entry xdr.LedgerEntryData assert.NoError(t, xdr.SafeUnmarshalBase64(result.XDR, &entry)) diff --git a/cmd/soroban-rpc/internal/test/integration.go b/cmd/soroban-rpc/internal/test/integration.go index 9521dfc75..ea918d13d 100644 --- a/cmd/soroban-rpc/internal/test/integration.go +++ b/cmd/soroban-rpc/internal/test/integration.go @@ -17,6 +17,8 @@ import ( "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/stellar/go/clients/stellarcore" + "github.com/stellar/go/keypair" + "github.com/stellar/go/txnbuild" "github.com/stellar/soroban-tools/cmd/soroban-rpc/internal/config" "github.com/stellar/soroban-tools/cmd/soroban-rpc/internal/daemon" @@ -47,6 +49,7 @@ type Test struct { coreClient *stellarcore.Client + masterAccount txnbuild.Account shutdownOnce sync.Once shutdownCalls []func() } @@ -64,6 +67,10 @@ func NewTest(t *testing.T) *Test { t: t, composePath: findDockerComposePath(), } + i.masterAccount = &txnbuild.SimpleAccount{ + AccountID: i.MasterKey().Address(), + Sequence: 0, + } i.runComposeCommand("up", "--detach", "--quiet-pull", "--no-color") i.prepareShutdownHandlers() i.coreClient = &stellarcore.Client{URL: "http://localhost:" + strconv.Itoa(stellarCorePort)} @@ -74,6 +81,14 @@ func NewTest(t *testing.T) *Test { return i } +func (i *Test) MasterKey() *keypair.Full { + return keypair.Root(StandaloneNetworkPassphrase) +} + +func (i *Test) MasterAccount() txnbuild.Account { + return i.masterAccount +} + func (i *Test) sorobanRPCURL() string { return fmt.Sprintf("http://localhost:%d", sorobanRPCPort) } @@ -121,7 +136,6 @@ func (i *Test) launchDaemon(coreBinaryPath string) { config.CaptiveCoreConfigPath = path.Join(i.composePath, "captive-core-integration-tests.cfg") config.CaptiveCoreStoragePath = i.t.TempDir() config.CaptiveCoreHTTPPort = 0 - config.CaptiveCoreUseDB = true config.FriendbotURL = friendbotURL config.NetworkPassphrase = StandaloneNetworkPassphrase config.HistoryArchiveURLs = []string{"http://localhost:1570"} diff --git a/cmd/soroban-rpc/internal/test/simulate_transaction_test.go b/cmd/soroban-rpc/internal/test/simulate_transaction_test.go index b47c609f0..340f68085 100644 --- a/cmd/soroban-rpc/internal/test/simulate_transaction_test.go +++ b/cmd/soroban-rpc/internal/test/simulate_transaction_test.go @@ -216,7 +216,7 @@ func TestSimulateTransactionSucceeds(t *testing.T) { contractHash := sha256.Sum256(contractBinary) contractHashBytes := xdr.ScBytes(contractHash[:]) expectedXdr := xdr.ScVal{Type: xdr.ScValTypeScvBytes, Bytes: &contractHashBytes} - assert.Greater(t, result.LatestLedger, int64(0)) + assert.Greater(t, result.LatestLedger, uint32(0)) assert.Greater(t, result.Cost.CPUInstructions, uint64(0)) assert.Greater(t, result.Cost.MemoryBytes, uint64(0)) @@ -232,11 +232,15 @@ func TestSimulateTransactionSucceeds(t *testing.T) { }, }, }, - Instructions: 6062311, + Instructions: 4378462, ReadBytes: 0, WriteBytes: 7048, }, - ResourceFee: 130498, + // the resulting fee is derived from the compute factors and a default padding is applied to instructions by preflight + // for test purposes, the most deterministic way to assert the resulting fee is expected value in test scope, is to capture + // the resulting fee from current preflight output and re-plug it in here, rather than try to re-implement the cost-model algo + // in the test. + ResourceFee: 135910, } // First, decode and compare the transaction data so we get a decent diff if it fails. @@ -244,7 +248,7 @@ func TestSimulateTransactionSucceeds(t *testing.T) { err := xdr.SafeUnmarshalBase64(result.TransactionData, &transactionData) assert.NoError(t, err) assert.Equal(t, expectedTransactionData.Resources.Footprint, transactionData.Resources.Footprint) - assert.InDelta(t, uint32(expectedTransactionData.Resources.Instructions), uint32(transactionData.Resources.Instructions), 200000) + assert.InDelta(t, uint32(expectedTransactionData.Resources.Instructions), uint32(transactionData.Resources.Instructions), 3200000) assert.InDelta(t, uint32(expectedTransactionData.Resources.ReadBytes), uint32(transactionData.Resources.ReadBytes), 10) assert.InDelta(t, uint32(expectedTransactionData.Resources.WriteBytes), uint32(transactionData.Resources.WriteBytes), 300) assert.InDelta(t, int64(expectedTransactionData.ResourceFee), int64(transactionData.ResourceFee), 3000) @@ -578,7 +582,7 @@ func TestSimulateTransactionError(t *testing.T) { }, } result := simulateTransactionFromTxParams(t, client, params) - assert.Greater(t, result.LatestLedger, int64(0)) + assert.Greater(t, result.LatestLedger, uint32(0)) assert.Contains(t, result.Error, "MissingValue") require.Len(t, result.Events, 1) var event xdr.DiagnosticEvent @@ -1122,7 +1126,11 @@ func TestSimulateSystemEvent(t *testing.T) { require.NoError(t, err) assert.InDelta(t, 7464, uint32(transactionData.Resources.ReadBytes), 200) - assert.InDelta(t, 98339, int64(transactionData.ResourceFee), 2000) + // the resulting fee is derived from compute factors and a default padding is applied to instructions by preflight + // for test purposes, the most deterministic way to assert the resulting fee is expected value in test scope, is to capture + // the resulting fee from current preflight output and re-plug it in here, rather than try to re-implement the cost-model algo + // in the test. + assert.InDelta(t, 100980, int64(transactionData.ResourceFee), 5000) assert.InDelta(t, 104, uint32(transactionData.Resources.WriteBytes), 15) require.GreaterOrEqual(t, len(response.Events), 3) } diff --git a/cmd/soroban-rpc/lib/preflight.h b/cmd/soroban-rpc/lib/preflight.h index fce089c95..81db0c54f 100644 --- a/cmd/soroban-rpc/lib/preflight.h +++ b/cmd/soroban-rpc/lib/preflight.h @@ -25,6 +25,10 @@ typedef struct xdr_vector_t { size_t len; } xdr_vector_t; +typedef struct resource_config_t { + uint64_t instruction_leeway; // Allow this many extra instructions when budgeting +} resource_config_t; + typedef struct preflight_result_t { char *error; // Error string in case of error, otherwise null xdr_vector_t auth; // array of SorobanAuthorizationEntries @@ -43,6 +47,7 @@ preflight_result_t *preflight_invoke_hf_op(uintptr_t handle, // Go Handle to for const xdr_t invoke_hf_op, // InvokeHostFunctionOp XDR const xdr_t source_account, // AccountId XDR const ledger_info_t ledger_info, + const resource_config_t resource_config, bool enable_debug); preflight_result_t *preflight_footprint_ttl_op(uintptr_t handle, // Go Handle to forward to SnapshotSourceGet diff --git a/cmd/soroban-rpc/lib/preflight/Cargo.toml b/cmd/soroban-rpc/lib/preflight/Cargo.toml index 6fb710f72..e78939588 100644 --- a/cmd/soroban-rpc/lib/preflight/Cargo.toml +++ b/cmd/soroban-rpc/lib/preflight/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "preflight" -version = "20.0.0-rc4" +version = "20.1.1" publish = false [lib] @@ -12,5 +12,7 @@ base64 = { workspace = true } thiserror = { workspace = true } libc = "0.2.147" sha2 = { workspace = true } -soroban-env-host = { workspace = true, features = ["recording_auth"]} +# we need the testutils feature in order to get backtraces in the preflight library +# when soroban rpc is configured to run with --preflight-enable-debug +soroban-env-host = { workspace = true, features = ["recording_auth", "testutils"]} rand = "0.8.5" diff --git a/cmd/soroban-rpc/lib/preflight/src/fees.rs b/cmd/soroban-rpc/lib/preflight/src/fees.rs index e32ab3e9b..7bb392cbc 100644 --- a/cmd/soroban-rpc/lib/preflight/src/fees.rs +++ b/cmd/soroban-rpc/lib/preflight/src/fees.rs @@ -14,8 +14,8 @@ use soroban_env_host::xdr; use soroban_env_host::xdr::ContractDataDurability::Persistent; use soroban_env_host::xdr::{ ConfigSettingEntry, ConfigSettingId, ContractEventType, DecoratedSignature, DiagnosticEvent, - ExtendFootprintTtlOp, ExtensionPoint, InvokeHostFunctionOp, LedgerFootprint, LedgerKey, Memo, - MuxedAccount, MuxedAccountMed25519, Operation, OperationBody, Preconditions, + ExtendFootprintTtlOp, ExtensionPoint, InvokeHostFunctionOp, LedgerFootprint, LedgerKey, Limits, + Memo, MuxedAccount, MuxedAccountMed25519, Operation, OperationBody, Preconditions, RestoreFootprintOp, ScVal, SequenceNumber, Signature, SignatureHint, SorobanResources, SorobanTransactionData, Transaction, TransactionExt, TransactionV1Envelope, Uint256, WriteXdr, }; @@ -23,25 +23,32 @@ use state_ttl::{get_restored_ledger_sequence, TTLLedgerEntry}; use std::cmp::max; use std::convert::{TryFrom, TryInto}; +use crate::CResourceConfig; + #[allow(clippy::too_many_arguments)] pub(crate) fn compute_host_function_transaction_data_and_min_fee( op: &InvokeHostFunctionOp, pre_storage: &LedgerStorage, post_storage: &Storage, budget: &Budget, + resource_config: CResourceConfig, events: &[DiagnosticEvent], invocation_result: &ScVal, bucket_list_size: u64, current_ledger_seq: u32, ) -> Result<(SorobanTransactionData, i64)> { let ledger_changes = get_ledger_changes(budget, post_storage, pre_storage, TtlEntryMap::new())?; - let soroban_resources = - calculate_host_function_soroban_resources(&ledger_changes, &post_storage.footprint, budget) - .context("cannot compute host function resources")?; + let soroban_resources = calculate_host_function_soroban_resources( + &ledger_changes, + &post_storage.footprint, + budget, + resource_config, + ) + .context("cannot compute host function resources")?; let contract_events_size = calculate_contract_events_size_bytes(events).context("cannot calculate events size")?; - let invocation_return_size = u32::try_from(invocation_result.to_xdr()?.len())?; + let invocation_return_size = u32::try_from(invocation_result.to_xdr(Limits::none())?.len())?; // This is totally unintuitive, but it's what's expected by the library let final_contract_events_size = contract_events_size + invocation_return_size; @@ -115,7 +122,7 @@ fn estimate_max_transaction_size_for_operation( signatures: signatures.try_into()?, }; - let envelope_xdr = envelope.to_xdr()?; + let envelope_xdr = envelope.to_xdr(Limits::none())?; let envelope_size = envelope_xdr.len(); // Add a 15% leeway @@ -128,6 +135,7 @@ fn calculate_host_function_soroban_resources( ledger_changes: &[LedgerEntryChange], footprint: &Footprint, budget: &Budget, + resource_config: CResourceConfig, ) -> Result { let ledger_footprint = storage_footprint_to_ledger_footprint(footprint) .context("cannot convert storage footprint to ledger footprint")?; @@ -138,11 +146,14 @@ fn calculate_host_function_soroban_resources( .map(|c| c.encoded_new_value.as_ref().map_or(0, Vec::len) as u32) .sum(); - // Add a 20% leeway with a minimum of 50k instructions + // Add a 20% leeway with a minimum of 3 million instructions let budget_instructions = budget .get_cpu_insns_consumed() .context("cannot get instructions consumed")?; - let instructions = max(budget_instructions + 50000, budget_instructions * 120 / 100); + let instructions = max( + budget_instructions + resource_config.instruction_leeway, + budget_instructions * 120 / 100, + ); Ok(SorobanResources { footprint: ledger_footprint, instructions: u32::try_from(instructions)?, @@ -247,7 +258,7 @@ fn calculate_contract_events_size_bytes(events: &[DiagnosticEvent]) -> Result = (&unmodified_entry_and_ttl) .try_into() @@ -455,7 +467,8 @@ fn compute_restore_footprint_rent_changes( let unmodified_entry_and_ttl = ledger_storage.get(key, true).with_context(|| { format!("cannot find restore footprint ledger entry with key {key:?}") })?; - let size = (key.to_xdr()?.len() + unmodified_entry_and_ttl.0.to_xdr()?.len()) as u32; + let size = (key.to_xdr(Limits::none())?.len() + + unmodified_entry_and_ttl.0.to_xdr(Limits::none())?.len()) as u32; let ttl_entry: Box = (&unmodified_entry_and_ttl) .try_into() diff --git a/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs b/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs index 3581e6956..264355a14 100644 --- a/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs +++ b/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs @@ -3,8 +3,8 @@ use soroban_env_host::storage::SnapshotSource; use soroban_env_host::xdr::ContractDataDurability::{Persistent, Temporary}; use soroban_env_host::xdr::{ ConfigSettingEntry, ConfigSettingId, Error as XdrError, Hash, LedgerEntry, LedgerEntryData, - LedgerKey, LedgerKeyConfigSetting, LedgerKeyTtl, ReadXdr, ScError, ScErrorCode, TtlEntry, - WriteXdr, + LedgerKey, LedgerKeyConfigSetting, LedgerKeyTtl, Limits, ReadXdr, ScError, ScErrorCode, + TtlEntry, WriteXdr, }; use soroban_env_host::HostError; use state_ttl::{get_restored_ledger_sequence, is_live, TTLLedgerEntry}; @@ -149,7 +149,7 @@ impl LedgerStorage { key: &LedgerKey, include_not_live: bool, ) -> Result<(LedgerEntry, Option), Error> { - let mut key_xdr = key.to_xdr()?; + let mut key_xdr = key.to_xdr(Limits::none())?; let xdr = self.get_xdr_internal(&mut key_xdr)?; let live_until_ledger_seq = match key { @@ -160,9 +160,9 @@ impl LedgerStorage { let ttl_key = LedgerKey::Ttl(LedgerKeyTtl { key_hash: Hash(key_hash), }); - let mut ttl_key_xdr = ttl_key.to_xdr()?; + let mut ttl_key_xdr = ttl_key.to_xdr(Limits::none())?; let ttl_entry_xdr = self.get_xdr_internal(&mut ttl_key_xdr)?; - let ttl_entry = LedgerEntry::from_xdr(ttl_entry_xdr)?; + let ttl_entry = LedgerEntry::from_xdr(ttl_entry_xdr, Limits::none())?; if let LedgerEntryData::Ttl(TtlEntry { live_until_ledger_seq, .. @@ -185,7 +185,7 @@ impl LedgerStorage { return Err(Error::NotLive); } - let entry = LedgerEntry::from_xdr(xdr)?; + let entry = LedgerEntry::from_xdr(xdr, Limits::none())?; Ok((entry, live_until_ledger_seq)) } @@ -197,7 +197,7 @@ impl LedgerStorage { // TODO: this can be optimized since for entry types other than ContractCode/ContractData, // they don't need to be deserialized and serialized again let (entry, _) = self.get(key, include_not_live)?; - Ok(entry.to_xdr()?) + Ok(entry.to_xdr(Limits::none())?) } pub(crate) fn get_configuration_setting( diff --git a/cmd/soroban-rpc/lib/preflight/src/lib.rs b/cmd/soroban-rpc/lib/preflight/src/lib.rs index 8f3a86431..e2c51c2db 100644 --- a/cmd/soroban-rpc/lib/preflight/src/lib.rs +++ b/cmd/soroban-rpc/lib/preflight/src/lib.rs @@ -14,7 +14,7 @@ use ledger_storage::LedgerStorage; use preflight::PreflightResult; use sha2::{Digest, Sha256}; use soroban_env_host::xdr::{ - AccountId, InvokeHostFunctionOp, LedgerFootprint, OperationBody, ReadXdr, WriteXdr, + AccountId, InvokeHostFunctionOp, LedgerFootprint, Limits, OperationBody, ReadXdr, WriteXdr, }; use soroban_env_host::LedgerInfo; use std::ffi::{CStr, CString}; @@ -81,6 +81,12 @@ fn get_default_c_xdr_vector() -> CXDRVector { } } +#[repr(C)] +#[derive(Copy, Clone)] +pub struct CResourceConfig { + pub instruction_leeway: u64, +} + #[repr(C)] #[derive(Copy, Clone)] pub struct CPreflightResult { @@ -133,6 +139,7 @@ pub extern "C" fn preflight_invoke_hf_op( invoke_hf_op: CXDR, // InvokeHostFunctionOp XDR in base64 source_account: CXDR, // AccountId XDR in base64 ledger_info: CLedgerInfo, + resource_config: CResourceConfig, enable_debug: bool, ) -> *mut CPreflightResult { catch_preflight_panic(Box::new(move || { @@ -142,6 +149,7 @@ pub extern "C" fn preflight_invoke_hf_op( invoke_hf_op, source_account, ledger_info, + resource_config, enable_debug, ) })) @@ -153,10 +161,12 @@ fn preflight_invoke_hf_op_or_maybe_panic( invoke_hf_op: CXDR, // InvokeHostFunctionOp XDR in base64 source_account: CXDR, // AccountId XDR in base64 ledger_info: CLedgerInfo, + resource_config: CResourceConfig, enable_debug: bool, ) -> Result { - let invoke_hf_op = InvokeHostFunctionOp::from_xdr(from_c_xdr(invoke_hf_op)).unwrap(); - let source_account = AccountId::from_xdr(from_c_xdr(source_account)).unwrap(); + let invoke_hf_op = + InvokeHostFunctionOp::from_xdr(from_c_xdr(invoke_hf_op), Limits::none()).unwrap(); + let source_account = AccountId::from_xdr(from_c_xdr(source_account), Limits::none()).unwrap(); let ledger_storage = LedgerStorage::with_restore_tracking(handle, ledger_info.sequence_number) .context("cannot create LedgerStorage")?; let result = preflight::preflight_invoke_hf_op( @@ -165,6 +175,7 @@ fn preflight_invoke_hf_op_or_maybe_panic( invoke_hf_op, source_account, LedgerInfo::from(ledger_info), + resource_config, enable_debug, )?; Ok(result.into()) @@ -196,8 +207,8 @@ fn preflight_footprint_ttl_op_or_maybe_panic( footprint: CXDR, current_ledger_seq: u32, ) -> Result { - let op_body = OperationBody::from_xdr(from_c_xdr(op_body)).unwrap(); - let footprint = LedgerFootprint::from_xdr(from_c_xdr(footprint)).unwrap(); + let op_body = OperationBody::from_xdr(from_c_xdr(op_body), Limits::none()).unwrap(); + let footprint = LedgerFootprint::from_xdr(from_c_xdr(footprint), Limits::none()).unwrap(); let ledger_storage = &LedgerStorage::new(handle, current_ledger_seq); let result = preflight::preflight_footprint_ttl_op( ledger_storage, @@ -244,7 +255,7 @@ fn catch_preflight_panic(op: Box Result>) -> *mut } fn xdr_to_c(v: impl WriteXdr) -> CXDR { - let (xdr, len) = vec_to_c_array(v.to_xdr().unwrap()); + let (xdr, len) = vec_to_c_array(v.to_xdr(Limits::none()).unwrap()); CXDR { xdr, len } } diff --git a/cmd/soroban-rpc/lib/preflight/src/preflight.rs b/cmd/soroban-rpc/lib/preflight/src/preflight.rs index a818b7dd2..cfafe14c7 100644 --- a/cmd/soroban-rpc/lib/preflight/src/preflight.rs +++ b/cmd/soroban-rpc/lib/preflight/src/preflight.rs @@ -16,6 +16,8 @@ use std::convert::{TryFrom, TryInto}; use std::iter::FromIterator; use std::rc::Rc; +use crate::CResourceConfig; + pub(crate) struct RestorePreamble { pub(crate) transaction_data: SorobanTransactionData, pub(crate) min_fee: i64, @@ -40,6 +42,7 @@ pub(crate) fn preflight_invoke_hf_op( invoke_hf_op: InvokeHostFunctionOp, source_account: AccountId, ledger_info: LedgerInfo, + resource_config: CResourceConfig, enable_debug: bool, ) -> Result { let ledger_storage_rc = Rc::new(ledger_storage); @@ -117,6 +120,7 @@ pub(crate) fn preflight_invoke_hf_op( &ledger_storage_rc, &storage, &budget, + resource_config, &diagnostic_events, &result, bucket_list_size, diff --git a/docs/soroban-cli-full-docs.md b/docs/soroban-cli-full-docs.md index 66bb14230..7be027c82 100644 --- a/docs/soroban-cli-full-docs.md +++ b/docs/soroban-cli-full-docs.md @@ -40,7 +40,12 @@ This document contains the help content for the `soroban` command-line program. * [`soroban lab token wrap`↴](#soroban-lab-token-wrap) * [`soroban lab token id`↴](#soroban-lab-token-id) * [`soroban lab xdr`↴](#soroban-lab-xdr) -* [`soroban lab xdr dec`↴](#soroban-lab-xdr-dec) +* [`soroban lab xdr types`↴](#soroban-lab-xdr-types) +* [`soroban lab xdr types list`↴](#soroban-lab-xdr-types-list) +* [`soroban lab xdr guess`↴](#soroban-lab-xdr-guess) +* [`soroban lab xdr decode`↴](#soroban-lab-xdr-decode) +* [`soroban lab xdr encode`↴](#soroban-lab-xdr-encode) +* [`soroban lab xdr version`↴](#soroban-lab-xdr-version) * [`soroban version`↴](#soroban-version) ## `soroban` @@ -820,36 +825,145 @@ Compute the expected contract id for the given asset Decode xdr -**Usage:** `soroban lab xdr ` +**Usage:** `soroban lab xdr [CHANNEL] ` ###### **Subcommands:** -* `dec` — Decode XDR +* `types` — View information about types +* `guess` — Guess the XDR type +* `decode` — Decode XDR +* `encode` — Encode XDR +* `version` — Print version information + +###### **Arguments:** + +* `` — Channel of XDR to operate on + + Default value: `+curr` + + Possible values: `+curr`, `+next` + + + + +## `soroban lab xdr types` + +View information about types + +**Usage:** `soroban lab xdr types ` + +###### **Subcommands:** + +* `list` — + + + +## `soroban lab xdr types list` + +**Usage:** `soroban lab xdr types list [OPTIONS]` + +###### **Options:** + +* `--output ` + + Default value: `plain` + + Possible values: `plain`, `json`, `json-formatted` + + + + +## `soroban lab xdr guess` + +Guess the XDR type + +**Usage:** `soroban lab xdr guess [OPTIONS] [FILE]` + +###### **Arguments:** + +* `` — File to decode, or stdin if omitted + +###### **Options:** + +* `--input ` + Default value: `single-base64` + Possible values: `single`, `single-base64`, `stream`, `stream-base64`, `stream-framed` -## `soroban lab xdr dec` +* `--output ` + + Default value: `list` + + Possible values: `list` + +* `--certainty ` — Certainty as an arbitrary value + + Default value: `2` + + + +## `soroban lab xdr decode` Decode XDR -**Usage:** `soroban lab xdr dec [OPTIONS] --type --xdr ` +**Usage:** `soroban lab xdr decode [OPTIONS] --type [FILES]...` + +###### **Arguments:** + +* `` — Files to decode, or stdin if omitted ###### **Options:** -* `--type ` — XDR type to decode to +* `--type ` — XDR type to decode +* `--input ` - Possible values: `Value`, `ScpBallot`, `ScpStatementType`, `ScpNomination`, `ScpStatement`, `ScpStatementPledges`, `ScpStatementPrepare`, `ScpStatementConfirm`, `ScpStatementExternalize`, `ScpEnvelope`, `ScpQuorumSet`, `ConfigSettingContractExecutionLanesV0`, `ConfigSettingContractComputeV0`, `ConfigSettingContractLedgerCostV0`, `ConfigSettingContractHistoricalDataV0`, `ConfigSettingContractEventsV0`, `ConfigSettingContractBandwidthV0`, `ContractCostType`, `ContractCostParamEntry`, `StateArchivalSettings`, `EvictionIterator`, `ContractCostParams`, `ConfigSettingId`, `ConfigSettingEntry`, `ScEnvMetaKind`, `ScEnvMetaEntry`, `ScMetaV0`, `ScMetaKind`, `ScMetaEntry`, `ScSpecType`, `ScSpecTypeOption`, `ScSpecTypeResult`, `ScSpecTypeVec`, `ScSpecTypeMap`, `ScSpecTypeTuple`, `ScSpecTypeBytesN`, `ScSpecTypeUdt`, `ScSpecTypeDef`, `ScSpecUdtStructFieldV0`, `ScSpecUdtStructV0`, `ScSpecUdtUnionCaseVoidV0`, `ScSpecUdtUnionCaseTupleV0`, `ScSpecUdtUnionCaseV0Kind`, `ScSpecUdtUnionCaseV0`, `ScSpecUdtUnionV0`, `ScSpecUdtEnumCaseV0`, `ScSpecUdtEnumV0`, `ScSpecUdtErrorEnumCaseV0`, `ScSpecUdtErrorEnumV0`, `ScSpecFunctionInputV0`, `ScSpecFunctionV0`, `ScSpecEntryKind`, `ScSpecEntry`, `ScValType`, `ScErrorType`, `ScErrorCode`, `ScError`, `UInt128Parts`, `Int128Parts`, `UInt256Parts`, `Int256Parts`, `ContractExecutableType`, `ContractExecutable`, `ScAddressType`, `ScAddress`, `ScVec`, `ScMap`, `ScBytes`, `ScString`, `ScSymbol`, `ScNonceKey`, `ScContractInstance`, `ScVal`, `ScMapEntry`, `StoredTransactionSet`, `StoredDebugTransactionSet`, `PersistedScpStateV0`, `PersistedScpStateV1`, `PersistedScpState`, `Thresholds`, `String32`, `String64`, `SequenceNumber`, `DataValue`, `PoolId`, `AssetCode4`, `AssetCode12`, `AssetType`, `AssetCode`, `AlphaNum4`, `AlphaNum12`, `Asset`, `Price`, `Liabilities`, `ThresholdIndexes`, `LedgerEntryType`, `Signer`, `AccountFlags`, `SponsorshipDescriptor`, `AccountEntryExtensionV3`, `AccountEntryExtensionV2`, `AccountEntryExtensionV2Ext`, `AccountEntryExtensionV1`, `AccountEntryExtensionV1Ext`, `AccountEntry`, `AccountEntryExt`, `TrustLineFlags`, `LiquidityPoolType`, `TrustLineAsset`, `TrustLineEntryExtensionV2`, `TrustLineEntryExtensionV2Ext`, `TrustLineEntry`, `TrustLineEntryExt`, `TrustLineEntryV1`, `TrustLineEntryV1Ext`, `OfferEntryFlags`, `OfferEntry`, `OfferEntryExt`, `DataEntry`, `DataEntryExt`, `ClaimPredicateType`, `ClaimPredicate`, `ClaimantType`, `Claimant`, `ClaimantV0`, `ClaimableBalanceIdType`, `ClaimableBalanceId`, `ClaimableBalanceFlags`, `ClaimableBalanceEntryExtensionV1`, `ClaimableBalanceEntryExtensionV1Ext`, `ClaimableBalanceEntry`, `ClaimableBalanceEntryExt`, `LiquidityPoolConstantProductParameters`, `LiquidityPoolEntry`, `LiquidityPoolEntryBody`, `LiquidityPoolEntryConstantProduct`, `ContractDataDurability`, `ContractDataEntry`, `ContractCodeEntry`, `TtlEntry`, `LedgerEntryExtensionV1`, `LedgerEntryExtensionV1Ext`, `LedgerEntry`, `LedgerEntryData`, `LedgerEntryExt`, `LedgerKey`, `LedgerKeyAccount`, `LedgerKeyTrustLine`, `LedgerKeyOffer`, `LedgerKeyData`, `LedgerKeyClaimableBalance`, `LedgerKeyLiquidityPool`, `LedgerKeyContractData`, `LedgerKeyContractCode`, `LedgerKeyConfigSetting`, `LedgerKeyTtl`, `EnvelopeType`, `UpgradeType`, `StellarValueType`, `LedgerCloseValueSignature`, `StellarValue`, `StellarValueExt`, `LedgerHeaderFlags`, `LedgerHeaderExtensionV1`, `LedgerHeaderExtensionV1Ext`, `LedgerHeader`, `LedgerHeaderExt`, `LedgerUpgradeType`, `ConfigUpgradeSetKey`, `LedgerUpgrade`, `ConfigUpgradeSet`, `BucketEntryType`, `BucketMetadata`, `BucketMetadataExt`, `BucketEntry`, `TxSetComponentType`, `TxSetComponent`, `TxSetComponentTxsMaybeDiscountedFee`, `TransactionPhase`, `TransactionSet`, `TransactionSetV1`, `GeneralizedTransactionSet`, `TransactionResultPair`, `TransactionResultSet`, `TransactionHistoryEntry`, `TransactionHistoryEntryExt`, `TransactionHistoryResultEntry`, `TransactionHistoryResultEntryExt`, `LedgerHeaderHistoryEntry`, `LedgerHeaderHistoryEntryExt`, `LedgerScpMessages`, `ScpHistoryEntryV0`, `ScpHistoryEntry`, `LedgerEntryChangeType`, `LedgerEntryChange`, `LedgerEntryChanges`, `OperationMeta`, `TransactionMetaV1`, `TransactionMetaV2`, `ContractEventType`, `ContractEvent`, `ContractEventBody`, `ContractEventV0`, `DiagnosticEvent`, `SorobanTransactionMeta`, `TransactionMetaV3`, `InvokeHostFunctionSuccessPreImage`, `TransactionMeta`, `TransactionResultMeta`, `UpgradeEntryMeta`, `LedgerCloseMetaV0`, `LedgerCloseMetaV1`, `LedgerCloseMeta`, `ErrorCode`, `SError`, `SendMore`, `SendMoreExtended`, `AuthCert`, `Hello`, `Auth`, `IpAddrType`, `PeerAddress`, `PeerAddressIp`, `MessageType`, `DontHave`, `SurveyMessageCommandType`, `SurveyMessageResponseType`, `SurveyRequestMessage`, `SignedSurveyRequestMessage`, `EncryptedBody`, `SurveyResponseMessage`, `SignedSurveyResponseMessage`, `PeerStats`, `PeerStatList`, `TopologyResponseBodyV0`, `TopologyResponseBodyV1`, `SurveyResponseBody`, `TxAdvertVector`, `FloodAdvert`, `TxDemandVector`, `FloodDemand`, `StellarMessage`, `AuthenticatedMessage`, `AuthenticatedMessageV0`, `LiquidityPoolParameters`, `MuxedAccount`, `MuxedAccountMed25519`, `DecoratedSignature`, `OperationType`, `CreateAccountOp`, `PaymentOp`, `PathPaymentStrictReceiveOp`, `PathPaymentStrictSendOp`, `ManageSellOfferOp`, `ManageBuyOfferOp`, `CreatePassiveSellOfferOp`, `SetOptionsOp`, `ChangeTrustAsset`, `ChangeTrustOp`, `AllowTrustOp`, `ManageDataOp`, `BumpSequenceOp`, `CreateClaimableBalanceOp`, `ClaimClaimableBalanceOp`, `BeginSponsoringFutureReservesOp`, `RevokeSponsorshipType`, `RevokeSponsorshipOp`, `RevokeSponsorshipOpSigner`, `ClawbackOp`, `ClawbackClaimableBalanceOp`, `SetTrustLineFlagsOp`, `LiquidityPoolDepositOp`, `LiquidityPoolWithdrawOp`, `HostFunctionType`, `ContractIdPreimageType`, `ContractIdPreimage`, `ContractIdPreimageFromAddress`, `CreateContractArgs`, `InvokeContractArgs`, `HostFunction`, `SorobanAuthorizedFunctionType`, `SorobanAuthorizedFunction`, `SorobanAuthorizedInvocation`, `SorobanAddressCredentials`, `SorobanCredentialsType`, `SorobanCredentials`, `SorobanAuthorizationEntry`, `InvokeHostFunctionOp`, `ExtendFootprintTtlOp`, `RestoreFootprintOp`, `Operation`, `OperationBody`, `HashIdPreimage`, `HashIdPreimageOperationId`, `HashIdPreimageRevokeId`, `HashIdPreimageContractId`, `HashIdPreimageSorobanAuthorization`, `MemoType`, `Memo`, `TimeBounds`, `LedgerBounds`, `PreconditionsV2`, `PreconditionType`, `Preconditions`, `LedgerFootprint`, `SorobanResources`, `SorobanTransactionData`, `TransactionV0`, `TransactionV0Ext`, `TransactionV0Envelope`, `Transaction`, `TransactionExt`, `TransactionV1Envelope`, `FeeBumpTransaction`, `FeeBumpTransactionInnerTx`, `FeeBumpTransactionExt`, `FeeBumpTransactionEnvelope`, `TransactionEnvelope`, `TransactionSignaturePayload`, `TransactionSignaturePayloadTaggedTransaction`, `ClaimAtomType`, `ClaimOfferAtomV0`, `ClaimOfferAtom`, `ClaimLiquidityAtom`, `ClaimAtom`, `CreateAccountResultCode`, `CreateAccountResult`, `PaymentResultCode`, `PaymentResult`, `PathPaymentStrictReceiveResultCode`, `SimplePaymentResult`, `PathPaymentStrictReceiveResult`, `PathPaymentStrictReceiveResultSuccess`, `PathPaymentStrictSendResultCode`, `PathPaymentStrictSendResult`, `PathPaymentStrictSendResultSuccess`, `ManageSellOfferResultCode`, `ManageOfferEffect`, `ManageOfferSuccessResult`, `ManageOfferSuccessResultOffer`, `ManageSellOfferResult`, `ManageBuyOfferResultCode`, `ManageBuyOfferResult`, `SetOptionsResultCode`, `SetOptionsResult`, `ChangeTrustResultCode`, `ChangeTrustResult`, `AllowTrustResultCode`, `AllowTrustResult`, `AccountMergeResultCode`, `AccountMergeResult`, `InflationResultCode`, `InflationPayout`, `InflationResult`, `ManageDataResultCode`, `ManageDataResult`, `BumpSequenceResultCode`, `BumpSequenceResult`, `CreateClaimableBalanceResultCode`, `CreateClaimableBalanceResult`, `ClaimClaimableBalanceResultCode`, `ClaimClaimableBalanceResult`, `BeginSponsoringFutureReservesResultCode`, `BeginSponsoringFutureReservesResult`, `EndSponsoringFutureReservesResultCode`, `EndSponsoringFutureReservesResult`, `RevokeSponsorshipResultCode`, `RevokeSponsorshipResult`, `ClawbackResultCode`, `ClawbackResult`, `ClawbackClaimableBalanceResultCode`, `ClawbackClaimableBalanceResult`, `SetTrustLineFlagsResultCode`, `SetTrustLineFlagsResult`, `LiquidityPoolDepositResultCode`, `LiquidityPoolDepositResult`, `LiquidityPoolWithdrawResultCode`, `LiquidityPoolWithdrawResult`, `InvokeHostFunctionResultCode`, `InvokeHostFunctionResult`, `ExtendFootprintTtlResultCode`, `ExtendFootprintTtlResult`, `RestoreFootprintResultCode`, `RestoreFootprintResult`, `OperationResultCode`, `OperationResult`, `OperationResultTr`, `TransactionResultCode`, `InnerTransactionResult`, `InnerTransactionResultResult`, `InnerTransactionResultExt`, `InnerTransactionResultPair`, `TransactionResult`, `TransactionResultResult`, `TransactionResultExt`, `Hash`, `Uint256`, `Uint32`, `Int32`, `Uint64`, `Int64`, `TimePoint`, `Duration`, `ExtensionPoint`, `CryptoKeyType`, `PublicKeyType`, `SignerKeyType`, `PublicKey`, `SignerKey`, `SignerKeyEd25519SignedPayload`, `Signature`, `SignatureHint`, `NodeId`, `AccountId`, `Curve25519Secret`, `Curve25519Public`, `HmacSha256Key`, `HmacSha256Mac` + Default value: `stream-base64` -* `--xdr ` — XDR (base64 encoded) to decode -* `--output ` — Type of output + Possible values: `single`, `single-base64`, `stream`, `stream-base64`, `stream-framed` - Default value: `default` +* `--output ` - Possible values: - - `default` - - `json`: - Json representation + Default value: `json` + + Possible values: `json`, `json-formatted` + + + + +## `soroban lab xdr encode` + +Encode XDR + +**Usage:** `soroban lab xdr encode [OPTIONS] --type [FILES]...` + +###### **Arguments:** + +* `` — Files to encode, or stdin if omitted + +###### **Options:** + +* `--type ` — XDR type to encode +* `--input ` + + Default value: `json` + + Possible values: `json` + +* `--output ` + + Default value: `single-base64` + + Possible values: `single`, `single-base64` + + + + +## `soroban lab xdr version` + +Print version information +**Usage:** `soroban lab xdr version` diff --git a/go.mod b/go.mod index f929c0e33..8c5d3c31f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.21.1 require ( github.com/Masterminds/squirrel v1.5.4 github.com/cenkalti/backoff/v4 v4.2.1 - github.com/creachadair/jrpc2 v1.1.1 + github.com/creachadair/jrpc2 v1.1.2 github.com/go-chi/chi v4.1.2+incompatible github.com/go-git/go-git/v5 v5.9.0 github.com/mattn/go-sqlite3 v1.14.17 @@ -18,7 +18,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 - github.com/stellar/go v0.0.0-20231114175958-eb2984b58392 + github.com/stellar/go v0.0.0-20231204183605-af6f4ebad728 github.com/stretchr/testify v1.8.4 golang.org/x/mod v0.13.0 gotest.tools/v3 v3.5.0 @@ -52,7 +52,7 @@ require ( github.com/aws/aws-sdk-go v1.45.27 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/creachadair/mds v0.2.3 // indirect + github.com/creachadair/mds v0.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -60,7 +60,7 @@ require ( github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -83,13 +83,13 @@ require ( github.com/spf13/afero v1.10.0 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/viper v1.17.0 // indirect - github.com/stellar/go-xdr v0.0.0-20230919160922-6c7b68458206 // indirect + github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2 // indirect github.com/stretchr/objx v0.5.1 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/sync v0.4.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 7ab9b159e..e398b0172 100644 --- a/go.sum +++ b/go.sum @@ -82,10 +82,10 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creachadair/jrpc2 v1.1.1 h1:xa7p3C5eSvwn/dFwCCmksp+RyQ/ytFY0NYzY7npsoI0= -github.com/creachadair/jrpc2 v1.1.1/go.mod h1:KajsO5dx7yfcwmuRJb5SHXsCVTzBoq7EsPzu5wxnsc0= -github.com/creachadair/mds v0.2.3 h1:Svuw/AXrUUMxGHdRyuDsWJ36oFJRprqP8+iI86XzZjM= -github.com/creachadair/mds v0.2.3/go.mod h1:PmXHgspUECelJVsAgDxWvjblna5BGjPxdEpr7SIEvNs= +github.com/creachadair/jrpc2 v1.1.2 h1:UOYMipEFYlwd5qmcvs9GZBurn3oXt1UDIX5JLjWWFzo= +github.com/creachadair/jrpc2 v1.1.2/go.mod h1:JcCe2Eny3lIvVwZLm92WXyU+tNUgTBWFCLMsfNkjEGk= +github.com/creachadair/mds v0.3.0 h1:uKbCKVtd3iOKVv3uviOm13fFNfe9qoCXJh1Vo7y3Kr0= +github.com/creachadair/mds v0.3.0/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -180,8 +180,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v0.0.0-20160401233042-9235644dd9e5 h1:oERTZ1buOUYlpmKaqlO5fYmz8cZ1rYu5DieJzF4ZVmU= github.com/google/go-querystring v0.0.0-20160401233042-9235644dd9e5/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -335,8 +335,12 @@ github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= github.com/stellar/go v0.0.0-20231114175958-eb2984b58392 h1:sYxHgLDT3z6cJrWuf0O9Fbs/E2UNGh3PPoOlM8DJ2vk= github.com/stellar/go v0.0.0-20231114175958-eb2984b58392/go.mod h1:g78pyZyDFnKMJUaBIXxH7xyQ7PdDrvrJTFCxdGMMb3c= +github.com/stellar/go v0.0.0-20231204183605-af6f4ebad728 h1:lyATpWxLxhZSZIGP3MfCs+C5bVJWvX/FcvQCslknK4E= +github.com/stellar/go v0.0.0-20231204183605-af6f4ebad728/go.mod h1:3wMphjCZGi42wsrrKknendsozw7g9FVBm4YSlI1LpA4= github.com/stellar/go-xdr v0.0.0-20230919160922-6c7b68458206 h1:UFuvvpbWL8+jqO1QmKYWSVhiMp4MRiIFd8/zQlUINH0= github.com/stellar/go-xdr v0.0.0-20230919160922-6c7b68458206/go.mod h1:yoxyU/M8nl9LKeWIoBrbDPQ7Cy+4jxRcWcOayZ4BMps= +github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2 h1:OzCVd0SV5qE3ZcDeSFCmOWLZfEWZ3Oe8KtmSOYKEVWE= +github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2/go.mod h1:yoxyU/M8nl9LKeWIoBrbDPQ7Cy+4jxRcWcOayZ4BMps= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -498,8 +502,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/scripts/check-dependencies.bash b/scripts/check-dependencies.bash index 63a863836..7415e3950 100755 --- a/scripts/check-dependencies.bash +++ b/scripts/check-dependencies.bash @@ -8,7 +8,6 @@ if [ -z "$(sed --version 2>&1 | grep GNU)" ]; then fi CURL="curl -sL --fail-with-body" -CARGO_PACKAGE_REVISION_EXTRACT_SED_COMMAND='s/.*rev=\(.*\)#.*/\1/' if ! CARGO_OUTPUT=$(cargo tree -p soroban-env-host 2>&1); then echo "The project depends on multiple versions of the soroban-env-host Rust library, please unify them." @@ -31,9 +30,28 @@ RS_STELLAR_XDR_REVISION="" # revision of https://github.com/stellar/stellar-xdr/ used by the Rust code STELLAR_XDR_REVISION_FROM_RUST="" +function stellar_xdr_version_from_rust_dep_tree { + LINE=$(grep stellar-xdr | head -n 1) + # try to obtain a commit + COMMIT=$(echo $LINE | $SED -n 's/.*rev=\(.*\)#.*/\1/p') + if [ -n "$COMMIT" ]; then + echo "$COMMIT" + return + fi + # obtain a crate version + echo $LINE | $SED -n 's/.*stellar-xdr \(v\)\{0,1\}\([^ ]*\).*/\2/p' +} + if CARGO_OUTPUT=$(cargo tree --depth 0 -p stellar-xdr 2>&1); then - RS_STELLAR_XDR_REVISION=$(echo $CARGO_OUTPUT | head -n 1 | $SED "$CARGO_PACKAGE_REVISION_EXTRACT_SED_COMMAND") - STELLAR_XDR_REVISION_FROM_RUST=$($CURL https://raw.githubusercontent.com/stellar/rs-stellar-xdr/${RS_STELLAR_XDR_REVISION}/xdr/curr-version) + RS_STELLAR_XDR_REVISION=$(echo "$CARGO_OUTPUT" | stellar_xdr_version_from_rust_dep_tree) + if [ ${#RS_STELLAR_XDR_REVISION} -eq 40 ]; then + # revision is a git hash + STELLAR_XDR_REVISION_FROM_RUST=$($CURL https://raw.githubusercontent.com/stellar/rs-stellar-xdr/${RS_STELLAR_XDR_REVISION}/xdr/curr-version) + else + # revision is a crate version + CARGO_SRC_BASE_DIR=$(realpath ${CARGO_HOME:-$HOME/.cargo}/registry/src/index*) + STELLAR_XDR_REVISION_FROM_RUST=$(cat "${CARGO_SRC_BASE_DIR}/stellar-xdr-${RS_STELLAR_XDR_REVISION}/xdr/curr-version") + fi else echo "The project depends on multiple versions of the Rust rs-stellar-xdr library" echo "Make sure a single version of stellar-xdr is used" @@ -63,7 +81,7 @@ fi # on the same XDR revision # TODO: The sed extractions below won't work when the commit is not included in the Core image tag/debian packages version -CORE_CONTAINER_REVISION=$($SED -n 's/.*\/\(stellar-core\|unsafe-stellar-core-next\)\:.*\..*-[^\.]*\.\(.*\)\..*/\2/p' < cmd/soroban-rpc/internal/test/docker-compose.yml) +CORE_CONTAINER_REVISION=$($SED -n 's/.*\/\(stellar-core\|unsafe-stellar-core\(-next\)\{0,1\}\)\:.*\..*-[^\.]*\.\(.*\)\..*/\3/p' < cmd/soroban-rpc/internal/test/docker-compose.yml) CAPTIVE_CORE_PKG_REVISION=$($SED -n 's/.*DEBIAN_PKG_VERSION:.*\..*-[^\.]*\.\(.*\)\..*/\1/p' < .github/workflows/soroban-rpc.yml) if [ "$CORE_CONTAINER_REVISION" != "$CAPTIVE_CORE_PKG_REVISION" ]; then @@ -81,7 +99,7 @@ fi CORE_HOST_DEP_TREE_CURR=$($CURL https://raw.githubusercontent.com/stellar/stellar-core/${CORE_CONTAINER_REVISION}/src/rust/src/host-dep-tree-curr.txt) -RS_STELLAR_XDR_REVISION_FROM_CORE=$(echo "$CORE_HOST_DEP_TREE_CURR" | grep stellar-xdr | head -n 1 | $SED "$CARGO_PACKAGE_REVISION_EXTRACT_SED_COMMAND") +RS_STELLAR_XDR_REVISION_FROM_CORE=$(echo "$CORE_HOST_DEP_TREE_CURR" | stellar_xdr_version_from_rust_dep_tree) if [ "$RS_STELLAR_XDR_REVISION" != "$RS_STELLAR_XDR_REVISION_FROM_CORE" ]; then echo "The Core revision used in integration tests (${CORE_CONTAINER_REVISION}) uses a different revision of https://github.com/stellar/rs-stellar-xdr" echo