diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 82323997d..5881ae129 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,4 +27,5 @@ jobs: - run: npm run lint - run: npm run compile - run: npm install esmify && npm run compile-browser - - run: npm test + - run: npm run tests-unit + - run: npm run tests-devnet diff --git a/.github/workflows/test-localnet.yml b/.github/workflows/test-localnet.yml new file mode 100644 index 000000000..61cdae4c0 --- /dev/null +++ b/.github/workflows/test-localnet.yml @@ -0,0 +1,65 @@ +name: MultiversX Integration Tests + +on: + push: + branches: + - main + pull_request: + +jobs: + integration_tests: + runs-on: ubuntu-latest + + steps: + # Step 1: Checkout the repository + - name: Checkout code + uses: actions/checkout@v3 + + # Step 2: Set up Python environment + - name: Set up Python 3.x + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + # Step 3: Install pipx (to manage Python tools) + - name: Install pipx + run: | + python3 -m pip install --user pipx + python3 -m pipx ensurepath + # Add the pipx binary location to PATH + echo "$HOME/.local/bin" >> $GITHUB_PATH + shell: bash + + # Step 4: Install mxpy (MultiversX Python SDK) + - name: Install mxpy (MultiversX SDK) + run: | + pipx install multiversx-sdk-cli --force + + # Step 5: Set up MultiversX localnet using mxpy + - name: Set up MultiversX localnet + run: | + # Start the local testnet with mxpy + mkdir -p ~/localnet && cd ~/localnet + mxpy localnet setup --configfile=${GITHUB_WORKSPACE}/localnet.toml + nohup mxpy localnet start --configfile=${GITHUB_WORKSPACE}/localnet.toml > localnet.log 2>&1 & echo $! > localnet.pid + sleep 120 # Allow time for the testnet to fully start + + # Step 6: Install Node.js and dependencies + - name: Set up Node.js environment + uses: actions/setup-node@v3 + with: + node-version: '16.x' + + - name: Install Node.js dependencies + run: npm install + + # Step 7: Run integration tests + - name: Run integration tests + run: | + npm run tests-localnet + + # Step 8: Stop the testnet using the stored PID + - name: Stop MultiversX local testnet + if: success() || failure() + run: | + kill $(cat localnet.pid) || echo "Testnet already stopped" diff --git a/.npmignore b/.npmignore index 565b2be53..f40235d51 100644 --- a/.npmignore +++ b/.npmignore @@ -1,2 +1,3 @@ src/testdata/** src/testutils/** +localnet.toml diff --git a/.vscode/settings.json b/.vscode/settings.json index e5c7eee47..37681e68f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,9 @@ }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" - } + }, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + }, + "prettier.printWidth": 120 } diff --git a/README.md b/README.md index 7985ca692..fbb658797 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,33 @@ Feel free to skip this section if you are not a contributor. ``` npm install --global browserify -npm install esmify +npm install esmify --no-save +``` + +## Optional Dependencies + +### axios + +This package can make HTTP requests using `axios`, which is not bundled by default. If you plan to use the API network provider or Proxy network provider, make sure to install `axios`: + +```bash +npm install axios +``` + +### @multiversx/sdk-bls-wasm + +This package requires `@multiversx/sdk-bls-wasm` for BLS (Boneh-Lynn-Shacham) cryptographic functions, which is not bundled by default. If you plan to use BLS functionality, make sure to install this optional dependency: + +```bash +npm install @multiversx/sdk-bls-wasm +``` + +### bip39 + +This package provides mnemonic and seed generation functionality using `bip39`, but it is not bundled by default. If you plan to use mnemonic-related features, make sure to install this optional dependency: + +```bash +npm install bip39 ``` ### Building the library diff --git a/browser-tests/index.html b/browser-tests/index.html index ceb4801ca..bbe645670 100644 --- a/browser-tests/index.html +++ b/browser-tests/index.html @@ -39,7 +39,7 @@ - + diff --git a/localnet.toml b/localnet.toml new file mode 100644 index 000000000..27b777910 --- /dev/null +++ b/localnet.toml @@ -0,0 +1,41 @@ +[general] +log_level = "*:DEBUG" +genesis_delay_seconds = 10 +rounds_per_epoch = 50 +round_duration_milliseconds = 6000 + +[metashard] +consensus_size = 1 +num_observers = 0 +num_validators = 1 + +[shards] +num_shards = 3 +consensus_size = 1 +num_observers_per_shard = 0 +num_validators_per_shard = 1 + +[networking] +host = "127.0.0.1" +port_seednode = 9999 +port_seednode_rest_api = 10000 +p2p_id_seednode = "16Uiu2HAkx4QqgXXDdHdUWbLu5kxhd3Uo2hqB2FfCxmxH5Sd7bZFk" +port_proxy = 7950 +port_first_observer = 21100 +port_first_observer_rest_api = 10100 +port_first_validator = 21500 +port_first_validator_rest_api = 10200 + +[software.mx_chain_go] +resolution = "remote" +archive_url = "https://github.com/multiversx/mx-chain-go/archive/refs/heads/master.zip" +archive_download_folder = "~/multiversx-sdk/localnet_software_remote/downloaded/mx-chain-go" +archive_extraction_folder = "~/multiversx-sdk/localnet_software_remote/extracted/mx-chain-go" +local_path = "~/multiversx-sdk/localnet_software_local/mx-chain-go" + +[software.mx_chain_proxy_go] +resolution = "remote" +archive_url = "https://github.com/multiversx/mx-chain-proxy-go/archive/refs/heads/master.zip" +archive_download_folder = "~/multiversx-sdk/localnet_software_remote/downloaded/mx-chain-proxy-go" +archive_extraction_folder = "~/multiversx-sdk/localnet_software_remote/extracted/mx-chain-proxy-go" +local_path = "~/multiversx-sdk/localnet_software_local/mx-chain-proxy-go" diff --git a/package-lock.json b/package-lock.json index 2a8292979..8d9c32d73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,32 +1,39 @@ { "name": "@multiversx/sdk-core", - "version": "13.4.0", + "version": "13.15.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@multiversx/sdk-core", - "version": "13.4.0", + "version": "13.15.0", "license": "MIT", "dependencies": { "@multiversx/sdk-transaction-decoder": "1.0.2", + "@noble/ed25519": "1.7.3", + "@noble/hashes": "1.3.0", "bech32": "1.1.4", "blake2b": "2.1.3", "buffer": "6.0.3", + "ed25519-hd-key": "1.1.2", + "ed2curve": "0.3.0", "json-bigint": "1.0.0", - "keccak": "3.0.2" + "keccak": "3.0.2", + "scryptsy": "2.1.0", + "tweetnacl": "1.0.3", + "uuid": "8.3.2" }, "devDependencies": { - "@multiversx/sdk-network-providers": "2.4.3", - "@multiversx/sdk-wallet": "4.5.0", "@types/assert": "1.4.6", "@types/chai": "4.2.11", + "@types/ed2curve": "0.2.2", "@types/mocha": "9.1.0", "@types/node": "13.13.2", + "@types/scryptsy": "2.0.0", + "@types/uuid": "8.3.0", "@typescript-eslint/eslint-plugin": "5.44.0", "@typescript-eslint/parser": "5.44.0", "assert": "2.0.0", - "axios": "1.6.5", "browserify": "17.0.0", "chai": "4.2.0", "eslint": "8.28.0", @@ -37,17 +44,16 @@ "ts-node": "9.1.1", "typescript": "4.1.2" }, + "optionalDependencies": { + "@multiversx/sdk-bls-wasm": "0.3.5", + "axios": "^1.7.4", + "bip39": "3.1.0" + }, "peerDependencies": { "bignumber.js": "^9.0.1", "protobufjs": "^7.2.6" } }, - "@multiversx/sdk-wallet:4.0.0-beta.3": { - "extraneous": true - }, - "@multiversx/sdk-wallet@4.0.0-beta.3": { - "extraneous": true - }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", @@ -156,35 +162,11 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@multiversx/sdk-bls-wasm/-/sdk-bls-wasm-0.3.5.tgz", "integrity": "sha512-c0tIdQUnbBLSt6NYU+OpeGPYdL0+GV547HeHT8Xc0BKQ7Cj0v82QUoA2QRtWrR1G4MNZmLsIacZSsf6DrIS2Bw==", - "dev": true, + "optional": true, "engines": { "node": ">=8.9.0" } }, - "node_modules/@multiversx/sdk-network-providers": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@multiversx/sdk-network-providers/-/sdk-network-providers-2.4.3.tgz", - "integrity": "sha512-tJmJuxU+BjtC2q29PuzQOM4Qr6aiXujKwQXgIAPHTiuNbMc3Yi6Q4B0DC1PfI3iG+M4DONwfXknvM1uwqnY2zA==", - "dev": true, - "dependencies": { - "axios": "1.6.8", - "bech32": "1.1.4", - "bignumber.js": "9.0.1", - "buffer": "6.0.3", - "json-bigint": "1.0.0" - } - }, - "node_modules/@multiversx/sdk-network-providers/node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/@multiversx/sdk-transaction-decoder": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@multiversx/sdk-transaction-decoder/-/sdk-transaction-decoder-1.0.2.tgz", @@ -198,45 +180,10 @@ "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" }, - "node_modules/@multiversx/sdk-wallet": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@multiversx/sdk-wallet/-/sdk-wallet-4.5.0.tgz", - "integrity": "sha512-2E/bMDcbFV7zl0KuSEPdNrIjIaMOp4e1BfctPO1q2F0Hd6aAHYO7bZIXNcYEj2v1zgvESybgVh5Zi5vQYtNZRg==", - "dev": true, - "dependencies": { - "@multiversx/sdk-bls-wasm": "0.3.5", - "@noble/ed25519": "1.7.3", - "@noble/hashes": "1.3.0", - "bech32": "1.1.4", - "bip39": "3.0.2", - "blake2b": "2.1.3", - "ed25519-hd-key": "1.1.2", - "ed2curve": "0.3.0", - "keccak": "3.0.1", - "scryptsy": "2.1.0", - "tweetnacl": "1.0.3", - "uuid": "8.3.2" - } - }, - "node_modules/@multiversx/sdk-wallet/node_modules/keccak": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", - "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/@noble/ed25519": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==", - "dev": true, "funding": [ { "type": "individual", @@ -248,7 +195,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", - "dev": true, "funding": [ { "type": "individual", @@ -367,6 +313,15 @@ "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==", "dev": true }, + "node_modules/@types/ed2curve": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@types/ed2curve/-/ed2curve-0.2.2.tgz", + "integrity": "sha512-G1sTX5xo91ydevQPINbL2nfgVAj/s1ZiqZxC8OCWduwu+edoNGUm5JXtTkg9F3LsBZbRI46/0HES4CPUE2wc9g==", + "dev": true, + "dependencies": { + "tweetnacl": "^1.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -406,12 +361,27 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz", "integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==" }, + "node_modules/@types/scryptsy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/scryptsy/-/scryptsy-2.0.0.tgz", + "integrity": "sha512-iDmneBKWSsmsR3SlGisOVnpCz7sB5Mqhv4I/pLg1DYq2zttWT65r+1gOVZtoxXiTsSf/JO8NhgyCKhx7cvGbaA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "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/@types/uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.44.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz", @@ -901,7 +871,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "optional": true }, "node_modules/available-typed-arrays": { "version": "1.0.5", @@ -916,12 +886,12 @@ } }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", - "dev": true, + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "optional": true, "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -974,23 +944,14 @@ } }, "node_modules/bip39": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz", - "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "optional": true, "dependencies": { - "@types/node": "11.11.6", - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1" + "@noble/hashes": "^1.2.0" } }, - "node_modules/bip39/node_modules/@types/node": { - "version": "11.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", - "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==", - "dev": true - }, "node_modules/blake2b": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.3.tgz", @@ -1417,7 +1378,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -1450,7 +1410,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, + "optional": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -1523,7 +1483,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -1536,7 +1495,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -1670,7 +1628,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, + "optional": true, "engines": { "node": ">=0.4.0" } @@ -1790,26 +1748,40 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/ed25519-hd-key/-/ed25519-hd-key-1.1.2.tgz", "integrity": "sha512-/0y9y6N7vM6Kj5ASr9J9wcMVDTtygxSOvYX+PJiMD7VcxCx2G03V5bLRl8Dug9EgkLFsLhGqBtQWQRcElEeWTA==", - "dev": true, "dependencies": { "bip39": "3.0.2", "create-hmac": "1.1.7", "tweetnacl": "1.0.3" } }, + "node_modules/ed25519-hd-key/node_modules/@types/node": { + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" + }, + "node_modules/ed25519-hd-key/node_modules/bip39": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz", + "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==", + "dependencies": { + "@types/node": "11.11.6", + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1" + } + }, "node_modules/ed2curve": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.3.0.tgz", "integrity": "sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ==", - "dev": true, "dependencies": { "tweetnacl": "1.x.x" } }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", + "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", "dev": true, "dependencies": { "bn.js": "^4.11.9", @@ -2428,13 +2400,13 @@ "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "optional": true, "engines": { "node": ">=4.0" }, @@ -2457,7 +2429,7 @@ "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, + "optional": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -2671,7 +2643,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -2685,7 +2656,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -3409,7 +3379,6 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -3432,12 +3401,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3467,7 +3436,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, + "optional": true, "engines": { "node": ">= 0.6" } @@ -3476,7 +3445,7 @@ "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, + "optional": true, "dependencies": { "mime-db": "1.52.0" }, @@ -3969,7 +3938,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, "dependencies": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -4231,7 +4199,7 @@ "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 + "optional": true }, "node_modules/public-encrypt": { "version": "4.0.3", @@ -4302,7 +4270,6 @@ "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" } @@ -4453,7 +4420,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -4510,8 +4476,7 @@ "node_modules/scryptsy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz", - "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==", - "dev": true + "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==" }, "node_modules/serialize-javascript": { "version": "6.0.0", @@ -4526,7 +4491,6 @@ "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" @@ -4882,8 +4846,7 @@ "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" }, "node_modules/type-check": { "version": "0.4.0", @@ -5042,7 +5005,6 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, "bin": { "uuid": "dist/bin/uuid" } @@ -5324,33 +5286,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@multiversx/sdk-bls-wasm/-/sdk-bls-wasm-0.3.5.tgz", "integrity": "sha512-c0tIdQUnbBLSt6NYU+OpeGPYdL0+GV547HeHT8Xc0BKQ7Cj0v82QUoA2QRtWrR1G4MNZmLsIacZSsf6DrIS2Bw==", - "dev": true - }, - "@multiversx/sdk-network-providers": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@multiversx/sdk-network-providers/-/sdk-network-providers-2.4.3.tgz", - "integrity": "sha512-tJmJuxU+BjtC2q29PuzQOM4Qr6aiXujKwQXgIAPHTiuNbMc3Yi6Q4B0DC1PfI3iG+M4DONwfXknvM1uwqnY2zA==", - "dev": true, - "requires": { - "axios": "1.6.8", - "bech32": "1.1.4", - "bignumber.js": "9.0.1", - "buffer": "6.0.3", - "json-bigint": "1.0.0" - }, - "dependencies": { - "axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "dev": true, - "requires": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - } - } + "optional": true }, "@multiversx/sdk-transaction-decoder": { "version": "1.0.2", @@ -5367,49 +5303,15 @@ } } }, - "@multiversx/sdk-wallet": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@multiversx/sdk-wallet/-/sdk-wallet-4.5.0.tgz", - "integrity": "sha512-2E/bMDcbFV7zl0KuSEPdNrIjIaMOp4e1BfctPO1q2F0Hd6aAHYO7bZIXNcYEj2v1zgvESybgVh5Zi5vQYtNZRg==", - "dev": true, - "requires": { - "@multiversx/sdk-bls-wasm": "0.3.5", - "@noble/ed25519": "1.7.3", - "@noble/hashes": "1.3.0", - "bech32": "1.1.4", - "bip39": "3.0.2", - "blake2b": "2.1.3", - "ed25519-hd-key": "1.1.2", - "ed2curve": "0.3.0", - "keccak": "3.0.1", - "scryptsy": "2.1.0", - "tweetnacl": "1.0.3", - "uuid": "8.3.2" - }, - "dependencies": { - "keccak": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", - "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", - "dev": true, - "requires": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - } - } - }, "@noble/ed25519": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", - "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==", - "dev": true + "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==" }, "@noble/hashes": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", - "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", - "dev": true + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==" }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -5513,6 +5415,15 @@ "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==", "dev": true }, + "@types/ed2curve": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@types/ed2curve/-/ed2curve-0.2.2.tgz", + "integrity": "sha512-G1sTX5xo91ydevQPINbL2nfgVAj/s1ZiqZxC8OCWduwu+edoNGUm5JXtTkg9F3LsBZbRI46/0HES4CPUE2wc9g==", + "dev": true, + "requires": { + "tweetnacl": "^1.0.0" + } + }, "@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -5552,12 +5463,27 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz", "integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==" }, + "@types/scryptsy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/scryptsy/-/scryptsy-2.0.0.tgz", + "integrity": "sha512-iDmneBKWSsmsR3SlGisOVnpCz7sB5Mqhv4I/pLg1DYq2zttWT65r+1gOVZtoxXiTsSf/JO8NhgyCKhx7cvGbaA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/semver": { "version": "7.5.6", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, + "@types/uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "5.44.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz", @@ -5893,7 +5819,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "optional": true }, "available-typed-arrays": { "version": "1.0.5", @@ -5902,12 +5828,12 @@ "dev": true }, "axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", - "dev": true, + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "optional": true, "requires": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -5940,23 +5866,12 @@ "dev": true }, "bip39": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz", - "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "optional": true, "requires": { - "@types/node": "11.11.6", - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1" - }, - "dependencies": { - "@types/node": { - "version": "11.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", - "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==", - "dev": true - } + "@noble/hashes": "^1.2.0" } }, "blake2b": { @@ -6327,7 +6242,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -6360,7 +6274,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, + "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -6429,7 +6343,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -6442,7 +6355,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -6544,7 +6456,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "optional": true }, "deps-sort": { "version": "2.0.1", @@ -6641,26 +6553,42 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/ed25519-hd-key/-/ed25519-hd-key-1.1.2.tgz", "integrity": "sha512-/0y9y6N7vM6Kj5ASr9J9wcMVDTtygxSOvYX+PJiMD7VcxCx2G03V5bLRl8Dug9EgkLFsLhGqBtQWQRcElEeWTA==", - "dev": true, "requires": { "bip39": "3.0.2", "create-hmac": "1.1.7", "tweetnacl": "1.0.3" + }, + "dependencies": { + "@types/node": { + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" + }, + "bip39": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz", + "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==", + "requires": { + "@types/node": "11.11.6", + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1" + } + } } }, "ed2curve": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.3.0.tgz", "integrity": "sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ==", - "dev": true, "requires": { "tweetnacl": "1.x.x" } }, "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", + "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", "dev": true, "requires": { "bn.js": "^4.11.9", @@ -7123,7 +7051,7 @@ "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true + "optional": true }, "for-each": { "version": "0.3.3", @@ -7138,7 +7066,7 @@ "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, + "optional": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -7294,7 +7222,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, "requires": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -7305,7 +7232,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7853,7 +7779,6 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -7873,12 +7798,12 @@ "dev": true }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, @@ -7904,13 +7829,13 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "optional": true }, "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, + "optional": true, "requires": { "mime-db": "1.52.0" } @@ -8286,7 +8211,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -8473,7 +8397,7 @@ "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 + "optional": true }, "public-encrypt": { "version": "4.0.3", @@ -8525,7 +8449,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -8647,7 +8570,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -8676,8 +8598,7 @@ "scryptsy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz", - "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==", - "dev": true + "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==" }, "serialize-javascript": { "version": "6.0.0", @@ -8692,7 +8613,6 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -8973,8 +8893,7 @@ "tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" }, "type-check": { "version": "0.4.0", @@ -9102,8 +9021,7 @@ "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "vm-browserify": { "version": "1.1.2", diff --git a/package.json b/package.json index fd87ca9e2..abe0b1d31 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,19 @@ { "name": "@multiversx/sdk-core", - "version": "13.4.0", + "version": "13.15.0", "description": "MultiversX SDK for JavaScript and TypeScript", + "author": "MultiversX", + "homepage": "https://multiversx.com", + "license": "MIT", + "repository": "github:multiversx/mx-sdk-js-core", + "bugs": { + "url": "https://github.com/multiversx/mx-sdk-js-core/issues" + }, + "keywords": [ + "multiversx", + "sdk", + "blockchain" + ], "main": "out/index.js", "types": "out/index.d.js", "files": [ @@ -10,10 +22,11 @@ ], "scripts": { "test": "npm run tests-unit", - "tests-unit": "mocha $(find . -name '*.spec.ts' ! -name '*.local.net.spec.*' ! -name '*.devnet.spec.*' ! -name '*.testnet.spec.*')", + "tests-unit": "mocha $(find . -name '*.spec.ts' ! -name '*.local.net.spec.*' ! -name '*.test.net.spec.*' ! -name '*.dev.net.spec.*' ! -name '*.main.net.spec.*')", "tests-localnet": "mocha $(find . -name '*.local.net.spec.ts')", - "tests-devnet": "mocha $(find . -name '*.devnet.spec.ts')", - "tests-testnet": "mocha $(find . -name '*.testnet.spec.ts')", + "tests-testnet": "mocha $(find . -name '*.test.net.spec.ts')", + "tests-devnet": "mocha $(find . -name '*.dev.net.spec.ts')", + "tests-mainnet": "mocha $(find . -name '*.main.net.spec.ts')", "compile-browser": "tsc -p tsconfig.json && browserify out/index.js -o out-browser/sdk-core.js --standalone multiversxSdkCore -p esmify", "compile": "tsc -p tsconfig.json", "compile-proto": "npx pbjs -t static-module -w default -o src/proto/compiled.js src/proto/transaction.proto", @@ -23,25 +36,29 @@ "pretest": "npm run compile", "prepare": "npm run compile" }, - "author": "MultiversX", - "license": "MIT", "dependencies": { "@multiversx/sdk-transaction-decoder": "1.0.2", "json-bigint": "1.0.0", "bech32": "1.1.4", "blake2b": "2.1.3", "buffer": "6.0.3", - "keccak": "3.0.2" + "ed25519-hd-key": "1.1.2", + "ed2curve": "0.3.0", + "keccak": "3.0.2", + "scryptsy": "2.1.0", + "tweetnacl": "1.0.3", + "@noble/ed25519": "1.7.3", + "@noble/hashes": "1.3.0", + "uuid": "8.3.2" }, "devDependencies": { - "@multiversx/sdk-network-providers": "2.4.3", - "@multiversx/sdk-wallet": "4.5.0", "@types/assert": "1.4.6", "@types/chai": "4.2.11", + "@types/ed2curve": "0.2.2", "@types/mocha": "9.1.0", "@types/node": "13.13.2", + "@types/scryptsy": "2.0.0", "assert": "2.0.0", - "axios": "1.6.5", "browserify": "17.0.0", "chai": "4.2.0", "mocha": "9.2.2", @@ -50,6 +67,7 @@ "typescript": "4.1.2", "@typescript-eslint/eslint-plugin": "5.44.0", "@typescript-eslint/parser": "5.44.0", + "@types/uuid": "8.3.0", "eslint": "8.28.0", "eslint-config-prettier": "9.1.0", "prettier": "3.2.4" @@ -57,5 +75,10 @@ "peerDependencies": { "bignumber.js": "^9.0.1", "protobufjs": "^7.2.6" + }, + "optionalDependencies": { + "axios": "^1.7.4", + "@multiversx/sdk-bls-wasm": "0.3.5", + "bip39": "3.1.0" } } diff --git a/src/abi/typeFormula.ts b/src/abi/typeFormula.ts index ca24926b8..500c051a0 100644 --- a/src/abi/typeFormula.ts +++ b/src/abi/typeFormula.ts @@ -1,18 +1,21 @@ export class TypeFormula { name: string; + metadata: any; typeParameters: TypeFormula[]; - constructor(name: string, typeParameters: TypeFormula[]) { + constructor(name: string, typeParameters: TypeFormula[], metadata?: any) { this.name = name; this.typeParameters = typeParameters; + this.metadata = metadata; } toString(): string { - if (this.typeParameters.length > 0) { - const typeParameters = this.typeParameters.map((typeParameter) => typeParameter.toString()).join(", "); - return `${this.name}<${typeParameters}>`; - } else { - return this.name; - } + const hasTypeParameters = this.typeParameters.length > 0; + const typeParameters = hasTypeParameters + ? `<${this.typeParameters.map((tp) => tp.toString()).join(", ")}>` + : ""; + const baseName = `${this.name}${typeParameters}`; + + return this.metadata !== undefined ? `${baseName}*${this.metadata}*` : baseName; } } diff --git a/src/abi/typeFormulaParser.ts b/src/abi/typeFormulaParser.ts index 02e7b9612..4353ed64c 100644 --- a/src/abi/typeFormulaParser.ts +++ b/src/abi/typeFormulaParser.ts @@ -12,7 +12,6 @@ export class TypeFormulaParser { parseExpression(expression: string): TypeFormula { expression = expression.trim(); - const tokens = this.tokenizeExpression(expression).filter((token) => token !== TypeFormulaParser.COMMA); const stack: any[] = []; @@ -32,7 +31,6 @@ export class TypeFormulaParser { stack.push(token); } } - if (stack.length !== 1) { throw new Error(`Unexpected stack length at end of parsing: ${stack.length}`); } @@ -83,6 +81,12 @@ export class TypeFormulaParser { private acquireTypeWithParameters(stack: any[]): TypeFormula { const typeParameters = this.acquireTypeParameters(stack); const typeName = stack.pop(); + + if (typeName === "ManagedDecimal" || typeName === "ManagedDecimalSigned") { + const metadata = typeParameters[0].name; + const typeFormula = new TypeFormula(typeName, [], metadata); + return typeFormula; + } const typeFormula = new TypeFormula(typeName, typeParameters.reverse()); return typeFormula; } @@ -92,7 +96,6 @@ export class TypeFormulaParser { while (true) { const item = stack.pop(); - if (item === undefined) { throw new Error("Badly specified type parameters"); } diff --git a/src/converters/transactionsConverter.ts b/src/converters/transactionsConverter.ts index c6001c5d6..966ec86e4 100644 --- a/src/converters/transactionsConverter.ts +++ b/src/converters/transactionsConverter.ts @@ -28,10 +28,6 @@ export class TransactionsConverter { guardian: transaction.guardian ? transaction.guardian : undefined, signature: this.toHexOrUndefined(transaction.signature), guardianSignature: this.toHexOrUndefined(transaction.guardianSignature), - relayer: transaction.relayer ? transaction.relayer : undefined, - innerTransactions: transaction.innerTransactions.length - ? transaction.innerTransactions.map((tx) => this.transactionToPlainObject(tx)) - : undefined, }; return plainObject; @@ -62,10 +58,6 @@ export class TransactionsConverter { options: Number(object.options), signature: this.bufferFromHex(object.signature), guardianSignature: this.bufferFromHex(object.guardianSignature), - relayer: object.relayer, - innerTransactions: object.innerTransactions - ? object.innerTransactions.map((tx) => this.plainObjectToTransaction(tx)) - : undefined, }); return transaction; @@ -79,6 +71,14 @@ export class TransactionsConverter { return Buffer.from(value || "", "hex"); } + /** + * @deprecated Where {@link TransactionOutcome} was needed (throughout the SDK), pass the {@link ITransactionOnNetwork} object instead. + * + * Summarizes the outcome of a transaction on the network, and maps it to the "standard" resources (according to the sdk-specs). + * + * In the future, this converter function will become obsolete, + * as the impedance mismatch between the network components and the "core" components will be reduced. + */ public transactionOnNetworkToOutcome(transactionOnNetwork: ITransactionOnNetwork): TransactionOutcome { // In the future, this will not be needed because the transaction, as returned from the API, // will hold the data corresponding to the direct smart contract call outcome (in case of smart contract calls). diff --git a/src/converters/transactionsConverters.spec.ts b/src/converters/transactionsConverters.spec.ts index a61dd3bc8..e491ab57a 100644 --- a/src/converters/transactionsConverters.spec.ts +++ b/src/converters/transactionsConverters.spec.ts @@ -2,11 +2,11 @@ import { ContractResultItem, ContractResults, TransactionEventData, - TransactionEvent as TransactionEventOnNetwork, + TransactionEventOnNetwork, TransactionEventTopic, - TransactionLogs as TransactionLogsOnNetwork, + TransactionLogsOnNetwork, TransactionOnNetwork, -} from "@multiversx/sdk-network-providers"; +} from "../networkProviders"; import { assert } from "chai"; import { Address } from "../address"; import { Transaction } from "../transaction"; @@ -59,85 +59,6 @@ describe("test transactions converter", async () => { guardian: undefined, signature: undefined, guardianSignature: undefined, - relayer: undefined, - innerTransactions: undefined, - }); - }); - - it("converts relayedV3 transaction to plain object and back", () => { - const converter = new TransactionsConverter(); - - const innerTx = new Transaction({ - nonce: 90, - value: BigInt("123456789000000000000000000000"), - sender: "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", - receiver: "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", - senderUsername: "alice", - receiverUsername: "bob", - gasPrice: 1000000000, - gasLimit: 80000, - data: Buffer.from("hello"), - chainID: "localnet", - version: 2, - relayer: "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", - }); - - const relayedTx = new Transaction({ - nonce: 77, - value: BigInt("0"), - sender: "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", - receiver: "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", - gasPrice: 1000000000, - gasLimit: 50000, - chainID: "localnet", - version: 2, - innerTransactions: [innerTx], - }); - - const plainObject = converter.transactionToPlainObject(relayedTx); - const restoredTransaction = converter.plainObjectToTransaction(plainObject); - - assert.deepEqual(plainObject, relayedTx.toPlainObject()); - assert.deepEqual(restoredTransaction, Transaction.fromPlainObject(plainObject)); - assert.deepEqual(restoredTransaction, relayedTx); - assert.deepEqual(plainObject, { - nonce: 77, - value: "0", - sender: "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", - receiver: "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", - senderUsername: undefined, - receiverUsername: undefined, - gasPrice: 1000000000, - gasLimit: 50000, - data: undefined, - chainID: "localnet", - version: 2, - options: undefined, - guardian: undefined, - signature: undefined, - guardianSignature: undefined, - relayer: undefined, - innerTransactions: [ - { - nonce: 90, - value: "123456789000000000000000000000", - sender: "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", - receiver: "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", - senderUsername: "YWxpY2U=", - receiverUsername: "Ym9i", - gasPrice: 1000000000, - gasLimit: 80000, - data: "aGVsbG8=", - chainID: "localnet", - version: 2, - options: undefined, - guardian: undefined, - signature: undefined, - guardianSignature: undefined, - relayer: "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", - innerTransactions: undefined, - }, - ], }); }); diff --git a/src/errors.ts b/src/errors.ts index 2bb4ff22a..a0a47f0ab 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -13,7 +13,7 @@ export class Err extends Error { * Returns a pretty, friendly summary for the error or for the chain of errros (if appropriate). */ summary(): any[] { - let result = []; + const result = []; result.push({ name: this.name, message: this.message }); @@ -77,7 +77,7 @@ export class ErrUnexpectedCondition extends Err { */ export class ErrAddressCannotCreate extends Err { public constructor(input: any, inner?: Error) { - let message = `Cannot create address from: ${input}`; + const message = `Cannot create address from: ${input}`; super(message, inner); } } @@ -141,7 +141,7 @@ export class ErrTransactionOptionsInvalid extends Err { */ export class ErrSignatureCannotCreate extends Err { public constructor(input: any, inner?: Error) { - let message = `Cannot create signature from: ${input}`; + const message = `Cannot create signature from: ${input}`; super(message, inner); } } @@ -384,3 +384,67 @@ export class ErrSmartContractQuery extends Err { this.returnCode = returnCode; } } + +/** + * Signals a wrong mnemonic format. + */ +export class ErrWrongMnemonic extends Err { + public constructor() { + super("Wrong mnemonic format"); + } +} + +/** + * Signals a bad mnemonic entropy. + */ +export class ErrBadMnemonicEntropy extends Err { + public constructor(inner: Error) { + super("Bad mnemonic entropy", inner); + } +} + +/** + * Signals a bad PEM file. + */ +export class ErrBadPEM extends Err { + public constructor(message?: string) { + super(message ? `Bad PEM: ${message}` : `Bad PEM`); + } +} + +/** + * Signals an error related to signing a message (a transaction). + */ +export class ErrSignerCannotSign extends Err { + public constructor(inner: Error) { + super(`Cannot sign`, inner); + } +} + +/** + * Signals a bad address. + */ +export class ErrBadAddress extends Err { + public constructor(value: string, inner?: Error) { + super(`Bad address: ${value}`, inner); + } +} + +/** + * Signals an error that happened during a request against the Network. + */ +export class ErrNetworkProvider extends Err { + public constructor(url: string, error: string, inner?: Error) { + const message = `Request error on url [${url}]: [${error}]`; + super(message, inner); + } +} + +/** + * Signals a generic error in the context of querying Smart Contracts. + */ +export class ErrContractQuery extends Err { + public constructor(originalError: Error) { + super(originalError.message.replace("executeQuery:", "")); + } +} diff --git a/src/index.ts b/src/index.ts index d244d0e0f..08c8affee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,3 +33,5 @@ export * from "./transactionWatcher"; export * from "./transactionsFactories"; export * from "./transactionsOutcomeParsers"; export * from "./utils"; +export * from "./networkProviders"; +export * from "./wallet"; diff --git a/src/interface.ts b/src/interface.ts index 1a1bc6324..97c86a54f 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -24,8 +24,6 @@ export interface IPlainTransactionObject { options?: number; signature?: string; guardianSignature?: string; - relayer?: string; - innerTransactions?: IPlainTransactionObject[]; } export interface ISignature { @@ -106,6 +104,4 @@ export interface ITransaction { guardian: string; signature: Uint8Array; guardianSignature: Uint8Array; - relayer: string; - innerTransactions: ITransaction[]; } diff --git a/src/interfaceOfNetwork.ts b/src/interfaceOfNetwork.ts index 526744239..eaee206aa 100644 --- a/src/interfaceOfNetwork.ts +++ b/src/interfaceOfNetwork.ts @@ -53,6 +53,7 @@ export interface IContractResultItem { data: string; returnMessage: string; logs: ITransactionLogs; + previousHash?: string; } export interface IContractQueryResponse { diff --git a/src/message.spec.ts b/src/message.spec.ts index b7c87c3c6..c7809d835 100644 --- a/src/message.spec.ts +++ b/src/message.spec.ts @@ -1,4 +1,4 @@ -import { UserVerifier } from "@multiversx/sdk-wallet"; +import { UserVerifier } from "./wallet"; import { assert } from "chai"; import { DEFAULT_MESSAGE_VERSION, SDK_JS_SIGNER, UNKNOWN_SIGNER } from "./constants"; import { Message, MessageComputer } from "./message"; diff --git a/src/networkProviders/accounts.ts b/src/networkProviders/accounts.ts new file mode 100644 index 000000000..cee89aea6 --- /dev/null +++ b/src/networkProviders/accounts.ts @@ -0,0 +1,80 @@ +import BigNumber from "bignumber.js"; +import { Address } from "../address"; +import { IAddress } from "./interface"; + +/** + * A plain view of an account, as queried from the Network. + */ +export class AccountOnNetwork { + address: IAddress = Address.empty(); + nonce: number = 0; + balance: BigNumber = new BigNumber(0); + code: string = ""; + userName: string = ""; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromHttpResponse(payload: any): AccountOnNetwork { + let result = new AccountOnNetwork(); + + result.address = new Address(payload["address"] || ""); + result.nonce = Number(payload["nonce"] || 0); + result.balance = new BigNumber(payload["balance"] || 0); + result.code = payload["code"] || ""; + result.userName = payload["username"] || ""; + + return result; + } +} + +export class GuardianData { + guarded: boolean = false; + activeGuardian?: Guardian; + pendingGuardian?: Guardian; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromHttpResponse(response: any): GuardianData { + const result = new GuardianData(); + + result.guarded = response["guarded"] || false; + + if (response["activeGuardian"]) { + result.activeGuardian = Guardian.fromHttpResponse(response["activeGuardian"]); + } + + if (response["pendingGuardian"]) { + result.pendingGuardian = Guardian.fromHttpResponse(response["pendingGuardian"]); + } + + return result; + } + + getCurrentGuardianAddress(): IAddress | undefined { + if (!this.guarded) { + return undefined; + } + + return this.activeGuardian?.address; + } +} + +class Guardian { + activationEpoch: number = 0; + address: IAddress = Address.empty(); + serviceUID: string = ""; + + static fromHttpResponse(responsePart: any): Guardian { + const result = new Guardian(); + + result.activationEpoch = Number(responsePart["activationEpoch"] || 0); + result.address = new Address(responsePart["address"] || ""); + result.serviceUID = responsePart["serviceUID"] || ""; + + return result; + } +} diff --git a/src/networkProviders/apiNetworkProvider.ts b/src/networkProviders/apiNetworkProvider.ts new file mode 100644 index 000000000..bf9cf6858 --- /dev/null +++ b/src/networkProviders/apiNetworkProvider.ts @@ -0,0 +1,244 @@ +import { ErrContractQuery, ErrNetworkProvider } from "../errors"; +import { getAxios } from "../utils"; +import { numberToPaddedHex } from "../utils.codec"; +import { AccountOnNetwork, GuardianData } from "./accounts"; +import { defaultAxiosConfig, defaultPagination } from "./config"; +import { BaseUserAgent } from "./constants"; +import { ContractQueryRequest } from "./contractQueryRequest"; +import { ContractQueryResponse } from "./contractQueryResponse"; +import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction, ITransactionNext } from "./interface"; +import { NetworkConfig } from "./networkConfig"; +import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +import { NetworkProviderConfig } from "./networkProviderConfig"; +import { NetworkStake } from "./networkStake"; +import { NetworkStatus } from "./networkStatus"; +import { PairOnNetwork } from "./pairs"; +import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; +import { extendUserAgentIfBackend } from "./userAgent"; + +// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". +export class ApiNetworkProvider implements INetworkProvider { + private url: string; + private config: NetworkProviderConfig; + private backingProxyNetworkProvider; + private userAgentPrefix = `${BaseUserAgent}/api`; + private axios: any; + + constructor(url: string, config?: NetworkProviderConfig) { + this.url = url; + const proxyConfig = this.getProxyConfig(config); + this.config = { ...defaultAxiosConfig, ...config }; + this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, proxyConfig); + this.axios = getAxios(); + extendUserAgentIfBackend(this.userAgentPrefix, this.config); + } + + private getProxyConfig(config: NetworkProviderConfig | undefined) { + let proxyConfig = JSON.parse(JSON.stringify(config || {})); + proxyConfig = { ...defaultAxiosConfig, ...proxyConfig }; + return proxyConfig; + } + + async getNetworkConfig(): Promise { + return await this.backingProxyNetworkProvider.getNetworkConfig(); + } + + async getNetworkStatus(): Promise { + return await this.backingProxyNetworkProvider.getNetworkStatus(); + } + + async getNetworkStakeStatistics(): Promise { + const response = await this.doGetGeneric("stake"); + const networkStake = NetworkStake.fromHttpResponse(response); + return networkStake; + } + + async getNetworkGeneralStatistics(): Promise { + const response = await this.doGetGeneric("stats"); + const stats = NetworkGeneralStatistics.fromHttpResponse(response); + return stats; + } + + async getAccount(address: IAddress): Promise { + const response = await this.doGetGeneric(`accounts/${address.bech32()}`); + const account = AccountOnNetwork.fromHttpResponse(response); + return account; + } + + async getGuardianData(address: IAddress): Promise { + return await this.backingProxyNetworkProvider.getGuardianData(address); + } + + async getFungibleTokensOfAccount( + address: IAddress, + pagination?: IPagination, + ): Promise { + pagination = pagination || defaultPagination; + + const url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`; + const response: any[] = await this.doGetGeneric(url); + const tokens = response.map((item) => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); + + // TODO: Fix sorting + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); + return tokens; + } + + async getNonFungibleTokensOfAccount( + address: IAddress, + pagination?: IPagination, + ): Promise { + pagination = pagination || defaultPagination; + + const url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; + const response: any[] = await this.doGetGeneric(url); + const tokens = response.map((item) => NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(item)); + + // TODO: Fix sorting + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); + return tokens; + } + + async getFungibleTokenOfAccount( + address: IAddress, + tokenIdentifier: string, + ): Promise { + const response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); + const tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response); + return tokenData; + } + + async getNonFungibleTokenOfAccount( + address: IAddress, + collection: string, + nonce: number, + ): Promise { + const nonceAsHex = numberToPaddedHex(nonce); + const response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonceAsHex}`); + const tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); + return tokenData; + } + + async getMexPairs(pagination?: IPagination): Promise { + let url = `mex/pairs`; + if (pagination) { + url = `${url}?from=${pagination.from}&size=${pagination.size}`; + } + + const response: any[] = await this.doGetGeneric(url); + + return response.map((item) => PairOnNetwork.fromApiHttpResponse(item)); + } + + async getTransaction(txHash: string): Promise { + const response = await this.doGetGeneric(`transactions/${txHash}`); + const transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response); + return transaction; + } + + async getTransactionStatus(txHash: string): Promise { + const response = await this.doGetGeneric(`transactions/${txHash}?fields=status`); + const status = new TransactionStatus(response.status); + return status; + } + + async sendTransaction(tx: ITransaction | ITransactionNext): Promise { + const transaction = prepareTransactionForBroadcasting(tx); + const response = await this.doPostGeneric("transactions", transaction); + return response.txHash; + } + + async sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise { + return await this.backingProxyNetworkProvider.sendTransactions(txs); + } + + async simulateTransaction(tx: ITransaction | ITransactionNext): Promise { + return await this.backingProxyNetworkProvider.simulateTransaction(tx); + } + + async queryContract(query: IContractQuery): Promise { + try { + const request = new ContractQueryRequest(query).toHttpRequest(); + const response = await this.doPostGeneric("query", request); + return ContractQueryResponse.fromHttpResponse(response); + } catch (error: any) { + throw new ErrContractQuery(error); + } + } + + async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { + const response = await this.doGetGeneric(`tokens/${tokenIdentifier}`); + const definition = DefinitionOfFungibleTokenOnNetwork.fromApiHttpResponse(response); + return definition; + } + + async getDefinitionOfTokenCollection(collection: string): Promise { + const response = await this.doGetGeneric(`collections/${collection}`); + const definition = DefinitionOfTokenCollectionOnNetwork.fromApiHttpResponse(response); + return definition; + } + + async getNonFungibleToken(collection: string, nonce: number): Promise { + const nonceAsHex = numberToPaddedHex(nonce); + const response = await this.doGetGeneric(`nfts/${collection}-${nonceAsHex}`); + const token = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); + return token; + } + + async doGetGeneric(resourceUrl: string): Promise { + const response = await this.doGet(resourceUrl); + return response; + } + + async doPostGeneric(resourceUrl: string, payload: any): Promise { + const response = await this.doPost(resourceUrl, payload); + return response; + } + + private buildPaginationParams(pagination: IPagination) { + return `from=${pagination.from}&size=${pagination.size}`; + } + + private async doGet(resourceUrl: string): Promise { + const url = `${this.url}/${resourceUrl}`; + + try { + const response = await this.axios.default.get(url, this.config); + return response.data; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private async doPost(resourceUrl: string, payload: any): Promise { + const url = `${this.url}/${resourceUrl}`; + + try { + const response = await this.axios.default.post(url, payload, { + ...this.config, + headers: { + "Content-Type": "application/json", + ...this.config.headers, + }, + }); + const responsePayload = response.data; + return responsePayload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private handleApiError(error: any, resourceUrl: string) { + if (!error.response) { + throw new ErrNetworkProvider(resourceUrl, error.toString(), error); + } + + const errorData = error.response.data; + const originalErrorMessage = errorData.message || errorData.error || JSON.stringify(errorData); + throw new ErrNetworkProvider(resourceUrl, originalErrorMessage, error); + } +} diff --git a/src/networkProviders/config.ts b/src/networkProviders/config.ts new file mode 100644 index 000000000..8239bfda9 --- /dev/null +++ b/src/networkProviders/config.ts @@ -0,0 +1,18 @@ +import { IPagination } from "./interface"; + +const JSONbig = require("json-bigint")({ constructorAction: 'ignore' }); + +export const defaultAxiosConfig = { + timeout: 5000, + // See: https://github.com/axios/axios/issues/983 regarding transformResponse + transformResponse: [ + function (data: any) { + return JSONbig.parse(data); + } + ] +}; + +export const defaultPagination: IPagination = { + from: 0, + size: 100 +}; diff --git a/src/networkProviders/constants.ts b/src/networkProviders/constants.ts new file mode 100644 index 000000000..d85d175b4 --- /dev/null +++ b/src/networkProviders/constants.ts @@ -0,0 +1,7 @@ +import BigNumber from "bignumber.js"; +import { Address } from "../address"; + +export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615"); +export const EsdtContractAddress = new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"); +export const BaseUserAgent = "multiversx-sdk"; +export const UnknownClientName = "unknown"; diff --git a/src/networkProviders/contractQueryRequest.ts b/src/networkProviders/contractQueryRequest.ts new file mode 100644 index 000000000..d64183c9a --- /dev/null +++ b/src/networkProviders/contractQueryRequest.ts @@ -0,0 +1,21 @@ +import { IContractQuery } from "./interface"; + +export class ContractQueryRequest { + private readonly query: IContractQuery; + + constructor(query: IContractQuery) { + this.query = query; + } + + toHttpRequest() { + let request: any = {}; + let query = this.query; + request.scAddress = query.address.bech32(); + request.caller = query.caller?.bech32() ? query.caller.bech32() : undefined; + request.funcName = query.func.toString(); + request.value = query.value ? query.value.toString() : undefined; + request.args = query.getEncodedArguments(); + + return request; + } +} diff --git a/src/networkProviders/contractQueryResponse.ts b/src/networkProviders/contractQueryResponse.ts new file mode 100644 index 000000000..40da09129 --- /dev/null +++ b/src/networkProviders/contractQueryResponse.ts @@ -0,0 +1,50 @@ +import BigNumber from "bignumber.js"; +import { MaxUint64AsBigNumber } from "./constants"; + +export class ContractQueryResponse { + returnData: string[]; + returnCode: string; + returnMessage: string; + gasUsed: number; + + constructor(init?: Partial) { + this.returnData = init?.returnData || []; + this.returnCode = init?.returnCode || ""; + this.returnMessage = init?.returnMessage || ""; + this.gasUsed = init?.gasUsed || 0; + } + + /** + * Constructs a QueryResponse object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): ContractQueryResponse { + let returnData = payload["returnData"] || payload["ReturnData"]; + let returnCode = payload["returnCode"] || payload["ReturnCode"]; + let returnMessage = payload["returnMessage"] || payload["ReturnMessage"]; + let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); + let gasUsed = MaxUint64AsBigNumber.minus(gasRemaining).toNumber(); + + return new ContractQueryResponse({ + returnData: returnData, + returnCode: returnCode, + returnMessage: returnMessage, + gasUsed: gasUsed, + }); + } + + getReturnDataParts(): Buffer[] { + return this.returnData.map((item) => Buffer.from(item || "", "base64")); + } + + /** + * Converts the object to a pretty, plain JavaScript object. + */ + toJSON(): object { + return { + returnData: this.returnData, + returnCode: this.returnCode, + returnMessage: this.returnMessage, + gasUsed: this.gasUsed.valueOf(), + }; + } +} diff --git a/src/networkProviders/contractResults.ts b/src/networkProviders/contractResults.ts new file mode 100644 index 000000000..a7f2a3674 --- /dev/null +++ b/src/networkProviders/contractResults.ts @@ -0,0 +1,80 @@ +import { Address } from "../address"; +import { IAddress } from "./interface"; +import { TransactionLogs } from "./transactionLogs"; + +export class ContractResults { + readonly items: ContractResultItem[]; + + constructor(items: ContractResultItem[]) { + this.items = items; + + this.items.sort(function (a: ContractResultItem, b: ContractResultItem) { + return a.nonce.valueOf() - b.nonce.valueOf(); + }); + } + + static fromProxyHttpResponse(results: any[]): ContractResults { + let items = results.map((item) => ContractResultItem.fromProxyHttpResponse(item)); + return new ContractResults(items); + } + + static fromApiHttpResponse(results: any[]): ContractResults { + let items = results.map((item) => ContractResultItem.fromApiHttpResponse(item)); + return new ContractResults(items); + } +} + +export class ContractResultItem { + hash: string = ""; + nonce: number = 0; + value: string = ""; + receiver: IAddress = Address.empty(); + sender: IAddress = Address.empty(); + data: string = ""; + previousHash: string = ""; + originalHash: string = ""; + gasLimit: number = 0; + gasPrice: number = 0; + callType: number = 0; + returnMessage: string = ""; + logs: TransactionLogs = new TransactionLogs(); + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromProxyHttpResponse(response: any): ContractResultItem { + let item = ContractResultItem.fromHttpResponse(response); + return item; + } + + static fromApiHttpResponse(response: any): ContractResultItem { + let item = ContractResultItem.fromHttpResponse(response); + + item.data = Buffer.from(item.data, "base64").toString(); + item.callType = Number(item.callType); + + return item; + } + + private static fromHttpResponse(response: any): ContractResultItem { + let item = new ContractResultItem(); + + item.hash = response.hash; + item.nonce = Number(response.nonce || 0); + item.value = (response.value || 0).toString(); + item.receiver = new Address(response.receiver); + item.sender = new Address(response.sender); + item.previousHash = response.prevTxHash; + item.originalHash = response.originalTxHash; + item.gasLimit = Number(response.gasLimit || 0); + item.gasPrice = Number(response.gasPrice || 0); + item.data = response.data || ""; + item.callType = response.callType; + item.returnMessage = response.returnMessage; + + item.logs = TransactionLogs.fromHttpResponse(response.logs || {}); + + return item; + } +} diff --git a/src/networkProviders/index.ts b/src/networkProviders/index.ts new file mode 100644 index 000000000..99c22853f --- /dev/null +++ b/src/networkProviders/index.ts @@ -0,0 +1,23 @@ +export { ApiNetworkProvider } from "./apiNetworkProvider"; +export { ProxyNetworkProvider } from "./proxyNetworkProvider"; + +export { AccountOnNetwork } from "./accounts"; +export { ContractQueryResponse } from "./contractQueryResponse"; +export { ContractResultItem, ContractResults } from "./contractResults"; +export { + TransactionEventData, + TransactionEvent as TransactionEventOnNetwork, + TransactionEventTopic, +} from "./transactionEvents"; +export { TransactionLogs as TransactionLogsOnNetwork } from "./transactionLogs"; +export { TransactionReceipt } from "./transactionReceipt"; +export { TransactionOnNetwork } from "./transactions"; +export { TransactionStatus } from "./transactionStatus"; + +export { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +export { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; + +export { NetworkConfig } from "./networkConfig"; +export { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +export { NetworkStake } from "./networkStake"; +export { NetworkStatus } from "./networkStatus"; diff --git a/src/networkProviders/interface.ts b/src/networkProviders/interface.ts new file mode 100644 index 000000000..eb73db286 --- /dev/null +++ b/src/networkProviders/interface.ts @@ -0,0 +1,150 @@ +import { ITransaction as ITransactionAsInSpecs } from "../interface"; +import { AccountOnNetwork } from "./accounts"; +import { ContractQueryResponse } from "./contractQueryResponse"; +import { NetworkConfig } from "./networkConfig"; +import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +import { NetworkStake } from "./networkStake"; +import { NetworkStatus } from "./networkStatus"; +import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; + +/** + * An interface that defines the endpoints of an HTTP API Provider. + */ +export interface INetworkProvider { + /** + * Fetches the Network configuration. + */ + getNetworkConfig(): Promise; + + /** + * Fetches the Network status. + */ + getNetworkStatus(): Promise; + + /** + * Fetches stake statistics. + */ + getNetworkStakeStatistics(): Promise; + + /** + * Fetches general statistics. + */ + getNetworkGeneralStatistics(): Promise; + + /** + * Fetches the state of an account. + */ + getAccount(address: IAddress): Promise; + + /** + * Fetches data about the fungible tokens held by an account. + */ + getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise; + + /** + * Fetches data about the non-fungible tokens held by account. + */ + getNonFungibleTokensOfAccount( + address: IAddress, + pagination?: IPagination, + ): Promise; + + /** + * Fetches data about a specific fungible token held by an account. + */ + getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise; + + /** + * Fetches data about a specific non-fungible token (instance) held by an account. + */ + getNonFungibleTokenOfAccount( + address: IAddress, + collection: string, + nonce: number, + ): Promise; + + /** + * Fetches the state of a transaction. + */ + getTransaction(txHash: string, withProcessStatus?: boolean): Promise; + + /** + * Queries the status of a transaction. + */ + getTransactionStatus(txHash: string): Promise; + + /** + * Broadcasts an already-signed transaction. + */ + sendTransaction(tx: ITransaction | ITransactionNext): Promise; + + /** + * Broadcasts a list of already-signed transactions. + */ + sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise; + + /** + * Simulates the processing of an already-signed transaction. + * + */ + simulateTransaction(tx: ITransaction): Promise; + + /** + * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. + */ + queryContract(query: IContractQuery): Promise; + + /** + * Fetches the definition of a fungible token. + */ + getDefinitionOfFungibleToken(tokenIdentifier: string): Promise; + + /** + * Fetches the definition of a SFT (including Meta ESDT) or NFT. + */ + getDefinitionOfTokenCollection(collection: string): Promise; + + /** + * Fetches data about a specific non-fungible token (instance). + */ + getNonFungibleToken(collection: string, nonce: number): Promise; + + /** + * Performs a generic GET action against the provider (useful for new HTTP endpoints). + */ + doGetGeneric(resourceUrl: string): Promise; + + /** + * Performs a generic POST action against the provider (useful for new HTTP endpoints). + */ + doPostGeneric(resourceUrl: string, payload: any): Promise; +} + +export interface IContractQuery { + address: IAddress; + caller?: IAddress; + func: { toString(): string }; + value?: { toString(): string }; + getEncodedArguments(): string[]; +} + +export interface IPagination { + from: number; + size: number; +} + +export interface ITransaction { + toSendable(): any; +} + +export interface IAddress { + bech32(): string; +} + +/** + * @deprecated This will be removed with the next release (replaced by the `ITransaction` interface from "src/interface.ts"). + */ +export type ITransactionNext = ITransactionAsInSpecs; diff --git a/src/networkProviders/networkConfig.ts b/src/networkProviders/networkConfig.ts new file mode 100644 index 000000000..be931e3c4 --- /dev/null +++ b/src/networkProviders/networkConfig.ts @@ -0,0 +1,84 @@ +import BigNumber from "bignumber.js"; + +/** + * An object holding Network configuration parameters. + */ +export class NetworkConfig { + /** + * The chain ID. E.g. "1" for the Mainnet. + */ + public ChainID: string; + + /** + * The gas required by the Network to process a byte of the transaction data. + */ + public GasPerDataByte: number; + /** + * The round duration. + */ + public RoundDuration: number; + /** + * The number of rounds per epoch. + */ + public RoundsPerEpoch: number; + + /** + * The Top Up Factor for APR calculation + */ + public TopUpFactor: number; + + /** + * The Top Up Factor for APR calculation + */ + public TopUpRewardsGradientPoint: BigNumber; + + public GasPriceModifier: number; + + /** + * The minimum gas limit required to be set when broadcasting a transaction. + */ + public MinGasLimit: number; + + /** + * The minimum gas price required to be set when broadcasting a transaction. + */ + public MinGasPrice: number; + + /** + * The oldest transaction version accepted by the Network. + */ + public MinTransactionVersion: number; + + constructor() { + this.ChainID = "T"; + this.GasPerDataByte = 1500; + this.TopUpFactor = 0; + this.RoundDuration = 0; + this.RoundsPerEpoch = 0; + this.TopUpRewardsGradientPoint = new BigNumber(0); + this.MinGasLimit = 50000; + this.MinGasPrice = 1000000000; + this.GasPriceModifier = 1; + this.MinTransactionVersion = 1; + } + + /** + * Constructs a configuration object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkConfig { + let networkConfig = new NetworkConfig(); + + networkConfig.ChainID = String(payload["erd_chain_id"]); + networkConfig.GasPerDataByte = Number(payload["erd_gas_per_data_byte"]); + networkConfig.TopUpFactor = Number(payload["erd_top_up_factor"]); + networkConfig.RoundDuration = Number(payload["erd_round_duration"]); + networkConfig.RoundsPerEpoch = Number(payload["erd_rounds_per_epoch"]); + networkConfig.TopUpRewardsGradientPoint = new BigNumber(payload["erd_rewards_top_up_gradient_point"]); + networkConfig.MinGasLimit = Number(payload["erd_min_gas_limit"]); + networkConfig.MinGasPrice = Number(payload["erd_min_gas_price"]); + networkConfig.MinTransactionVersion = Number(payload["erd_min_transaction_version"]); + networkConfig.GasPriceModifier = Number(payload["erd_gas_price_modifier"]); + + return networkConfig; + } +} diff --git a/src/networkProviders/networkGeneralStatistics.ts b/src/networkProviders/networkGeneralStatistics.ts new file mode 100644 index 000000000..2935b1cbc --- /dev/null +++ b/src/networkProviders/networkGeneralStatistics.ts @@ -0,0 +1,73 @@ +/** + * An object holding general Network statistics and parameters. + */ +export class NetworkGeneralStatistics { + /** + * The number of Shards. + */ + public Shards: number; + + /** + * The Number of Blocks. + */ + public Blocks: number; + + /** + * The Number of Accounts. + */ + public Accounts: number; + + /** + * The Number of transactions. + */ + public Transactions: number; + + /** + * The Refresh rate. + */ + public RefreshRate: number; + + /** + * The Number of the current Epoch. + */ + public Epoch: number; + + /** + * The Number of rounds passed. + */ + public RoundsPassed: number; + + /** + * The Number of Rounds per epoch. + */ + public RoundsPerEpoch: number; + + constructor() { + this.Shards = 0; + this.Blocks = 0; + this.Accounts = 0; + this.Transactions = 0; + this.RefreshRate = 0; + this.Epoch = 0; + this.RoundsPassed = 0; + this.RoundsPerEpoch = 0; + } + + /** + * Constructs a stats object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkGeneralStatistics { + let stats = new NetworkGeneralStatistics(); + + stats.Shards = Number(payload["shards"]); + stats.Blocks = Number(payload["blocks"]); + stats.Accounts = Number(payload["accounts"]); + stats.Transactions = Number(payload["transactions"]); + stats.RefreshRate = Number(payload["refreshRate"]); + stats.Epoch = Number(payload["epoch"]); + stats.RoundsPassed = Number(payload["roundsPassed"]); + stats.RoundsPerEpoch = Number(payload["roundsPerEpoch"]); + + return stats; + } +} diff --git a/src/networkProviders/networkProviderConfig.ts b/src/networkProviders/networkProviderConfig.ts new file mode 100644 index 000000000..b66bffbcc --- /dev/null +++ b/src/networkProviders/networkProviderConfig.ts @@ -0,0 +1,5 @@ +import { AxiosRequestConfig } from 'axios'; + +export interface NetworkProviderConfig extends AxiosRequestConfig { + clientName?: string; +} diff --git a/src/networkProviders/networkStake.ts b/src/networkProviders/networkStake.ts new file mode 100644 index 000000000..5806f9eb2 --- /dev/null +++ b/src/networkProviders/networkStake.ts @@ -0,0 +1,47 @@ +import BigNumber from "bignumber.js"; + +/** + * An object holding Network stake parameters. + */ +export class NetworkStake { + private static default: NetworkStake; + + /** + * The Total Validators Number. + */ + public TotalValidators: number; + + /** + * The Active Validators Number. + */ + public ActiveValidators: number; + /** + * The Queue Size. + */ + public QueueSize: number; + /** + * The Total Validators Number. + */ + public TotalStaked: BigNumber; + + constructor() { + this.TotalValidators = 0; + this.ActiveValidators = 0; + this.QueueSize = 0; + this.TotalStaked = new BigNumber(0); + } + + /** + * Constructs a configuration object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkStake { + let networkStake = new NetworkStake(); + + networkStake.TotalValidators = Number(payload["totalValidators"]); + networkStake.ActiveValidators = Number(payload["activeValidators"]); + networkStake.QueueSize = Number(payload["queueSize"]); + networkStake.TotalStaked = new BigNumber(payload["totalStaked"]); + + return networkStake; + } +} diff --git a/src/networkProviders/networkStatus.ts b/src/networkProviders/networkStatus.ts new file mode 100644 index 000000000..ec42a479c --- /dev/null +++ b/src/networkProviders/networkStatus.ts @@ -0,0 +1,82 @@ +/** + * An object holding network status configuration parameters. + */ +export class NetworkStatus { + private static default: NetworkStatus; + + /** + * The current round. + */ + public CurrentRound: number; + + /** + * The epoch number. + */ + public EpochNumber: number; + + /** + * The Highest final nonce. + */ + public HighestFinalNonce: number; + + /** + * The erd nonce. + */ + public Nonce: number; + + /** + * The nonce at epoch start. + */ + public NonceAtEpochStart: number; + + /** + * The nonces passed in current epoch. + */ + public NoncesPassedInCurrentEpoch: number; + + /** + * The round at epoch start + */ + public RoundAtEpochStart: number; + + /** + * The rounds passed in current epoch + */ + public RoundsPassedInCurrentEpoch: number; + + /** + * The rounds per epoch + */ + public RoundsPerEpoch: number; + + constructor() { + this.CurrentRound = 0; + this.EpochNumber = 0; + this.HighestFinalNonce = 0; + this.Nonce = 0; + this.NonceAtEpochStart = 0; + this.NoncesPassedInCurrentEpoch = 0; + this.RoundAtEpochStart = 0; + this.RoundsPassedInCurrentEpoch = 0; + this.RoundsPerEpoch = 0; + } + + /** + * Constructs a configuration object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkStatus { + let networkStatus = new NetworkStatus(); + + networkStatus.CurrentRound = Number(payload["erd_current_round"]); + networkStatus.EpochNumber = Number(payload["erd_epoch_number"]); + networkStatus.HighestFinalNonce = Number(payload["erd_highest_final_nonce"]); + networkStatus.Nonce = Number(payload["erd_nonce"]); + networkStatus.NonceAtEpochStart = Number(payload["erd_nonce_at_epoch_start"]); + networkStatus.NoncesPassedInCurrentEpoch = Number(payload["erd_nonces_passed_in_current_epoch"]); + networkStatus.RoundAtEpochStart = Number(payload["erd_round_at_epoch_start"]); + networkStatus.RoundsPassedInCurrentEpoch = Number(payload["erd_rounds_passed_in_current_epoch"]); + networkStatus.RoundsPerEpoch = Number(payload["erd_rounds_per_epoch"]); + + return networkStatus; + } +} diff --git a/src/networkProviders/pairs.ts b/src/networkProviders/pairs.ts new file mode 100644 index 000000000..31a92bf12 --- /dev/null +++ b/src/networkProviders/pairs.ts @@ -0,0 +1,55 @@ +import BigNumber from "bignumber.js"; +import { Address } from "../address"; +import { IAddress } from "./interface"; + +export class PairOnNetwork { + address: IAddress = Address.empty(); + id: string = ""; + symbol: string = ""; + name: string = ""; + price: BigNumber = new BigNumber(0); + baseId: string = ""; + basePrice: BigNumber = new BigNumber(0); + baseSymbol: string = ""; + baseName: string = ""; + quoteId: string = ""; + quotePrice: BigNumber = new BigNumber(0); + quoteSymbol: string = ""; + quoteName: string = ""; + totalValue: BigNumber = new BigNumber(0); + volume24h: BigNumber = new BigNumber(0); + state: string = ""; + type: string = ""; + + rawResponse: any = {}; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromApiHttpResponse(payload: any): PairOnNetwork { + let result = new PairOnNetwork(); + + result.address = new Address(payload.address || ""); + result.id = payload.id || ""; + result.symbol = payload.symbol || ""; + result.name = payload.name || ""; + result.price = new BigNumber(payload.price || 0); + result.baseId = payload.baseId || ""; + result.basePrice = new BigNumber(payload.basePrice || 0); + result.baseSymbol = payload.baseSymbol || ""; + result.baseName = payload.baseName || ""; + result.quoteId = payload.quoteId || ""; + result.quotePrice = new BigNumber(payload.quotePrice || 0); + result.quoteSymbol = payload.quoteSymbol || ""; + result.quoteName = payload.quoteName || ""; + result.totalValue = new BigNumber(payload.totalValue || 0); + result.volume24h = new BigNumber(payload.volume24h || 0); + result.state = payload.state || ""; + result.type = payload.type || ""; + + result.rawResponse = payload; + + return result; + } +} diff --git a/src/networkProviders/providers.dev.net.spec.ts b/src/networkProviders/providers.dev.net.spec.ts new file mode 100644 index 000000000..d08e5b4f7 --- /dev/null +++ b/src/networkProviders/providers.dev.net.spec.ts @@ -0,0 +1,466 @@ +import { AxiosHeaders } from "axios"; +import { assert } from "chai"; +import { Address } from "../address"; +import { MockQuery } from "../testutils/dummyQuery"; +import { ApiNetworkProvider } from "./apiNetworkProvider"; +import { INetworkProvider, ITransactionNext } from "./interface"; +import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionEventData } from "./transactionEvents"; +import { TransactionOnNetwork } from "./transactions"; + +describe("test network providers on devnet: Proxy and API", function () { + let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); + let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); + const MAX_NUMBER_OF_ITEMS_BY_DEFAULT = 20; + + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { + timeout: 10000, + clientName: "test", + }); + let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { + timeout: 10000, + clientName: "test", + }); + + it("should create providers without configuration", async function () { + const apiProviderWithoutConfig = new ApiNetworkProvider("https://devnet-api.multiversx.com"); + const proxyProviderWithoutConfig = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com"); + + const apiResponse = await apiProviderWithoutConfig.getNetworkConfig(); + const proxyResponse = await proxyProviderWithoutConfig.getNetworkConfig(); + + assert.equal(apiResponse.ChainID, "D"); + assert.equal(proxyResponse.ChainID, "D"); + }); + + it("should have same response for getNetworkConfig()", async function () { + let apiResponse = await apiProvider.getNetworkConfig(); + let proxyResponse = await proxyProvider.getNetworkConfig(); + + assert.deepEqual(apiResponse, proxyResponse); + }); + + it("should add userAgent unknown for clientName when no clientName passed", async function () { + const expectedApiUserAgent = "multiversx-sdk/api/unknown"; + const expectedProxyUserAgent = "multiversx-sdk/proxy/unknown"; + + let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000 }); + let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { + timeout: 10000, + }); + + assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent); + assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent); + }); + + it("should set userAgent with specified clientName ", async function () { + const expectedApiUserAgent = "multiversx-sdk/api/test"; + const expectedProxyUserAgent = "multiversx-sdk/proxy/test"; + + let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { + timeout: 10000, + clientName: "test", + }); + let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { + timeout: 10000, + clientName: "test", + }); + + assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent); + assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent); + }); + + it("should keep the set userAgent and add the sdk to it", async function () { + const expectedApiUserAgent = "Client-info multiversx-sdk/api/test"; + const expectedProxyUserAgent = "Client-info multiversx-sdk/proxy/test"; + + let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { + timeout: 10000, + headers: new AxiosHeaders({ "User-Agent": "Client-info" }), + clientName: "test", + }); + let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { + timeout: 10000, + headers: new AxiosHeaders({ "User-Agent": "Client-info" }), + clientName: "test", + }); + + assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent); + assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent); + }); + + it("should have same response for getNetworkStatus()", async function () { + let apiResponse = await apiProvider.getNetworkStatus(); + let proxyResponse = await proxyProvider.getNetworkStatus(); + + assert.equal(apiResponse.EpochNumber, proxyResponse.EpochNumber); + assert.equal(apiResponse.NonceAtEpochStart, proxyResponse.NonceAtEpochStart); + assert.equal(apiResponse.RoundAtEpochStart, proxyResponse.RoundAtEpochStart); + assert.equal(apiResponse.RoundsPerEpoch, proxyResponse.RoundsPerEpoch); + // done this way because the nonces may change until both requests are executed + assert.approximately(apiResponse.CurrentRound, proxyResponse.CurrentRound, 1); + assert.approximately(apiResponse.HighestFinalNonce, proxyResponse.HighestFinalNonce, 1); + assert.approximately(apiResponse.Nonce, proxyResponse.Nonce, 1); + assert.approximately(apiResponse.NoncesPassedInCurrentEpoch, proxyResponse.NoncesPassedInCurrentEpoch, 1); + }); + + // TODO: Enable test after implementing ProxyNetworkProvider.getNetworkStakeStatistics(). + it.skip("should have same response for getNetworkStakeStatistics()", async function () { + let apiResponse = await apiProvider.getNetworkStakeStatistics(); + let proxyResponse = await proxyProvider.getNetworkStakeStatistics(); + + assert.deepEqual(apiResponse, proxyResponse); + }); + + // TODO: Enable test after implementing ProxyNetworkProvider.getNetworkGeneralStatistics(). + it.skip("should have same response for getNetworkGeneralStatistics()", async function () { + let apiResponse = await apiProvider.getNetworkGeneralStatistics(); + let proxyResponse = await proxyProvider.getNetworkGeneralStatistics(); + + assert.deepEqual(apiResponse, proxyResponse); + }); + + it("should have same response for getAccount()", async function () { + let apiResponse = await apiProvider.getAccount(alice); + let proxyResponse = await proxyProvider.getAccount(alice); + + assert.deepEqual(apiResponse, proxyResponse); + }); + + it("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { + this.timeout(30000); + + for (const user of [carol, dan]) { + let apiResponse = (await apiProvider.getFungibleTokensOfAccount(user)).slice( + 0, + MAX_NUMBER_OF_ITEMS_BY_DEFAULT, + ); + let proxyResponse = (await proxyProvider.getFungibleTokensOfAccount(user)).slice( + 0, + MAX_NUMBER_OF_ITEMS_BY_DEFAULT, + ); + + for (let i = 0; i < apiResponse.length; i++) { + assert.equal(apiResponse[i].identifier, proxyResponse[i].identifier); + assert.equal(apiResponse[i].balance.valueOf, proxyResponse[i].balance.valueOf); + } + } + }); + + it("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { + this.timeout(30000); + + let apiResponse = (await apiProvider.getNonFungibleTokensOfAccount(dan)).slice( + 0, + MAX_NUMBER_OF_ITEMS_BY_DEFAULT, + ); + let proxyResponse = (await proxyProvider.getNonFungibleTokensOfAccount(dan)).slice( + 0, + MAX_NUMBER_OF_ITEMS_BY_DEFAULT, + ); + + assert.isTrue(apiResponse.length > 0, "For the sake of the test, there should be at least one item."); + assert.equal(apiResponse.length, proxyResponse.length); + + for (let i = 0; i < apiResponse.length; i++) { + removeInconsistencyForNonFungibleTokenOfAccount(apiResponse[i], proxyResponse[i]); + } + + assert.deepEqual(apiResponse, proxyResponse); + + const item = apiResponse[0]; + let apiItemResponse = await apiProvider.getNonFungibleTokenOfAccount(dan, item.collection, item.nonce); + let proxyItemResponse = await proxyProvider.getNonFungibleTokenOfAccount(dan, item.collection, item.nonce); + + removeInconsistencyForNonFungibleTokenOfAccount(apiItemResponse, proxyItemResponse); + assert.deepEqual(apiResponse, proxyResponse, `user: ${dan.bech32()}, token: ${item.identifier}`); + }); + + // TODO: Strive to have as little differences as possible between Proxy and API. + function removeInconsistencyForNonFungibleTokenOfAccount( + apiResponse: NonFungibleTokenOfAccountOnNetwork, + proxyResponse: NonFungibleTokenOfAccountOnNetwork, + ) { + // unset unconsistent fields + apiResponse.type = ""; + proxyResponse.type = ""; + apiResponse.name = ""; + proxyResponse.name = ""; + apiResponse.decimals = 0; + proxyResponse.decimals = 0; + } + + it("should be able to send transaction(s)", async function () { + this.timeout(5000); + + const txs = [ + { + toSendable: function () { + return { + nonce: 42, + value: "1", + receiver: "erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7", + sender: "erd15x2panzqvfxul2lvstfrmdcl5t4frnsylfrhng8uunwdssxw4y9succ9sq", + gasPrice: 1000000000, + gasLimit: 50000, + chainID: "D", + version: 1, + signature: + "c8eb539e486db7d703d8c70cab3b7679113f77c4685d8fcc94db027ceacc6b8605115034355386dffd7aa12e63dbefa03251a2f1b1d971f52250187298d12900", + }; + }, + }, + { + toSendable: function () { + return { + nonce: 43, + value: "1", + receiver: "erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7", + sender: "erd15x2panzqvfxul2lvstfrmdcl5t4frnsylfrhng8uunwdssxw4y9succ9sq", + gasPrice: 1000000000, + gasLimit: 50000, + chainID: "D", + version: 1, + signature: + "9c4c22d0ae1b5a10c39583a5ab9020b00b27aa69d4ac8ab4922620dbf0df4036ed890f9946d38a9d0c85d6ac485c0d9b2eac0005e752f249fd0ad863b0471d02", + }; + }, + }, + { + toSendable: function () { + return { + nonce: 44, + }; + }, + }, + ]; + + const expectedHashes = [ + "6e2fa63ea02937f00d7549f3e4eb9af241e4ac13027aa65a5300816163626c01", + "37d7e84313a5baea2a61c6ab10bb29b52bc54f7ac9e3918a9faeb1e08f42081c", + null, + ]; + + assert.equal(await apiProvider.sendTransaction(txs[0]), expectedHashes[0]); + assert.equal(await proxyProvider.sendTransaction(txs[1]), expectedHashes[1]); + + assert.deepEqual(await apiProvider.sendTransactions(txs), expectedHashes); + assert.deepEqual(await proxyProvider.sendTransactions(txs), expectedHashes); + }); + + it("should have same response for getTransaction()", async function () { + this.timeout(20000); + + let hashes = [ + "08acf8cbd71306a56eb58f9593cb2e23f109c94e27acdd906c82a5c3a5f84d9d", + "410efb1db2ab86678b8dbc503beb695b5b7d52754fb0de86c09cbb433de5f6a8", + ]; + + for (const hash of hashes) { + let apiResponse = await apiProvider.getTransaction(hash); + let proxyResponse = await proxyProvider.getTransaction(hash, true); + + ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); + assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); + + // Also assert completion + assert.isTrue(apiResponse.isCompleted); + assert.isTrue(proxyResponse.isCompleted); + } + }); + + // TODO: Strive to have as little differences as possible between Proxy and API. + function ignoreKnownTransactionDifferencesBetweenProviders( + apiResponse: TransactionOnNetwork, + proxyResponse: TransactionOnNetwork, + ) { + // Proxy and API exhibit differences in the "function" field, in case of move-balance transactions. + apiResponse.function = proxyResponse.function; + + // Ignore fields which are not present on API response: + proxyResponse.epoch = 0; + proxyResponse.blockNonce = 0; + proxyResponse.hyperblockNonce = 0; + proxyResponse.hyperblockHash = ""; + } + + it("should have the same response for transactions with events", async function () { + const hash = "1b04eb849cf87f2d3086c77b4b825d126437b88014327bbf01437476751cb040"; + + let apiResponse = await apiProvider.getTransaction(hash); + let proxyResponse = await proxyProvider.getTransaction(hash); + + assert.exists(apiResponse.logs); + assert.exists(proxyResponse.logs); + assert.exists(apiResponse.logs.events); + assert.exists(proxyResponse.logs.events); + assert.equal(apiResponse.logs.events[0].topics[0].hex(), "414c4943452d353632376631"); + assert.equal(apiResponse.logs.events[0].topics[1].hex(), ""); + assert.equal(apiResponse.logs.events[0].topics[2].hex(), "01"); + assert.equal( + apiResponse.logs.events[0].topics[3].hex(), + "0000000000000000050032e141d21536e2dfc3d64b9e7dd0c2c53f201dc469e1", + ); + assert.equal(proxyResponse.logs.events[0].topics[0].hex(), "414c4943452d353632376631"); + assert.equal(proxyResponse.logs.events[0].topics[1].hex(), ""); + assert.equal(proxyResponse.logs.events[0].topics[2].hex(), "01"); + assert.equal( + proxyResponse.logs.events[0].topics[3].hex(), + "0000000000000000050032e141d21536e2dfc3d64b9e7dd0c2c53f201dc469e1", + ); + }); + + it("should have same response for getTransactionStatus()", async function () { + this.timeout(20000); + + let hashes = [ + "08acf8cbd71306a56eb58f9593cb2e23f109c94e27acdd906c82a5c3a5f84d9d", + "410efb1db2ab86678b8dbc503beb695b5b7d52754fb0de86c09cbb433de5f6a8", + ]; + + for (const hash of hashes) { + let apiResponse = await apiProvider.getTransactionStatus(hash); + let proxyResponse = await proxyProvider.getTransactionStatus(hash); + + assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); + } + }); + + it("should have same response for getDefinitionOfFungibleToken()", async function () { + this.timeout(10000); + + let identifier = "CHOCOLATE-daf625"; + + let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); + let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); + + // Assets are only present on API responses, thus we ignore them for comparison. + apiResponse.assets = {}; + + assert.equal(apiResponse.identifier, identifier); + assert.deepEqual(apiResponse, proxyResponse); + }); + + it("should have same response for getDefinitionOfTokenCollection()", async function () { + this.timeout(10000); + + let collections = ["TEST-37adcf"]; + + for (const collection of collections) { + let apiResponse = await apiProvider.getDefinitionOfTokenCollection(collection); + let proxyResponse = await proxyProvider.getDefinitionOfTokenCollection(collection); + + assert.equal(apiResponse.collection, collection); + assert.deepEqual(apiResponse, proxyResponse); + } + }); + + it("should have same response for getNonFungibleToken()", async function () { + this.timeout(10000); + + let tokens = [{ id: "TEST-37adcf", nonce: 1 }]; + + for (const token of tokens) { + let apiResponse = await apiProvider.getNonFungibleToken(token.id, token.nonce); + + assert.equal(apiResponse.collection, token.id); + + // TODO: Uncomment after implementing the function in the proxy provider. + // let proxyResponse = await proxyProvider.getNonFungibleToken(token.id, token.nonce); + // assert.deepEqual(apiResponse, proxyResponse); + } + }); + + it("should have same response for queryContract()", async function () { + this.timeout(10000); + + // Query: get sum (of adder contract) + let query = new MockQuery({ + address: new Address("erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts"), + func: "getSum", + }); + + let apiResponse = await apiProvider.queryContract(query); + let proxyResponse = await proxyProvider.queryContract(query); + + // Ignore "gasUsed" due to numerical imprecision (API). + apiResponse.gasUsed = 0; + proxyResponse.gasUsed = 0; + + assert.deepEqual(apiResponse, proxyResponse); + assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); + }); + + it("should handle events 'data' and 'additionalData'", async function () { + this.timeout(50000); + + const apiResponse = await apiProvider.getTransaction( + "a419271407a2ec217739811805e3a751e30dbc72ae0777e3b4c825f036995184", + ); + const proxyResponse = await proxyProvider.getTransaction( + "a419271407a2ec217739811805e3a751e30dbc72ae0777e3b4c825f036995184", + ); + + assert.equal(apiResponse.logs.events[0].data, Buffer.from("test").toString()); + assert.equal(proxyResponse.logs.events[0].data, Buffer.from("test").toString()); + + assert.deepEqual(apiResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("dGVzdA==")); + assert.deepEqual(proxyResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("dGVzdA==")); + + assert.deepEqual(apiResponse.logs.events[0].additionalData, [TransactionEventData.fromBase64("dGVzdA==")]); + assert.deepEqual(proxyResponse.logs.events[0].additionalData, [TransactionEventData.fromBase64("dGVzdA==")]); + }); + + it("should send both `Transaction` and `TransactionNext`", async function () { + this.timeout(50000); + + const transaction = { + toSendable: function () { + return { + nonce: 7, + value: "0", + receiver: "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + sender: "erd1zztjf9fhwvuvquzsllknq4qcmffwad6n0hjtn5dyzytr5tgz7uas0mkgrq", + gasPrice: 1000000000, + gasLimit: 50000, + chainID: "D", + version: 2, + signature: + "149f1d8296efcb9489c5b3142ae659aacfa3a7daef3645f1d3747a96dc9cee377070dd8b83b322997c15ba3c305ac18daaee0fd25760eba334b14a9272b34802", + }; + }, + }; + + const transactionNext: ITransactionNext = { + nonce: BigInt(8), + value: BigInt(0), + receiver: "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + sender: "erd1zztjf9fhwvuvquzsllknq4qcmffwad6n0hjtn5dyzytr5tgz7uas0mkgrq", + data: new Uint8Array(Buffer.from("test")), + gasPrice: BigInt(1000000000), + gasLimit: BigInt(80000), + chainID: "D", + version: 2, + signature: Buffer.from( + "3fa42d97b4f85442850340a11411a3cbd63885e06ff3f84c7a75d0ef59c780f7a18aa4f331cf460300bc8bd99352aea10b7c3bc17e40287337ae9f9842470205", + "hex", + ), + senderUsername: "", + receiverUsername: "", + guardian: "", + guardianSignature: new Uint8Array(), + options: 0, + }; + + const apiLegacyTxHash = await apiProvider.sendTransaction(transaction); + const apiTxNextHash = await apiProvider.sendTransaction(transactionNext); + + const proxyLegacyTxHash = await proxyProvider.sendTransaction(transaction); + const proxyTxNextHash = await proxyProvider.sendTransaction(transactionNext); + + assert.equal(apiLegacyTxHash, proxyLegacyTxHash); + assert.equal(apiTxNextHash, proxyTxNextHash); + }); +}); diff --git a/src/networkProviders/proxyNetworkProvider.ts b/src/networkProviders/proxyNetworkProvider.ts new file mode 100644 index 000000000..5b2059752 --- /dev/null +++ b/src/networkProviders/proxyNetworkProvider.ts @@ -0,0 +1,268 @@ +import { ErrContractQuery, ErrNetworkProvider } from "../errors"; +import { getAxios } from "../utils"; +import { AccountOnNetwork, GuardianData } from "./accounts"; +import { defaultAxiosConfig } from "./config"; +import { BaseUserAgent, EsdtContractAddress } from "./constants"; +import { ContractQueryRequest } from "./contractQueryRequest"; +import { ContractQueryResponse } from "./contractQueryResponse"; +import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction, ITransactionNext } from "./interface"; +import { NetworkConfig } from "./networkConfig"; +import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +import { NetworkProviderConfig } from "./networkProviderConfig"; +import { NetworkStake } from "./networkStake"; +import { NetworkStatus } from "./networkStatus"; +import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; +import { extendUserAgentIfBackend } from "./userAgent"; + +// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". +export class ProxyNetworkProvider implements INetworkProvider { + private url: string; + private config: NetworkProviderConfig; + private userAgentPrefix = `${BaseUserAgent}/proxy`; + private axios: any; + + constructor(url: string, config?: NetworkProviderConfig) { + this.url = url; + this.config = { ...defaultAxiosConfig, ...config }; + this.axios = getAxios(); + extendUserAgentIfBackend(this.userAgentPrefix, this.config); + } + + async getNetworkConfig(): Promise { + const response = await this.doGetGeneric("network/config"); + const networkConfig = NetworkConfig.fromHttpResponse(response.config); + return networkConfig; + } + + async getNetworkStatus(): Promise { + const response = await this.doGetGeneric("network/status/4294967295"); + const networkStatus = NetworkStatus.fromHttpResponse(response.status); + return networkStatus; + } + + async getNetworkStakeStatistics(): Promise { + // TODO: Implement wrt.: + // https://github.com/multiversx/mx-api-service/blob/main/src/endpoints/stake/stake.service.ts + throw new Error("Method not implemented."); + } + + async getNetworkGeneralStatistics(): Promise { + // TODO: Implement wrt. (full implementation may not be possible): + // https://github.com/multiversx/mx-api-service/blob/main/src/endpoints/network/network.service.ts + throw new Error("Method not implemented."); + } + + async getAccount(address: IAddress): Promise { + const response = await this.doGetGeneric(`address/${address.bech32()}`); + const account = AccountOnNetwork.fromHttpResponse(response.account); + return account; + } + + async getGuardianData(address: IAddress): Promise { + const response = await this.doGetGeneric(`address/${address.bech32()}/guardian-data`); + const accountGuardian = GuardianData.fromHttpResponse(response.guardianData); + return accountGuardian; + } + + async getFungibleTokensOfAccount( + address: IAddress, + _pagination?: IPagination, + ): Promise { + const url = `address/${address.bech32()}/esdt`; + const response = await this.doGetGeneric(url); + const responseItems: any[] = Object.values(response.esdts); + // Skip NFTs / SFTs. + const responseItemsFiltered = responseItems.filter((item) => !item.nonce); + const tokens = responseItemsFiltered.map((item) => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); + + // TODO: Fix sorting + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); + return tokens; + } + + async getNonFungibleTokensOfAccount( + address: IAddress, + _pagination?: IPagination, + ): Promise { + const url = `address/${address.bech32()}/esdt`; + const response = await this.doGetGeneric(url); + const responseItems: any[] = Object.values(response.esdts); + // Skip fungible tokens. + const responseItemsFiltered = responseItems.filter((item) => item.nonce >= 0); + const tokens = responseItemsFiltered.map((item) => + NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(item), + ); + + // TODO: Fix sorting + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); + return tokens; + } + + async getFungibleTokenOfAccount( + address: IAddress, + tokenIdentifier: string, + ): Promise { + const response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); + const tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); + return tokenData; + } + + async getNonFungibleTokenOfAccount( + address: IAddress, + collection: string, + nonce: number, + ): Promise { + const response = await this.doGetGeneric( + `address/${address.bech32()}/nft/${collection}/nonce/${nonce.valueOf()}`, + ); + const tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponseByNonce(response.tokenData); + return tokenData; + } + + async getTransaction(txHash: string, _?: boolean): Promise { + const url = this.buildUrlWithQueryParameters(`transaction/${txHash}`, { withResults: "true" }); + const [data, status] = await Promise.all([this.doGetGeneric(url), this.getTransactionStatus(txHash)]); + return TransactionOnNetwork.fromProxyHttpResponse(txHash, data.transaction, status); + } + + async getTransactionStatus(txHash: string): Promise { + const response = await this.doGetGeneric(`transaction/${txHash}/process-status`); + const status = new TransactionStatus(response.status); + return status; + } + + async sendTransaction(tx: ITransaction | ITransactionNext): Promise { + const transaction = prepareTransactionForBroadcasting(tx); + const response = await this.doPostGeneric("transaction/send", transaction); + return response.txHash; + } + + async sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise { + const data = txs.map((tx) => prepareTransactionForBroadcasting(tx)); + + const response = await this.doPostGeneric("transaction/send-multiple", data); + const hashes = Array(txs.length).fill(null); + + for (let i = 0; i < txs.length; i++) { + hashes[i] = response.txsHashes[i.toString()] || null; + } + + return hashes; + } + + async simulateTransaction(tx: ITransaction | ITransactionNext): Promise { + const transaction = prepareTransactionForBroadcasting(tx); + const response = await this.doPostGeneric("transaction/simulate", transaction); + return response; + } + + async queryContract(query: IContractQuery): Promise { + try { + const request = new ContractQueryRequest(query).toHttpRequest(); + const response = await this.doPostGeneric("vm-values/query", request); + return ContractQueryResponse.fromHttpResponse(response.data); + } catch (error: any) { + throw new ErrContractQuery(error); + } + } + + async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { + const properties = await this.getTokenProperties(tokenIdentifier); + const definition = DefinitionOfFungibleTokenOnNetwork.fromResponseOfGetTokenProperties( + tokenIdentifier, + properties, + ); + return definition; + } + + private async getTokenProperties(identifier: string): Promise { + const encodedIdentifier = Buffer.from(identifier).toString("hex"); + + const queryResponse = await this.queryContract({ + address: EsdtContractAddress, + func: "getTokenProperties", + getEncodedArguments: () => [encodedIdentifier], + }); + + const properties = queryResponse.getReturnDataParts(); + return properties; + } + + async getDefinitionOfTokenCollection(collection: string): Promise { + const properties = await this.getTokenProperties(collection); + const definition = DefinitionOfTokenCollectionOnNetwork.fromResponseOfGetTokenProperties( + collection, + properties, + ); + return definition; + } + + async getNonFungibleToken(_collection: string, _nonce: number): Promise { + throw new Error("Method not implemented."); + } + + async doGetGeneric(resourceUrl: string): Promise { + const response = await this.doGet(resourceUrl); + return response; + } + + async doPostGeneric(resourceUrl: string, payload: any): Promise { + const response = await this.doPost(resourceUrl, payload); + return response; + } + + private async doGet(resourceUrl: string): Promise { + const url = `${this.url}/${resourceUrl}`; + + try { + const response = await this.axios.default.get(url, this.config); + const payload = response.data.data; + return payload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private async doPost(resourceUrl: string, payload: any): Promise { + const url = `${this.url}/${resourceUrl}`; + + try { + const response = await this.axios.default.post(url, payload, { + ...this.config, + headers: { + "Content-Type": "application/json", + ...this.config.headers, + }, + }); + const responsePayload = response.data.data; + return responsePayload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private buildUrlWithQueryParameters(endpoint: string, params: Record): string { + const searchParams = new URLSearchParams(); + + for (let [key, value] of Object.entries(params)) { + if (value) { + searchParams.append(key, value); + } + } + + return `${endpoint}?${searchParams.toString()}`; + } + + private handleApiError(error: any, resourceUrl: string) { + if (!error.response) { + throw new ErrNetworkProvider(resourceUrl, error.toString(), error); + } + + const errorData = error.response.data; + const originalErrorMessage = errorData.message || errorData.error || JSON.stringify(errorData); + throw new ErrNetworkProvider(resourceUrl, originalErrorMessage, error); + } +} diff --git a/src/networkProviders/serialization.spec.ts b/src/networkProviders/serialization.spec.ts new file mode 100644 index 000000000..6ffc83096 --- /dev/null +++ b/src/networkProviders/serialization.spec.ts @@ -0,0 +1,16 @@ +import assert from "assert"; + +describe("test JSON serialization", function () { + it("should not deserialize", async function () { + const JSONbig = require("json-bigint"); + const data = `{"Costum":{"foo_constructor":1}}`; + assert.throws(() => JSONbig.parse(data)); + }); + + it("should deserialize", async function () { + const JSONbig = require("json-bigint")({ constructorAction: 'ignore' }); + const data = `{"Costum":{"foo_constructor":1}}`; + JSONbig.parse(data); + }); +}); + diff --git a/src/networkProviders/tokenDefinitions.ts b/src/networkProviders/tokenDefinitions.ts new file mode 100644 index 000000000..fbaccf2ac --- /dev/null +++ b/src/networkProviders/tokenDefinitions.ts @@ -0,0 +1,160 @@ +import BigNumber from "bignumber.js"; +import { Address } from "../address"; +import { IAddress } from "./interface"; + +export class DefinitionOfFungibleTokenOnNetwork { + identifier: string = ""; + name: string = ""; + ticker: string = ""; + owner: IAddress = Address.empty(); + decimals: number = 0; + supply: BigNumber = new BigNumber(0); + isPaused: boolean = false; + canUpgrade: boolean = false; + canMint: boolean = false; + canBurn: boolean = false; + canChangeOwner: boolean = false; + canPause: boolean = false; + canFreeze: boolean = false; + canWipe: boolean = false; + canAddSpecialRoles: boolean = false; + assets: Record = {}; + + static fromApiHttpResponse(payload: any): DefinitionOfFungibleTokenOnNetwork { + let result = new DefinitionOfFungibleTokenOnNetwork(); + + result.identifier = payload.identifier || ""; + result.name = payload.name || ""; + result.ticker = payload.ticker || ""; + result.owner = new Address(payload.owner || ""); + result.decimals = payload.decimals || 0; + result.supply = new BigNumber(payload.supply || "0"); + result.isPaused = payload.isPaused || false; + result.canUpgrade = payload.canUpgrade || false; + result.canMint = payload.canMint || false; + result.canBurn = payload.canBurn || false; + result.canChangeOwner = payload.canChangeOwner || false; + result.canPause = payload.canPause || false; + result.canFreeze = payload.canFreeze || false; + result.canWipe = payload.canWipe || false; + result.assets = payload.assets || {}; + + return result; + } + + /** + * The implementation has been moved here from the following location: + * https://github.com/multiversx/mx-sdk-js-core/blob/release/v9/src/token.ts + */ + static fromResponseOfGetTokenProperties(identifier: string, data: Buffer[]): DefinitionOfFungibleTokenOnNetwork { + let result = new DefinitionOfFungibleTokenOnNetwork(); + + let [tokenName, _tokenType, owner, supply, ...propertiesBuffers] = data; + let properties = parseTokenProperties(propertiesBuffers); + + result.identifier = identifier; + result.name = tokenName.toString(); + result.ticker = identifier; + result.owner = new Address(owner); + result.decimals = properties.NumDecimals.toNumber(); + result.supply = new BigNumber(supply.toString()).shiftedBy(-result.decimals); + result.isPaused = properties.IsPaused; + result.canUpgrade = properties.CanUpgrade; + result.canMint = properties.CanMint; + result.canBurn = properties.CanBurn; + result.canChangeOwner = properties.CanChangeOwner; + result.canPause = properties.CanPause; + result.canFreeze = properties.CanFreeze; + result.canWipe = properties.CanWipe; + + return result; + } +} + +export class DefinitionOfTokenCollectionOnNetwork { + collection: string = ""; + type: string = ""; + name: string = ""; + ticker: string = ""; + owner: IAddress = Address.empty(); + decimals: number = 0; + canPause: boolean = false; + canFreeze: boolean = false; + canWipe: boolean = false; + canUpgrade: boolean = false; + canChangeOwner: boolean = false; + canAddSpecialRoles: boolean = false; + canTransferNftCreateRole: boolean = false; + canCreateMultiShard: boolean = false; + + static fromApiHttpResponse(payload: any): DefinitionOfTokenCollectionOnNetwork { + let result = new DefinitionOfTokenCollectionOnNetwork(); + + result.collection = payload.collection || ""; + result.type = payload.type || ""; + result.name = payload.name || ""; + result.ticker = payload.ticker || ""; + result.owner = new Address(payload.owner || ""); + result.decimals = payload.decimals || 0; + result.canPause = payload.canPause || false; + result.canFreeze = payload.canFreeze || false; + result.canWipe = payload.canWipe || false; + result.canUpgrade = payload.canUpgrade || false; + result.canAddSpecialRoles = payload.canAddSpecialRoles || false; + result.canTransferNftCreateRole = payload.canTransferNftCreateRole || false; + + return result; + } + + /** + * The implementation has been moved here from the following location: + * https://github.com/multiversx/mx-sdk-js-core/blob/release/v9/src/token.ts + */ + static fromResponseOfGetTokenProperties(collection: string, data: Buffer[]): DefinitionOfTokenCollectionOnNetwork { + let result = new DefinitionOfTokenCollectionOnNetwork(); + + let [tokenName, tokenType, owner, _, __, ...propertiesBuffers] = data; + let properties = parseTokenProperties(propertiesBuffers); + + result.collection = collection; + result.type = tokenType.toString(); + result.name = tokenName.toString(); + result.ticker = collection; + result.owner = new Address(owner); + result.decimals = properties.NumDecimals.toNumber() ?? 0; + result.canPause = properties.CanPause || false; + result.canFreeze = properties.CanFreeze || false; + result.canWipe = properties.CanWipe || false; + result.canUpgrade = properties.CanUpgrade || false; + result.canChangeOwner = properties.CanChangeOwner || false; + result.canAddSpecialRoles = properties.CanAddSpecialRoles || false; + result.canTransferNftCreateRole = properties.CanTransferNFTCreateRole || false; + result.canCreateMultiShard = properties.CanCreateMultiShard || false; + + return result; + } +} + +// Token properties have the following format: {PropertyName}-{PropertyValue}. +function parseTokenProperties(propertiesBuffers: Buffer[]): Record { + let properties: Record = {}; + + for (let buffer of propertiesBuffers) { + let [name, value] = buffer.toString().split("-"); + properties[name] = parseValueOfTokenProperty(value); + } + + return properties; +} + +// This only handles booleans and numbers. +function parseValueOfTokenProperty(value: string): any { + switch (value) { + case "true": + return true; + case "false": + return false; + default: + return new BigNumber(value); + } +} diff --git a/src/networkProviders/tokens.ts b/src/networkProviders/tokens.ts new file mode 100644 index 000000000..1c838f070 --- /dev/null +++ b/src/networkProviders/tokens.ts @@ -0,0 +1,95 @@ +import { BigNumber } from "bignumber.js"; +import { Address } from "../address"; +import { numberToPaddedHex } from "../utils.codec"; +import { IAddress } from "./interface"; + +export class FungibleTokenOfAccountOnNetwork { + identifier: string = ""; + balance: BigNumber = new BigNumber(0); + rawResponse: any = {}; + + static fromHttpResponse(payload: any): FungibleTokenOfAccountOnNetwork { + let result = new FungibleTokenOfAccountOnNetwork(); + + result.identifier = payload.tokenIdentifier || payload.identifier || ""; + result.balance = new BigNumber(payload.balance || 0); + result.rawResponse = payload; + + return result; + } +} + +export class NonFungibleTokenOfAccountOnNetwork { + identifier: string = ""; + collection: string = ""; + timestamp: number = 0; + attributes: Buffer = Buffer.from([]); + nonce: number = 0; + type: string = ""; + name: string = ""; + creator: IAddress = Address.empty(); + supply: BigNumber = new BigNumber(0); + decimals: number = 0; + royalties: BigNumber = new BigNumber(0); + assets: string[] = []; + balance: BigNumber = new BigNumber(0); + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromProxyHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); + + result.identifier = payload.tokenIdentifier || ""; + result.collection = NonFungibleTokenOfAccountOnNetwork.parseCollectionFromIdentifier(result.identifier); + result.royalties = new BigNumber(payload.royalties || 0).div(100); + + return result; + } + + static fromProxyHttpResponseByNonce(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); + let nonceAsHex = numberToPaddedHex(result.nonce); + + result.identifier = `${payload.tokenIdentifier}-${nonceAsHex}`; + result.collection = payload.tokenIdentifier || ""; + result.royalties = new BigNumber(payload.royalties || 0).div(100); + + return result; + } + + static fromApiHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); + + result.identifier = payload.identifier || ""; + result.collection = payload.collection || ""; + + return result; + } + + // TODO: Compare results from Proxy and API and try to reconciliate them. + private static fromHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = new NonFungibleTokenOfAccountOnNetwork(); + + result.timestamp = Number(payload.timestamp || 0); + result.attributes = Buffer.from(payload.attributes || "", "base64"); + result.nonce = payload.nonce || 0; + result.type = payload.type || ""; + result.name = payload.name || ""; + result.creator = new Address(payload.creator || ""); + result.decimals = Number(payload.decimals || 0); + result.supply = new BigNumber(payload.balance || 1); + result.royalties = new BigNumber(payload.royalties || 0); + result.assets = payload.assets || []; + result.balance = new BigNumber(payload.balance || 1); + + return result; + } + + private static parseCollectionFromIdentifier(identifier: string): string { + let parts = identifier.split("-"); + let collection = parts.slice(0, 2).join("-"); + return collection; + } +} diff --git a/src/networkProviders/transactionEvents.ts b/src/networkProviders/transactionEvents.ts new file mode 100644 index 000000000..ab11c5892 --- /dev/null +++ b/src/networkProviders/transactionEvents.ts @@ -0,0 +1,90 @@ +import { Address } from "../address"; +import { IAddress } from "./interface"; + +export class TransactionEvent { + address: IAddress = Address.empty(); + identifier: string = ""; + topics: TransactionEventTopic[] = []; + + /** + * @deprecated Use "dataPayload" instead. + */ + data: string = ""; + dataPayload: TransactionEventData = new TransactionEventData(Buffer.from("", "utf8")); + additionalData: TransactionEventData[] = []; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromHttpResponse(responsePart: { + address: string; + identifier: string; + topics: string[]; + data: string; + additionalData?: string[]; + }): TransactionEvent { + let result = new TransactionEvent(); + result.address = new Address(responsePart.address); + result.identifier = responsePart.identifier || ""; + result.topics = (responsePart.topics || []).map((topic) => new TransactionEventTopic(topic)); + + result.dataPayload = TransactionEventData.fromBase64(responsePart.data); + result.additionalData = (responsePart.additionalData || []).map(TransactionEventData.fromBase64); + result.data = result.dataPayload.toString(); + + return result; + } + + findFirstOrNoneTopic(predicate: (topic: TransactionEventTopic) => boolean): TransactionEventTopic | undefined { + return this.topics.filter((topic) => predicate(topic))[0]; + } + + getLastTopic(): TransactionEventTopic { + return this.topics[this.topics.length - 1]; + } +} + +export class TransactionEventData { + private readonly raw: Buffer; + + constructor(data: Buffer) { + this.raw = data; + } + + static fromBase64(str: string): TransactionEventData { + return new TransactionEventData(Buffer.from(str || "", "base64")); + } + + toString(): string { + return this.raw.toString("utf8"); + } + + hex(): string { + return this.raw.toString("hex"); + } + + valueOf(): Buffer { + return this.raw; + } +} + +export class TransactionEventTopic { + private readonly raw: Buffer; + + constructor(topic: string) { + this.raw = Buffer.from(topic || "", "base64"); + } + + toString(): string { + return this.raw.toString("utf8"); + } + + hex(): string { + return this.raw.toString("hex"); + } + + valueOf(): Buffer { + return this.raw; + } +} diff --git a/src/networkProviders/transactionLogs.ts b/src/networkProviders/transactionLogs.ts new file mode 100644 index 000000000..36c10690d --- /dev/null +++ b/src/networkProviders/transactionLogs.ts @@ -0,0 +1,51 @@ +import { Address } from "../address"; +import { ErrUnexpectedCondition } from "./../errors"; +import { IAddress } from "./interface"; +import { TransactionEvent } from "./transactionEvents"; + +export class TransactionLogs { + address: IAddress = Address.empty(); + events: TransactionEvent[] = []; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromHttpResponse(logs: any): TransactionLogs { + let result = new TransactionLogs(); + result.address = new Address(logs.address); + result.events = (logs.events || []).map((event: any) => TransactionEvent.fromHttpResponse(event)); + + return result; + } + + findSingleOrNoneEvent( + identifier: string, + predicate?: (event: TransactionEvent) => boolean, + ): TransactionEvent | undefined { + let events = this.findEvents(identifier, predicate); + + if (events.length > 1) { + throw new ErrUnexpectedCondition(`more than one event of type ${identifier}`); + } + + return events[0]; + } + + findFirstOrNoneEvent( + identifier: string, + predicate?: (event: TransactionEvent) => boolean, + ): TransactionEvent | undefined { + return this.findEvents(identifier, predicate)[0]; + } + + findEvents(identifier: string, predicate?: (event: TransactionEvent) => boolean): TransactionEvent[] { + let events = this.events.filter((event) => event.identifier == identifier); + + if (predicate) { + events = events.filter((event) => predicate(event)); + } + + return events; + } +} diff --git a/src/networkProviders/transactionReceipt.ts b/src/networkProviders/transactionReceipt.ts new file mode 100644 index 000000000..49d14d62e --- /dev/null +++ b/src/networkProviders/transactionReceipt.ts @@ -0,0 +1,25 @@ +import { Address } from "../address"; +import { IAddress } from "./interface"; + +export class TransactionReceipt { + value: string = ""; + sender: IAddress = Address.empty(); + data: string = ""; + hash: string = ""; + + static fromHttpResponse(response: { + value: string; + sender: string; + data: string; + txHash: string; + }): TransactionReceipt { + let receipt = new TransactionReceipt(); + + receipt.value = (response.value || 0).toString(); + receipt.sender = new Address(response.sender); + receipt.data = response.data; + receipt.hash = response.txHash; + + return receipt; + } +} diff --git a/src/networkProviders/transactionStatus.ts b/src/networkProviders/transactionStatus.ts new file mode 100644 index 000000000..bb509cbcf --- /dev/null +++ b/src/networkProviders/transactionStatus.ts @@ -0,0 +1,86 @@ +/** + * An abstraction for handling and interpreting the "status" field of a transaction. + */ +export class TransactionStatus { + /** + * The raw status, as fetched from the Network. + */ + readonly status: string; + + /** + * Creates a new TransactionStatus object. + */ + constructor(status: string) { + this.status = (status || "").toLowerCase(); + } + + /** + * Creates an unknown status. + */ + static createUnknown(): TransactionStatus { + return new TransactionStatus("unknown"); + } + + /** + * Returns whether the transaction is pending (e.g. in mempool). + */ + isPending(): boolean { + return ( + this.status == "received" || + this.status == "pending" + ); + } + + /** + * Returns whether the transaction has been executed (not necessarily with success). + */ + isExecuted(): boolean { + return this.isSuccessful() || this.isFailed() || this.isInvalid(); + } + + /** + * Returns whether the transaction has been executed successfully. + */ + isSuccessful(): boolean { + return ( + this.status == "executed" || + this.status == "success" || + this.status == "successful" + ); + } + + /** + * Returns whether the transaction has been executed, but with a failure. + */ + isFailed(): boolean { + return ( + this.status == "fail" || + this.status == "failed" || + this.status == "unsuccessful" || + this.isInvalid() + ); + } + + /** + * Returns whether the transaction has been executed, but marked as invalid (e.g. due to "insufficient funds"). + */ + isInvalid(): boolean { + return this.status == "invalid"; + } + + toString(): string { + return this.status; + } + + valueOf(): string { + return this.status; + } + + equals(other: TransactionStatus) { + if (!other) { + return false; + } + + return this.status == other.status; + } +} diff --git a/src/networkProviders/transactions.ts b/src/networkProviders/transactions.ts new file mode 100644 index 000000000..232691315 --- /dev/null +++ b/src/networkProviders/transactions.ts @@ -0,0 +1,123 @@ +import { Address } from "../address"; +import { ContractResults } from "./contractResults"; +import { IAddress, ITransaction, ITransactionNext } from "./interface"; +import { TransactionLogs } from "./transactionLogs"; +import { TransactionReceipt } from "./transactionReceipt"; +import { TransactionStatus } from "./transactionStatus"; + +export function prepareTransactionForBroadcasting(transaction: ITransaction | ITransactionNext): any { + if ("toSendable" in transaction) { + return transaction.toSendable(); + } + + return { + nonce: Number(transaction.nonce), + value: transaction.value.toString(), + receiver: transaction.receiver, + sender: transaction.sender, + senderUsername: transaction.senderUsername + ? Buffer.from(transaction.senderUsername).toString("base64") + : undefined, + receiverUsername: transaction.receiverUsername + ? Buffer.from(transaction.receiverUsername).toString("base64") + : undefined, + gasPrice: Number(transaction.gasPrice), + gasLimit: Number(transaction.gasLimit), + data: transaction.data.length === 0 ? undefined : Buffer.from(transaction.data).toString("base64"), + chainID: transaction.chainID, + version: transaction.version, + options: transaction.options, + guardian: transaction.guardian || undefined, + signature: Buffer.from(transaction.signature).toString("hex"), + guardianSignature: + transaction.guardianSignature.length === 0 + ? undefined + : Buffer.from(transaction.guardianSignature).toString("hex"), + }; +} + +export class TransactionOnNetwork { + isCompleted?: boolean; + hash: string = ""; + type: string = ""; + nonce: number = 0; + round: number = 0; + epoch: number = 0; + value: string = ""; + receiver: IAddress = Address.empty(); + sender: IAddress = Address.empty(); + gasLimit: number = 0; + gasPrice: number = 0; + function: string = ""; + data: Buffer = Buffer.from([]); + signature: string = ""; + status: TransactionStatus = TransactionStatus.createUnknown(); + timestamp: number = 0; + + blockNonce: number = 0; + hyperblockNonce: number = 0; + hyperblockHash: string = ""; + + receipt: TransactionReceipt = new TransactionReceipt(); + contractResults: ContractResults = new ContractResults([]); + logs: TransactionLogs = new TransactionLogs(); + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromProxyHttpResponse( + txHash: string, + response: any, + processStatus?: TransactionStatus | undefined, + ): TransactionOnNetwork { + let result = TransactionOnNetwork.fromHttpResponse(txHash, response); + result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); + + if (processStatus) { + result.status = processStatus; + result.isCompleted = result.status.isSuccessful() || result.status.isFailed(); + } + + return result; + } + + static fromApiHttpResponse(txHash: string, response: any): TransactionOnNetwork { + let result = TransactionOnNetwork.fromHttpResponse(txHash, response); + result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); + result.isCompleted = !result.status.isPending(); + return result; + } + + private static fromHttpResponse(txHash: string, response: any): TransactionOnNetwork { + let result = new TransactionOnNetwork(); + + result.hash = txHash; + result.type = response.type || ""; + result.nonce = response.nonce || 0; + result.round = response.round; + result.epoch = response.epoch || 0; + result.value = (response.value || 0).toString(); + result.sender = new Address(response.sender); + result.receiver = new Address(response.receiver); + result.gasPrice = response.gasPrice || 0; + result.gasLimit = response.gasLimit || 0; + result.function = response.function || ""; + result.data = Buffer.from(response.data || "", "base64"); + result.status = new TransactionStatus(response.status); + result.timestamp = response.timestamp || 0; + + result.blockNonce = response.blockNonce || 0; + result.hyperblockNonce = response.hyperblockNonce || 0; + result.hyperblockHash = response.hyperblockHash || ""; + + result.receipt = TransactionReceipt.fromHttpResponse(response.receipt || {}); + result.logs = TransactionLogs.fromHttpResponse(response.logs || {}); + + return result; + } + + getDateTime(): Date { + return new Date(this.timestamp * 1000); + } +} diff --git a/src/networkProviders/userAgent.ts b/src/networkProviders/userAgent.ts new file mode 100644 index 000000000..bea3d1cbf --- /dev/null +++ b/src/networkProviders/userAgent.ts @@ -0,0 +1,33 @@ +import { AxiosHeaders } from "axios"; +import { UnknownClientName } from "./constants"; +import { NetworkProviderConfig } from "./networkProviderConfig"; + +export function extendUserAgentIfBackend(userAgentPrefix: string, config: NetworkProviderConfig) { + if (isBackend()) { + extendUserAgent(userAgentPrefix, config); + } +} + +function extendUserAgent(userAgentPrefix: string, config: NetworkProviderConfig) { + if (!config.headers) { + config.headers = new AxiosHeaders({}); + } + if (!config.clientName) { + console.log( + "We recommend providing the `clientName` when instantiating a NetworkProvider (e.g. ProxyNetworkProvider, ApiNetworkProvider). This information will be used for metrics collection and improving our services.", + ); + } + const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); + const resolvedClientName = config.clientName || UnknownClientName; + + const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ""; + const newUserAgent = currentUserAgent + ? `${currentUserAgent} ${userAgentPrefix}/${resolvedClientName}` + : `${userAgentPrefix}/${resolvedClientName}`; + + headers.setUserAgent(newUserAgent, true); +} + +function isBackend(): boolean { + return typeof window === "undefined"; +} diff --git a/src/proto/compiled.js b/src/proto/compiled.js index 2d02a2512..feed796f9 100644 --- a/src/proto/compiled.js +++ b/src/proto/compiled.js @@ -46,8 +46,6 @@ * @property {number|null} [Options] Transaction Options * @property {Uint8Array|null} [GuardianAddr] Transaction GuardianAddr * @property {Uint8Array|null} [GuardianSignature] Transaction GuardianSignature - * @property {Uint8Array|null} [Relayer] Transaction Relayer - * @property {Array.|null} [InnerTransactions] Transaction InnerTransactions */ /** @@ -59,7 +57,6 @@ * @param {proto.ITransaction=} [properties] Properties to set */ function Transaction(properties) { - this.InnerTransactions = []; if (properties) for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) if (properties[keys[i]] != null) @@ -186,22 +183,6 @@ */ Transaction.prototype.GuardianSignature = $util.newBuffer([]); - /** - * Transaction Relayer. - * @member {Uint8Array} Relayer - * @memberof proto.Transaction - * @instance - */ - Transaction.prototype.Relayer = $util.newBuffer([]); - - /** - * Transaction InnerTransactions. - * @member {Array.} InnerTransactions - * @memberof proto.Transaction - * @instance - */ - Transaction.prototype.InnerTransactions = $util.emptyArray; - /** * Creates a new Transaction instance using the specified properties. * @function create @@ -256,11 +237,6 @@ writer.uint32(/* id 14, wireType 2 =*/114).bytes(message.GuardianAddr); if (message.GuardianSignature != null && Object.hasOwnProperty.call(message, "GuardianSignature")) writer.uint32(/* id 15, wireType 2 =*/122).bytes(message.GuardianSignature); - if (message.Relayer != null && Object.hasOwnProperty.call(message, "Relayer")) - writer.uint32(/* id 16, wireType 2 =*/130).bytes(message.Relayer); - if (message.InnerTransactions != null && message.InnerTransactions.length) - for (var i = 0; i < message.InnerTransactions.length; ++i) - $root.proto.Transaction.encode(message.InnerTransactions[i], writer.uint32(/* id 17, wireType 2 =*/138).fork()).ldelim(); return writer; }; @@ -355,16 +331,6 @@ message.GuardianSignature = reader.bytes(); break; } - case 16: { - message.Relayer = reader.bytes(); - break; - } - case 17: { - if (!(message.InnerTransactions && message.InnerTransactions.length)) - message.InnerTransactions = []; - message.InnerTransactions.push($root.proto.Transaction.decode(reader, reader.uint32())); - break; - } default: reader.skipType(tag & 7); break; @@ -445,18 +411,6 @@ if (message.GuardianSignature != null && message.hasOwnProperty("GuardianSignature")) if (!(message.GuardianSignature && typeof message.GuardianSignature.length === "number" || $util.isString(message.GuardianSignature))) return "GuardianSignature: buffer expected"; - if (message.Relayer != null && message.hasOwnProperty("Relayer")) - if (!(message.Relayer && typeof message.Relayer.length === "number" || $util.isString(message.Relayer))) - return "Relayer: buffer expected"; - if (message.InnerTransactions != null && message.hasOwnProperty("InnerTransactions")) { - if (!Array.isArray(message.InnerTransactions)) - return "InnerTransactions: array expected"; - for (var i = 0; i < message.InnerTransactions.length; ++i) { - var error = $root.proto.Transaction.verify(message.InnerTransactions[i]); - if (error) - return "InnerTransactions." + error; - } - } return null; }; @@ -553,21 +507,6 @@ $util.base64.decode(object.GuardianSignature, message.GuardianSignature = $util.newBuffer($util.base64.length(object.GuardianSignature)), 0); else if (object.GuardianSignature.length >= 0) message.GuardianSignature = object.GuardianSignature; - if (object.Relayer != null) - if (typeof object.Relayer === "string") - $util.base64.decode(object.Relayer, message.Relayer = $util.newBuffer($util.base64.length(object.Relayer)), 0); - else if (object.Relayer.length >= 0) - message.Relayer = object.Relayer; - if (object.InnerTransactions) { - if (!Array.isArray(object.InnerTransactions)) - throw TypeError(".proto.Transaction.InnerTransactions: array expected"); - message.InnerTransactions = []; - for (var i = 0; i < object.InnerTransactions.length; ++i) { - if (typeof object.InnerTransactions[i] !== "object") - throw TypeError(".proto.Transaction.InnerTransactions: object expected"); - message.InnerTransactions[i] = $root.proto.Transaction.fromObject(object.InnerTransactions[i]); - } - } return message; }; @@ -584,8 +523,6 @@ if (!options) options = {}; var object = {}; - if (options.arrays || options.defaults) - object.InnerTransactions = []; if (options.defaults) { if ($util.Long) { var long = new $util.Long(0, 0, true); @@ -674,13 +611,6 @@ if (options.bytes !== Array) object.GuardianSignature = $util.newBuffer(object.GuardianSignature); } - if (options.bytes === String) - object.Relayer = ""; - else { - object.Relayer = []; - if (options.bytes !== Array) - object.Relayer = $util.newBuffer(object.Relayer); - } } if (message.Nonce != null && message.hasOwnProperty("Nonce")) if (typeof message.Nonce === "number") @@ -721,13 +651,6 @@ object.GuardianAddr = options.bytes === String ? $util.base64.encode(message.GuardianAddr, 0, message.GuardianAddr.length) : options.bytes === Array ? Array.prototype.slice.call(message.GuardianAddr) : message.GuardianAddr; if (message.GuardianSignature != null && message.hasOwnProperty("GuardianSignature")) object.GuardianSignature = options.bytes === String ? $util.base64.encode(message.GuardianSignature, 0, message.GuardianSignature.length) : options.bytes === Array ? Array.prototype.slice.call(message.GuardianSignature) : message.GuardianSignature; - if (message.Relayer != null && message.hasOwnProperty("Relayer")) - object.Relayer = options.bytes === String ? $util.base64.encode(message.Relayer, 0, message.Relayer.length) : options.bytes === Array ? Array.prototype.slice.call(message.Relayer) : message.Relayer; - if (message.InnerTransactions && message.InnerTransactions.length) { - object.InnerTransactions = []; - for (var j = 0; j < message.InnerTransactions.length; ++j) - object.InnerTransactions[j] = $root.proto.Transaction.toObject(message.InnerTransactions[j], options); - } return object; }; diff --git a/src/proto/serializer.spec.ts b/src/proto/serializer.spec.ts index 53ecfbb68..97a88b5ca 100644 --- a/src/proto/serializer.spec.ts +++ b/src/proto/serializer.spec.ts @@ -7,7 +7,6 @@ import { TokenTransfer } from "../tokens"; import { Transaction } from "../transaction"; import { TransactionPayload } from "../transactionPayload"; import { ProtoSerializer } from "./serializer"; -import { TransactionComputer } from "../transactionComputer"; describe("serialize transactions", () => { let wallets: Record; @@ -146,42 +145,4 @@ describe("serialize transactions", () => { "08cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d086035201545802624051e6cd78fb3ab4b53ff7ad6864df27cb4a56d70603332869d47a5cf6ea977c30e696103e41e8dddf2582996ad335229fdf4acb726564dbc1a0bc9e705b511f06", ); }); - - it("serialize with inner transactions", async () => { - const innerTransaction = new Transaction({ - nonce: 204, - value: "1000000000000000000", - sender: Address.fromBech32("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"), - receiver: Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), - senderUsername: "carol", - receiverUsername: "alice", - gasLimit: 50000, - chainID: "T", - }); - - const signer = wallets.carol.signer; - const txComputer = new TransactionComputer(); - innerTransaction.signature = await signer.sign(txComputer.computeBytesForSigning(innerTransaction)); - - const relayedTransaction = new Transaction({ - nonce: 204, - value: "1000000000000000000", - sender: Address.fromBech32("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"), - receiver: Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), - senderUsername: "carol", - receiverUsername: "alice", - gasLimit: 50000, - chainID: "T", - relayer: wallets["carol"].address.toBech32(), - innerTransactions: [innerTransaction], - }); - - relayedTransaction.signature = await signer.sign(txComputer.computeBytesForSigning(relayedTransaction)); - - const serializedTransaction = serializer.serializeTransaction(relayedTransaction); - assert.equal( - serializedTransaction.toString("hex"), - "08cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d0860352015458026240901a6a974d6ab36546e7881c6e0364ec4c61a891aa70e5eb60f818d6c92a39cfa0beac6fab73f503853cfe8fe6149b4be207ddb93788f8450d75a07fa8759d06820120b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba8a01b10108cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d086035201545802624051e6cd78fb3ab4b53ff7ad6864df27cb4a56d70603332869d47a5cf6ea977c30e696103e41e8dddf2582996ad335229fdf4acb726564dbc1a0bc9e705b511f06", - ); - }); }); diff --git a/src/proto/serializer.ts b/src/proto/serializer.ts index 2fff28ff1..2f46ee425 100644 --- a/src/proto/serializer.ts +++ b/src/proto/serializer.ts @@ -60,12 +60,6 @@ export class ProtoSerializer { protoTransaction.GuardianSignature = transaction.guardianSignature; } - if (transaction.relayer) { - protoTransaction.Relayer = new Address(transaction.relayer).getPublicKey(); - } - - protoTransaction.InnerTransactions = transaction.innerTransactions.map((tx) => this.convertToProtoMessage(tx)); - return protoTransaction; } diff --git a/src/proto/transaction.proto b/src/proto/transaction.proto index 90f4feecd..b3b7dfd1f 100644 --- a/src/proto/transaction.proto +++ b/src/proto/transaction.proto @@ -25,6 +25,4 @@ message Transaction { uint32 Options = 13; bytes GuardianAddr = 14; bytes GuardianSignature = 15; - bytes Relayer = 16; - repeated Transaction InnerTransactions = 17; } diff --git a/src/signature.ts b/src/signature.ts index 95fe99778..e9ab00f24 100644 --- a/src/signature.ts +++ b/src/signature.ts @@ -8,15 +8,16 @@ const SIGNATURE_LENGTH = 64; export class Signature { private valueHex: string = ""; - constructor(value?: string | Buffer) { + constructor(value?: string | Buffer | Uint8Array) { if (!value) { return; } if (typeof value === "string") { return Signature.fromHex(value); } - if (value instanceof Buffer) { - return Signature.fromBuffer(value); + + if (ArrayBuffer.isView(value)) { + return Signature.fromBuffer(Buffer.from(value)); } } diff --git a/src/smartContractQueriesController.spec.ts b/src/smartContractQueriesController.spec.ts index c65309833..07bc570d8 100644 --- a/src/smartContractQueriesController.spec.ts +++ b/src/smartContractQueriesController.spec.ts @@ -1,4 +1,4 @@ -import { ContractQueryResponse } from "@multiversx/sdk-network-providers"; +import { ContractQueryResponse } from "./networkProviders"; import BigNumber from "bignumber.js"; import { assert } from "chai"; import { QueryRunnerAdapter } from "./adapters/queryRunnerAdapter"; diff --git a/src/smartcontracts/codeMetadata.spec.ts b/src/smartcontracts/codeMetadata.spec.ts index 7b0eab88c..7d184c4eb 100644 --- a/src/smartcontracts/codeMetadata.spec.ts +++ b/src/smartcontracts/codeMetadata.spec.ts @@ -63,7 +63,7 @@ describe("CodeMetadata Class Tests", function () { CodeMetadata.fromBuffer(buffer); }, Error, - "Buffer is too short.", + "code metadata buffer has length 1, expected 2", ); }); diff --git a/src/smartcontracts/codeMetadata.ts b/src/smartcontracts/codeMetadata.ts index 9d2fa2bc2..7efff036a 100644 --- a/src/smartcontracts/codeMetadata.ts +++ b/src/smartcontracts/codeMetadata.ts @@ -1,3 +1,5 @@ +export const CodeMetadataLength = 2; + /** * The metadata of a Smart Contract, as an abstraction. */ @@ -6,7 +8,6 @@ export class CodeMetadata { public readable: boolean; public payable: boolean; public payableBySc: boolean; - private static readonly codeMetadataLength = 2; static ByteZero = { Upgradeable: 1, @@ -48,8 +49,8 @@ export class CodeMetadata { * Creates a metadata object from a buffer. */ static fromBuffer(buffer: Buffer): CodeMetadata { - if (buffer.length < this.codeMetadataLength) { - throw new Error("Buffer is too short."); + if (buffer.length != CodeMetadataLength) { + throw new Error(`code metadata buffer has length ${buffer.length}, expected ${CodeMetadataLength}`); } const byteZero = buffer[0]; diff --git a/src/smartcontracts/codec/binary.spec.ts b/src/smartcontracts/codec/binary.spec.ts index 33df7e6c1..8e6f92eca 100644 --- a/src/smartcontracts/codec/binary.spec.ts +++ b/src/smartcontracts/codec/binary.spec.ts @@ -1,54 +1,55 @@ -import * as errors from "../../errors"; +import BigNumber from "bignumber.js"; import { assert } from "chai"; -import { BinaryCodec, BinaryCodecConstraints } from "./binary"; +import { Address } from "../../address"; +import * as errors from "../../errors"; import { AddressType, AddressValue, + ArrayVec, + ArrayVecType, BigIntType, + BigIntValue, BigUIntType, BigUIntValue, BooleanType, BooleanValue, + EnumType, + EnumValue, + EnumVariantDefinition, + Field, I16Type, + I16Value, I32Type, + I32Value, I64Type, + I64Value, I8Type, + I8Value, + List, + ListType, NumericalType, NumericalValue, + StringType, + StringValue, Struct, - Field, StructType, + TokenIdentifierType, + TokenIdentifierValue, TypedValue, U16Type, + U16Value, U32Type, U32Value, U64Type, U64Value, U8Type, U8Value, - List, - ListType, - EnumType, - EnumVariantDefinition, - EnumValue, - ArrayVec, - ArrayVecType, - U16Value, - TokenIdentifierType, - TokenIdentifierValue, - StringValue, - StringType, - BigIntValue, - I64Value, - I32Value, - I16Value, - I8Value, } from "../typesystem"; -import { isMsbOne } from "./utils"; -import { Address } from "../../address"; import { BytesType, BytesValue } from "../typesystem/bytes"; -import BigNumber from "bignumber.js"; +import { ExplicitEnumType, ExplicitEnumValue, ExplicitEnumVariantDefinition } from "../typesystem/explicit-enum"; import { FieldDefinition } from "../typesystem/fields"; +import { BinaryCodec, BinaryCodecConstraints } from "./binary"; +import { isMsbOne } from "./utils"; describe("test binary codec (basic)", () => { let codec = new BinaryCodec(); @@ -175,6 +176,21 @@ describe("test binary codec (basic)", () => { ]); assert.deepEqual(codec.decodeTopLevel(Buffer.from(payload), new StringType()), stringValue); }); + + it("should create explicit-enums, encode and decode", async () => { + let length = [0x00, 0x00, 0x00, 0x04]; + let payload = [0x74, 0x65, 0x73, 0x74]; + let enumType = new ExplicitEnumType("Colour", [new ExplicitEnumVariantDefinition("test")]); + let enumValue = ExplicitEnumValue.fromName(enumType, "test"); + + assert.deepEqual(codec.encodeNested(enumValue), Buffer.from([...length, ...payload])); + assert.deepEqual(codec.encodeTopLevel(enumValue), Buffer.from(payload)); + assert.deepEqual(codec.decodeNested(Buffer.from([...length, ...payload]), enumType), [ + enumValue, + 8, + ]); + assert.deepEqual(codec.decodeTopLevel(Buffer.from(payload), enumType), enumValue); + }); }); describe("test binary codec (advanced)", () => { diff --git a/src/smartcontracts/codec/binary.ts b/src/smartcontracts/codec/binary.ts index 1b9709315..bd6be3ad3 100644 --- a/src/smartcontracts/codec/binary.ts +++ b/src/smartcontracts/codec/binary.ts @@ -1,8 +1,17 @@ import * as errors from "../../errors"; +import { guardTrue } from "../../utils"; import { - Type, + ArrayVec, + ArrayVecType, EnumType, + EnumValue, + ExplicitEnumType, + ExplicitEnumValue, List, + ManagedDecimalSignedType, + ManagedDecimalSignedValue, + ManagedDecimalType, + ManagedDecimalValue, onTypedValueSelect, onTypeSelect, OptionValue, @@ -10,21 +19,21 @@ import { PrimitiveValue, Struct, StructType, - TypedValue, - EnumValue, - TupleType, Tuple, - ArrayVecType, - ArrayVec, + TupleType, + Type, + TypedValue, } from "../typesystem"; -import { guardTrue } from "../../utils"; +import { ArrayVecBinaryCodec } from "./arrayVec"; +import { EnumBinaryCodec } from "./enum"; +import { ExplicitEnumBinaryCodec } from "./explicit-enum"; +import { ListBinaryCodec } from "./list"; +import { ManagedDecimalCodec } from "./managedDecimal"; +import { ManagedDecimalSignedCodec } from "./managedDecimalSigned"; import { OptionValueBinaryCodec } from "./option"; import { PrimitiveBinaryCodec } from "./primitive"; -import { ListBinaryCodec } from "./list"; import { StructBinaryCodec } from "./struct"; -import { EnumBinaryCodec } from "./enum"; import { TupleBinaryCodec } from "./tuple"; -import { ArrayVecBinaryCodec } from "./arrayVec"; export class BinaryCodec { readonly constraints: BinaryCodecConstraints; @@ -35,6 +44,9 @@ export class BinaryCodec { private readonly structCodec: StructBinaryCodec; private readonly tupleCodec: TupleBinaryCodec; private readonly enumCodec: EnumBinaryCodec; + private readonly explicitEnumCodec: ExplicitEnumBinaryCodec; + private readonly managedDecimalCodec: ManagedDecimalCodec; + private readonly managedDecimalSignedCodec: ManagedDecimalSignedCodec; constructor(constraints: BinaryCodecConstraints | null = null) { this.constraints = constraints || new BinaryCodecConstraints(); @@ -45,6 +57,9 @@ export class BinaryCodec { this.structCodec = new StructBinaryCodec(this); this.tupleCodec = new TupleBinaryCodec(this); this.enumCodec = new EnumBinaryCodec(this); + this.explicitEnumCodec = new ExplicitEnumBinaryCodec(); + this.managedDecimalCodec = new ManagedDecimalCodec(this); + this.managedDecimalSignedCodec = new ManagedDecimalSignedCodec(this); } decodeTopLevel(buffer: Buffer, type: Type): TResult { @@ -58,6 +73,10 @@ export class BinaryCodec { onStruct: () => this.structCodec.decodeTopLevel(buffer, type), onTuple: () => this.tupleCodec.decodeTopLevel(buffer, type), onEnum: () => this.enumCodec.decodeTopLevel(buffer, type), + onExplicitEnum: () => this.explicitEnumCodec.decodeTopLevel(buffer, type), + onManagedDecimal: () => this.managedDecimalCodec.decodeTopLevel(buffer, type), + onManagedDecimalSigned: () => + this.managedDecimalSignedCodec.decodeTopLevel(buffer, type), }); return typedValue; @@ -74,6 +93,10 @@ export class BinaryCodec { onStruct: () => this.structCodec.decodeNested(buffer, type), onTuple: () => this.tupleCodec.decodeNested(buffer, type), onEnum: () => this.enumCodec.decodeNested(buffer, type), + onExplicitEnum: () => this.explicitEnumCodec.decodeNested(buffer, type), + onManagedDecimal: () => this.managedDecimalCodec.decodeNested(buffer, type), + onManagedDecimalSigned: () => + this.managedDecimalSignedCodec.decodeNested(buffer, type), }); return [typedResult, decodedLength]; @@ -90,6 +113,10 @@ export class BinaryCodec { onStruct: () => this.structCodec.encodeNested(typedValue), onTuple: () => this.tupleCodec.encodeNested(typedValue), onEnum: () => this.enumCodec.encodeNested(typedValue), + onExplicitEnum: () => this.explicitEnumCodec.encodeNested(typedValue), + onManagedDecimal: () => this.managedDecimalCodec.encodeNested(typedValue), + onManagedDecimalSigned: () => + this.managedDecimalSignedCodec.encodeNested(typedValue), }); } @@ -104,6 +131,10 @@ export class BinaryCodec { onStruct: () => this.structCodec.encodeTopLevel(typedValue), onTuple: () => this.tupleCodec.encodeTopLevel(typedValue), onEnum: () => this.enumCodec.encodeTopLevel(typedValue), + onExplicitEnum: () => this.explicitEnumCodec.encodeTopLevel(typedValue), + onManagedDecimal: () => this.managedDecimalCodec.encodeTopLevel(typedValue), + onManagedDecimalSigned: () => + this.managedDecimalSignedCodec.encodeTopLevel(typedValue), }); } } diff --git a/src/smartcontracts/codec/codemetadata.ts b/src/smartcontracts/codec/codemetadata.ts new file mode 100644 index 000000000..e5502ad8e --- /dev/null +++ b/src/smartcontracts/codec/codemetadata.ts @@ -0,0 +1,22 @@ +import { CodeMetadata, CodeMetadataLength } from "../codeMetadata"; +import { CodeMetadataValue } from "../typesystem/codeMetadata"; + +export class CodeMetadataCodec { + decodeNested(buffer: Buffer): [CodeMetadataValue, number] { + const codeMetadata = CodeMetadata.fromBuffer(buffer.slice(0, CodeMetadataLength)); + return [new CodeMetadataValue(codeMetadata), CodeMetadataLength]; + } + + decodeTopLevel(buffer: Buffer): CodeMetadataValue { + const codeMetadata = CodeMetadata.fromBuffer(buffer); + return new CodeMetadataValue(codeMetadata); + } + + encodeNested(codeMetadata: CodeMetadataValue): Buffer { + return codeMetadata.valueOf().toBuffer(); + } + + encodeTopLevel(codeMetadata: CodeMetadataValue): Buffer { + return codeMetadata.valueOf().toBuffer(); + } +} diff --git a/src/smartcontracts/codec/explicit-enum.ts b/src/smartcontracts/codec/explicit-enum.ts new file mode 100644 index 000000000..a88eef81c --- /dev/null +++ b/src/smartcontracts/codec/explicit-enum.ts @@ -0,0 +1,33 @@ +import { StringValue } from "../typesystem"; +import { ExplicitEnumType, ExplicitEnumValue, ExplicitEnumVariantDefinition } from "../typesystem/explicit-enum"; +import { StringBinaryCodec } from "./string"; + +export class ExplicitEnumBinaryCodec { + private readonly stringCodec: StringBinaryCodec; + + constructor() { + this.stringCodec = new StringBinaryCodec(); + } + + decodeTopLevel(buffer: Buffer, type: ExplicitEnumType): ExplicitEnumValue { + const stringValue = this.stringCodec.decodeTopLevel(buffer); + return new ExplicitEnumValue(type, new ExplicitEnumVariantDefinition(stringValue.valueOf())); + } + + decodeNested(buffer: Buffer, type: ExplicitEnumType): [ExplicitEnumValue, number] { + const [value, length] = this.stringCodec.decodeNested(buffer); + const enumValue = new ExplicitEnumValue(type, new ExplicitEnumVariantDefinition(value.valueOf())); + + return [enumValue, length]; + } + + encodeNested(enumValue: ExplicitEnumValue): Buffer { + const buffer = this.stringCodec.encodeNested(new StringValue(enumValue.valueOf().name)); + return buffer; + } + + encodeTopLevel(enumValue: ExplicitEnumValue): Buffer { + const buffer = this.stringCodec.encodeTopLevel(new StringValue(enumValue.valueOf().name)); + return buffer; + } +} diff --git a/src/smartcontracts/codec/managedDecimal.ts b/src/smartcontracts/codec/managedDecimal.ts new file mode 100644 index 000000000..0e2c5e43c --- /dev/null +++ b/src/smartcontracts/codec/managedDecimal.ts @@ -0,0 +1,56 @@ +import BigNumber from "bignumber.js"; +import { BigUIntType, BigUIntValue, ManagedDecimalType, ManagedDecimalValue, U32Value } from "../typesystem"; +import { BinaryCodec } from "./binary"; +import { bufferToBigInt } from "./utils"; +import { SizeOfU32 } from "./constants"; + +export class ManagedDecimalCodec { + private readonly binaryCodec: BinaryCodec; + + constructor(binaryCodec: BinaryCodec) { + this.binaryCodec = binaryCodec; + } + + decodeNested(buffer: Buffer, type: ManagedDecimalType): [ManagedDecimalValue, number] { + const length = buffer.readUInt32BE(0); + const payload = buffer.slice(0, length); + + const result = this.decodeTopLevel(payload, type); + return [result, length]; + } + + decodeTopLevel(buffer: Buffer, type: ManagedDecimalType): ManagedDecimalValue { + if (buffer.length === 0) { + return new ManagedDecimalValue(new BigNumber(0), 0); + } + + if (type.isVariable()) { + const bigUintSize = buffer.length - SizeOfU32; + + const [value] = this.binaryCodec.decodeNested(buffer.slice(0, bigUintSize), new BigUIntType()); + const scale = buffer.readUInt32BE(bigUintSize); + return new ManagedDecimalValue(value.valueOf().shiftedBy(-scale), scale); + } + + const value = bufferToBigInt(buffer); + const metadata = type.getMetadata(); + const scale = metadata !== "usize" ? parseInt(metadata.toString()) : 0; + return new ManagedDecimalValue(value.shiftedBy(-scale), scale); + } + + encodeNested(value: ManagedDecimalValue): Buffer { + let buffers: Buffer[] = []; + const rawValue = new BigUIntValue(value.valueOf().shiftedBy(value.getScale())); + if (value.isVariable()) { + buffers.push(Buffer.from(this.binaryCodec.encodeNested(rawValue))); + buffers.push(Buffer.from(this.binaryCodec.encodeNested(new U32Value(value.getScale())))); + } else { + buffers.push(this.binaryCodec.encodeTopLevel(rawValue)); + } + return Buffer.concat(buffers); + } + + encodeTopLevel(value: ManagedDecimalValue): Buffer { + return this.encodeNested(value); + } +} diff --git a/src/smartcontracts/codec/managedDecimalSigned.ts b/src/smartcontracts/codec/managedDecimalSigned.ts new file mode 100644 index 000000000..181d275b8 --- /dev/null +++ b/src/smartcontracts/codec/managedDecimalSigned.ts @@ -0,0 +1,57 @@ +import BigNumber from "bignumber.js"; +import { BigIntType, BigIntValue, ManagedDecimalSignedType, ManagedDecimalSignedValue, U32Value } from "../typesystem"; +import { BinaryCodec } from "./binary"; +import { bufferToBigInt } from "./utils"; +import { SizeOfU32 } from "./constants"; + +export class ManagedDecimalSignedCodec { + private readonly binaryCodec: BinaryCodec; + + constructor(binaryCodec: BinaryCodec) { + this.binaryCodec = binaryCodec; + } + + decodeNested(buffer: Buffer, type: ManagedDecimalSignedType): [ManagedDecimalSignedValue, number] { + const length = buffer.readUInt32BE(0); + const payload = buffer.slice(0, length); + + const result = this.decodeTopLevel(payload, type); + return [result, length]; + } + + decodeTopLevel(buffer: Buffer, type: ManagedDecimalSignedType): ManagedDecimalSignedValue { + if (buffer.length === 0) { + return new ManagedDecimalSignedValue(new BigNumber(0), 0); + } + + if (type.isVariable()) { + const bigintSize = buffer.length - SizeOfU32; + + const [value] = this.binaryCodec.decodeNested(buffer.slice(0, bigintSize), new BigIntType()); + const scale = buffer.readUInt32BE(bigintSize); + + return new ManagedDecimalSignedValue(value.valueOf().shiftedBy(-scale), scale); + } + + const value = bufferToBigInt(buffer); + const metadata = type.getMetadata(); + const scale = metadata !== "usize" ? parseInt(metadata.toString()) : 0; + return new ManagedDecimalSignedValue(value.shiftedBy(-scale), scale); + } + + encodeNested(value: ManagedDecimalSignedValue): Buffer { + let buffers: Buffer[] = []; + const rawValue = new BigIntValue(value.valueOf().shiftedBy(value.getScale())); + if (value.isVariable()) { + buffers.push(Buffer.from(this.binaryCodec.encodeNested(rawValue))); + buffers.push(Buffer.from(this.binaryCodec.encodeNested(new U32Value(value.getScale())))); + } else { + buffers.push(Buffer.from(this.binaryCodec.encodeTopLevel(rawValue))); + } + return Buffer.concat(buffers); + } + + encodeTopLevel(value: ManagedDecimalSignedValue): Buffer { + return this.encodeNested(value); + } +} diff --git a/src/smartcontracts/codec/primitive.ts b/src/smartcontracts/codec/primitive.ts index f761c0df2..2a6cd9e26 100644 --- a/src/smartcontracts/codec/primitive.ts +++ b/src/smartcontracts/codec/primitive.ts @@ -1,4 +1,5 @@ import { + CodeMetadataValue, PrimitiveType, PrimitiveValue, onPrimitiveTypeSelect, @@ -19,6 +20,7 @@ import { H256Value } from "../typesystem/h256"; import { BytesBinaryCodec } from "./bytes"; import { TokenIdentifierCodec } from "./tokenIdentifier"; import { TokenIdentifierValue } from "../typesystem/tokenIdentifier"; +import { CodeMetadataCodec } from "./codemetadata"; import { NothingCodec } from "./nothing"; import { StringBinaryCodec } from "./string"; @@ -32,6 +34,7 @@ export class PrimitiveBinaryCodec { private readonly bytesCodec: BytesBinaryCodec; private readonly stringCodec: StringBinaryCodec; private readonly tokenIdentifierCodec: TokenIdentifierCodec; + private readonly codeMetadataCodec: CodeMetadataCodec; private readonly nothingCodec: NothingCodec; constructor(binaryCodec: BinaryCodec) { @@ -44,6 +47,7 @@ export class PrimitiveBinaryCodec { this.bytesCodec = new BytesBinaryCodec(); this.stringCodec = new StringBinaryCodec(); this.tokenIdentifierCodec = new TokenIdentifierCodec(); + this.codeMetadataCodec = new CodeMetadataCodec(); this.nothingCodec = new NothingCodec(); } @@ -56,6 +60,7 @@ export class PrimitiveBinaryCodec { onString: () => this.stringCodec.decodeNested(buffer), onH256: () => this.h256Codec.decodeNested(buffer), onTokenIndetifier: () => this.tokenIdentifierCodec.decodeNested(buffer), + onCodeMetadata: () => this.codeMetadataCodec.decodeNested(buffer), onNothing: () => this.nothingCodec.decodeNested(), }); } @@ -69,6 +74,7 @@ export class PrimitiveBinaryCodec { onString: () => this.stringCodec.decodeTopLevel(buffer), onH256: () => this.h256Codec.decodeTopLevel(buffer), onTokenIndetifier: () => this.tokenIdentifierCodec.decodeTopLevel(buffer), + onCodeMetadata: () => this.codeMetadataCodec.decodeTopLevel(buffer), onNothing: () => this.nothingCodec.decodeTopLevel(), }); } @@ -82,6 +88,7 @@ export class PrimitiveBinaryCodec { onString: () => this.stringCodec.encodeNested(value), onH256: () => this.h256Codec.encodeNested(value), onTypeIdentifier: () => this.tokenIdentifierCodec.encodeNested(value), + onCodeMetadata: () => this.codeMetadataCodec.encodeNested(value), onNothing: () => this.nothingCodec.encodeNested(), }); } @@ -95,6 +102,7 @@ export class PrimitiveBinaryCodec { onString: () => this.stringCodec.encodeTopLevel(value), onH256: () => this.h256Codec.encodeTopLevel(value), onTypeIdentifier: () => this.tokenIdentifierCodec.encodeTopLevel(value), + onCodeMetadata: () => this.codeMetadataCodec.encodeTopLevel(value), onNothing: () => this.nothingCodec.encodeTopLevel(), }); } diff --git a/src/smartcontracts/interaction.local.net.spec.ts b/src/smartcontracts/interaction.local.net.spec.ts index 16247af5f..05b8a8106 100644 --- a/src/smartcontracts/interaction.local.net.spec.ts +++ b/src/smartcontracts/interaction.local.net.spec.ts @@ -15,6 +15,7 @@ import { ResultsParser } from "./resultsParser"; import { TransactionWatcher } from "../transactionWatcher"; import { SmartContractQueriesController } from "../smartContractQueriesController"; import { QueryRunnerAdapter } from "../adapters/queryRunnerAdapter"; +import { ManagedDecimalSignedValue, ManagedDecimalValue } from "./typesystem"; describe("test smart contract interactor", function () { let provider = createLocalnetProvider(); @@ -184,6 +185,138 @@ describe("test smart contract interactor", function () { assert.isTrue(typedBundle.returnCode.equals(ReturnCode.Ok)); }); + it("should interact with 'basic-features' (local testnet)", async function () { + this.timeout(140000); + + let abiRegistry = await loadAbiRegistry("src/testdata/basic-features.abi.json"); + let contract = new SmartContract({ abi: abiRegistry }); + let controller = new ContractController(provider); + + let network = await provider.getNetworkConfig(); + await alice.sync(provider); + + // Deploy the contract + let deployTransaction = await prepareDeployment({ + contract: contract, + deployer: alice, + codePath: "src/testdata/basic-features.wasm", + gasLimit: 600000000, + initArguments: [], + chainID: network.ChainID, + }); + + let { + bundle: { returnCode }, + } = await controller.deploy(deployTransaction); + assert.isTrue(returnCode.isSuccess()); + + let returnEgldInteraction = ( + contract.methods + .returns_egld_decimal([]) + .withGasLimit(10000000) + .withChainID(network.ChainID) + .withSender(alice.address) + .withValue(1) + ); + + // returnEgld() + let returnEgldTransaction = returnEgldInteraction + .withSender(alice.address) + .useThenIncrementNonceOf(alice.account) + .buildTransaction(); + + let additionInteraction = contract.methods + .managed_decimal_addition([new ManagedDecimalValue("2.5", 2), new ManagedDecimalValue("2.7", 2)]) + .withGasLimit(10000000) + .withChainID(network.ChainID) + .withSender(alice.address) + .withValue(0); + + // addition() + let additionTransaction = additionInteraction + .withSender(alice.address) + .useThenIncrementNonceOf(alice.account) + .buildTransaction(); + + // log + let mdLnInteraction = contract.methods + .managed_decimal_ln([new ManagedDecimalValue("23", 9)]) + .withGasLimit(10000000) + .withChainID(network.ChainID) + .withSender(alice.address) + .withValue(0); + + // mdLn() + let mdLnTransaction = mdLnInteraction + .withSender(alice.address) + .useThenIncrementNonceOf(alice.account) + .buildTransaction(); + + let additionVarInteraction = contract.methods + .managed_decimal_addition_var([ + new ManagedDecimalValue("4", 2, true), + new ManagedDecimalValue("5", 2, true), + ]) + .withGasLimit(50000000) + .withChainID(network.ChainID) + .withSender(alice.address) + .withValue(0); + + // addition() + let additionVarTransaction = additionVarInteraction + .withSender(alice.address) + .useThenIncrementNonceOf(alice.account) + .buildTransaction(); + + let lnVarInteraction = contract.methods + .managed_decimal_ln_var([new ManagedDecimalValue("23", 9, true)]) + .withGasLimit(50000000) + .withChainID(network.ChainID) + .withSender(alice.address) + .withValue(0); + + // managed_decimal_ln_var() + let lnVarTransaction = lnVarInteraction + .withSender(alice.address) + .useThenIncrementNonceOf(alice.account) + .buildTransaction(); + + // returnEgld() + await signTransaction({ transaction: returnEgldTransaction, wallet: alice }); + let { bundle: bundleEgld } = await controller.execute(returnEgldInteraction, returnEgldTransaction); + assert.isTrue(bundleEgld.returnCode.equals(ReturnCode.Ok)); + assert.lengthOf(bundleEgld.values, 1); + assert.deepEqual(bundleEgld.values[0], new ManagedDecimalValue("0.000000000000000001", 18)); + + // addition with const decimals() + await signTransaction({ transaction: additionTransaction, wallet: alice }); + let { bundle: bundleAdditionConst } = await controller.execute(additionInteraction, additionTransaction); + assert.isTrue(bundleAdditionConst.returnCode.equals(ReturnCode.Ok)); + assert.lengthOf(bundleAdditionConst.values, 1); + assert.deepEqual(bundleAdditionConst.values[0], new ManagedDecimalValue("5.2", 2)); + + // log + await signTransaction({ transaction: mdLnTransaction, wallet: alice }); + let { bundle: bundleMDLn } = await controller.execute(mdLnInteraction, mdLnTransaction); + assert.isTrue(bundleMDLn.returnCode.equals(ReturnCode.Ok)); + assert.lengthOf(bundleMDLn.values, 1); + assert.deepEqual(bundleMDLn.values[0], new ManagedDecimalSignedValue("3.135553845", 9)); + + // addition with var decimals + await signTransaction({ transaction: additionVarTransaction, wallet: alice }); + let { bundle: bundleAddition } = await controller.execute(additionVarInteraction, additionVarTransaction); + assert.isTrue(bundleAddition.returnCode.equals(ReturnCode.Ok)); + assert.lengthOf(bundleAddition.values, 1); + assert.deepEqual(bundleAddition.values[0], new ManagedDecimalValue("9", 2)); + + // log + await signTransaction({ transaction: lnVarTransaction, wallet: alice }); + let { bundle: bundleLnVar } = await controller.execute(lnVarInteraction, lnVarTransaction); + assert.isTrue(bundleLnVar.returnCode.equals(ReturnCode.Ok)); + assert.lengthOf(bundleLnVar.values, 1); + assert.deepEqual(bundleLnVar.values[0], new ManagedDecimalSignedValue("3.135553845", 9)); + }); + it("should interact with 'counter' (local testnet)", async function () { this.timeout(120000); diff --git a/src/smartcontracts/interaction.spec.ts b/src/smartcontracts/interaction.spec.ts index 4777691cd..e88789a90 100644 --- a/src/smartcontracts/interaction.spec.ts +++ b/src/smartcontracts/interaction.spec.ts @@ -1,4 +1,4 @@ -import { ContractQueryResponse } from "@multiversx/sdk-network-providers"; +import { ContractQueryResponse } from "../networkProviders"; import BigNumber from "bignumber.js"; import { assert } from "chai"; import { Address } from "../address"; diff --git a/src/smartcontracts/interactionChecker.ts b/src/smartcontracts/interactionChecker.ts index ac122c558..744525f56 100644 --- a/src/smartcontracts/interactionChecker.ts +++ b/src/smartcontracts/interactionChecker.ts @@ -10,6 +10,9 @@ import BigNumber from "bignumber.js"; * - errors related to calling "non-payable" functions with some value provided * - gas estimation errors (not yet implemented) */ +/** + * @deprecated The Interaction checker is deprecated due to lack of use. + */ export class InteractionChecker { checkInteraction(interaction: Interaction, definition: EndpointDefinition): void { this.checkPayable(interaction, definition); diff --git a/src/smartcontracts/nativeSerializer.spec.ts b/src/smartcontracts/nativeSerializer.spec.ts index 30879d6c2..060ee3a8d 100644 --- a/src/smartcontracts/nativeSerializer.spec.ts +++ b/src/smartcontracts/nativeSerializer.spec.ts @@ -16,6 +16,8 @@ import { EndpointModifiers, EndpointParameterDefinition, ListType, + ManagedDecimalType, + ManagedDecimalValue, NullType, OptionalType, OptionalValue, @@ -401,6 +403,47 @@ describe("test native serializer", () => { ]); }); + it("should accept managed decimals with constants and variable decimals", async () => { + const endpoint = AbiRegistry.create({ + endpoints: [ + { + name: "foo", + inputs: [ + { + type: "ManagedDecimal<8>", + }, + { + type: "ManagedDecimal", + }, + ], + outputs: [], + }, + ], + }).getEndpoint("foo"); + + // Pass only native values + let typedValues = NativeSerializer.nativeToTypedValues( + [ + [2, 8], + [12.5644, 6], + ], + endpoint, + ); + + assert.deepEqual(typedValues[0].getType(), new ManagedDecimalType(8)); + assert.deepEqual(typedValues[0].valueOf(), new BigNumber(2)); + assert.deepEqual(typedValues[1].getType(), new ManagedDecimalType("usize")); + assert.deepEqual(typedValues[1].valueOf(), new BigNumber(12.5644)); + + // Pass a mix of native and typed values + typedValues = NativeSerializer.nativeToTypedValues([new ManagedDecimalValue(2, 8), [12.5644, 6]], endpoint); + + assert.deepEqual(typedValues[0].getType(), new ManagedDecimalType(8)); + assert.deepEqual(typedValues[0].valueOf(), new BigNumber(2)); + assert.deepEqual(typedValues[1].getType(), new ManagedDecimalType("usize")); + assert.deepEqual(typedValues[1].valueOf(), new BigNumber(12.5644)); + }); + it("should accept no value for variadic types", async () => { const endpoint = AbiRegistry.create({ endpoints: [ @@ -514,6 +557,19 @@ describe("test native serializer", () => { }, ], }, + OperationCompletionStatus: { + type: "explicit-enum", + variants: [ + { + docs: ["indicates that operation was completed"], + name: "completed", + }, + { + docs: ["indicates that operation was interrupted prematurely, due to low gas"], + name: "interrupted", + }, + ], + }, }, }); @@ -547,6 +603,46 @@ describe("test native serializer", () => { assert.deepEqual(typedValues[3].valueOf(), { name: "Else", fields: [new BigNumber(42), new BigNumber(43)] }); }); + it("should perform type inference (explicit-enums)", async () => { + const abiRegistry = AbiRegistry.create({ + endpoints: [ + { + name: "foo", + inputs: [ + { + type: "OperationCompletionStatus", + }, + ], + outputs: [], + }, + ], + types: { + OperationCompletionStatus: { + type: "explicit-enum", + variants: [ + { + docs: ["indicates that operation was completed"], + name: "completed", + }, + { + docs: ["indicates that operation was interrupted prematurely, due to low gas"], + name: "interrupted", + }, + ], + }, + }, + }); + + const endpoint = abiRegistry.getEndpoint("foo"); + const enumType = abiRegistry.getExplicitEnum("OperationCompletionStatus"); + const enumString = "completed"; + + const typedValues = NativeSerializer.nativeToTypedValues([enumString], endpoint); + + assert.deepEqual(typedValues[0].getType(), enumType); + assert.deepEqual(typedValues[0].valueOf(), { name: enumString }); + }); + it("should getArgumentsCardinality", async () => { const abi = AbiRegistry.create({ endpoints: [ diff --git a/src/smartcontracts/nativeSerializer.ts b/src/smartcontracts/nativeSerializer.ts index 9375a2a95..e1c10c610 100644 --- a/src/smartcontracts/nativeSerializer.ts +++ b/src/smartcontracts/nativeSerializer.ts @@ -22,6 +22,8 @@ import { EndpointParameterDefinition, EnumType, EnumValue, + ExplicitEnumType, + ExplicitEnumValue, Field, I16Type, I16Value, @@ -34,6 +36,8 @@ import { isTyped, List, ListType, + ManagedDecimalType, + ManagedDecimalValue, NumericalType, OptionalType, OptionalValue, @@ -99,7 +103,6 @@ export namespace NativeSerializer { // With respect to the notes of "repackNonCountedVariadicParameters", "getArgumentsCardinality" will not be needed anymore. // Currently, it is used only for a arguments count check, which will become redundant. const { min, max } = getArgumentsCardinality(endpoint.input); - if (!(min <= args.length && args.length <= max)) { throw new ErrInvalidArgument( `Wrong number of arguments for endpoint ${endpoint.name}: expected between ${min} and ${max} arguments, have ${args.length}`, @@ -202,6 +205,12 @@ export namespace NativeSerializer { if (type instanceof EnumType) { return toEnumValue(value, type, errorContext); } + if (type instanceof ExplicitEnumType) { + return toExplicitEnumValue(value, type, errorContext); + } + if (type instanceof ManagedDecimalType) { + return toManagedDecimal(value, type, errorContext); + } errorContext.throwError(`convertToTypedValue: unhandled type ${type}`); } @@ -333,6 +342,26 @@ export namespace NativeSerializer { errorContext.throwError(`(function: toEnumValue) unsupported native type ${typeof native}`); } + function toExplicitEnumValue(native: any, type: ExplicitEnumType, errorContext: ArgumentErrorContext): TypedValue { + if (typeof native === "string") { + return ExplicitEnumValue.fromName(type, native); + } + if (typeof native === "object") { + errorContext.guardHasField(native, "name"); + const variant = type.getVariantByName(native.name); + + return new ExplicitEnumValue(type, variant); + } + errorContext.throwError(`(function: toExplicitEnumValue) unsupported native type ${typeof native}`); + } + + function toManagedDecimal(native: any, type: ManagedDecimalType, errorContext: ArgumentErrorContext): TypedValue { + if (typeof native === "object") { + return new ManagedDecimalValue(native[0], native[1], type.isVariable()); + } + errorContext.throwError(`(function: toManagedDecimal) unsupported native type ${typeof native}`); + } + // TODO: move logic to typesystem/bytes.ts function convertNativeToBytesValue(native: NativeTypes.NativeBytes, errorContext: ArgumentErrorContext) { const innerValue = native.valueOf(); diff --git a/src/smartcontracts/resultsParser.spec.ts b/src/smartcontracts/resultsParser.spec.ts index 30757b908..c21234d1c 100644 --- a/src/smartcontracts/resultsParser.spec.ts +++ b/src/smartcontracts/resultsParser.spec.ts @@ -1,21 +1,17 @@ +import BigNumber from "bignumber.js"; +import { assert } from "chai"; +import { Address } from "../address"; +import { IAddress } from "../interface"; import { ContractQueryResponse, ContractResultItem, ContractResults, - TransactionEvent, + TransactionEventData, + TransactionEventOnNetwork, TransactionEventTopic, - TransactionLogs, + TransactionLogsOnNetwork, TransactionOnNetwork, -} from "@multiversx/sdk-network-providers"; -import { TransactionEventData } from "@multiversx/sdk-network-providers/out/transactionEvents"; -import BigNumber from "bignumber.js"; -import { assert } from "chai"; -import * as fs from "fs"; -import path from "path"; -import { Address } from "../address"; -import { IAddress } from "../interface"; -import { ITransactionOnNetwork } from "../interfaceOfNetwork"; -import { LogLevel, Logger } from "../logger"; +} from "../networkProviders"; import { loadAbiRegistry } from "../testutils"; import { ArgSerializer } from "./argSerializer"; import { ResultsParser } from "./resultsParser"; @@ -220,10 +216,10 @@ describe("test smart contract results parser", () => { it("should parse contract outcome, on signal error", async () => { let transaction = new TransactionOnNetwork({ - logs: new TransactionLogs({ + logs: new TransactionLogsOnNetwork({ address: Address.empty(), events: [ - new TransactionEvent({ + new TransactionEventOnNetwork({ identifier: "signalError", topics: [new TransactionEventTopic(Buffer.from("something happened").toString("base64"))], data: `@${Buffer.from("user error").toString("hex")}@07`, @@ -240,10 +236,10 @@ describe("test smart contract results parser", () => { it("should parse contract outcome, on too much gas warning", async () => { let transaction = new TransactionOnNetwork({ - logs: new TransactionLogs({ + logs: new TransactionLogsOnNetwork({ address: Address.empty(), events: [ - new TransactionEvent({ + new TransactionEventOnNetwork({ identifier: "writeLog", topics: [ new TransactionEventTopic( @@ -258,10 +254,7 @@ describe("test smart contract results parser", () => { let bundle = parser.parseUntypedOutcome(transaction); assert.deepEqual(bundle.returnCode, ReturnCode.Ok); - assert.equal( - bundle.returnMessage, - "@too much gas provided for processing: gas provided = 596384500, gas used = 733010", - ); + assert.equal(bundle.returnMessage, "ok"); assert.deepEqual(bundle.values, []); }); @@ -269,7 +262,7 @@ describe("test smart contract results parser", () => { const abiRegistry = await loadAbiRegistry("src/testdata/esdt-safe.abi.json"); const eventDefinition = abiRegistry.getEvent("deposit"); - const event = new TransactionEvent({ + const event = new TransactionEventOnNetwork({ topics: [ new TransactionEventTopic("ZGVwb3NpdA=="), new TransactionEventTopic("cmzC1LRt1r10pMhNAnFb+FyudjGMq4G8CefCYdQUmmc="), @@ -383,47 +376,4 @@ describe("test smart contract results parser", () => { assert.deepEqual(bundle.b, new BigNumber(43)); assert.deepEqual(bundle.c, new BigNumber(44)); }); - - // This test should be enabled manually and run against a set of sample transactions. - // 2022-04-03: test ran against ~1800 transactions sampled from devnet. - it.skip("should parse real-world contract outcomes", async () => { - let oldLogLevel = Logger.logLevel; - Logger.setLevel(LogLevel.Trace); - - let folder = path.resolve(process.env["SAMPLES"] || "SAMPLES"); - let samples = loadRealWorldSamples(folder); - - for (const [transaction, _] of samples) { - console.log("Transaction:", transaction.hash.toString()); - - let bundle = parser.parseUntypedOutcome(transaction); - - console.log("Return code:", bundle.returnCode.toString()); - console.log("Return message:", bundle.returnMessage); - console.log("Num values:", bundle.values.length); - console.log("=".repeat(80)); - - assert.include(KnownReturnCodes, bundle.returnCode.valueOf()); - } - - Logger.setLevel(oldLogLevel); - }); - - function loadRealWorldSamples(folder: string): [ITransactionOnNetwork, string][] { - let transactionFiles = fs.readdirSync(folder); - let samples: [ITransactionOnNetwork, string][] = []; - - for (const file of transactionFiles) { - let txHash = path.basename(file, ".json"); - let filePath = path.resolve(folder, file); - let jsonContent: string = fs.readFileSync(filePath, { encoding: "utf8" }); - let json = JSON.parse(jsonContent); - let payload = json["data"]["transaction"]; - let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, payload); - - samples.push([transaction, jsonContent]); - } - - return samples; - } }); diff --git a/src/smartcontracts/resultsParser.ts b/src/smartcontracts/resultsParser.ts index 3b15bc5d3..4b4d71860 100644 --- a/src/smartcontracts/resultsParser.ts +++ b/src/smartcontracts/resultsParser.ts @@ -196,7 +196,7 @@ export class ResultsParser { throw new ErrCannotParseContractResults(`transaction ${transaction.hash.toString()}`); } - private parseTransactionMetadata(transaction: ITransactionOnNetwork): TransactionMetadata { + protected parseTransactionMetadata(transaction: ITransactionOnNetwork): TransactionMetadata { return new TransactionDecoder().getTransactionMetadata({ sender: transaction.sender.bech32(), receiver: transaction.receiver.bech32(), @@ -205,7 +205,7 @@ export class ResultsParser { }); } - private createBundleOnSimpleMoveBalance(transaction: ITransactionOnNetwork): UntypedOutcomeBundle | null { + protected createBundleOnSimpleMoveBalance(transaction: ITransactionOnNetwork): UntypedOutcomeBundle | null { let noResults = transaction.contractResults.items.length == 0; let noLogs = transaction.logs.events.length == 0; @@ -220,7 +220,7 @@ export class ResultsParser { return null; } - private createBundleOnInvalidTransaction(transaction: ITransactionOnNetwork): UntypedOutcomeBundle | null { + protected createBundleOnInvalidTransaction(transaction: ITransactionOnNetwork): UntypedOutcomeBundle | null { if (transaction.status.isInvalid()) { if (transaction.receipt.data) { return { @@ -236,7 +236,7 @@ export class ResultsParser { return null; } - private createBundleOnEasilyFoundResultWithReturnData(results: IContractResults): UntypedOutcomeBundle | null { + protected createBundleOnEasilyFoundResultWithReturnData(results: IContractResults): UntypedOutcomeBundle | null { let resultItemWithReturnData = results.items.find( (item) => item.nonce.valueOf() != 0 && item.data.startsWith("@"), ); @@ -254,7 +254,7 @@ export class ResultsParser { }; } - private createBundleOnSignalError(logs: ITransactionLogs): UntypedOutcomeBundle | null { + protected createBundleOnSignalError(logs: ITransactionLogs): UntypedOutcomeBundle | null { let eventSignalError = logs.findSingleOrNoneEvent(WellKnownEvents.OnSignalError); if (!eventSignalError) { return null; @@ -271,7 +271,7 @@ export class ResultsParser { }; } - private createBundleOnTooMuchGasWarning(logs: ITransactionLogs): UntypedOutcomeBundle | null { + protected createBundleOnTooMuchGasWarning(logs: ITransactionLogs): UntypedOutcomeBundle | null { let eventTooMuchGas = logs.findSingleOrNoneEvent( WellKnownEvents.OnWriteLog, (event) => @@ -284,17 +284,15 @@ export class ResultsParser { } let { returnCode, returnDataParts } = this.sliceDataFieldInParts(eventTooMuchGas.data); - let lastTopic = eventTooMuchGas.getLastTopic(); - let returnMessage = lastTopic?.toString() || returnCode.toString(); return { returnCode: returnCode, - returnMessage: returnMessage, + returnMessage: returnCode.toString(), values: returnDataParts, }; } - private createBundleOnWriteLogWhereFirstTopicEqualsAddress( + protected createBundleOnWriteLogWhereFirstTopicEqualsAddress( logs: ITransactionLogs, address: IAddress, ): UntypedOutcomeBundle | null { @@ -329,7 +327,7 @@ export class ResultsParser { return null; } - private createBundleWithFallbackHeuristics( + protected createBundleWithFallbackHeuristics( transaction: ITransactionOnNetwork, transactionMetadata: TransactionMetadata, ): UntypedOutcomeBundle | null { @@ -355,6 +353,25 @@ export class ResultsParser { } } + // Additional fallback heuristics (alter search constraints): + for (const resultItem of transaction.contractResults.items) { + let writeLogWithReturnData = resultItem.logs.findSingleOrNoneEvent(WellKnownEvents.OnWriteLog, (event) => { + const addressIsContract = event.address.bech32() == contractAddress.toBech32(); + return addressIsContract; + }); + + if (writeLogWithReturnData) { + const { returnCode, returnDataParts } = this.sliceDataFieldInParts(writeLogWithReturnData.data); + const returnMessage = returnCode.toString(); + + return { + returnCode: returnCode, + returnMessage: returnMessage, + values: returnDataParts, + }; + } + } + return null; } diff --git a/src/smartcontracts/smartContract.spec.ts b/src/smartcontracts/smartContract.spec.ts index 7fc958b29..bf5e2a132 100644 --- a/src/smartcontracts/smartContract.spec.ts +++ b/src/smartcontracts/smartContract.spec.ts @@ -1,4 +1,4 @@ -import { TransactionStatus } from "@multiversx/sdk-network-providers"; +import { TransactionStatus } from "../networkProviders"; import { assert } from "chai"; import { Address } from "../address"; import { diff --git a/src/smartcontracts/typesystem/abiRegistry.spec.ts b/src/smartcontracts/typesystem/abiRegistry.spec.ts index d3d966e8e..216cddba2 100644 --- a/src/smartcontracts/typesystem/abiRegistry.spec.ts +++ b/src/smartcontracts/typesystem/abiRegistry.spec.ts @@ -30,6 +30,12 @@ describe("test abi registry", () => { let getStatus = registry.getEndpoint("status"); let getLotteryInfo = registry.getEndpoint("getLotteryInfo"); + // basic-features + registry = await loadAbiRegistry("src/testdata/basic-features.abi.json"); + let returnManagedDecimal = registry.getEndpoint("returns_egld_decimal"); + let returnsManagedDecimalSigned = registry.getEndpoint("managed_decimal_ln"); + let returnsManagedDecimalVariable = registry.getEndpoint("managed_decimal_addition_var"); + assert.isFalse(start.modifiers.isReadonly()); assert.isTrue(getStatus.modifiers.isReadonly()); assert.isTrue(getLotteryInfo.modifiers.isReadonly()); @@ -54,6 +60,11 @@ describe("test abi registry", () => { assert.instanceOf(getLotteryInfo.input[0].type, BytesType); assert.instanceOf(getLotteryInfo.output[0].type, StructType); assert.equal(getLotteryInfo.output[0].type.getName(), "LotteryInfo"); + assert.equal(returnManagedDecimal.output[0].type.getName(), "ManagedDecimal"); + assert.equal(returnsManagedDecimalSigned.output[0].type.getName(), "ManagedDecimalSigned"); + assert.equal(returnsManagedDecimalSigned.output[0].type.getMetadata(), "9"); + assert.equal(returnsManagedDecimalVariable.output[0].type.getName(), "ManagedDecimal"); + assert.equal(returnsManagedDecimalVariable.output[0].type.getMetadata(), "usize"); let fieldDefinitions = (getLotteryInfo.output[0].type).getFieldsDefinitions(); assert.instanceOf(fieldDefinitions[0].type, TokenIdentifierType); @@ -182,14 +193,20 @@ describe("test abi registry", () => { }); it("should load ABI explicit-enum", async () => { - const registry = await loadAbiRegistry("src/testdata/explicit-enum.abi.json"); + const registry = await loadAbiRegistry("src/testdata/basic-features.abi.json"); - const enumType = registry.getEnum("OperationCompletionStatus"); + const enumType = registry.getExplicitEnum("OperationCompletionStatus"); assert.deepEqual(enumType.variants[0].name, "completed"); - assert.deepEqual(enumType.variants[0].discriminant, 0); assert.deepEqual(enumType.variants[1].name, "interrupted"); - assert.deepEqual(enumType.variants[1].discriminant, 1); + }); + + it("should load abi with title for endpoint", async () => { + const registry = await loadAbiRegistry("src/testdata/lottery-esdt.abi.json"); + + const endpoint = registry.getEndpoint("createLotteryPool"); + + assert.equal(endpoint.title, "Create lottery pool"); }); }); diff --git a/src/smartcontracts/typesystem/abiRegistry.ts b/src/smartcontracts/typesystem/abiRegistry.ts index 25162de22..60a6c46ff 100644 --- a/src/smartcontracts/typesystem/abiRegistry.ts +++ b/src/smartcontracts/typesystem/abiRegistry.ts @@ -3,6 +3,7 @@ import { guardValueIsSetWithMessage } from "../../utils"; import { EndpointDefinition, EndpointParameterDefinition } from "./endpoint"; import { EnumType } from "./enum"; import { EventDefinition, EventTopicDefinition } from "./event"; +import { ExplicitEnumType } from "./explicit-enum"; import { StructType } from "./struct"; import { TypeMapper } from "./typeMapper"; import { CustomType } from "./types"; @@ -63,8 +64,12 @@ export class AbiRegistry { if (typeDefinition.type == "struct") { customTypes.push(StructType.fromJSON({ name: customTypeName, fields: typeDefinition.fields })); - } else if (typeDefinition.type == "enum" || typeDefinition.type == "explicit-enum") { + } else if (typeDefinition.type == "enum") { customTypes.push(EnumType.fromJSON({ name: customTypeName, variants: typeDefinition.variants })); + } else if (typeDefinition.type == "explicit-enum") { + customTypes.push( + ExplicitEnumType.fromJSON({ name: customTypeName, variants: typeDefinition.variants }), + ); } else { throw new errors.ErrTypingSystem(`Cannot handle custom type: ${customTypeName}`); } @@ -107,6 +112,12 @@ export class AbiRegistry { return result!; } + getExplicitEnum(name: string): ExplicitEnumType { + const result = this.customTypes.find((e) => e.getName() == name && e.hasExactClass(ExplicitEnumType.ClassName)); + guardValueIsSetWithMessage(`enum [${name}] not found`, result); + return result!; + } + getEnums(names: string[]): EnumType[] { return names.map((name) => this.getEnum(name)); } @@ -214,7 +225,7 @@ function mapEndpoint(endpoint: EndpointDefinition, mapper: TypeMapper): Endpoint (e) => new EndpointParameterDefinition(e.name, e.description, mapper.mapType(e.type)), ); - return new EndpointDefinition(endpoint.name, newInput, newOutput, endpoint.modifiers); + return new EndpointDefinition(endpoint.name, newInput, newOutput, endpoint.modifiers, endpoint.title); } function mapEvent(event: EventDefinition, mapper: TypeMapper): EventDefinition { diff --git a/src/smartcontracts/typesystem/address.ts b/src/smartcontracts/typesystem/address.ts index 53391e952..ef8db6d02 100644 --- a/src/smartcontracts/typesystem/address.ts +++ b/src/smartcontracts/typesystem/address.ts @@ -23,7 +23,7 @@ export class AddressValue extends PrimitiveValue { constructor(value: IAddress) { super(new AddressType()); - this.value = new Address(value.bech32()); + this.value = Address.newFromBech32(value.bech32()); } getClassName(): string { diff --git a/src/smartcontracts/typesystem/endpoint.ts b/src/smartcontracts/typesystem/endpoint.ts index 9868b72dd..90f5de39c 100644 --- a/src/smartcontracts/typesystem/endpoint.ts +++ b/src/smartcontracts/typesystem/endpoint.ts @@ -6,6 +6,7 @@ const DescriptionPlaceholder = "N / A"; export class EndpointDefinition { readonly name: string; + readonly title: string; readonly input: EndpointParameterDefinition[] = []; readonly output: EndpointParameterDefinition[] = []; readonly modifiers: EndpointModifiers; @@ -15,8 +16,10 @@ export class EndpointDefinition { input: EndpointParameterDefinition[], output: EndpointParameterDefinition[], modifiers: EndpointModifiers, + title?: string, ) { this.name = name; + this.title = title || ""; this.input = input || []; this.output = output || []; this.modifiers = modifiers; @@ -28,6 +31,7 @@ export class EndpointDefinition { static fromJSON(json: { name: string; + title?: string; onlyOwner?: boolean; mutability: string; payableInTokens: string[]; @@ -36,6 +40,7 @@ export class EndpointDefinition { }): EndpointDefinition { json.name = json.name == null ? NamePlaceholder : json.name; json.onlyOwner = json.onlyOwner || false; + json.title = json.title || ""; json.payableInTokens = json.payableInTokens || []; json.inputs = json.inputs || []; json.outputs = json.outputs || []; @@ -44,7 +49,7 @@ export class EndpointDefinition { let output = json.outputs.map((param) => EndpointParameterDefinition.fromJSON(param)); let modifiers = new EndpointModifiers(json.mutability, json.payableInTokens, json.onlyOwner); - return new EndpointDefinition(json.name, input, output, modifiers); + return new EndpointDefinition(json.name, input, output, modifiers, json.title); } } diff --git a/src/smartcontracts/typesystem/explicit-enum.spec.ts b/src/smartcontracts/typesystem/explicit-enum.spec.ts new file mode 100644 index 000000000..8c726aecc --- /dev/null +++ b/src/smartcontracts/typesystem/explicit-enum.spec.ts @@ -0,0 +1,22 @@ +import { assert } from "chai"; +import { ExplicitEnumType, ExplicitEnumValue, ExplicitEnumVariantDefinition } from "./explicit-enum"; + +describe("test explicit-enums", () => { + it("should get valueOf()", () => { + // Define variants + let greenVariant = new ExplicitEnumVariantDefinition("Green"); + + let orangeVariant = new ExplicitEnumVariantDefinition("Orange"); + + let yellowVariant = new ExplicitEnumVariantDefinition("Yellow"); + + // Define enum type + let explicitEnumType = new ExplicitEnumType("Colour", [greenVariant, orangeVariant, yellowVariant]); + + // Create enum values + let green = new ExplicitEnumValue(explicitEnumType, greenVariant); + + // Test valueOf() + assert.deepEqual(green.valueOf(), { name: "Green" }); + }); +}); diff --git a/src/smartcontracts/typesystem/explicit-enum.ts b/src/smartcontracts/typesystem/explicit-enum.ts new file mode 100644 index 000000000..264e18fa1 --- /dev/null +++ b/src/smartcontracts/typesystem/explicit-enum.ts @@ -0,0 +1,74 @@ +import { guardValueIsSet } from "../../utils"; +import { CustomType, TypedValue } from "./types"; + +export class ExplicitEnumType extends CustomType { + static ClassName = "ExplicitEnumType"; + readonly variants: ExplicitEnumVariantDefinition[] = []; + + constructor(name: string, variants: ExplicitEnumVariantDefinition[]) { + super(name); + this.variants = variants; + } + + getClassName(): string { + return ExplicitEnumType.ClassName; + } + + static fromJSON(json: { name: string; variants: any[] }): ExplicitEnumType { + const variants = json.variants.map((variant) => ExplicitEnumVariantDefinition.fromJSON(variant)); + return new ExplicitEnumType(json.name, variants); + } + + getVariantByName(name: string): ExplicitEnumVariantDefinition { + let result = this.variants.find((e) => e.name == name); + guardValueIsSet(`variant by name (${name})`, result); + return result!; + } +} + +export class ExplicitEnumVariantDefinition { + readonly name: string; + + constructor(name: string) { + this.name = name; + } + + static fromJSON(json: { name: string }): ExplicitEnumVariantDefinition { + return new ExplicitEnumVariantDefinition(json.name); + } +} + +export class ExplicitEnumValue extends TypedValue { + static ClassName = "ExplicitEnumValue"; + readonly name: string; + + constructor(type: ExplicitEnumType, variant: ExplicitEnumVariantDefinition) { + super(type); + this.name = variant.name; + } + + getClassName(): string { + return ExplicitEnumValue.ClassName; + } + + /** + * Utility (named constructor) to create a simple (i.e. without fields) enum value. + */ + static fromName(type: ExplicitEnumType, name: string): ExplicitEnumValue { + let variant = type.getVariantByName(name); + + return new ExplicitEnumValue(type, variant); + } + + equals(other: ExplicitEnumValue): boolean { + if (!this.getType().equals(other.getType())) { + return false; + } + + return this.name == other.name; + } + + valueOf() { + return { name: this.name }; + } +} diff --git a/src/smartcontracts/typesystem/index.ts b/src/smartcontracts/typesystem/index.ts index f7bc39d45..936c40328 100644 --- a/src/smartcontracts/typesystem/index.ts +++ b/src/smartcontracts/typesystem/index.ts @@ -8,14 +8,18 @@ export * from "./address"; export * from "./algebraic"; export * from "./boolean"; export * from "./bytes"; +export * from "./codeMetadata"; export * from "./composite"; export * from "./endpoint"; export * from "./enum"; +export * from "./explicit-enum"; export * from "./factory"; export * from "./fields"; export * from "./generic"; export * from "./genericArray"; export * from "./h256"; +export * from "./managedDecimal"; +export * from "./managedDecimalSigned"; export * from "./matchers"; export * from "./nothing"; export * from "./numerical"; diff --git a/src/smartcontracts/typesystem/managedDecimal.spec.ts b/src/smartcontracts/typesystem/managedDecimal.spec.ts new file mode 100644 index 000000000..2257d5f5d --- /dev/null +++ b/src/smartcontracts/typesystem/managedDecimal.spec.ts @@ -0,0 +1,55 @@ +import { assert } from "chai"; +import { ManagedDecimalType, ManagedDecimalValue } from "./managedDecimal"; + +describe("test managed decimal", () => { + it("should get correct metadata set", () => { + const type = new ManagedDecimalType(8); + const expectedMetadata = 8; + + assert.equal(type.getMetadata(), expectedMetadata); + assert.isFalse(type.isVariable()); + }); + + it("should get correct metadata set when variable", () => { + let type = new ManagedDecimalType("usize"); + const expectedMetadata = "usize"; + + assert.equal(type.getMetadata(), expectedMetadata); + assert.isTrue(type.isVariable()); + }); + + it("should return the expected values for scale and metadata", () => { + const firstValue = new ManagedDecimalValue("1", 2, false); + const secondValue = new ManagedDecimalValue("2", 2, false); + const expectedMetadata = 2; + const type = firstValue.getType(); + + assert.equal(type.getMetadata(), expectedMetadata); + assert.isFalse(firstValue.isVariable()); + assert.equal(firstValue.getScale(), 2); + assert.equal(firstValue.toString(), "1.00"); + assert.isFalse(firstValue.equals(secondValue)); + }); + + it("should compare correctly two managed decimals even with different scale", () => { + const firstValue = new ManagedDecimalValue("1.234", 3, false); + const secondValue = new ManagedDecimalValue("12.34", 2, false); + + assert.isFalse(firstValue.equals(secondValue)); + }); + + it("should compare correctly two managed decimals even with different scale", () => { + const firstValue = new ManagedDecimalValue("1.234", 3, false); + const secondValue = new ManagedDecimalValue("1.234", 3, false); + + assert.isTrue(firstValue.equals(secondValue)); + }); + + it("should set the correct scale when variable decimals", () => { + const value = new ManagedDecimalValue("1.3", 2, true); + + assert.isTrue(value.isVariable()); + assert.equal(value.toString(), "1.30"); + assert.equal(value.getScale(), 2); + }); +}); diff --git a/src/smartcontracts/typesystem/managedDecimal.ts b/src/smartcontracts/typesystem/managedDecimal.ts new file mode 100644 index 000000000..b65b26a49 --- /dev/null +++ b/src/smartcontracts/typesystem/managedDecimal.ts @@ -0,0 +1,71 @@ +import BigNumber from "bignumber.js"; +import { Type, TypedValue } from "./types"; + +export class ManagedDecimalType extends Type { + static ClassName = "ManagedDecimalType"; + + constructor(metadata: number | "usize") { + super("ManagedDecimal", undefined, undefined, metadata); + } + + getClassName(): string { + return ManagedDecimalType.ClassName; + } + + getMetadata(): number | "usize" { + return this.metadata; + } + + isVariable(): boolean { + return this.metadata == "usize"; + } +} + +export class ManagedDecimalValue extends TypedValue { + static ClassName = "ManagedDecimalValue"; + private readonly value: BigNumber; + private readonly scale: number; + private readonly variable: boolean; + + constructor(value: BigNumber.Value, scale: number, isVariable: boolean = false) { + super(new ManagedDecimalType(isVariable ? "usize" : scale)); + this.value = new BigNumber(value); + this.scale = scale; + this.variable = isVariable; + } + + getClassName(): string { + return ManagedDecimalValue.ClassName; + } + + getScale(): number { + return this.scale; + } + + getPrecision(): number { + return this.value.toFixed(this.scale).replace(".", "").length; + } + + /** + * Returns whether two objects have the same value. + */ + equals(other: ManagedDecimalValue): boolean { + if (this.getPrecision() != other.getPrecision()) { + return false; + } + + return new BigNumber(this.value).eq(other.value); + } + + valueOf(): BigNumber { + return this.value; + } + + toString(): string { + return this.value.toFixed(this.scale); + } + + isVariable(): boolean { + return this.variable; + } +} diff --git a/src/smartcontracts/typesystem/managedDecimalSigned.ts b/src/smartcontracts/typesystem/managedDecimalSigned.ts new file mode 100644 index 000000000..032626f01 --- /dev/null +++ b/src/smartcontracts/typesystem/managedDecimalSigned.ts @@ -0,0 +1,71 @@ +import BigNumber from "bignumber.js"; +import { Type, TypedValue } from "./types"; + +export class ManagedDecimalSignedType extends Type { + static ClassName = "ManagedDecimalSignedType"; + + constructor(metadata: number | "usize") { + super("ManagedDecimalSigned", undefined, undefined, metadata); + } + + getClassName(): string { + return ManagedDecimalSignedType.ClassName; + } + + getMetadata(): number | "usize" { + return this.metadata; + } + + isVariable(): boolean { + return this.metadata == "usize"; + } +} + +export class ManagedDecimalSignedValue extends TypedValue { + static ClassName = "ManagedDecimalSignedValue"; + private readonly value: BigNumber; + private readonly scale: number; + private readonly variable: boolean; + + constructor(value: BigNumber.Value, scale: number, isVariable: boolean = false) { + super(new ManagedDecimalSignedType(isVariable ? "usize" : scale)); + this.value = new BigNumber(value); + this.scale = scale; + this.variable = isVariable; + } + + getClassName(): string { + return ManagedDecimalSignedValue.ClassName; + } + + getPrecision(): number { + return this.value.toFixed(this.scale).replace(".", "").length; + } + + getScale(): number { + return this.scale; + } + + /** + * Returns whether two objects have the same value. + */ + equals(other: ManagedDecimalSignedValue): boolean { + if (this.getPrecision() != other.getPrecision()) { + return false; + } + + return new BigNumber(this.value).eq(other.value); + } + + valueOf(): BigNumber { + return this.value; + } + + toString(): string { + return this.value.toFixed(this.scale); + } + + isVariable(): boolean { + return this.variable; + } +} diff --git a/src/smartcontracts/typesystem/matchers.ts b/src/smartcontracts/typesystem/matchers.ts index 43957d535..a877a9660 100644 --- a/src/smartcontracts/typesystem/matchers.ts +++ b/src/smartcontracts/typesystem/matchers.ts @@ -2,18 +2,21 @@ import * as errors from "../../errors"; import { AddressType, AddressValue } from "./address"; import { BooleanType, BooleanValue } from "./boolean"; import { BytesType, BytesValue } from "./bytes"; +import { CodeMetadataType, CodeMetadataValue } from "./codeMetadata"; import { EnumType, EnumValue } from "./enum"; -import { OptionType, OptionValue, List, ListType } from "./generic"; +import { ExplicitEnumType, ExplicitEnumValue } from "./explicit-enum"; +import { List, ListType, OptionType, OptionValue } from "./generic"; +import { ArrayVec, ArrayVecType } from "./genericArray"; import { H256Type, H256Value } from "./h256"; -import { NumericalType, NumericalValue } from "./numerical"; +import { ManagedDecimalType, ManagedDecimalValue } from "./managedDecimal"; +import { ManagedDecimalSignedType, ManagedDecimalSignedValue } from "./managedDecimalSigned"; import { NothingType, NothingValue } from "./nothing"; +import { NumericalType, NumericalValue } from "./numerical"; +import { StringType, StringValue } from "./string"; import { Struct, StructType } from "./struct"; import { TokenIdentifierType, TokenIdentifierValue } from "./tokenIdentifier"; import { Tuple, TupleType } from "./tuple"; -import { Type, PrimitiveType, PrimitiveValue } from "./types"; -import { ArrayVec, ArrayVecType } from "./genericArray"; -import { TypedValue } from "./types"; -import { StringType, StringValue } from "./string"; +import { PrimitiveType, PrimitiveValue, Type, TypedValue } from "./types"; // TODO: Extend functionality or rename wrt. restricted / reduced functionality (not all types are handled: composite, variadic). export function onTypeSelect( @@ -26,6 +29,9 @@ export function onTypeSelect( onStruct: () => TResult; onTuple: () => TResult; onEnum: () => TResult; + onExplicitEnum: () => TResult; + onManagedDecimal: () => TResult; + onManagedDecimalSigned: () => TResult; onOther?: () => TResult; }, ): TResult { @@ -50,6 +56,17 @@ export function onTypeSelect( if (type.hasExactClass(EnumType.ClassName)) { return selectors.onEnum(); } + if (type.hasExactClass(ExplicitEnumType.ClassName)) { + return selectors.onExplicitEnum(); + } + + if (type.hasExactClass(ManagedDecimalType.ClassName)) { + return selectors.onManagedDecimal(); + } + + if (type.hasExactClass(ManagedDecimalSignedType.ClassName)) { + return selectors.onManagedDecimalSigned(); + } if (selectors.onOther) { return selectors.onOther(); @@ -68,6 +85,9 @@ export function onTypedValueSelect( onStruct: () => TResult; onTuple: () => TResult; onEnum: () => TResult; + onExplicitEnum: () => TResult; + onManagedDecimal: () => TResult; + onManagedDecimalSigned: () => TResult; onOther?: () => TResult; }, ): TResult { @@ -92,6 +112,15 @@ export function onTypedValueSelect( if (value.hasExactClass(EnumValue.ClassName)) { return selectors.onEnum(); } + if (value.hasExactClass(ExplicitEnumValue.ClassName)) { + return selectors.onExplicitEnum(); + } + if (value.hasExactClass(ManagedDecimalValue.ClassName)) { + return selectors.onManagedDecimal(); + } + if (value.hasExactClass(ManagedDecimalSignedValue.ClassName)) { + return selectors.onManagedDecimalSigned(); + } if (selectors.onOther) { return selectors.onOther(); @@ -110,6 +139,7 @@ export function onPrimitiveValueSelect( onString: () => TResult; onH256: () => TResult; onTypeIdentifier: () => TResult; + onCodeMetadata: () => TResult; onNothing: () => TResult; onOther?: () => TResult; }, @@ -135,9 +165,13 @@ export function onPrimitiveValueSelect( if (value.hasExactClass(TokenIdentifierValue.ClassName)) { return selectors.onTypeIdentifier(); } + if (value.hasExactClass(CodeMetadataValue.ClassName)) { + return selectors.onCodeMetadata(); + } if (value.hasExactClass(NothingValue.ClassName)) { return selectors.onNothing(); } + if (selectors.onOther) { return selectors.onOther(); } @@ -155,6 +189,7 @@ export function onPrimitiveTypeSelect( onString: () => TResult; onH256: () => TResult; onTokenIndetifier: () => TResult; + onCodeMetadata: () => TResult; onNothing: () => TResult; onOther?: () => TResult; }, @@ -180,6 +215,9 @@ export function onPrimitiveTypeSelect( if (type.hasExactClass(TokenIdentifierType.ClassName)) { return selectors.onTokenIndetifier(); } + if (type.hasExactClass(CodeMetadataType.ClassName)) { + return selectors.onCodeMetadata(); + } if (type.hasExactClass(NothingType.ClassName)) { return selectors.onNothing(); } diff --git a/src/smartcontracts/typesystem/typeExpressionParser.ts b/src/smartcontracts/typesystem/typeExpressionParser.ts index 62d2216c5..0c61d502f 100644 --- a/src/smartcontracts/typesystem/typeExpressionParser.ts +++ b/src/smartcontracts/typesystem/typeExpressionParser.ts @@ -26,6 +26,6 @@ export class TypeExpressionParser { private typeFormulaToType(typeFormula: TypeFormula): Type { const typeParameters = typeFormula.typeParameters.map((typeFormula) => this.typeFormulaToType(typeFormula)); - return new Type(typeFormula.name, typeParameters); + return new Type(typeFormula.name, typeParameters, undefined, typeFormula.metadata); } } diff --git a/src/smartcontracts/typesystem/typeMapper.ts b/src/smartcontracts/typesystem/typeMapper.ts index edc40769f..8eebdf5f8 100644 --- a/src/smartcontracts/typesystem/typeMapper.ts +++ b/src/smartcontracts/typesystem/typeMapper.ts @@ -6,10 +6,13 @@ import { BytesType } from "./bytes"; import { CodeMetadataType } from "./codeMetadata"; import { CompositeType } from "./composite"; import { EnumType, EnumVariantDefinition } from "./enum"; +import { ExplicitEnumType, ExplicitEnumVariantDefinition } from "./explicit-enum"; import { FieldDefinition } from "./fields"; import { ListType, OptionType } from "./generic"; import { ArrayVecType } from "./genericArray"; import { H256Type } from "./h256"; +import { ManagedDecimalType } from "./managedDecimal"; +import { ManagedDecimalSignedType } from "./managedDecimalSigned"; import { NothingType } from "./nothing"; import { BigIntType, @@ -31,14 +34,15 @@ import { CustomType, Type } from "./types"; import { VariadicType } from "./variadic"; type TypeFactory = (...typeParameters: Type[]) => Type; +type TypeWithMetadataFactory = (...metadata: any) => Type; export class TypeMapper { - private readonly openTypesFactories: Map; + private readonly openTypesFactories: Map; private readonly closedTypesMap: Map; private readonly learnedTypesMap: Map; constructor(learnedTypes: CustomType[] = []) { - this.openTypesFactories = new Map([ + this.openTypesFactories = new Map([ ["Option", (...typeParameters: Type[]) => new OptionType(typeParameters[0])], ["List", (...typeParameters: Type[]) => new ListType(typeParameters[0])], // For the following open generics, we use a slightly different typing than the one defined by mx-sdk-rs (temporary workaround). @@ -74,6 +78,8 @@ export class TypeMapper { ["array64", (...typeParameters: Type[]) => new ArrayVecType(64, typeParameters[0])], ["array128", (...typeParameters: Type[]) => new ArrayVecType(128, typeParameters[0])], ["array256", (...typeParameters: Type[]) => new ArrayVecType(256, typeParameters[0])], + ["ManagedDecimal", (...metadata: any) => new ManagedDecimalType(metadata)], + ["ManagedDecimalSigned", (...metadata: any) => new ManagedDecimalSignedType(metadata)], ]); // For closed types, we hold actual type instances instead of type constructors / factories (no type parameters needed). @@ -106,7 +112,11 @@ export class TypeMapper { // Boostrap from previously learned types, if any. for (const type of learnedTypes) { - this.learnedTypesMap.set(type.getName(), type); + if (type.getName() === "ManagedDecimal" || type.getName() === "ManagedDecimalSigned") { + this.learnedTypesMap.set(`${type.getName()}_${type.getMetadata()}`, type); + } else { + this.learnedTypesMap.set(type.getName(), type); + } } } @@ -134,6 +144,7 @@ export class TypeMapper { private mapTypeRecursively(type: Type): Type | null { let isGeneric = type.isGenericType(); + let hasMetadata = type.hasMetadata(); let previouslyLearnedType = this.learnedTypesMap.get(type.getName()); if (previouslyLearnedType) { @@ -150,12 +161,17 @@ export class TypeMapper { return this.mapEnumType(type); } + if (type.hasExactClass(ExplicitEnumType.ClassName)) { + // This will call mapType() recursively, for all the explicit enum variant fields. + return this.mapExplicitEnumType(type); + } + if (type.hasExactClass(StructType.ClassName)) { // This will call mapType() recursively, for all the struct's fields. return this.mapStructType(type); } - if (isGeneric) { + if (isGeneric || hasMetadata) { // This will call mapType() recursively, for all the type parameters. return this.mapGenericType(type); } @@ -164,8 +180,15 @@ export class TypeMapper { } private learnType(type: Type): void { - this.learnedTypesMap.delete(type.getName()); - this.learnedTypesMap.set(type.getName(), type); + if (type.getName() === "ManagedDecimal" || type.getName() === "ManagedDecimalSigned") { + const learnedTypeKey = `${type.getName()}_${type.getMetadata()}`; + this.learnedTypesMap.delete(learnedTypeKey); + this.learnedTypesMap.set(learnedTypeKey, type); + } else { + const learnedTypeKey = type.getName(); + this.learnedTypesMap.delete(learnedTypeKey); + this.learnedTypesMap.set(learnedTypeKey, type); + } } private mapStructType(type: StructType): StructType { @@ -187,6 +210,12 @@ export class TypeMapper { return mappedEnum; } + private mapExplicitEnumType(type: ExplicitEnumType): ExplicitEnumType { + let variants = type.variants.map((variant) => new ExplicitEnumVariantDefinition(variant.name)); + let mappedEnum = new ExplicitEnumType(type.getName(), variants); + return mappedEnum; + } + private mappedFields(definitions: FieldDefinition[]): FieldDefinition[] { return definitions.map( (definition) => new FieldDefinition(definition.name, definition.description, this.mapType(definition.type)), @@ -201,6 +230,9 @@ export class TypeMapper { if (!factory) { throw new errors.ErrTypingSystem(`Cannot map the generic type "${type.getName()}" to a known type`); } + if (type.hasMetadata()) { + return factory(type.getMetadata()); + } return factory(...mappedTypeParameters); } diff --git a/src/smartcontracts/typesystem/types.spec.ts b/src/smartcontracts/typesystem/types.spec.ts index 0639b9615..eb77985aa 100644 --- a/src/smartcontracts/typesystem/types.spec.ts +++ b/src/smartcontracts/typesystem/types.spec.ts @@ -9,6 +9,8 @@ import { I64Type, NumericalValue, U16Type, U32Type, U32Value } from "./numerical import { StringType } from "./string"; import { TypeExpressionParser } from "./typeExpressionParser"; import { NullType, PrimitiveType, Type } from "./types"; +import { ManagedDecimalType } from "./managedDecimal"; +import { ManagedDecimalSignedType } from "./managedDecimalSigned"; describe("test types", () => { let parser = new TypeExpressionParser(); @@ -63,6 +65,16 @@ describe("test types", () => { parser.parse("Option").getFullyQualifiedName(), "multiversx:types:Option", ); + assert.equal(new ManagedDecimalType(8).getFullyQualifiedName(), "multiversx:types:ManagedDecimal*8*"); + assert.equal(new ManagedDecimalType("usize").getFullyQualifiedName(), "multiversx:types:ManagedDecimal*usize*"); + assert.equal( + new ManagedDecimalSignedType(8).getFullyQualifiedName(), + "multiversx:types:ManagedDecimalSigned*8*", + ); + assert.equal( + new ManagedDecimalSignedType("usize").getFullyQualifiedName(), + "multiversx:types:ManagedDecimalSigned*usize*", + ); }); it("types and values should have correct JavaScript class hierarchy", () => { diff --git a/src/smartcontracts/typesystem/types.ts b/src/smartcontracts/typesystem/types.ts index b3e68d5bb..792d66e4b 100644 --- a/src/smartcontracts/typesystem/types.ts +++ b/src/smartcontracts/typesystem/types.ts @@ -10,18 +10,20 @@ export class Type { private readonly name: string; private readonly typeParameters: Type[]; - protected readonly cardinality: TypeCardinality; + private readonly cardinality: TypeCardinality; + protected readonly metadata: any; public constructor( name: string, typeParameters: Type[] = [], cardinality: TypeCardinality = TypeCardinality.fixed(1), + metadata?: any, ) { guardValueIsSet("name", name); - this.name = name; this.typeParameters = typeParameters; this.cardinality = cardinality; + this.metadata = metadata; } getName(): string { @@ -42,15 +44,28 @@ export class Type { * Gets the fully qualified name of the type, to allow for better (efficient and non-ambiguous) type comparison within the custom typesystem. */ getFullyQualifiedName(): string { - let joinedTypeParameters = this.getTypeParameters() - .map((type) => type.getFullyQualifiedName()) - .join(", "); - - return this.isGenericType() - ? `multiversx:types:${this.getName()}<${joinedTypeParameters}>` + return this.isGenericType() || this.hasMetadata() + ? this.getFullNameForGeneric() : `multiversx:types:${this.getName()}`; } + private getFullNameForGeneric(): string { + const hasTypeParameters = this.getTypeParameters().length > 0; + const joinedTypeParameters = hasTypeParameters + ? `${this.getTypeParameters() + .map((type) => type.getFullyQualifiedName()) + .join(", ")}` + : ""; + let baseName = `multiversx:types:${this.getName()}`; + if (hasTypeParameters) { + baseName = `${baseName}<${joinedTypeParameters}>`; + } + if (this.metadata !== undefined) { + baseName = `${baseName}*${this.metadata}*`; + } + return baseName; + } + hasExactClass(className: string): boolean { return this.getClassName() == className; } @@ -64,10 +79,18 @@ export class Type { return this.typeParameters; } + getMetadata(): any { + return this.metadata; + } + isGenericType(): boolean { return this.typeParameters.length > 0; } + hasMetadata(): boolean { + return !!this.metadata; + } + getFirstTypeParameter(): Type { guardTrue(this.typeParameters.length > 0, "type parameters length > 0"); return this.typeParameters[0]; diff --git a/src/testdata/README.md b/src/testdata/README.md new file mode 100644 index 000000000..841b24e37 --- /dev/null +++ b/src/testdata/README.md @@ -0,0 +1,132 @@ +# Testdata + +## Files `transactions.mainnet.json` + +Transactions were sampled from the mainnet BigQuery dataset: + +```sql +DECLARE + TIMESTAMP_START DATE DEFAULT '2024-09-01'; +DECLARE + TIMESTAMP_END DATE DEFAULT '2024-09-03'; + -- Contract execute, with success + ( + SELECT + `_id` `hash`, + 'execute_success' `kind` + FROM + `multiversx-blockchain-etl.crypto_multiversx_mainnet_eu.transactions` + WHERE + DATE(`timestamp`) >= TIMESTAMP_START + AND DATE(`timestamp`) <= TIMESTAMP_END + AND `isScCall` = TRUE + AND ARRAY_LENGTH(`esdtValues`) = 0 + AND `status` = 'success' + AND RAND() < 0.25 + LIMIT + 250 ) +UNION ALL + -- Contract execute, with error + ( + SELECT + `_id` `hash`, + 'execute_error' `kind` + FROM + `multiversx-blockchain-etl.crypto_multiversx_mainnet_eu.transactions` + WHERE + DATE(`timestamp`) >= TIMESTAMP_START + AND DATE(`timestamp`) <= TIMESTAMP_END + AND `isScCall` = TRUE + AND ARRAY_LENGTH(`esdtValues`) = 0 + AND `status` = 'fail' + AND RAND() < 0.25 + LIMIT + 250 ) +UNION ALL + -- Contract transfer & execute, with success + ( + SELECT + `_id` `hash`, + 'transfer_execute_success' `kind` + FROM + `multiversx-blockchain-etl.crypto_multiversx_mainnet_eu.transactions` + WHERE + DATE(`timestamp`) >= TIMESTAMP_START + AND DATE(`timestamp`) <= TIMESTAMP_END + AND `isScCall` = TRUE + AND ARRAY_LENGTH(`esdtValues`) > 0 + AND `status` = 'success' + AND RAND() < 0.25 + LIMIT + 250 ) +UNION ALL + -- Contract transfer & execute, with error + ( + SELECT + `_id` `hash`, + 'transfer_execute_error' `kind` + FROM + `multiversx-blockchain-etl.crypto_multiversx_mainnet_eu.transactions` + WHERE + DATE(`timestamp`) >= TIMESTAMP_START + AND DATE(`timestamp`) <= TIMESTAMP_END + AND `isScCall` = TRUE + AND ARRAY_LENGTH(`esdtValues`) > 0 + AND `status` = 'fail' + AND RAND() < 0.25 + LIMIT + 250) +UNION ALL + -- Relayed, with success + ( + SELECT + `_id` `hash`, + 'relayed_success' `kind` + FROM + `multiversx-blockchain-etl.crypto_multiversx_mainnet_eu.transactions` + WHERE + DATE(`timestamp`) >= TIMESTAMP_START + AND DATE(`timestamp`) <= TIMESTAMP_END + AND `isRelayed` = TRUE + AND `status` = 'success' + AND RAND() < 0.25 + LIMIT + 50) +UNION ALL + -- Relayed, with failure + ( + SELECT + `_id` `hash`, + 'relayed_error' `kind` + FROM + `multiversx-blockchain-etl.crypto_multiversx_mainnet_eu.transactions` + WHERE + DATE(`timestamp`) >= TIMESTAMP_START + AND DATE(`timestamp`) <= TIMESTAMP_END + AND `isRelayed` = TRUE + AND `status` = 'fail' + AND RAND() < 0.25 + LIMIT + 50) +UNION ALL + -- MultiESDTNFTTransfer, with too much gas + ( + SELECT + `_id` `hash`, + 'multi_transfer_too_much_gas' `kind` + FROM + `multiversx-blockchain-etl.crypto_multiversx_mainnet_eu.transactions` + WHERE + DATE(`timestamp`) >= TIMESTAMP_START + AND DATE(`timestamp`) <= TIMESTAMP_END + AND `operation` = 'MultiESDTNFTTransfer' + AND `function` IS NULL + AND `isRelayed` IS NULL + AND `status` = 'success' + AND `gasLimit` = `gasUsed` + AND ARRAY_LENGTH(`tokens`) = 1 + AND `receiversShardIDs`[0] != `senderShard` + AND RAND() < 0.25 + LIMIT + 20) +``` diff --git a/src/testdata/adder.abi.json b/src/testdata/adder.abi.json index fd809ce91..a65dbff8f 100644 --- a/src/testdata/adder.abi.json +++ b/src/testdata/adder.abi.json @@ -52,7 +52,9 @@ ] }, { - "docs": ["Add desired amount to the storage variable."], + "docs": [ + "Add desired amount to the storage variable." + ], "name": "add", "mutability": "mutable", "inputs": [ diff --git a/src/testdata/basic-features.abi.json b/src/testdata/basic-features.abi.json new file mode 100644 index 000000000..733da10f4 --- /dev/null +++ b/src/testdata/basic-features.abi.json @@ -0,0 +1,6200 @@ +{ + "buildInfo": { + "rustc": { + "version": "1.80.0", + "commitHash": "051478957371ee0084a7c0913941d2a8c4757bb9", + "commitDate": "2024-07-21", + "channel": "Stable", + "short": "rustc 1.80.0 (051478957 2024-07-21)" + }, + "contractCrate": { + "name": "basic-features", + "version": "0.0.0", + "gitVersion": "v0.53.0-3-g49a82cb19" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.53.0" + } + }, + "name": "BasicFeatures", + "constructor": { + "inputs": [], + "outputs": [] + }, + "endpoints": [ + { + "name": "panicWithMessage", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "docs": [ + "Operation that has caused issues in the past" + ], + "name": "count_ones", + "mutability": "mutable", + "inputs": [ + { + "name": "arg", + "type": "u64" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "endpoint_with_mutable_arg", + "mutability": "mutable", + "inputs": [ + { + "name": "arg1", + "type": "BigUint" + }, + { + "name": "arg2", + "type": "u64" + }, + { + "name": "arg3", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "sqrt_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "sqrt_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "log2_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "log2_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "pow_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "pow_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "pow_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "pow_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "big_uint_to_u64", + "mutability": "mutable", + "inputs": [ + { + "name": "bu", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "biguint_overwrite_u64", + "mutability": "mutable", + "inputs": [ + { + "name": "bu", + "type": "BigUint" + }, + { + "name": "small", + "type": "u64" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "big_uint_zero", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "big_uint_from_u64_1", + "mutability": "mutable", + "inputs": [ + { + "name": "small", + "type": "u64" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "big_uint_from_u64_2", + "mutability": "mutable", + "inputs": [ + { + "name": "small", + "type": "u64" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "biguint_from_u128", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "big_uint_from_managed_buffer", + "mutability": "mutable", + "inputs": [ + { + "name": "mb", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "big_uint_from_managed_buffer_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "mb", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "big_int_zero", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "big_int_from_i64_1", + "mutability": "mutable", + "inputs": [ + { + "name": "small", + "type": "i64" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "big_int_from_i64_2", + "mutability": "mutable", + "inputs": [ + { + "name": "small", + "type": "i64" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "big_uint_eq_u64", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "BigUint" + }, + { + "name": "small", + "type": "u64" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "big_int_to_i64", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "bigint_overwrite_i64", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "BigInt" + }, + { + "name": "small", + "type": "i64" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_big_int_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_big_uint_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_big_int_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_big_uint_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "add_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "sub_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "sub_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "sub_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "sub_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "mul_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "mul_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "mul_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "mul_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "div_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "div_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "div_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "div_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "rem_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "rem_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "rem_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "rem_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "add_assign_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_assign_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "add_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "add_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "sub_assign_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "sub_assign_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "sub_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "sub_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "mul_assign_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "mul_assign_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "mul_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "mul_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "div_assign_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "div_assign_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "div_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "div_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "rem_assign_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "rem_assign_big_int_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigInt" + }, + { + "name": "b", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "rem_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "rem_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_and_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_and_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_or_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_or_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_xor_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_xor_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_and_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_and_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_or_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_or_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_xor_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "bit_xor_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shr_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shr_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shl_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shl_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shr_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shr_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shl_assign_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "shl_assign_big_uint_ref", + "mutability": "mutable", + "inputs": [ + { + "name": "a", + "type": "BigUint" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "get_block_timestamp", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_block_nonce", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_block_round", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_block_epoch", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_block_random_seed", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "array48" + } + ] + }, + { + "name": "get_prev_block_timestamp", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_prev_block_nonce", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_prev_block_round", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_prev_block_epoch", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_prev_block_random_seed", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "array48" + } + ] + }, + { + "name": "get_caller", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "Address" + } + ] + }, + { + "name": "get_owner_address", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "Address" + } + ] + }, + { + "name": "get_shard_of_address", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "is_smart_contract", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "get_state_root_hash", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "array32" + } + ] + }, + { + "name": "get_tx_hash", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "array32" + } + ] + }, + { + "name": "get_gas_left", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "get_cumulated_validator_rewards", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "get_code_metadata", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "CodeMetadata" + } + ] + }, + { + "name": "is_builtin_function", + "mutability": "mutable", + "inputs": [ + { + "name": "function_name", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "codec_err_finish", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "CodecErrorTestType" + } + ] + }, + { + "name": "codec_err_storage_key", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "i32" + } + ] + }, + { + "name": "codec_err_storage_get", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "CodecErrorTestType" + } + ] + }, + { + "name": "codec_err_storage_set", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "codec_err_event_topic", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "codec_err_event_data", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "docs": [ + "Never actually calls any deploy/upgrade, so it is appropriate in this contract.", + "It just covers contract init serialization errors." + ], + "name": "codec_err_contract_init", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "docs": [ + "Never actually calls any async/sync call, so it is appropriate in this contract.", + "It just covers contract call serialization errors." + ], + "name": "codec_err_contract_call", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "compute_sha256", + "mutability": "mutable", + "inputs": [ + { + "name": "input", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "array32" + } + ] + }, + { + "name": "compute_keccak256", + "mutability": "mutable", + "inputs": [ + { + "name": "input", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "array32" + } + ] + }, + { + "name": "compute_ripemd160", + "mutability": "mutable", + "inputs": [ + { + "name": "input", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "array20" + } + ] + }, + { + "name": "verify_bls_signature", + "mutability": "mutable", + "inputs": [ + { + "name": "key", + "type": "bytes" + }, + { + "name": "message", + "type": "bytes" + }, + { + "name": "signature", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "verify_ed25519_signature", + "mutability": "mutable", + "inputs": [ + { + "name": "key", + "type": "bytes" + }, + { + "name": "message", + "type": "bytes" + }, + { + "name": "signature", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "verify_secp256k1_signature", + "mutability": "mutable", + "inputs": [ + { + "name": "key", + "type": "bytes" + }, + { + "name": "message", + "type": "bytes" + }, + { + "name": "signature", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "compute_secp256k1_der_signature", + "mutability": "mutable", + "inputs": [ + { + "name": "r", + "type": "bytes" + }, + { + "name": "s", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "echo_u64", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "u64" + } + ], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "echo_i64", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "i64" + } + ], + "outputs": [ + { + "type": "i64" + } + ] + }, + { + "name": "echo_i32", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "i32" + } + ], + "outputs": [ + { + "type": "i32" + } + ] + }, + { + "name": "echo_u32", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "echo_isize", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "i32" + } + ], + "outputs": [ + { + "type": "i32" + } + ] + }, + { + "name": "echo_usize", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "echo_i8", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "i8" + } + ], + "outputs": [ + { + "type": "i8" + } + ] + }, + { + "name": "echo_u8", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "u8" + } + ], + "outputs": [ + { + "type": "u8" + } + ] + }, + { + "name": "echo_bool", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "bool" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "echo_opt_bool", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "Option" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "echo_multi_value_u32", + "mutability": "mutable", + "inputs": [ + { + "name": "m", + "type": "variadic", + "multi_arg": true + } + ], + "outputs": [ + { + "type": "u32" + }, + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "echo_multi_value_tuples", + "mutability": "mutable", + "inputs": [ + { + "name": "m", + "type": "variadic>", + "multi_arg": true + } + ], + "outputs": [ + { + "type": "variadic>", + "multi_result": true + } + ] + }, + { + "name": "echo_ser_example_2", + "mutability": "mutable", + "inputs": [ + { + "name": "se", + "type": "ExampleEnumWithFields" + } + ], + "outputs": [ + { + "type": "ExampleEnumWithFields" + } + ] + }, + { + "name": "echo_simple_enum", + "mutability": "readonly", + "inputs": [ + { + "name": "se", + "type": "ExampleEnumSimple" + } + ], + "outputs": [ + { + "type": "ExampleEnumSimple" + } + ] + }, + { + "name": "finish_simple_enum_variant_1", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "ExampleEnumSimple" + } + ] + }, + { + "name": "echo_arrayvec", + "mutability": "readonly", + "inputs": [ + { + "name": "av", + "type": "List" + } + ], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "echo_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "echo_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "BigInt" + } + ], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "echo_managed_buffer", + "mutability": "mutable", + "inputs": [ + { + "name": "mb", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "echo_managed_address", + "mutability": "mutable", + "inputs": [ + { + "name": "ma", + "type": "Address" + } + ], + "outputs": [ + { + "type": "Address" + } + ] + }, + { + "docs": [ + "This tests that nested serialization of big ints within unmanaged types works." + ], + "name": "echo_big_int_managed_vec", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "List" + } + ], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "docs": [ + "This tests that nested serialization of big ints within unmanaged types works." + ], + "name": "echo_big_int_tuple", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "tuple" + } + ], + "outputs": [ + { + "type": "tuple" + } + ] + }, + { + "docs": [ + "This tests that nested serialization of big ints within unmanaged types works." + ], + "name": "echo_big_int_option", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "Option" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "echo_tuple_into_multiresult", + "mutability": "mutable", + "inputs": [ + { + "name": "addr", + "type": "Address" + }, + { + "name": "vec", + "type": "List" + } + ], + "outputs": [ + { + "type": "Address" + }, + { + "type": "List" + } + ] + }, + { + "name": "echo_managed_vec_of_managed_vec", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List>" + } + ], + "outputs": [ + { + "type": "List>" + } + ] + }, + { + "name": "echo_managed_vec_of_token_identifier", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List" + } + ], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "echo_varags_managed_eager", + "mutability": "mutable", + "inputs": [ + { + "name": "m", + "type": "variadic", + "multi_arg": true + } + ], + "outputs": [ + { + "type": "u32" + }, + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "echo_varags_managed_sum", + "mutability": "mutable", + "inputs": [ + { + "name": "m", + "type": "variadic>", + "multi_arg": true + } + ], + "outputs": [ + { + "type": "variadic>", + "multi_result": true + } + ] + }, + { + "name": "compute_get_values", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + } + ], + "outputs": [ + { + "type": "tuple" + } + ] + }, + { + "name": "compute_create_ec", + "mutability": "mutable", + "inputs": [ + { + "name": "curve", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "tuple" + } + ] + }, + { + "name": "compute_get_ec_length", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "compute_get_priv_key_byte_length", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "compute_ec_add", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "x_first_point", + "type": "BigUint" + }, + { + "name": "y_first_point", + "type": "BigUint" + }, + { + "name": "x_second_point", + "type": "BigUint" + }, + { + "name": "y_second_point", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + }, + { + "type": "BigUint" + } + ] + }, + { + "name": "compute_ec_double", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "x_point", + "type": "BigUint" + }, + { + "name": "y_point", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "BigUint" + }, + { + "type": "BigUint" + } + ] + }, + { + "name": "compute_is_on_curve_ec", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "x_point", + "type": "BigUint" + }, + { + "name": "y_point", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "compute_scalar_mult", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "x_point", + "type": "BigUint" + }, + { + "name": "y_point", + "type": "BigUint" + }, + { + "name": "data", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "BigUint" + }, + { + "type": "BigUint" + } + ] + }, + { + "name": "compute_scalar_base_mult", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "data", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "BigUint" + }, + { + "type": "BigUint" + } + ] + }, + { + "name": "compute_marshal_ec", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "x_pair", + "type": "BigUint" + }, + { + "name": "y_pair", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "compute_marshal_compressed_ec", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "x_pair", + "type": "BigUint" + }, + { + "name": "y_pair", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "compute_unmarshal_ec", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "data", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "BigUint" + }, + { + "type": "BigUint" + } + ] + }, + { + "name": "compute_unmarshal_compressed_ec", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + }, + { + "name": "data", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "BigUint" + }, + { + "type": "BigUint" + } + ] + }, + { + "name": "compute_generate_key_ec", + "mutability": "mutable", + "inputs": [ + { + "name": "curve_bitsize", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + }, + { + "type": "BigUint" + }, + { + "type": "bytes" + } + ] + }, + { + "name": "logEventA", + "mutability": "mutable", + "inputs": [ + { + "name": "data", + "type": "u32" + } + ], + "outputs": [] + }, + { + "docs": [ + "Logs `event_a` a repeated number of times." + ], + "name": "logEventARepeat", + "mutability": "mutable", + "inputs": [ + { + "name": "num_logs", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "logEventB", + "mutability": "mutable", + "inputs": [ + { + "name": "arg1", + "type": "BigUint" + }, + { + "name": "arg2", + "type": "Address" + }, + { + "name": "data", + "type": "variadic", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "only_owner_endpoint", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "only_user_account_endpoint", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "require_equals", + "mutability": "readonly", + "inputs": [ + { + "name": "a", + "type": "u32" + }, + { + "name": "b", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "sc_panic", + "mutability": "readonly", + "inputs": [], + "outputs": [] + }, + { + "name": "maddress_from_array", + "mutability": "mutable", + "inputs": [ + { + "name": "array", + "type": "array32" + } + ], + "outputs": [ + { + "type": "Address" + } + ] + }, + { + "name": "maddress_from_managed_buffer", + "mutability": "mutable", + "inputs": [ + { + "name": "managed_buffer", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "Address" + } + ] + }, + { + "name": "mbuffer_new", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "mbuffer_concat", + "mutability": "mutable", + "inputs": [ + { + "name": "mb1", + "type": "bytes" + }, + { + "name": "mb2", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "mbuffer_copy_slice", + "mutability": "mutable", + "inputs": [ + { + "name": "mb", + "type": "bytes" + }, + { + "name": "starting_position", + "type": "u32" + }, + { + "name": "slice_len", + "type": "u32" + } + ], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "mbuffer_set_random", + "mutability": "mutable", + "inputs": [ + { + "name": "nr_bytes", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "mbuffer_eq", + "mutability": "mutable", + "inputs": [ + { + "name": "mb1", + "type": "bytes" + }, + { + "name": "mb2", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "managed_address_zero", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "Address" + } + ] + }, + { + "name": "managed_address_eq", + "mutability": "mutable", + "inputs": [ + { + "name": "mb1", + "type": "Address" + }, + { + "name": "mb2", + "type": "Address" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "managed_vec_new", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "managed_vec_biguint_push", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List" + }, + { + "name": "item", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "managed_vec_biguint_eq", + "mutability": "mutable", + "inputs": [ + { + "name": "mv1", + "type": "List" + }, + { + "name": "mv2", + "type": "List" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "managed_vec_address_push", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List
" + }, + { + "name": "item", + "type": "Address" + } + ], + "outputs": [ + { + "type": "List
" + } + ] + }, + { + "name": "managed_vec_set", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List" + }, + { + "name": "index", + "type": "u32" + }, + { + "name": "item", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "managed_vec_remove", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List" + }, + { + "name": "index", + "type": "u32" + } + ], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "managed_vec_find", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List" + }, + { + "name": "item", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "managed_vec_contains", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List" + }, + { + "name": "item", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "managed_ref_explicit", + "mutability": "mutable", + "inputs": [ + { + "name": "mv", + "type": "List" + }, + { + "name": "index", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "storage_read_raw", + "mutability": "mutable", + "inputs": [ + { + "name": "storage_key", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "storage_write_raw", + "mutability": "mutable", + "inputs": [ + { + "name": "storage_key", + "type": "bytes" + }, + { + "name": "value", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "storage_read_from_address", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + }, + { + "name": "storage_key", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "load_bytes", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "load_big_uint", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "load_big_int", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "load_u64", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "load_usize", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "load_i64", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i64" + } + ] + }, + { + "name": "load_bool", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "load_addr", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "Address" + } + ] + }, + { + "name": "load_opt_addr", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "optional
", + "multi_result": true + } + ] + }, + { + "name": "is_empty_opt_addr", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "get_nr_to_clear", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "clear_storage_value", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "load_ser_2", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "ExampleEnumWithFields" + } + ] + }, + { + "name": "load_map1", + "mutability": "mutable", + "inputs": [ + { + "name": "addr", + "type": "Address" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "load_map2", + "mutability": "mutable", + "inputs": [ + { + "name": "addr1", + "type": "Address" + }, + { + "name": "addr2", + "type": "Address" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "load_map3", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "load_from_address_raw", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + }, + { + "name": "key", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "store_bytes", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "store_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "store_big_int", + "mutability": "mutable", + "inputs": [ + { + "name": "bi", + "type": "BigInt" + } + ], + "outputs": [] + }, + { + "name": "store_usize", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "store_i32", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "i32" + } + ], + "outputs": [] + }, + { + "name": "store_u64", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "u64" + } + ], + "outputs": [] + }, + { + "name": "store_i64", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "i64" + } + ], + "outputs": [] + }, + { + "name": "store_bool", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "bool" + } + ], + "outputs": [] + }, + { + "name": "store_addr", + "mutability": "mutable", + "inputs": [ + { + "name": "arg", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "store_opt_addr", + "mutability": "mutable", + "inputs": [ + { + "name": "opt_addr", + "type": "optional
", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "store_ser_2", + "mutability": "mutable", + "inputs": [ + { + "name": "arg", + "type": "ExampleEnumWithFields" + } + ], + "outputs": [] + }, + { + "name": "store_map1", + "mutability": "mutable", + "inputs": [ + { + "name": "addr", + "type": "Address" + }, + { + "name": "bi", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "store_map2", + "mutability": "mutable", + "inputs": [ + { + "name": "addr1", + "type": "Address" + }, + { + "name": "addr2", + "type": "Address" + }, + { + "name": "bi", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "store_map3", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "u32" + }, + { + "name": "b", + "type": "bool" + } + ], + "outputs": [] + }, + { + "name": "store_reserved_i64", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "i64" + } + ], + "outputs": [] + }, + { + "name": "store_reserved_big_uint", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "store_reserved_vec_u8", + "mutability": "mutable", + "inputs": [ + { + "name": "i", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "address_to_id_mapper_get_id", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "address_to_id_mapper_get_id_non_zero", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "address_to_id_mapper_get_address", + "mutability": "mutable", + "inputs": [ + { + "name": "address_id", + "type": "u64" + } + ], + "outputs": [ + { + "type": "Option
" + } + ] + }, + { + "name": "address_to_id_mapper_contains", + "mutability": "mutable", + "inputs": [ + { + "name": "address_id", + "type": "u64" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "address_to_id_mapper_set", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "address_to_id_mapper_get_id_or_insert", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "address_to_id_mapper_remove_by_id", + "mutability": "mutable", + "inputs": [ + { + "name": "address_id", + "type": "u64" + } + ], + "outputs": [ + { + "type": "Option
" + } + ] + }, + { + "name": "address_to_id_mapper_remove_by_address", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "getListMapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "listMapperPushBack", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "listMapperPushFront", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "listMapperPopFront", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "listMapperPopBack", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "listMapperFront", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "listMapperBack", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "listMapperPushAfter", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + }, + { + "name": "element", + "type": "u32" + } + ], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "listMapperPushBefore", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + }, + { + "name": "element", + "type": "u32" + } + ], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "listMapperRemoveNode", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "listMapperRemoveNodeById", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "optional", + "multi_result": true + } + ] + }, + { + "name": "listMapperSetValue", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + }, + { + "name": "new_value", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "listMapperSetValueById", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + }, + { + "name": "new_value", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "listMapperIterateByHand", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "listMapperIterateByIter", + "mutability": "mutable", + "inputs": [ + { + "name": "node_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "queue_mapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "queue_mapper_push_back", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "queue_mapper_pop_front", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "queue_mapper_front", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_mapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic>", + "multi_result": true + } + ] + }, + { + "name": "map_mapper_keys", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "map_mapper_values", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "map_mapper_insert", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "value", + "type": "u32" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "map_mapper_contains_key", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "map_mapper_get", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "map_mapper_remove", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "map_mapper_entry_or_default_update_increment", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "increment", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_mapper_entry_or_insert_default", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "default", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_mapper_entry_and_modify", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "increment", + "type": "u32" + }, + { + "name": "otherwise", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_mapper_entry_or_insert_with_key", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "key_increment", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_storage_mapper_view", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "map_storage_mapper_insert_default", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "map_storage_mapper_contains_key", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "map_storage_mapper_get", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "map_storage_mapper_insert_value", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "key", + "type": "u32" + }, + { + "name": "value", + "type": "u32" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "map_storage_mapper_get_value", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "key", + "type": "u32" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "map_storage_mapper_remove", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "map_storage_mapper_clear", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "map_storage_mapper_entry_or_default_update_increment", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "key", + "type": "u32" + }, + { + "name": "increment", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_storage_mapper_entry_and_modify_increment_or_default", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "key", + "type": "u32" + }, + { + "name": "value", + "type": "u32" + }, + { + "name": "other", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_storage_mapper_entry_or_default_update", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + }, + { + "name": "key", + "type": "u32" + }, + { + "name": "value", + "type": "u32" + } + ], + "outputs": [ + { + "type": "Option" + } + ] + }, + { + "name": "set_mapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "set_mapper_insert", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "set_mapper_contains", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "set_mapper_remove", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "set_mapper_front", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "set_mapper_back", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "set_mapper_next", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "set_mapper_previous", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "set_mapper_iter_from_and_count", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "map_my_single_value_mapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigInt" + } + ] + }, + { + "name": "my_single_value_mapper_increment_1", + "mutability": "mutable", + "inputs": [ + { + "name": "amount", + "type": "BigInt" + } + ], + "outputs": [] + }, + { + "docs": [ + "Same as my_single_value_mapper_increment_1, but expressed more compactly." + ], + "name": "my_single_value_mapper_increment_2", + "mutability": "mutable", + "inputs": [ + { + "name": "amount", + "type": "BigInt" + } + ], + "outputs": [] + }, + { + "name": "my_single_value_mapper_subtract_with_require", + "mutability": "mutable", + "inputs": [ + { + "name": "amount", + "type": "BigInt" + } + ], + "outputs": [] + }, + { + "name": "my_single_value_mapper_set_if_empty", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "BigInt" + } + ], + "outputs": [] + }, + { + "name": "clear_single_value_mapper", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "get_from_address_single_value_mapper", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "is_empty_single_value_mapper", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "is_empty_at_address_single_value_mapper", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "raw_byte_length_single_value_mapper", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "set_single_value_mapper_with_key", + "mutability": "mutable", + "inputs": [ + { + "name": "key", + "type": "u32" + }, + { + "name": "value", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "vec_mapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "vec_mapper_push", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "vec_mapper_get", + "mutability": "readonly", + "inputs": [ + { + "name": "index", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "vec_mapper_get_at_address", + "mutability": "readonly", + "inputs": [ + { + "name": "address", + "type": "Address" + }, + { + "name": "index", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "vec_mapper_len", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "vec_mapper_len_at_address", + "mutability": "readonly", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "token_attributes_set", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "attributes", + "type": "TokenAttributesStruct" + } + ], + "outputs": [] + }, + { + "name": "token_attributes_update", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "attributes", + "type": "TokenAttributesStruct" + } + ], + "outputs": [] + }, + { + "name": "token_attributes_get_attributes", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + } + ], + "outputs": [ + { + "type": "TokenAttributesStruct" + } + ] + }, + { + "name": "token_attributes_get_nonce", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "TokenIdentifier" + }, + { + "name": "attributes", + "type": "TokenAttributesStruct" + } + ], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "token_attributes_clear", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + } + ], + "outputs": [] + }, + { + "name": "token_attributes_has_attributes", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "add_to_whitelist", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "remove_from_whitelist", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "check_contains", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "check_contains_at_address", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + }, + { + "name": "item", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "require_contains", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "require_contains_at_address", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + }, + { + "name": "item", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "issue_fungible_default_callback", + "mutability": "mutable", + "payableInTokens": [ + "EGLD" + ], + "inputs": [ + { + "name": "token_ticker", + "type": "bytes" + }, + { + "name": "initial_supply", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "issue_fungible_custom_callback", + "mutability": "mutable", + "payableInTokens": [ + "EGLD" + ], + "inputs": [ + { + "name": "token_ticker", + "type": "bytes" + }, + { + "name": "initial_supply", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "issue_and_set_all_roles_fungible", + "mutability": "mutable", + "payableInTokens": [ + "EGLD" + ], + "inputs": [ + { + "name": "token_ticker", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "set_local_roles_fungible", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "mint_fungible", + "mutability": "mutable", + "inputs": [ + { + "name": "amount", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "EsdtTokenPayment" + } + ] + }, + { + "name": "mint_and_send_fungible", + "mutability": "mutable", + "inputs": [ + { + "name": "to", + "type": "Address" + }, + { + "name": "amount", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "EsdtTokenPayment" + } + ] + }, + { + "name": "burn_fungible", + "mutability": "mutable", + "inputs": [ + { + "name": "amount", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "get_balance_fungible", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "require_same_token_fungible", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [], + "outputs": [] + }, + { + "name": "require_all_same_token_fungible", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [], + "outputs": [] + }, + { + "name": "getFungibleTokenId", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "TokenIdentifier" + } + ] + }, + { + "name": "issue_and_set_all_roles_meta", + "mutability": "mutable", + "payableInTokens": [ + "EGLD" + ], + "inputs": [ + { + "name": "token_ticker", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "mapper_nft_set_token_id", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "TokenIdentifier" + } + ], + "outputs": [] + }, + { + "name": "mapper_nft_create", + "mutability": "mutable", + "inputs": [ + { + "name": "amount", + "type": "BigUint" + }, + { + "name": "attributes", + "type": "RgbColor" + } + ], + "outputs": [ + { + "type": "EsdtTokenPayment" + } + ] + }, + { + "name": "mapper_nft_create_and_send", + "mutability": "mutable", + "inputs": [ + { + "name": "to", + "type": "Address" + }, + { + "name": "amount", + "type": "BigUint" + }, + { + "name": "attributes", + "type": "RgbColor" + } + ], + "outputs": [ + { + "type": "EsdtTokenPayment" + } + ] + }, + { + "name": "mapper_nft_add_quantity", + "mutability": "mutable", + "inputs": [ + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "amount", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "EsdtTokenPayment" + } + ] + }, + { + "name": "mapper_nft_add_quantity_and_send", + "mutability": "mutable", + "inputs": [ + { + "name": "to", + "type": "Address" + }, + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "amount", + "type": "BigUint" + } + ], + "outputs": [ + { + "type": "EsdtTokenPayment" + } + ] + }, + { + "name": "mapper_nft_burn", + "mutability": "mutable", + "inputs": [ + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "amount", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "mapper_nft_get_balance", + "mutability": "mutable", + "inputs": [ + { + "name": "token_nonce", + "type": "u64" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "mapper_get_token_attributes", + "mutability": "mutable", + "inputs": [ + { + "name": "token_nonce", + "type": "u64" + } + ], + "outputs": [ + { + "type": "RgbColor" + } + ] + }, + { + "name": "getNonFungibleTokenId", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "TokenIdentifier" + } + ] + }, + { + "name": "init_unique_id_mapper", + "mutability": "mutable", + "inputs": [ + { + "name": "len", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "unique_id_mapper_get", + "mutability": "mutable", + "inputs": [ + { + "name": "index", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "unique_id_mapper_swap_remove", + "mutability": "mutable", + "inputs": [ + { + "name": "index", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "unique_id_mapper_set", + "mutability": "mutable", + "inputs": [ + { + "name": "index", + "type": "u32" + }, + { + "name": "id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "unique_id_mapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "unordered_set_mapper", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "unordered_set_mapper_insert", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "unordered_set_mapper_contains", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "unordered_set_mapper_remove", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "managed_struct_eq", + "mutability": "mutable", + "inputs": [ + { + "name": "s1", + "type": "ExampleStructManaged" + }, + { + "name": "s2", + "type": "ExampleStructManaged" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "no_overflow_usize", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "no_overflow_u8", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u8" + } + ] + }, + { + "name": "no_overflow_u16", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u16" + } + ] + }, + { + "name": "no_overflow_u32", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "no_overflow_u64", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "overflow_usize", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "overflow_u8", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u8" + } + ] + }, + { + "name": "overflow_u16", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u16" + } + ] + }, + { + "name": "overflow_u32", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "overflow_u64", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "no_overflow_isize", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i32" + } + ] + }, + { + "name": "no_overflow_i8", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i8" + } + ] + }, + { + "name": "no_overflow_i16", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i16" + } + ] + }, + { + "name": "no_overflow_i32", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i32" + } + ] + }, + { + "name": "no_overflow_i64", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i64" + } + ] + }, + { + "name": "overflow_isize", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i32" + } + ] + }, + { + "name": "overflow_i8", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i8" + } + ] + }, + { + "name": "overflow_i16", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i16" + } + ] + }, + { + "name": "overflow_i32", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i32" + } + ] + }, + { + "name": "overflow_i64", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "i64" + } + ] + }, + { + "name": "token_identifier_egld", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "EgldOrEsdtTokenIdentifier" + } + ] + }, + { + "name": "token_identifier_is_valid_1", + "mutability": "mutable", + "inputs": [ + { + "name": "token_id", + "type": "EgldOrEsdtTokenIdentifier" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "token_identifier_is_valid_2", + "mutability": "mutable", + "inputs": [ + { + "name": "bytes", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "returns_egld_decimal", + "mutability": "mutable", + "payableInTokens": [ + "EGLD" + ], + "inputs": [], + "outputs": [ + { + "type": "ManagedDecimal<18>" + } + ] + }, + { + "name": "set_contract_address", + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "is_empty_at_address", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "contains_at_address", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "len_at_address", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "next_at_address", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "previous_at_address", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "front_at_address", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "back_at_address", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "keys_at_address", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "values_at_address", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "List" + } + ] + }, + { + "name": "contains_unordered_at_address", + "mutability": "mutable", + "inputs": [ + { + "name": "item", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "get_by_index", + "mutability": "mutable", + "inputs": [ + { + "name": "index", + "type": "u32" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "fill_set_mapper", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "fill_map_mapper", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "fill_unordered_set_mapper", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "get_value_from_address_with_keys", + "mutability": "readonly", + "inputs": [ + { + "name": "address", + "type": "Address" + }, + { + "name": "extra_key", + "type": "u32" + } + ], + "outputs": [ + { + "type": "bytes" + } + ] + }, + { + "name": "managed_decimal_addition", + "mutability": "mutable", + "inputs": [ + { + "name": "first", + "type": "ManagedDecimal<2>" + }, + { + "name": "second", + "type": "ManagedDecimal<2>" + } + ], + "outputs": [ + { + "type": "ManagedDecimal<2>" + } + ] + }, + { + "name": "managed_decimal_subtraction", + "mutability": "mutable", + "inputs": [ + { + "name": "first", + "type": "ManagedDecimal<2>" + }, + { + "name": "second", + "type": "ManagedDecimal<2>" + } + ], + "outputs": [ + { + "type": "ManagedDecimal<2>" + } + ] + }, + { + "name": "managed_decimal_eq", + "mutability": "mutable", + "inputs": [ + { + "name": "first", + "type": "ManagedDecimal<2>" + }, + { + "name": "second", + "type": "ManagedDecimal<2>" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "managed_decimal_trunc", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "managed_decimal_into_raw_units", + "mutability": "mutable", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "managed_decimal_ln", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "ManagedDecimal<9>" + } + ], + "outputs": [ + { + "type": "ManagedDecimalSigned<9>" + } + ] + }, + { + "name": "managed_decimal_log2", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "ManagedDecimal<9>" + } + ], + "outputs": [ + { + "type": "ManagedDecimalSigned<9>" + } + ] + }, + { + "name": "managed_decimal_addition_var", + "mutability": "mutable", + "inputs": [ + { + "name": "first", + "type": "ManagedDecimal" + }, + { + "name": "second", + "type": "ManagedDecimal" + } + ], + "outputs": [ + { + "type": "ManagedDecimal" + } + ] + }, + { + "name": "managed_decimal_subtraction_var", + "mutability": "mutable", + "inputs": [ + { + "name": "first", + "type": "ManagedDecimal" + }, + { + "name": "second", + "type": "ManagedDecimal" + } + ], + "outputs": [ + { + "type": "ManagedDecimal" + } + ] + }, + { + "name": "managed_decimal_eq_var", + "mutability": "mutable", + "inputs": [ + { + "name": "first", + "type": "ManagedDecimal" + }, + { + "name": "second", + "type": "ManagedDecimal" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "managed_decimal_ln_var", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "ManagedDecimal" + } + ], + "outputs": [ + { + "type": "ManagedDecimalSigned<9>" + } + ] + }, + { + "name": "managed_decimal_log2_var", + "mutability": "mutable", + "inputs": [ + { + "name": "x", + "type": "ManagedDecimal" + } + ], + "outputs": [ + { + "type": "ManagedDecimalSigned<9>" + } + ] + } + ], + "events": [ + { + "identifier": "event_err_topic", + "inputs": [ + { + "name": "err_topic", + "type": "CodecErrorTestType", + "indexed": true + } + ] + }, + { + "identifier": "event_err_data", + "inputs": [ + { + "name": "data", + "type": "CodecErrorTestType" + } + ] + }, + { + "identifier": "event_a", + "inputs": [ + { + "name": "data", + "type": "u32" + } + ] + }, + { + "identifier": "event_b", + "inputs": [ + { + "name": "arg1", + "type": "BigUint", + "indexed": true + }, + { + "name": "arg2", + "type": "Address", + "indexed": true + }, + { + "name": "data", + "type": "List" + } + ] + } + ], + "esdtAttributes": [], + "hasCallback": true, + "types": { + "CodecErrorTestType": { + "type": "struct", + "docs": [ + "Helper type to explore encode/decode errors." + ] + }, + "OperationCompletionStatus": { + "type": "explicit-enum", + "variants": [ + { + "docs": [ + "indicates that operation was completed" + ], + "name": "completed" + }, + { + "docs": [ + "indicates that operation was interrupted prematurely, due to low gas" + ], + "name": "interrupted" + } + ] + }, + "EsdtTokenPayment": { + "type": "struct", + "fields": [ + { + "name": "token_identifier", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "amount", + "type": "BigUint" + } + ] + }, + "ExampleEnumSimple": { + "type": "enum", + "docs": [ + "Copied from multiversx-sc serialization tests." + ], + "variants": [ + { + "docs": [ + "Variant 0 doc comment.", + "This will show up in the ABI." + ], + "name": "Variant0", + "discriminant": 0 + }, + { + "name": "Variant1", + "discriminant": 1 + }, + { + "docs": [ + "One line is enough. The one above doesn't have any." + ], + "name": "Variant2", + "discriminant": 2 + } + ] + }, + "ExampleEnumWithFields": { + "type": "enum", + "docs": [ + "Copied from multiversx-sc serialization tests." + ], + "variants": [ + { + "name": "Unit", + "discriminant": 0 + }, + { + "name": "Newtype", + "discriminant": 1, + "fields": [ + { + "name": "0", + "type": "u32" + } + ] + }, + { + "name": "Tuple", + "discriminant": 2, + "fields": [ + { + "name": "0", + "type": "u32" + }, + { + "name": "1", + "type": "u32" + } + ] + }, + { + "name": "Struct", + "discriminant": 3, + "fields": [ + { + "name": "a", + "type": "u32" + } + ] + } + ] + }, + "ExampleStructManaged": { + "type": "struct", + "fields": [ + { + "name": "big_uint", + "type": "BigUint" + }, + { + "name": "int", + "type": "u32" + }, + { + "name": "bytes", + "type": "bytes" + } + ] + }, + "RgbColor": { + "type": "struct", + "fields": [ + { + "name": "r", + "type": "u8" + }, + { + "name": "g", + "type": "u8" + }, + { + "name": "b", + "type": "u8" + } + ] + }, + "TokenAttributesStruct": { + "type": "struct", + "fields": [ + { + "name": "field_biguint", + "type": "BigUint" + }, + { + "name": "field_u64", + "type": "u64" + }, + { + "name": "field_vec_u32", + "type": "List" + } + ] + } + } +} diff --git a/src/testdata/basic-features.wasm b/src/testdata/basic-features.wasm new file mode 100755 index 000000000..47005bc7f Binary files /dev/null and b/src/testdata/basic-features.wasm differ diff --git a/src/testdata/lottery-esdt.abi.json b/src/testdata/lottery-esdt.abi.json index a9fa48c5e..53be0bbed 100644 --- a/src/testdata/lottery-esdt.abi.json +++ b/src/testdata/lottery-esdt.abi.json @@ -68,6 +68,7 @@ }, { "name": "createLotteryPool", + "title": "Create lottery pool", "mutability": "mutable", "inputs": [ { diff --git a/src/testutils/testwallets/alice.json b/src/testdata/testwallets/alice.json similarity index 100% rename from src/testutils/testwallets/alice.json rename to src/testdata/testwallets/alice.json diff --git a/src/testutils/testwallets/alice.pem b/src/testdata/testwallets/alice.pem similarity index 100% rename from src/testutils/testwallets/alice.pem rename to src/testdata/testwallets/alice.pem diff --git a/src/testutils/testwallets/bob.json b/src/testdata/testwallets/bob.json similarity index 100% rename from src/testutils/testwallets/bob.json rename to src/testdata/testwallets/bob.json diff --git a/src/testutils/testwallets/bob.pem b/src/testdata/testwallets/bob.pem similarity index 100% rename from src/testutils/testwallets/bob.pem rename to src/testdata/testwallets/bob.pem diff --git a/src/testutils/testwallets/carol.json b/src/testdata/testwallets/carol.json similarity index 100% rename from src/testutils/testwallets/carol.json rename to src/testdata/testwallets/carol.json diff --git a/src/testutils/testwallets/carol.pem b/src/testdata/testwallets/carol.pem similarity index 100% rename from src/testutils/testwallets/carol.pem rename to src/testdata/testwallets/carol.pem diff --git a/src/testutils/testwallets/dan.json b/src/testdata/testwallets/dan.json similarity index 100% rename from src/testutils/testwallets/dan.json rename to src/testdata/testwallets/dan.json diff --git a/src/testutils/testwallets/dan.pem b/src/testdata/testwallets/dan.pem similarity index 100% rename from src/testutils/testwallets/dan.pem rename to src/testdata/testwallets/dan.pem diff --git a/src/testutils/testwallets/eve.json b/src/testdata/testwallets/eve.json similarity index 100% rename from src/testutils/testwallets/eve.json rename to src/testdata/testwallets/eve.json diff --git a/src/testutils/testwallets/eve.pem b/src/testdata/testwallets/eve.pem similarity index 100% rename from src/testutils/testwallets/eve.pem rename to src/testdata/testwallets/eve.pem diff --git a/src/testutils/testwallets/frank.json b/src/testdata/testwallets/frank.json similarity index 100% rename from src/testutils/testwallets/frank.json rename to src/testdata/testwallets/frank.json diff --git a/src/testutils/testwallets/frank.pem b/src/testdata/testwallets/frank.pem similarity index 100% rename from src/testutils/testwallets/frank.pem rename to src/testdata/testwallets/frank.pem diff --git a/src/testutils/testwallets/grace.json b/src/testdata/testwallets/grace.json similarity index 100% rename from src/testutils/testwallets/grace.json rename to src/testdata/testwallets/grace.json diff --git a/src/testutils/testwallets/grace.pem b/src/testdata/testwallets/grace.pem similarity index 100% rename from src/testutils/testwallets/grace.pem rename to src/testdata/testwallets/grace.pem diff --git a/src/testutils/testwallets/heidi.json b/src/testdata/testwallets/heidi.json similarity index 100% rename from src/testutils/testwallets/heidi.json rename to src/testdata/testwallets/heidi.json diff --git a/src/testutils/testwallets/heidi.pem b/src/testdata/testwallets/heidi.pem similarity index 100% rename from src/testutils/testwallets/heidi.pem rename to src/testdata/testwallets/heidi.pem diff --git a/src/testutils/testwallets/ivan.json b/src/testdata/testwallets/ivan.json similarity index 100% rename from src/testutils/testwallets/ivan.json rename to src/testdata/testwallets/ivan.json diff --git a/src/testutils/testwallets/ivan.pem b/src/testdata/testwallets/ivan.pem similarity index 100% rename from src/testutils/testwallets/ivan.pem rename to src/testdata/testwallets/ivan.pem diff --git a/src/testutils/testwallets/judy.json b/src/testdata/testwallets/judy.json similarity index 100% rename from src/testutils/testwallets/judy.json rename to src/testdata/testwallets/judy.json diff --git a/src/testutils/testwallets/judy.pem b/src/testdata/testwallets/judy.pem similarity index 100% rename from src/testutils/testwallets/judy.pem rename to src/testdata/testwallets/judy.pem diff --git a/src/testutils/testwallets/mallory.json b/src/testdata/testwallets/mallory.json similarity index 100% rename from src/testutils/testwallets/mallory.json rename to src/testdata/testwallets/mallory.json diff --git a/src/testutils/testwallets/mallory.pem b/src/testdata/testwallets/mallory.pem similarity index 100% rename from src/testutils/testwallets/mallory.pem rename to src/testdata/testwallets/mallory.pem diff --git a/src/testutils/testwallets/mike.json b/src/testdata/testwallets/mike.json similarity index 100% rename from src/testutils/testwallets/mike.json rename to src/testdata/testwallets/mike.json diff --git a/src/testutils/testwallets/mike.pem b/src/testdata/testwallets/mike.pem similarity index 100% rename from src/testutils/testwallets/mike.pem rename to src/testdata/testwallets/mike.pem diff --git a/src/testutils/testwallets/mnemonic.txt b/src/testdata/testwallets/mnemonic.txt similarity index 100% rename from src/testutils/testwallets/mnemonic.txt rename to src/testdata/testwallets/mnemonic.txt diff --git a/src/testutils/testwallets/password.txt b/src/testdata/testwallets/password.txt similarity index 100% rename from src/testutils/testwallets/password.txt rename to src/testdata/testwallets/password.txt diff --git a/src/testdata/testwallets/withDummyMnemonic.json b/src/testdata/testwallets/withDummyMnemonic.json new file mode 100644 index 000000000..29a585296 --- /dev/null +++ b/src/testdata/testwallets/withDummyMnemonic.json @@ -0,0 +1,21 @@ +{ + "version": 4, + "id": "5b448dbc-5c72-4d83-8038-938b1f8dff19", + "kind": "mnemonic", + "crypto": { + "ciphertext": "6d70fbdceba874f56f15af4b1d060223799288cfc5d276d9ebb91732f5a38c3c59f83896fa7e7eb6a04c05475a6fe4d154de9b9441864c507abd0eb6987dac521b64c0c82783a3cd1e09270cd6cb5ae493f9af694b891253ac1f1ffded68b5ef39c972307e3c33a8354337540908acc795d4df72298dda1ca28ac920983e6a39a01e2bc988bd0b21f864c6de8b5356d11e4b77bc6f75ef", + "cipherparams": { + "iv": "2da5620906634972d9a623bc249d63d4" + }, + "cipher": "aes-128-ctr", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "salt": "aa9e0ba6b188703071a582c10e5331f2756279feb0e2768f1ba0fd38ec77f035", + "n": 4096, + "r": 8, + "p": 1 + }, + "mac": "5bc1b20b6d903b8ef3273eedf028112d65eaf85a5ef4215917c1209ec2df715a" + } +} diff --git a/src/testdata/testwallets/withDummySecretKey.json b/src/testdata/testwallets/withDummySecretKey.json new file mode 100644 index 000000000..cfba75528 --- /dev/null +++ b/src/testdata/testwallets/withDummySecretKey.json @@ -0,0 +1,23 @@ +{ + "version": 4, + "kind": "secretKey", + "id": "c1d4b111-b8d2-4916-a213-bcfd237edd29", + "address": "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "bech32": "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + "crypto": { + "ciphertext": "75fbe213fc1964ce03100cf7d873748edf83a02631c8af9abdb23d210b9a2a15940bea2e56718f7bd710a938df5eb424c629e6a39b6ee056ed80d6e5f3b97791", + "cipherparams": { + "iv": "226d13be12373603af2b4edefcaa436f" + }, + "cipher": "aes-128-ctr", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "salt": "d57862c212bac142a89da97fb9bf9f5c91c8e8ddba952262dafe928e1c8a9906", + "n": 4096, + "r": 8, + "p": 1 + }, + "mac": "5bab92263237c5d595f565622dd2e61ea3dfd43580cecda7fd2f42d469b42e7f" + } +} diff --git a/src/testdata/testwallets/withoutKind.json b/src/testdata/testwallets/withoutKind.json new file mode 100644 index 000000000..9e83170cf --- /dev/null +++ b/src/testdata/testwallets/withoutKind.json @@ -0,0 +1,22 @@ +{ + "version": 4, + "id": "0dc10c02-b59b-4bac-9710-6b2cfa4284ba", + "address": "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "bech32": "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + "crypto": { + "ciphertext": "4c41ef6fdfd52c39b1585a875eb3c86d30a315642d0e35bb8205b6372c1882f135441099b11ff76345a6f3a930b5665aaf9f7325a32c8ccd60081c797aa2d538", + "cipherparams": { + "iv": "033182afaa1ebaafcde9ccc68a5eac31" + }, + "cipher": "aes-128-ctr", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "salt": "4903bd0e7880baa04fc4f886518ac5c672cdc745a6bd13dcec2b6c12e9bffe8d", + "n": 4096, + "r": 8, + "p": 1 + }, + "mac": "5b4a6f14ab74ba7ca23db6847e28447f0e6a7724ba9664cf425df707a84f5a8b" + } +} diff --git a/src/testdata/transactions.mainnet.json b/src/testdata/transactions.mainnet.json new file mode 100644 index 000000000..0be4e0b94 --- /dev/null +++ b/src/testdata/transactions.mainnet.json @@ -0,0 +1,11590 @@ +[ + { + "hash": "5ccad2b5a95d0b74ec32f5fc9f8978ceb1b2d0fce4fb936ba6f50c384b6adbbe", + "kind": "relayed_error" + }, + { + "hash": "b7bcdee4d2df0b59ce111ad31c9434dcd710b5fac62834f0a560e30d0f6c121d", + "kind": "relayed_error" + }, + { + "hash": "e952ce801d2d0474ab3e8d488bcb4b4be7cd00c7127c993bcfe82dd5c4a2ae44", + "kind": "relayed_error" + }, + { + "hash": "dda6e3d9b351f81978f97182c525eb0022ca1fb1f902e0c748ac847a65bfd1e3", + "kind": "relayed_error" + }, + { + "hash": "1bee7f5224ac0f16b639bee88be9724b8cd1fc6f54b733dbc5d9dfc47ea77afa", + "kind": "relayed_error" + }, + { + "hash": "8dc4453a333417ec4ecd4f4ca7832b8efd18058d0b9b2e5e364b51e7e5684ee9", + "kind": "relayed_error" + }, + { + "hash": "8a4aa6072725f7d7a9e37a3e971204c39e5ea4d4e1a6c699856d0903ba26cdd3", + "kind": "relayed_error" + }, + { + "hash": "2852edc27664b24e7fa3aed9bdad1ebb4838860ee02be6bdce9014443b3b244d", + "kind": "relayed_error" + }, + { + "hash": "85908022aae1d915a05676c772d1ed5c25b4d310f3ee98903f42856582cc41fc", + "kind": "relayed_error" + }, + { + "hash": "66db5ab89ccf7e73ada98c69c979f1f533c89ae929fc2b666d75097a27a0221e", + "kind": "relayed_success" + }, + { + "hash": "1876dea546cf58ae7b6223fd51e215475191a586691d57f222754a6a9847642c", + "kind": "relayed_success" + }, + { + "hash": "8222625f24273eb8f2aa0d751ac3aa10040f71fdb7b4f2bfdb8a7a10ef258def", + "kind": "relayed_success" + }, + { + "hash": "f349af0924b762ae41d71a918ceba96b4736925437e40248ec569d6a494654aa", + "kind": "relayed_success" + }, + { + "hash": "e6e68d07d2fa11b9d968e30d128ed85364b169ed6ad500ef7ed1f269dbc44d24", + "kind": "relayed_success" + }, + { + "hash": "f36ce71ef2374bb79a3766bd4e5216666ee23443d619a09dd6586833bd5d2500", + "kind": "relayed_success" + }, + { + "hash": "d8009977c564604462089922267c3feeb8b5994759e16fd9d8b1a8b11053b717", + "kind": "relayed_success" + }, + { + "hash": "421edabd3d17e7e6100c0881129a6aa4258b8e50ffbffb08a50d741be25d7ffd", + "kind": "relayed_success" + }, + { + "hash": "d95f492e99f4c87e355349dee2ed03f0f9089f4bc42c90a7a5b1e4e96c236d5e", + "kind": "relayed_success" + }, + { + "hash": "2994b9d41461d9e69531126be1b31e4d13109d05858ba19a9444d79d02479d0d", + "kind": "relayed_success" + }, + { + "hash": "7d804aebc33026e77ed243c89a4a8557b69991769e07985fe07535d4747351fc", + "kind": "relayed_success" + }, + { + "hash": "27069fdfa81c724568d56527c8ce90c4637e26df9227a1463c8ac4de4deac27e", + "kind": "relayed_success" + }, + { + "hash": "be9e050c351e3799826d7df39f3c2322fcd62cf748c78c91accc63b360bf759d", + "kind": "relayed_success" + }, + { + "hash": "327a7571d06aab65e598e4f6bf12627a50121d5aee36d787255a689ab2553fbc", + "kind": "relayed_success" + }, + { + "hash": "01e6ece6c6944234dd4daba1a5f305ca938ee95b07ecdc926aabe07d269d8874", + "kind": "relayed_success" + }, + { + "hash": "895fb3848c3fd67c8d6833d1fd6fe026896aa091d2296e7f38bf108c380723c4", + "kind": "relayed_success" + }, + { + "hash": "6b54f879d8bbfaa56a4381e7fb934e2214fd5b09d581268252612bd8a0a198a4", + "kind": "relayed_success" + }, + { + "hash": "ccd2d86e515ab9ee8e213e49f50a3ff2142d736f1669bcfbd17eebadb02edc0f", + "kind": "relayed_success" + }, + { + "hash": "3b23eb988e438baecf709cd0ed2a8bbf944f7f24d3e5542693cd3dcc9cfa6c27", + "kind": "relayed_success" + }, + { + "hash": "823756ea813d7d8da01a263c7791398459f0fc954b5b4fd2b19fc12f8cda546b", + "kind": "relayed_success" + }, + { + "hash": "dfe82a3e4870eefd5c5f9174539ebdf3847668aae4d56a8b4c6577c6ae6c7eda", + "kind": "relayed_success" + }, + { + "hash": "786d37562ea7c75ecefc6d006651ba700405eda382ae68f0d15345b342ada647", + "kind": "relayed_success" + }, + { + "hash": "377ebc87b837c34ac397358be3ab44fdd8d1f013ceadfda8dfca1d3a6833be95", + "kind": "relayed_success" + }, + { + "hash": "7550855629b61c1f8299f4bd9add1c382a63dfdd71fa66c99d71c6ebc7f762aa", + "kind": "relayed_success" + }, + { + "hash": "19ffc5ad0538480d4ae44e80a9f84aaed3835181da4732a3c4315c55ffc38c57", + "kind": "relayed_success" + }, + { + "hash": "3091da9934afc22c3fc0998eb4cf54017e58a574acb0333095c86efcf843dc20", + "kind": "relayed_success" + }, + { + "hash": "a4d6effc8d86df4834add82283cbb862037863bedabf6fb443bc4ba3ad912dbb", + "kind": "relayed_success" + }, + { + "hash": "c1e96a041180cf3b56ba357856cb6e7c31e551e17fb44693d66d177f662ccebe", + "kind": "relayed_success" + }, + { + "hash": "79fa9572ace90b58f8b91713b2b565d1c6dbf63d2fc018a7bf843bb464f9d789", + "kind": "relayed_success" + }, + { + "hash": "0579365f030845e6e2fd5cdaa119488c1eeae9933def91c058be15cc2bbb78d2", + "kind": "relayed_success" + }, + { + "hash": "ab211f6ad844f55e624bb21da5f5d1bcb79664c92feccb25c5cfd0bafa5894db", + "kind": "relayed_success" + }, + { + "hash": "968560eba192e06591caaf2c7e9c3f7a7a80f1c890e9a80e886f3477150faddd", + "kind": "relayed_success" + }, + { + "hash": "f827fc6ff7ef72210a94091f728e8b6dd65498fd4de59a2caab00bd2ab1f15a3", + "kind": "relayed_success" + }, + { + "hash": "5e384449d9e91c16288a22edb61dcc28038bebd3356bfddae4b3c77052151ac7", + "kind": "relayed_success" + }, + { + "hash": "a451b2ce0bc059f041179f349c6787d6bab88118166e5d3b7b00be26edaf977e", + "kind": "relayed_success" + }, + { + "hash": "85a9aa117cc77e17c32dea058cf3474400dc5f885d8057022804666f9987e41d", + "kind": "relayed_success" + }, + { + "hash": "b2079bb405ecac2a13be00b49bad0520f9af1c326450985de415fe96f5c12f7e", + "kind": "relayed_success" + }, + { + "hash": "0e016460a656d8e79af5d771d9f50db72c3218afe9991f38fff29e62d2722490", + "kind": "relayed_success" + }, + { + "hash": "709ff4c01562ba87080c5b0e31aade1ba6377c863a4f5c90a7999cf641e17a0f", + "kind": "relayed_success" + }, + { + "hash": "dcb12b9ef74fed99ab64df357dfeb41951d40fa2e7bfe89c42dd320ac80756f8", + "kind": "relayed_success" + }, + { + "hash": "c2f751f7e1cc324dbde61c26bf07b0ee307c82fb56af157f0290a863dae32d79", + "kind": "relayed_success" + }, + { + "hash": "c5fb5387780860114702fc1eb09d4a3d01a992bffac42864be431402750b398e", + "kind": "relayed_success" + }, + { + "hash": "2ec6b6b4d9e14e0381c998e59b6e82b9965d9aeb71fc7f0a2f5a1703e1aabdbe", + "kind": "relayed_success" + }, + { + "hash": "61869bd85187ff81ab5459ca66571057415b449d6807a6a34a4fda0694fb59af", + "kind": "relayed_success" + }, + { + "hash": "a3a2d0c8bf7066b55a1d0217d843af3200fd57dba01327cf492d5eeb3c0d5015", + "kind": "relayed_success" + }, + { + "hash": "5b8f1687a363af85cc217919458c67a01275958c09e75e61f2a126aaec5a09bc", + "kind": "relayed_success" + }, + { + "hash": "736ab5709a97e05c85c6d238dbaadc2b76ea5cf1fe81aa3d557135eb0533e2f5", + "kind": "relayed_success" + }, + { + "hash": "90f74bac6aac332114289f58bfe4187e7a6a795673e4c98734c1d40c22bfe146", + "kind": "relayed_success" + }, + { + "hash": "ed9750f814027e1124c0407dbd4c6184b6b966c56813a0e3e71b5afd8375a4f3", + "kind": "relayed_success" + }, + { + "hash": "05d02ee4123bffab1617fa37d161f4f599379b78dcbb868c1d5d741a5b5d9c41", + "kind": "relayed_success" + }, + { + "hash": "df355a84f0fef2820de20a8098ee319413b710cfaa87c035d2700c3994b2133f", + "kind": "transfer_execute_success" + }, + { + "hash": "c81f233c71d0b4a821b4b171b1cb870707985ebcf49235e1883b1a5a770ec686", + "kind": "transfer_execute_success" + }, + { + "hash": "66d2e456aeb5555bb73ac99ca49fb1c44cda1fdfe1e94e9c7e834cd841cdec27", + "kind": "transfer_execute_success" + }, + { + "hash": "7946d09309a20aa13914e25c67f93467aa8f9d31eba8447d9b1271ac1ed7d41a", + "kind": "transfer_execute_success" + }, + { + "hash": "d879137dc12776f2a83c720679d40e9b16b2efbeef80e2eba64dcec99875e9fe", + "kind": "transfer_execute_success" + }, + { + "hash": "e8504b0aec16a9709bb88ea7685115e603eef77eecab410d4f3ae9197ea3f0b0", + "kind": "transfer_execute_success" + }, + { + "hash": "0298cd40356b04f972e83142daae17272319043a559c8a5e91b1c526488fa677", + "kind": "transfer_execute_success" + }, + { + "hash": "0dcdb1186898cc292bd7e9931dd2053b9f7001ffb4c334ef90719de7881bbd0a", + "kind": "transfer_execute_success" + }, + { + "hash": "4cd8ebc2a540a70da6fdf6361db0ec0d99629ad5d228f5107a1d1693fd877397", + "kind": "transfer_execute_success" + }, + { + "hash": "1537a3655ede964220e98f20d9491db7ef8dca9c329e51b8512c912af4f9e329", + "kind": "transfer_execute_success" + }, + { + "hash": "59d90307f08674f86d7976f4e5b7cd8dd64d3f0a829224b82546ff4297a16d52", + "kind": "transfer_execute_success" + }, + { + "hash": "f98dd1c9f50c88949d8f3a5eb3b301c4dd0ff096a938e09cbe709c10317dc7b7", + "kind": "transfer_execute_success" + }, + { + "hash": "8f5463d3a7742e0bd091a68e788bb021e0fd571c3290fd27db02ab23836f31df", + "kind": "transfer_execute_success" + }, + { + "hash": "eb09c718e216b735a82aaf66e7b1bac5388ba18a38e28dd9f9cbd23f2be6cbb8", + "kind": "transfer_execute_success" + }, + { + "hash": "97d7af39f5552e734c846317ff490eaf0fe8d3076a14f3616450ab383883ac42", + "kind": "transfer_execute_success" + }, + { + "hash": "71d630caefa5f3a8a6702a074f154de931fbd0f1168a617a67cb5a569eead774", + "kind": "transfer_execute_success" + }, + { + "hash": "b6f919d9376c630ee566a14ea147c4de93abd53b1bad03ca094657fb78ba9b70", + "kind": "transfer_execute_success" + }, + { + "hash": "9e1a98ff735ca9a4ff5899d04366a099a3100313a28a2524bb8210a71d82d059", + "kind": "transfer_execute_success" + }, + { + "hash": "489dacbed71679447924ddccb616bd147028685f6de9b66feb602127455c5073", + "kind": "transfer_execute_success" + }, + { + "hash": "050c26f02fa1fc5ba977259804afc1739805488d9a49e3c97469cc01758109b9", + "kind": "transfer_execute_success" + }, + { + "hash": "264a2db992f4950ef62712c25c41fca45a16bf178e1123cb173358fcb82d6a65", + "kind": "transfer_execute_success" + }, + { + "hash": "d4a092aca9778199ce50beb17426a54671132a8bc080a4cb1b544d5b38671b8c", + "kind": "transfer_execute_success" + }, + { + "hash": "c2319e7f867c523a09ee3364f7c4ea682fe05881f8199ef329d3f1ae95a0d224", + "kind": "transfer_execute_success" + }, + { + "hash": "36e9b824a39ffa2a8071ba068693f44d5516bd40aaf76ad3fce515899e259925", + "kind": "transfer_execute_success" + }, + { + "hash": "e7fd32ed847712e25a32255adb32aab172e96de2a48c2c5a36704b826e895544", + "kind": "transfer_execute_success" + }, + { + "hash": "a7fb4b4c1402385b5a312b930c53477de5178dff1661e6a52ca62c286dc3219c", + "kind": "transfer_execute_success" + }, + { + "hash": "b84aa2c8b83591318633999748238e0c0067193b96d569defeb63254d6c058e1", + "kind": "transfer_execute_success" + }, + { + "hash": "99a4aa636ce915fc8e646ba7f5ec582278dd6017a0734278ca51db6fac145538", + "kind": "transfer_execute_success" + }, + { + "hash": "08052d156ddeefa4312ed3d35dd3062ed3a8521faeedcfbe834061871fa19e42", + "kind": "transfer_execute_success" + }, + { + "hash": "f9b1544d282742555f6daae5886e16885241115d327ee8af6c6cba16e3af55a4", + "kind": "transfer_execute_success" + }, + { + "hash": "871312e21580ad02f3447cbf8a19341572914144009edd54822983c482b53970", + "kind": "transfer_execute_success" + }, + { + "hash": "f96eae1671492a291f3876128cdc4616833a985d0a9d6f3e08a2a561aa31dc58", + "kind": "transfer_execute_success" + }, + { + "hash": "fdeb014c94eb5fa68e33ea7a802bc8a7c771358a2193419bad7fa1ede382fd16", + "kind": "transfer_execute_success" + }, + { + "hash": "558b1817151cf11e64ee89f9158612339680dd17a01c22610dbf05367e2083f7", + "kind": "transfer_execute_success" + }, + { + "hash": "f992e1b9c35a4349a2edaf12b3055984a0fa05df9c153afe52c61b7a157fc5f8", + "kind": "transfer_execute_success" + }, + { + "hash": "6100efb2212f8ef6e97d59b8deaeb697cb507705caf2f47e9ec736e2da79f447", + "kind": "transfer_execute_success" + }, + { + "hash": "577880cda0d0ae0ff2cf7ce4c14ef945e2a8d2c0752586ab002860c029800dfd", + "kind": "transfer_execute_success" + }, + { + "hash": "44117630865f6f2020ba6977740dd6b3950021350e7e2d27a0c9428cb1156667", + "kind": "transfer_execute_success" + }, + { + "hash": "c6c47982db3e2fc67b7a08376b50478f50547b7a9cc391340eb431eac42e218d", + "kind": "transfer_execute_success" + }, + { + "hash": "0fb257ee30145a5108d4691121865024b33909eb4c3a5ce8fc35aed41b0048d4", + "kind": "transfer_execute_success" + }, + { + "hash": "b8bbf613060e33a7bfafdc46eba194245134943166ab61c2269509b78d94f4e1", + "kind": "transfer_execute_success" + }, + { + "hash": "aa7d589795f5cf700b02088b213d18d11b9e2b08b58d81a03de0c8c8da2e898b", + "kind": "transfer_execute_success" + }, + { + "hash": "c3bb799583f748b29a05fd8e4ba5164402790c2b4a54b0edc8139ad7e61f4100", + "kind": "transfer_execute_success" + }, + { + "hash": "dae0ea75692390df4fa719946b4e29b61716db645a7f2b14f58052b2212414dd", + "kind": "transfer_execute_success" + }, + { + "hash": "85e28df306f09b2f0f2107bb0d9bf75915770deeeb2feaeb5216087f49e2879e", + "kind": "transfer_execute_success" + }, + { + "hash": "883d6de36abaaaf6fbc568c1228ddf83f59c2752bfc203871570a6db11a39df2", + "kind": "transfer_execute_success" + }, + { + "hash": "0054c8aed9ab0903f531fa8f57a9d0ed60e9bd96feff2bd1e5c7507b1082a986", + "kind": "transfer_execute_success" + }, + { + "hash": "e5b9a2c933f14f75cb6068ce1e16fe8022373d51d60544adeac1dc5215f5d4a7", + "kind": "transfer_execute_success" + }, + { + "hash": "2e18cb508d180e382e9cf89db4b284586cdc4c6df1e0c1c0e8ba9879ca2e7592", + "kind": "transfer_execute_success" + }, + { + "hash": "1d82c617af5df1684918d29b004d8efc497e66eed03f8bb5ea68c4854e568ee8", + "kind": "transfer_execute_success" + }, + { + "hash": "25db8124e9ab999b11e3d181d6e6c3dea6a457ef1c95e54b311cbd17fabb22cf", + "kind": "transfer_execute_success" + }, + { + "hash": "7bf6b69b8e49f219ceca45bba2584a89f357ed1478a935a08037a4fc30bc96ac", + "kind": "transfer_execute_success" + }, + { + "hash": "aa7809c8751a865b9218faa4def5ad602798f348fd2209748589d7dbd342ecdf", + "kind": "transfer_execute_success" + }, + { + "hash": "e2aff82d1c25ce322f17a3544b186b1d3bc2fe4604d24c1286d37a3ea76467b9", + "kind": "transfer_execute_success" + }, + { + "hash": "f9d8881677b9e287ff0b4c614500e6dcd757d46f19cd993687410f91b7159c8b", + "kind": "transfer_execute_success" + }, + { + "hash": "97d7a3cc1a0e935cf1cb6205fbf850022d6c508f2a02b8312700ae6965c8967b", + "kind": "transfer_execute_success" + }, + { + "hash": "f310ab9e1abf9ff496d9fcbb0d74fffae6fe97343a32ef1faced427e93c5b4a2", + "kind": "transfer_execute_success" + }, + { + "hash": "09e2111598e60c423eb773bf1f6f830449c663ee152bd27962f48cbb036d87eb", + "kind": "transfer_execute_success" + }, + { + "hash": "e8bb0cd81a1207a983c2ae132ca522b80600754ffa3db0d68149519e672d1789", + "kind": "transfer_execute_success" + }, + { + "hash": "934919f3982800b536cac32ec9f4358f2ab3b96784cebab16de315c2956e8147", + "kind": "transfer_execute_success" + }, + { + "hash": "2bc90cd54fcee644b7d9bbbceb5c0bd9337b3f1b7c40b3a335a2beb21c7efa32", + "kind": "transfer_execute_success" + }, + { + "hash": "9d2b077e5e91122513de302cd9fc82c5e59acba35df805da93d64023091196d9", + "kind": "transfer_execute_success" + }, + { + "hash": "40e535f38bb641405c1d8a044ff7d8dcce55cb66285e19df34e895e609e330ee", + "kind": "transfer_execute_success" + }, + { + "hash": "efd86c0a5ac69f7d5f8d8ac4b12de573d78455ac24b190116ba27fc73a56400f", + "kind": "transfer_execute_success" + }, + { + "hash": "d03159f9f5dad1f33915643c0a9ea129b805276bb8647c10b12a29308a833f57", + "kind": "transfer_execute_success" + }, + { + "hash": "66d1b065ec9c11918b38ec0a3e1be13ab6313fe0ddb2c13e7b76b224f4751e45", + "kind": "transfer_execute_success" + }, + { + "hash": "c6db408ed5b3d5498bc18185a72a780db3422dd579302ce3d759f9a642c1e169", + "kind": "transfer_execute_success" + }, + { + "hash": "55bf6b07dcf07dd13e88a5da72ce7d4c966870085a7a90bd3da8dc6ce0415596", + "kind": "transfer_execute_success" + }, + { + "hash": "c20a9b6c8ca59a65f056fdcdeff95d6d3e6e9c1e8e26742c05ab45db64b3f3d4", + "kind": "transfer_execute_success" + }, + { + "hash": "7c0f5b11b6ffd60446b29408820a1acf05a2774a713a8e1a84f587656458608b", + "kind": "transfer_execute_success" + }, + { + "hash": "89b9f4f810bf62ec68696e76ad800dbf1b656f5e06e0fd57cdc869458c0c07c7", + "kind": "transfer_execute_success" + }, + { + "hash": "a774fa9f0339996dce7b926ef6b99230925cd5d43c7764e6c55726ff4544fc1f", + "kind": "transfer_execute_success" + }, + { + "hash": "30d08ae0e622b0ad8581ded0ef7accc761829942f5aa1388ed98f6dacb4634f7", + "kind": "transfer_execute_success" + }, + { + "hash": "93a381a52651db2dca06d2375f372b43e39b35425705be1b07d4ec406849f7ae", + "kind": "transfer_execute_success" + }, + { + "hash": "75a776f2ce9b5bc06fa35883b5f7b215cb778fcd9bdaf9273edf356f7dea7832", + "kind": "transfer_execute_success" + }, + { + "hash": "5e63e64c164f4994e0506a283f0f481fa169a58b42af231b6650f7a7f271bc35", + "kind": "transfer_execute_success" + }, + { + "hash": "6322434de883c5f6a6148a99ef866aaa60741d386abc62c77d3441996fc6f6ce", + "kind": "transfer_execute_success" + }, + { + "hash": "4243dc52bf975cc2c477de21949032dda8635df16c88929ca7492ea06bec4996", + "kind": "transfer_execute_success" + }, + { + "hash": "3ecf0796ac753f4ae58dd6224537d3d4357aad0fd0e277681b6d75592cb0f53a", + "kind": "transfer_execute_success" + }, + { + "hash": "5594933ad3f50f3ab6cdd2a5f20cd7f01ce2f27d5dc323a33fd445be18f69308", + "kind": "transfer_execute_success" + }, + { + "hash": "a3778ca41953ac4ce9cc0d7e391ecafdf4a3968aa9edda8800c33597d020e050", + "kind": "transfer_execute_success" + }, + { + "hash": "6296b2ebe340bababe8a21548c0abb9bb0b440f6ad0a97cb7a01f25ffa146de4", + "kind": "transfer_execute_success" + }, + { + "hash": "196528c1dc81c1cb38128b2dfea6701df5a2f755643ffae8a4f83ccc6963da75", + "kind": "transfer_execute_success" + }, + { + "hash": "beedc1ebb613b4a33fac570c66ffb0a48e5f1f48fd1c5e94d8f84312d86dd3b1", + "kind": "transfer_execute_success" + }, + { + "hash": "550bece89970c7d5bd7c197260e10dcb0bac2014d9958f9259f3ebbd10f48d9f", + "kind": "transfer_execute_success" + }, + { + "hash": "88a472717fd1e550bec59cb2b58cf4bbdcf5cc0efe3c3207caded4b5f11974f2", + "kind": "transfer_execute_success" + }, + { + "hash": "37b40959b10551597fdbc4656f6c3d948e6748fba4e8c1d4e9306fea7992ffaf", + "kind": "transfer_execute_success" + }, + { + "hash": "c97ca0d0d2770bc076b7c02524464a0aac69d7f1e45063d5b99530faba117402", + "kind": "transfer_execute_success" + }, + { + "hash": "539605febc0acad1a987805e745150e58d20db782677f49a2d159ed30b0a0dc6", + "kind": "transfer_execute_success" + }, + { + "hash": "368582f02384ecd737fd993933ea428d267aa6d7f48947378c1d147f95321b3d", + "kind": "transfer_execute_success" + }, + { + "hash": "a20533a13e2a77be0f37335fd67c7c0b65339a94ba6ae6ec99797e91ab301204", + "kind": "transfer_execute_success" + }, + { + "hash": "6c434acf2965909e6a2d2765875b88c381e7ae879b46a2027fd1ddc6b8ea40ff", + "kind": "transfer_execute_success" + }, + { + "hash": "6dce78c1310b8957082a9818832b22f81e48bcf31e27d71860b319b57840125b", + "kind": "transfer_execute_success" + }, + { + "hash": "f7d541524c7d2cd746ed6ba0a35c27ac3fcfa7ca46504819e391cd677c284ad4", + "kind": "transfer_execute_success" + }, + { + "hash": "8cdfbf690a89183068e097cbb9d299c0e37bcfa7d86beec4e8c515e0bc7e2352", + "kind": "transfer_execute_success" + }, + { + "hash": "ea3faf33db6ae940791d543141df4764cd842b18910006f33cf3d56293f1b738", + "kind": "transfer_execute_success" + }, + { + "hash": "525d3b777290f62e720dadb555e4f77de33110359b039f0faeab6e69b89bebdd", + "kind": "transfer_execute_success" + }, + { + "hash": "c8a28615b7f3c26df372263f0fc636ff353097018cb78d51df08c9a2e6bb1f1a", + "kind": "transfer_execute_success" + }, + { + "hash": "30f9d652834566e2e441e8d406aed60020508e5e31e33c2677eb169d1de6a044", + "kind": "transfer_execute_success" + }, + { + "hash": "5d312838ba9e91031c786076d71624afdfcb4f454721212595658ca09b59af1a", + "kind": "transfer_execute_success" + }, + { + "hash": "da41dff31fc227261477e7c545c15a28b131609ab0b48ee3a4a5a2a1e44562cf", + "kind": "transfer_execute_success" + }, + { + "hash": "c685619229b34b288151de6c6e83b98300687c5f76f2dd3e0a922b452271a3cd", + "kind": "transfer_execute_success" + }, + { + "hash": "061460dcae19402e63b51d56190201b15e9da27d0f91673e74c7dfc9abea3dad", + "kind": "transfer_execute_success" + }, + { + "hash": "0fc56543ed48ba54948f5e0e1ff27ea3e74fe807ecd8a8b8bd57829f39df5993", + "kind": "transfer_execute_success" + }, + { + "hash": "3b55b2a242488d830cb5cb01efb8337bda79d6e680f2c5db9f03d0ac1803be19", + "kind": "transfer_execute_success" + }, + { + "hash": "14381f1759dd64398128c8b6bb625b8ea0d77c08143c6e2594331f5df030dd3b", + "kind": "transfer_execute_success" + }, + { + "hash": "d028d2fbb155efcd0e7533bc5a605c65c77aaffbf16154d280592ad97cb954c2", + "kind": "transfer_execute_success" + }, + { + "hash": "8e3f6e05f43ee2f0232708fcaa315e5d6cb45f191c7ccc6f53db7851342d461b", + "kind": "transfer_execute_success" + }, + { + "hash": "938cec69c96bc4ef03b4d7bf206d0e39a060691a08ff1e496e1d0719d7e75934", + "kind": "transfer_execute_success" + }, + { + "hash": "96fb964e3b4249c89b3004a4fc9fbddd2e913e92b47ca3672804ec144668f25f", + "kind": "transfer_execute_success" + }, + { + "hash": "79d46371c06bb02d1e72149a55fec471b8e0e214236f072c882d4dadb54a1bba", + "kind": "transfer_execute_success" + }, + { + "hash": "747243ef5886ef56d156e8a134605852b020fe7337259405daffaba1ca4d7009", + "kind": "transfer_execute_success" + }, + { + "hash": "988d6efa4d203fba24591542025f52c8c9cafdbd7bdbff57efed19b2d77746c8", + "kind": "transfer_execute_success" + }, + { + "hash": "368ccab5ab37af36d9e8b405b14894bf36c33d56a573e853e1028b913ebb09d9", + "kind": "transfer_execute_success" + }, + { + "hash": "44ca5b8a6bfe25477a0663f452711c70cd2a66729f359694ad06ed12312768ab", + "kind": "transfer_execute_success" + }, + { + "hash": "e676063e93a0bfc16d0cde231e9b9228246139541e060fee92c7519071e1e0b5", + "kind": "transfer_execute_success" + }, + { + "hash": "0b7cc1d85c2c8002e0f467cfb2251219d825d1605027d87deca5cb90bfb153e9", + "kind": "transfer_execute_success" + }, + { + "hash": "c723402a7752b312721ba31c7ef79bb2d075f0686dde15aadb121475373133a8", + "kind": "transfer_execute_success" + }, + { + "hash": "cb8e4434d67de3d5e511057ac1607acaf1e101b55be88ee5747f684afb833b42", + "kind": "transfer_execute_success" + }, + { + "hash": "9f0ae1b5d5701a823fb4f46492d2728a8542e863be3ded324c38caf8fdcc836f", + "kind": "transfer_execute_success" + }, + { + "hash": "0d94c1ee18a11c7d00407b212ad5b685f484e034fdba6fe4dd1439e4c3f49245", + "kind": "transfer_execute_success" + }, + { + "hash": "6493e04efeceba3f865ab7986752d2a3678586cac80f6f220b5e8e24d4b899d8", + "kind": "transfer_execute_success" + }, + { + "hash": "04243c91e30e706b14f4256f8d603df65e21e38b7a7108887e9a02144f1a4160", + "kind": "transfer_execute_success" + }, + { + "hash": "6ba733693fc546e457c9e7ee17a12f980f76e3454bbb4658c7bb711bde1d9922", + "kind": "transfer_execute_success" + }, + { + "hash": "14591144b949cb17ae7a2955a8629fe6cd95631c52b15ba6dc9cdf8cccfad546", + "kind": "transfer_execute_success" + }, + { + "hash": "94eecf7c26df6f96db76e3eafdd1b10efd9d8d75a2a53ac7ba869a72ce3cceb5", + "kind": "transfer_execute_success" + }, + { + "hash": "1d18dd7854d4b66dd121044b94d148880998468cfbe9c3597526b1eebf7e90b1", + "kind": "transfer_execute_success" + }, + { + "hash": "68783f007de1288f2a7d01ea93fc20b60d66f9c61acbdd912627d91622247b11", + "kind": "transfer_execute_success" + }, + { + "hash": "96e9e11bf3b5ff3199f7841750bc5bc2666e809f37409eb7fd24d8fd89c8f2b0", + "kind": "transfer_execute_success" + }, + { + "hash": "2d0a9d2fc9f41e3030afbecf50225cd1002a2846ab2b3edbbde62623656f8656", + "kind": "transfer_execute_success" + }, + { + "hash": "5c818db2a110384bc3fe7c8f02e4c6bd85104682a08085c88e8cdb148b61f64c", + "kind": "transfer_execute_success" + }, + { + "hash": "73c43df4f93c60beb7b2152e3ccd2fbd3c801776b95642cee5eb00704065a4aa", + "kind": "transfer_execute_success" + }, + { + "hash": "d3a11b79f07ff1fdacb2515e47bb1e1978c8838d9716cace1ceda6f708948043", + "kind": "transfer_execute_success" + }, + { + "hash": "02b5de381f24a3cedf3571793cf125be1f28b3ecf6952b6bcc9a3de26251bd1a", + "kind": "transfer_execute_success" + }, + { + "hash": "8043bca630df9806e675f3357967c5a66cbffaded2c42bbbcb27bdb327614d11", + "kind": "transfer_execute_success" + }, + { + "hash": "5f4ac430090265af02d4abb9d609e37579f639db175eabb9e562035972af888f", + "kind": "transfer_execute_success" + }, + { + "hash": "b506abffe92dc1f82cefe0e839ee6f6e2977f0e7e174e2efe17e8b03d2f20a6a", + "kind": "transfer_execute_success" + }, + { + "hash": "e1bc61d443caca9aacb7a8fa73fc2baa7b9ee173cecf2772d91f2a4d1d15d62c", + "kind": "transfer_execute_success" + }, + { + "hash": "0d5920e66f95cf80ea649c7eb905595cd459b522e4a731a81f3778dcc625a5fc", + "kind": "transfer_execute_success" + }, + { + "hash": "49fb4683ed4d5697fc95c4d3eb6f73954b971a31f50dd62b67cfa8f65aaea3cf", + "kind": "transfer_execute_success" + }, + { + "hash": "d9bfb8473202b21930ef78a750a2ecc2a556da07a07835d14d1edf916ada6ab5", + "kind": "transfer_execute_success" + }, + { + "hash": "dd00aa4b7cfe84e9bcd539a68029b8dabf72257234e84838077f7ec82be19eb3", + "kind": "transfer_execute_success" + }, + { + "hash": "623b9f4a60c9e165eb59d145aed491ada56d3bd0e7df84ed6060f5b0b89dd6be", + "kind": "transfer_execute_success" + }, + { + "hash": "f7a244b39ee18f6c7049d1c5580cd6c0cc0cbdf00fa7d1cb16cad52c84a172bc", + "kind": "transfer_execute_success" + }, + { + "hash": "53667aa3bd11d3119796f0a72c83db0bec3c3e52c1cc58b15530bfe2caaa5c0a", + "kind": "transfer_execute_success" + }, + { + "hash": "97cbe9954d3b5f1a785edd4c776f51742f7cab05b5d9dc396c67e35bb5f7100d", + "kind": "transfer_execute_success" + }, + { + "hash": "8ce3d7238216a55a8c22045e5bf7c6cca433ba36336fec50eafd09f547c43189", + "kind": "transfer_execute_success" + }, + { + "hash": "eaba5cc31802c73d7c6be17d7dcb3d36231e24d7268e078f40963dfa2693a7d7", + "kind": "transfer_execute_success" + }, + { + "hash": "62f25df0decc99a8f27c8b7f0a9d409d44f0d4b79f671ffdb5edbcc16e9abc5b", + "kind": "transfer_execute_success" + }, + { + "hash": "b9ae7a58db5a1877dd13cb5518693d59626fd229b5f9fdadfd71d86df870f5b4", + "kind": "transfer_execute_success" + }, + { + "hash": "2fdb7ada51d3d0c19eec9acb3a41dc0855118a7364eb515f4c518c019b676226", + "kind": "transfer_execute_success" + }, + { + "hash": "0d67eefba8e91cbc5e06965d440796e213d706d8e87d176c9f8e9b3e1a8ae84c", + "kind": "transfer_execute_success" + }, + { + "hash": "3cc38f9d15bad8d9bf3c7036d2c323e6a219ef8cf6ba246ea4600fa446306321", + "kind": "transfer_execute_success" + }, + { + "hash": "bde8f6ab6ddeeea13962e44662161450aca1303affe69d24c2c6ccd744fa3ec9", + "kind": "transfer_execute_success" + }, + { + "hash": "765525cbc346fbf5d5c8ffd208ebebbc7233f514b31f5a92cef0c860906e44fb", + "kind": "transfer_execute_success" + }, + { + "hash": "e0a05eee524c06b45e36950193cbef87baab916d21062b8d6ef09dac0a89230d", + "kind": "transfer_execute_success" + }, + { + "hash": "6af63ae99528e63067b416b5d58c84541d51266663ef335cfb6a1646fc72e312", + "kind": "transfer_execute_success" + }, + { + "hash": "c05a78eb16ffe377228ffd44dfd3aa5357baa7e02a9c54c1f2cc8629917c91e7", + "kind": "transfer_execute_success" + }, + { + "hash": "3406f088c81b4a108ad073bc981fb3846abc1a67f86f09923ce52bd2efd66ae4", + "kind": "transfer_execute_success" + }, + { + "hash": "a2e81319f8fda76f751626c79de31009e8174b84283b9bd44237d0b2ca7aea1a", + "kind": "transfer_execute_success" + }, + { + "hash": "2afca49a9033308ea789c04c5fae1876d78fda05d6a4b036406f47fd7bf17bc2", + "kind": "transfer_execute_success" + }, + { + "hash": "4caba37a7298ef3be05c50b670fa7ca896c96ba7eabaf6c57e23b67f0238841b", + "kind": "transfer_execute_success" + }, + { + "hash": "48cb95f33d37ef4f3dd134ff2bd62203f084726085751a51f9557a2ae561f923", + "kind": "transfer_execute_success" + }, + { + "hash": "95860bba0ec07b3b41684ad631ede9fa1353d194cebcc49dbfbe06f9a0538263", + "kind": "transfer_execute_success" + }, + { + "hash": "2bacfe1b9c24632c807a0f3e6059647e70f00540199ef4d83543784c0e3a35fc", + "kind": "transfer_execute_success" + }, + { + "hash": "4f9ebfb705fe37a093f1a8686df72d8d9032f0afa0118ba068efa38d408d700e", + "kind": "transfer_execute_success" + }, + { + "hash": "408073b6a16d8d2a72571469df944748e39be3c058f110b5ef1ee28d28857162", + "kind": "transfer_execute_success" + }, + { + "hash": "6413d9789e4b98823708a99fe6b269a8c706618bbc22837940f8bfd800efde29", + "kind": "transfer_execute_success" + }, + { + "hash": "77c80df106655a90dda9bec4b5f4918d2a310b7d983c66a2ab107b9c58e13ce7", + "kind": "transfer_execute_success" + }, + { + "hash": "bcb09c36cf86e208900a1726df7c98f337fc4a3e534d04ccaeaaa696f4c4916e", + "kind": "transfer_execute_success" + }, + { + "hash": "d1be37a7d3315c69cfb903ba95b4dffee6162ab6195c4c05302080f4f475fd45", + "kind": "transfer_execute_success" + }, + { + "hash": "729dbfd40643e7d08929923d84751f3decd5132e553eebfa04d9fb29bf3a1b48", + "kind": "transfer_execute_success" + }, + { + "hash": "4103a2d1fe01f69150d9e8c0abbfab07beefee25bc86d28eee548a34eb624e34", + "kind": "transfer_execute_success" + }, + { + "hash": "9e85f094d5e9cf0f942a79ff11f6b9c53dcb1372869341ffda4c83e8317f7290", + "kind": "transfer_execute_success" + }, + { + "hash": "a095c3bdb3e9b997205aea240e3877accccfabf64a10950bb76eacacf9940808", + "kind": "transfer_execute_success" + }, + { + "hash": "c2b4246147270cfb3c72e7828f5915b4408151dbf99a0b204e4434d2eac74b5f", + "kind": "transfer_execute_success" + }, + { + "hash": "bb3689d1d7f1a09214d4d4cf471a60f2e790e1d4465ad7a4df9c16cf29eb6100", + "kind": "transfer_execute_success" + }, + { + "hash": "c5c5579136fd0c32633606b8d8c3e7e67deff2c87ab396c92e3f4655ed585b93", + "kind": "transfer_execute_success" + }, + { + "hash": "974c89c2acdd83487cb617753d94c8f618d1225bf23f4c286b2cff7c58524809", + "kind": "transfer_execute_success" + }, + { + "hash": "deae8ff29c438c6d68e248b714fc17d11f50b636a489c3747047e2c0e6f30a9a", + "kind": "transfer_execute_success" + }, + { + "hash": "cf5f407e72872f6bd848c2285cf0c5266339e81812eccf40502528e9180335b6", + "kind": "transfer_execute_success" + }, + { + "hash": "e08a33439b03ed1aa88343136a954661d31cec461a5d845f7a5e15c3ded5914e", + "kind": "transfer_execute_success" + }, + { + "hash": "47f7c85c5a9572bd14c918c29d642fa789f3dbebab37dc07398e205c1de0fa5b", + "kind": "transfer_execute_success" + }, + { + "hash": "79af538b95c057731b89bbf9204a33eb7430fde7fb70b4c27f641b7995186b23", + "kind": "transfer_execute_success" + }, + { + "hash": "50d1753e62cca94c940f88ad5c5dc6c66d4036216e412550601dcbe7d93151eb", + "kind": "transfer_execute_success" + }, + { + "hash": "6878d3e4530908ced27f26f8643e22137cf5c82c8cbf8abc11fd581f3f3818c5", + "kind": "transfer_execute_success" + }, + { + "hash": "f7e6afd200d92c542fbef39871059889c34f060c18cd48b79aae4de0b606160c", + "kind": "transfer_execute_success" + }, + { + "hash": "bd68695c26f53803af17a2cb00b2e73fdaef39f5241f3e85c5665112f1e75787", + "kind": "transfer_execute_success" + }, + { + "hash": "c89471b2a53fcf0ebd0d2ee4e3c81e0cffafba180534d0de8a293f6beca3adfc", + "kind": "transfer_execute_success" + }, + { + "hash": "6906015fc5e5dcfdf6250f5f77d7cd626553eca60b9bfd2fcf03938b961e5b25", + "kind": "transfer_execute_success" + }, + { + "hash": "28d18a078d16bba75ede62cfff05e9e219cddf9b9d7b04dc5b0e0cb2fadbbdca", + "kind": "transfer_execute_success" + }, + { + "hash": "3df208610a9dab3c5e9a8ad5dcd9fc008e26cb3a8a8397e1b1ee875252a2a71c", + "kind": "transfer_execute_success" + }, + { + "hash": "593c8833079fd0160ad8e4dda6db978f3beea999a7a6030226d1269750cf8927", + "kind": "transfer_execute_success" + }, + { + "hash": "a935b1388466a8811748b80d8a8b7b1d4054b54ed8ce5722078d6c8ed99221c8", + "kind": "transfer_execute_success" + }, + { + "hash": "7875f3b23b7a5686c4989e716288bac85d3b988230dfd18395c587325598211d", + "kind": "transfer_execute_success" + }, + { + "hash": "5e66a5528073a5f3235fb5a246725683e2ef4599bd87f4c79009a9b68a2a436c", + "kind": "transfer_execute_success" + }, + { + "hash": "0ad0557b15cf5573ecd90f4cd3dcc23af89e76d6c163d795c1d5792189b9967e", + "kind": "transfer_execute_success" + }, + { + "hash": "f6482ad6c4eb03ca159807482e5220c7f98d67b03b30ab28f528e5f1cd20a58d", + "kind": "transfer_execute_success" + }, + { + "hash": "9b7280002d8afea44e32c74904786e973f521f4d18977912ff2ed3895b761ce0", + "kind": "transfer_execute_success" + }, + { + "hash": "4bff31fb3f2b1b7f91d09734ccd5a588a0d3c5361727e300063c2721adfff02e", + "kind": "transfer_execute_success" + }, + { + "hash": "44473cd8f1789e08b5b177feb7ebb7d7a06966a80d8f70882b0cdc4bd53306f2", + "kind": "transfer_execute_success" + }, + { + "hash": "6dbec3bfc9b2d801be02f41d9101ab4ce815eb1ea6558ce8283313f7e6ce36e4", + "kind": "transfer_execute_success" + }, + { + "hash": "0d77421403bbe082760902a9c272a4719540d69b07991164678df54c6d901d68", + "kind": "transfer_execute_success" + }, + { + "hash": "fea7f63fd247d2c4e0a7a8ea023b7606ea95c4a077df1ed0570a417782ffffd7", + "kind": "transfer_execute_success" + }, + { + "hash": "550e59f9b1e718005e63d67150daafae638a3b4c6f0cbdb8e98b90a73200636b", + "kind": "transfer_execute_success" + }, + { + "hash": "bf4a62197da10b07224485a00261fd2d6f9e6f4ad32cb61d1530e2431ecfa1fb", + "kind": "transfer_execute_success" + }, + { + "hash": "f49ea16a340ba21229a47496780bc8c0815a69f346f9a1baccb73b7dc128c904", + "kind": "transfer_execute_success" + }, + { + "hash": "36e69e006929a4cada9b789d2791f030d0729ffd2a6de73de34bdd75b7933b64", + "kind": "transfer_execute_success" + }, + { + "hash": "6438ee8e0b24362008acbaf004ff71802239879b6896e2e3bb11eff64eaeeb37", + "kind": "transfer_execute_success" + }, + { + "hash": "f2504b2bb2990af454d597559fae40c396a19cd17d0101eb71238419c11eb975", + "kind": "transfer_execute_success" + }, + { + "hash": "28141265f06092c76c7287e83bf3e087bb0288229677f06d448ab697046f66cd", + "kind": "transfer_execute_success" + }, + { + "hash": "c8960c7cee84bf3f7596908011d797e5bafabe01c1102a6e7d3b9828ee172aa7", + "kind": "transfer_execute_success" + }, + { + "hash": "ab05c3e2aaed9c6346ac9a22bd84c17aafbf797551b3ef3174acbaf31d42d00e", + "kind": "transfer_execute_success" + }, + { + "hash": "f5f306d56b9c60f816ad83453a9be7918d7f6e19513f01dab2013a116ed2db23", + "kind": "transfer_execute_success" + }, + { + "hash": "4ef525d72e9f772f019b322702dd242fd19eda0df09fc0df2309fb440f0ad0ed", + "kind": "transfer_execute_success" + }, + { + "hash": "2832300bd79aecc88e01235f3b4e09407e03c6afbc585ca4ade6076357f0f424", + "kind": "transfer_execute_success" + }, + { + "hash": "243115cc8d9c7558bb735197f95eddcec73a8ccd0d042874349cb321aac64205", + "kind": "transfer_execute_success" + }, + { + "hash": "16f7a7744b15ee2fff7a015e72e7c53cb405b7b5cd9676cbc6b53d3ffa7318d2", + "kind": "transfer_execute_success" + }, + { + "hash": "64fa55a0e4e27d04c862c1a6872f1c02c296f91ffbd14b4137c8ffb1e2f77d8b", + "kind": "transfer_execute_success" + }, + { + "hash": "6b83b6de7c32be624a9d0c32adf4b08ec589b230fcfd55d7cb590d67208817c5", + "kind": "transfer_execute_success" + }, + { + "hash": "07cbbebdcc8f6d8080c4188f1580a7d414444ebdf0010500e752765b6dabfd1f", + "kind": "transfer_execute_success" + }, + { + "hash": "d4e86b1b9a78640d62d7d0eac98806d5ed20649cdf419720cee5e7ed36fde36e", + "kind": "transfer_execute_success" + }, + { + "hash": "6b653f8fb3c9dbaae2d4988de43b040e271e0ba2ad855af3b9330b343d8364c4", + "kind": "transfer_execute_success" + }, + { + "hash": "09b1ad4baec2295b6ed9dc719f179f126acbc1c19acb3a0ed7f33fafb1bc1b21", + "kind": "transfer_execute_success" + }, + { + "hash": "90094e69836a74f5aaf824b2efc9ef1673b550b4bed41b0f04ebcb0e0509f535", + "kind": "transfer_execute_success" + }, + { + "hash": "eef4c8a7ce68bc598f76ff3b7e615bfc15fbe3a1cbea3f1797d876a1c772f9fa", + "kind": "transfer_execute_success" + }, + { + "hash": "69cf2787dec9bfc20975a1b99ba86c6316cb9aa5e8732b7176f5a9e2c953d8d6", + "kind": "transfer_execute_success" + }, + { + "hash": "6d8d2b478b4404206b8cf16c398ebee7e3a5b05bd1f455a3e7ea28311ce9ede0", + "kind": "transfer_execute_success" + }, + { + "hash": "2c393c126f8a8b55e7c1d7f8b6923f1e0657500bcbcfa2d58f606f1e2c666f2a", + "kind": "transfer_execute_success" + }, + { + "hash": "af9d7351a9522ced89ef5631b542541ff750ed6b3da6a63de4ddcc8550a755bd", + "kind": "transfer_execute_success" + }, + { + "hash": "fefae52039a8f5a9e937de170ed14468f450f6c417029e574ddf77f7ef05fdf7", + "kind": "transfer_execute_success" + }, + { + "hash": "e47db2615e10b4d8a90b02072e509442bd40bc6add83703bc3ce6e0b6a75a8d1", + "kind": "transfer_execute_success" + }, + { + "hash": "b31c7d00d69bb60492e0b6e590592c5cdd520b563a4cc8e11d13947fbb0e78e2", + "kind": "transfer_execute_success" + }, + { + "hash": "9e2008259a97108eeb2027d585c62024a89ff9b11165bf12c3c472b54efca627", + "kind": "transfer_execute_success" + }, + { + "hash": "a90953411221b47440e810f327be9c9f82c8f8a0607eead68e62aa5c6c5c01b5", + "kind": "transfer_execute_success" + }, + { + "hash": "c080103c38169abb3113445c5ed2d412e1a695b1f0663d85fe5537f5d5e094ab", + "kind": "transfer_execute_success" + }, + { + "hash": "9f79fd212bc5e5fa8a6a54c1a4f7fcc4ae043f33d34d27361671db6fec07abc4", + "kind": "transfer_execute_success" + }, + { + "hash": "b2a3e4b4266b89ff13b73e60a0037412c6354d10a8d81171327bfbbd34c76be2", + "kind": "transfer_execute_success" + }, + { + "hash": "720426ee2983fd324233b4d4279c6dae46f562057071f6899269a1e48c6b171e", + "kind": "transfer_execute_success" + }, + { + "hash": "96cfceb9539e23fc677d03d3c1239fe9cd3ea1e3cb789723ca182ef0931b48f6", + "kind": "transfer_execute_success" + }, + { + "hash": "be06dc045d68de6e307156c40ffa4fc196b57dcab1560e6169cb837eebcc3ae0", + "kind": "transfer_execute_success" + }, + { + "hash": "f91bbe0502de7a5df14d8b22819564ef5c0a6a44dab29386463d8b3e9ba9ccac", + "kind": "transfer_execute_success" + }, + { + "hash": "16bb0e4216e8a1114a0feba4cccb7df71c729abde4ba0513789d6b380015b916", + "kind": "transfer_execute_success" + }, + { + "hash": "e6fa9935437c2d99e46fe3b029b6e5899e1d00ec5ccb674e994a969cd0386aba", + "kind": "transfer_execute_success" + }, + { + "hash": "b6a029dfe06f9c237aefb55d6276ed4eb0882a6e4a571a264f946e423f882c2e", + "kind": "transfer_execute_success" + }, + { + "hash": "be4d6451176924dde97d765d4a98e70b68d72a06178cddfe747c32f64ef6f29d", + "kind": "transfer_execute_success" + }, + { + "hash": "7c4ad93888403def2d84396ec1aadaa6c0c1b99ba7ef4d711f5f357d351441e0", + "kind": "transfer_execute_success" + }, + { + "hash": "e9af0a4af84ae0b0b3057f2b7a746ad15cf342e16662d3963d11e605c28014fb", + "kind": "transfer_execute_success" + }, + { + "hash": "25b67a33d9020e49843c4712f279eef4b90e5aa315c398ffea9881c33d8d468b", + "kind": "transfer_execute_success" + }, + { + "hash": "c5bc4b8dbd623be3f3e6d0e3ca72ee974d511da459c8c348aac6215f5d0db12a", + "kind": "transfer_execute_success" + }, + { + "hash": "68658911227fc1c52dd0053a807a18890953f98da75150c8a223780b58a1cb5f", + "kind": "execute_error" + }, + { + "hash": "364f197c04f42475b5ef2bd676ad1451bfa4772fba172f2efc1fd11c8dedf568", + "kind": "execute_error" + }, + { + "hash": "5b0acb61a651a64865427b135d011aa8523795bc79dea3b607aab3c4a80f7d40", + "kind": "execute_error" + }, + { + "hash": "32bc4bc3de5e22b1d8428773c48dc0a23bd0dbe940c3b84c3601d1c739417d93", + "kind": "execute_error" + }, + { + "hash": "c9e9522595c331f291a3ae36de82a1c7c09b269df7fa0f18e1e2a0c01f4eb064", + "kind": "execute_error" + }, + { + "hash": "2c3a15c4d71acacad5d55d588642cc2d5c69fd01964fb00fa5d1bb3b484a6566", + "kind": "execute_error" + }, + { + "hash": "dc0e2551fb55a5d2ce05f76b7d1bebe487c0900d976b4251a4b49e447c5fcb30", + "kind": "execute_error" + }, + { + "hash": "95d6cc96ad9895d2166e39e6c4729e7a366291c3ff22fe0471fa26404f23431e", + "kind": "execute_error" + }, + { + "hash": "d7860c2566f56d8f983d86136071c258a493b25e3b3b2e089284e69d2075889d", + "kind": "execute_error" + }, + { + "hash": "e44e51f62042a2084c742afaa3238e696d3cdcd0d64c6daa931e613b17c6eba3", + "kind": "execute_error" + }, + { + "hash": "996a169c678cae218b590e541c44f4e7c101a403c2ff859ee27b7afe3548a667", + "kind": "execute_error" + }, + { + "hash": "c6d7785024e7a4c51c581ab48cba303337f61845a69babaef4fcff5a641e9db4", + "kind": "execute_error" + }, + { + "hash": "05ec4b7a2ea19e44810d0ae946556906497c86388a1c92d2ba8dc72aa9a1a81c", + "kind": "execute_error" + }, + { + "hash": "a4d1602e235131564295459c9728a8fc94bef59395f9a7081d2e57e04c681ae5", + "kind": "execute_error" + }, + { + "hash": "f50fdc607c1d10b1b48e31aa3ca94cd48b52ecc386033e2e975a9a5bbf95704b", + "kind": "execute_error" + }, + { + "hash": "0c06f9d558ba203975ff8e93813b504a211b229b15b1db927831a8a6b430d5cd", + "kind": "execute_error" + }, + { + "hash": "1109ab32565112a3a50b626430794a2f41addde7fc1930c41d90afbdc1463d3e", + "kind": "execute_error" + }, + { + "hash": "7f53b6b80f5b95af3a20cb8ad3e1006cf871942a01a77f2c66eaaf5807712859", + "kind": "execute_error" + }, + { + "hash": "6f1818c3d5c9be5976622a0a3288e1e0940c04d7979236d0aa25ab98107c54cd", + "kind": "execute_error" + }, + { + "hash": "f7f57c1a8eefb82fe727e3ef608163e9f34373379b63baad4bf48f010af51c1f", + "kind": "execute_error" + }, + { + "hash": "465751f505380bf6b1ea87779bb4f895270e6ed199b31ba4d285c9e6984d8b76", + "kind": "execute_error" + }, + { + "hash": "64002aa624010aa71b46412ecec97239f678c367e1f065d511f28c5f1230773d", + "kind": "execute_error" + }, + { + "hash": "eb30e1e2b36e397272ff32e58c73a3267990913b4329c31c08a83e3e6fdd5e52", + "kind": "execute_error" + }, + { + "hash": "23bbbecf10289988b399e6237b0fdf8fb56a7c688dd8246425a36386e0c5d397", + "kind": "execute_error" + }, + { + "hash": "e0e1343ec7b587ca821ab10b21be86df396ead37f87d82c1924080fe536de5ee", + "kind": "execute_error" + }, + { + "hash": "8f94a6f16f99b6484578d9d71d1687d269bf39c65de41ab25013e8c93793b747", + "kind": "execute_error" + }, + { + "hash": "047a0615ef078e3652f959306dcf7d5d54bdc238417d4b480ddf35e36a92ec7f", + "kind": "execute_error" + }, + { + "hash": "a39d63a12bc3a59bde8c748e6831e30b601619d98eced42c1b6a254e60a57ca2", + "kind": "execute_error" + }, + { + "hash": "cf742432345b55b401f2fad3e629f97b7d5055c94808c066dae68dd48939fadc", + "kind": "execute_error" + }, + { + "hash": "5c527a209c1b8d092abdce2aec486132f5e9f779b3f7a5db20decf64e3352214", + "kind": "execute_error" + }, + { + "hash": "321c0e6d05b0cded89d1c00102d423e5c294ee78f31c303860e20aa246200e26", + "kind": "execute_error" + }, + { + "hash": "108ee39f9186c52360703dbe7f21f4af7a363415dc20fdf549665a9657c2de72", + "kind": "execute_error" + }, + { + "hash": "95c816075c1ce2e0561cf121fc847c12d70e026b4806c002e01bc5988c377cab", + "kind": "execute_error" + }, + { + "hash": "5a04718cb5c266f71cb6653c0aeeb1f98a31b9a1b510ab938a137eb82652fa65", + "kind": "execute_error" + }, + { + "hash": "2ea85583f036d4f9c97d63d355fa0c54a01604a3facc49ccfa8ed64d5dc77702", + "kind": "execute_error" + }, + { + "hash": "5351f56e12d95ebab4b52a9a6588264596f6e49f33950acfeced70ed5b48eb51", + "kind": "execute_error" + }, + { + "hash": "60ba23002d2021d0cb43c67309c71130d6d08eedd2892f5b6219b8e4b1064ea1", + "kind": "execute_error" + }, + { + "hash": "f371954aa0d2ebd436d5642a7ac3b471de575f3ca2be4986306db705183cf434", + "kind": "execute_error" + }, + { + "hash": "3c9c72a923132469cff0f2719839720f78be8fa9c0ccf90c5bf871318e880a2b", + "kind": "execute_error" + }, + { + "hash": "d2101e30351186903a2c7415762d6389f53e166bc6f423f70a67c7e2ffc73056", + "kind": "execute_error" + }, + { + "hash": "7d8bc27982e6b28e9e6e14dc48e926bf2ea393d45761b7bf909742886d100a74", + "kind": "execute_error" + }, + { + "hash": "6c785acdffe0f46a8a84875319a172c0491767fffc7b3c616f33e0665758ce71", + "kind": "execute_error" + }, + { + "hash": "1d1bbab21c5b73c5db1f10b92dbafb586f9ee46eb2432ed2b9599ba850706df1", + "kind": "execute_error" + }, + { + "hash": "187e59a99daebc694eb644d90c6cbfc3352df8236fd37448413a6e58e5e36883", + "kind": "execute_error" + }, + { + "hash": "43e2783b27e6b23f5a22d4accdc5b98e2328db56145a32afcc1a8bb7ca4bb1c2", + "kind": "execute_error" + }, + { + "hash": "82621f96f5d7b888a772cba6d3853881f2b026da623e1fdd6c992090f5147081", + "kind": "execute_error" + }, + { + "hash": "d8350e4693c1f756ba97f8f82f4a77fd3bfecda0a15d48ecd8eaf28fe860fd84", + "kind": "execute_error" + }, + { + "hash": "ec4c4c07b44c368c7b659a033bb2a1c7b46a8bb5346026b88539514368018c13", + "kind": "execute_error" + }, + { + "hash": "81da874cf96d158175600775a1e50ecfb42004e55098f233fd0f14d659861b5e", + "kind": "execute_error" + }, + { + "hash": "cb3b3a3c22aff29d3ae9d3955c144770fd804cda06764ed867daac2d21c3bf2f", + "kind": "execute_error" + }, + { + "hash": "ba580fabdd8e8c122cedade1f3e6beb47b8fa914b5fec312d0f0113cbe0cd05f", + "kind": "execute_error" + }, + { + "hash": "2bbfdb1d64eba529532c4f4ab1c12b6a29904c22da86f00072c195364aa44008", + "kind": "execute_error" + }, + { + "hash": "f3ac00c690e6ee741c48e766dcd25b4b3d140c227f5b8f870dc079b89e141b45", + "kind": "execute_error" + }, + { + "hash": "c509ad240503ba4160000297c5cfd8998918856e120a5c14dc2745c09fe15906", + "kind": "execute_error" + }, + { + "hash": "8d57d02866453741c4850699b4e5cf87a2a5936bfb297852685b4108bc8cff55", + "kind": "execute_error" + }, + { + "hash": "64ccd0c00b89097c82cb58aa6f2107278ea863bbf7b6a69ef867023dd4e94d4e", + "kind": "execute_error" + }, + { + "hash": "07aabe74362bbe6d373fa7eec43b3dad7e4921ced349edff7e10c1f413305271", + "kind": "execute_error" + }, + { + "hash": "f84f6e49bbd0e6a5aa5ea81d2d4a931bcd363b9152c15270695f821ea880d6f3", + "kind": "execute_error" + }, + { + "hash": "3e1d2eefd129f31ba5fcde85cb79a40c9a9b5f66266d36b8d46b257e10feebbc", + "kind": "execute_error" + }, + { + "hash": "d7d6ad5d8c0c9dcc06c8f4d04abc1210f6e091eb11837a32a59da87996c49821", + "kind": "execute_error" + }, + { + "hash": "1b29fec5baa118050da93323f64cd9263e27fda7c29d3f89aaac9a101ea39a55", + "kind": "execute_error" + }, + { + "hash": "d68e03bfc10b902e72a06e8ee002c8f31c3b3e09ae092b83f6ed5cd7dad545f8", + "kind": "execute_error" + }, + { + "hash": "80dfc384788de73980c73f3cde66edf8979ff91eb9025dbc6d8a6189dd93d390", + "kind": "execute_error" + }, + { + "hash": "e036270a2c2c62d9f0858f64b68cb6855bcd41eaa790c124687a3aa615ae382e", + "kind": "execute_error" + }, + { + "hash": "8afc10448ef5acd679668f228eb6673a5762009c180eb7f958030a0cfa39cd45", + "kind": "execute_error" + }, + { + "hash": "143f0a24004295895b108dce6b09ae6be14a592582c5f05131dac25b0d489f26", + "kind": "execute_error" + }, + { + "hash": "50c8b3e089307f5bffe49e51da704a02d085864b4e735f8471ffcd1918ce4eaa", + "kind": "execute_error" + }, + { + "hash": "85ffc7b6fcac6424061286f52d42606ef2c3ce17f04981bed13c28313759d88c", + "kind": "execute_error" + }, + { + "hash": "a6e99e0b9bd168d88b36c4e8ed22527f0b6ffcd5365526234e5f41587688ec9a", + "kind": "execute_error" + }, + { + "hash": "ba8b1a9a0d97681bec688aa5c724dc51e06f722c7cd028c80299643ba9fe9681", + "kind": "execute_error" + }, + { + "hash": "f54584db6c068a3511bf817d711283ecc3290309fd3f55371b18f381a021110f", + "kind": "execute_error" + }, + { + "hash": "da0dab446b1667471e300981e7e059f61c4c290538d502691e730af2ac8136fc", + "kind": "execute_error" + }, + { + "hash": "77c6a7106c8769eea84e7989bc2166c4aa8826e62799534d7ed4944c0d009534", + "kind": "execute_error" + }, + { + "hash": "450bf9091e1ca7c60fe0cd613d81fd722e2e370ab41c90ba7f5b0572c5c50a34", + "kind": "execute_error" + }, + { + "hash": "52f0d8ec4d8500cf70480b9a3ea2acd5f70b79521f5d3866ed62b7c779ca21d2", + "kind": "execute_error" + }, + { + "hash": "e23e9f72e95fccd9d7b0464f7ef929d7c697e2d581f7214b619cdffe83c3ee8f", + "kind": "execute_error" + }, + { + "hash": "37f6b8bc6edc418a2b690595ee8c47b0d699fb7bcb64a105b6177607cc54dc7c", + "kind": "execute_error" + }, + { + "hash": "237d1bc1329afae7b28befaee809021b5da32f3f614f03451e2cf0e625b8bc69", + "kind": "execute_error" + }, + { + "hash": "16236f5213dd9957937ecf2c976c753faf1cc60f051d96408885e0406c57e54c", + "kind": "execute_error" + }, + { + "hash": "94307facd8fd547b7eedba05f9e3590238ca4b1eb5cef732c9d353df69dafba4", + "kind": "execute_error" + }, + { + "hash": "faa28554b420f9567f09a9b55a87d8f4c23f0626def01421847c0a3edd106801", + "kind": "execute_error" + }, + { + "hash": "b2a3d0684f58dfd12856ef9ff21ab76fb5de8ef2d76054ec7c70db55b0347214", + "kind": "execute_error" + }, + { + "hash": "7981d03b225aa410f514eb6ff7de8dfcf919db7f5ae6f307f876a210b26187c5", + "kind": "execute_error" + }, + { + "hash": "3f5313e613e5ce4c78b9d4bbe64e7e7512c82784512f613211fbcb07a924a1e6", + "kind": "execute_success" + }, + { + "hash": "ce08e0a8775e5d27ac6d2f260dd41704140591cebbd85fb1216457227887a0ea", + "kind": "execute_success" + }, + { + "hash": "5e9e2e1e89dea15321e1d18949626ca5b37849bc476008a33fb3499b2eefe941", + "kind": "execute_success" + }, + { + "hash": "87c4f2f1c059dde3fcfefeaad185ff00e1bb2b849c0229b2b4451e45e3f3e32e", + "kind": "execute_success" + }, + { + "hash": "5bf2a0d9276221696e8e2ef77c4ca1c2baaa2e1e023d1cded34dc222863133ed", + "kind": "execute_success" + }, + { + "hash": "00b4cb5240969764754accb7f76bee838fa6133199fb951756215fcca6888175", + "kind": "execute_success" + }, + { + "hash": "0879e4b000e31157049a430236d9e47079d8d58f61547643aa1324659dcc2dcf", + "kind": "execute_success" + }, + { + "hash": "cad31aaecdf7e86c6c0215f49b3745f2e70e7a2742ec54c53e3691fd680fa801", + "kind": "execute_success" + }, + { + "hash": "ba2841b1a4fd3de4a34271c18e8d1b4d8037a8a1ebcbaaf9f07f91dd4cdc0c63", + "kind": "execute_success" + }, + { + "hash": "2b7f6fcf5807dfacf8cc7778707125e3b13d6cdda5148b109fb26bc51d07612d", + "kind": "execute_success" + }, + { + "hash": "21f922769ae663e6fe2a5ef1d4605ff6c412a34bcd3def0241130d1cdbb18031", + "kind": "execute_success" + }, + { + "hash": "01573b6a6b2b9334f6317730f87297725d7e486105e7f8dc78f709a27e4c36ff", + "kind": "execute_success" + }, + { + "hash": "12cdb26c35c9c651d0554d5fb8c170b0411806c8aaa7c714e34e9dc6730307fe", + "kind": "execute_success" + }, + { + "hash": "37b252d1433b54233725177c7d9d4ee087140765d7d25f9629e0c2f9c2549445", + "kind": "execute_success" + }, + { + "hash": "2a5a4a6e3c12b02c5bdc510546ecf60ad974ec245f2d08fb4634a2efd79886fa", + "kind": "execute_success" + }, + { + "hash": "8b465fee2d0bc449cd06217138b885b0fdba30f2d189e939e469e4cb6e093fa9", + "kind": "execute_success" + }, + { + "hash": "0d376b12e4fcbcee69f8f342bdd472a814aaafc1bddfed4dece18c38c221b6a9", + "kind": "execute_success" + }, + { + "hash": "28da81ebbe8f0af35b64e9c3d888cb5bc180153ec30f8ede8abc173a7cc25f21", + "kind": "execute_success" + }, + { + "hash": "68aacdf4c01c86b6cd9ff5b009ccd9f5d5b069675a039ec4511de091178e7dfc", + "kind": "execute_success" + }, + { + "hash": "39f3d5b9e1c1256156d4512002adfb0fa071c4914d18a0f8f3d864aa0fdcc25a", + "kind": "execute_success" + }, + { + "hash": "4714a3c865edfb6c57a32af0174772ad74e80c8626dc91482d67cc3690463063", + "kind": "execute_success" + }, + { + "hash": "14c0225c8640e947515b72c302b51f3544e4dcaf494e68458eba427957da42a3", + "kind": "execute_success" + }, + { + "hash": "88885520d769f2c4f410943787b3f298cf776a8e8403108934dfc6eb27378636", + "kind": "execute_success" + }, + { + "hash": "1596f0a92a0399354a04da54ab5470cf8e90875302b77da260af1585beb6b96e", + "kind": "execute_success" + }, + { + "hash": "13ae20a3a2ce9fc65d53a6ceb319736c9ccfa15478c65bdc6c183d26697312cc", + "kind": "execute_success" + }, + { + "hash": "57f0d7fc8b5c4ebde3a9a14f1f87edcb02d5d09bad4a63295f6257f3afa43e38", + "kind": "execute_success" + }, + { + "hash": "0ecb9dd069b1dee2a5ec26a4f310cda8143f0e11906ffe9f9dbe0dffb179a593", + "kind": "execute_success" + }, + { + "hash": "4d057df4f2020a02a4f58b28d8d1a267bbaceea0c1838790516c69f8944dafe0", + "kind": "execute_success" + }, + { + "hash": "5e064fb0dcd72349cdd77db77b14b83c9c3a2c27f807c2ecee6a801d85665f0a", + "kind": "execute_success" + }, + { + "hash": "288e137f161fd1b9ebf73b27742288cd6d14dcb04a12361b2b2d47a5aa90539e", + "kind": "execute_success" + }, + { + "hash": "451b80c81bc3c4328110b19e785d6c1cd172925280e0a54b2157a01cb8a445e9", + "kind": "execute_success" + }, + { + "hash": "3a8503ee107207791125e78e480bc2ffb4db115d1503508d9a76e5a28ffb7b28", + "kind": "execute_success" + }, + { + "hash": "594aaa755b142d9416820cc6b1f03becd44322dd62ed75eb59a7a32c3175d300", + "kind": "execute_success" + }, + { + "hash": "84f5057bb7d1672909b8a08e2cab0689b76ff7b015438350366161ec9cee2216", + "kind": "execute_success" + }, + { + "hash": "beec3357cf83acfccfbf700dc558f9ae954520bb467f0ce63de11c6cea842e28", + "kind": "execute_success" + }, + { + "hash": "38ef3aafe29642cfb5894903ae7392b8a36afb939c4d5f27bedbf08358bfd3a2", + "kind": "execute_success" + }, + { + "hash": "6f57cc2225a4b35bf2c0b775b3eca7296b3c82268d34504fc73ce3003cbdf15a", + "kind": "execute_success" + }, + { + "hash": "ab7c5ca8ddfa407209dcf060c9bd4869f38842a6a97ecea29b4d216290a550f6", + "kind": "execute_success" + }, + { + "hash": "745d6dccf1b8fc690f7fcddf624ccad2cd8906828f87532f948885d5df2402b2", + "kind": "execute_success" + }, + { + "hash": "7747bbede8fcc9d26171dd31b1902664f7969c17d24914790e16ec9b66fb0830", + "kind": "execute_success" + }, + { + "hash": "52c1d7f0ca46ec97a681a84dd4a8e599961884ebca360a86b208d19d32ca8bd5", + "kind": "execute_success" + }, + { + "hash": "a322933b17f7b4da6a66b56ff2af10859d0a9db2e0c5c276c5ab8c2ebe587749", + "kind": "execute_success" + }, + { + "hash": "8f8a73df1b02fcae889e9a1155a8bb9ff6725b87b027836e8220cc5385a01f32", + "kind": "execute_success" + }, + { + "hash": "81e35599333368cf5eb19f8bfbdb6eb862ec9ca35fa366e8d3a360791145d7ce", + "kind": "execute_success" + }, + { + "hash": "11072fd1958dde56ffb12230de2ffa24672f77e244b21ffebf2d02d7f94b2777", + "kind": "execute_success" + }, + { + "hash": "4134e6825452ee0fe0a361c0c979212465767216e2d25402dd922c3421b895ea", + "kind": "execute_success" + }, + { + "hash": "79a60bedfa3ba8cb83ca2803dd36a8c39e5c5330179c8ef86ddd1724c42b719f", + "kind": "execute_success" + }, + { + "hash": "6ea679903a8ad88adfbdd5713db197a71b3fe88b899aad61ee5ec04fccfb6484", + "kind": "execute_success" + }, + { + "hash": "8a18fd071504bf6fe8f03c913eca12bfdb01a0d7baacea958918af0024dc8c3b", + "kind": "execute_success" + }, + { + "hash": "f4e9533615a51b5d475c7669276da071f72227a5c6353b50dee8d48447ed42d2", + "kind": "execute_success" + }, + { + "hash": "0249ac88277bab224e4ed5ba023720ff966673d24cdf8d27c60129bb51cc4478", + "kind": "execute_success" + }, + { + "hash": "713a0961b48c3b9a5bc38480428b5a380b93581eb0409f48295b28856d6b6767", + "kind": "execute_success" + }, + { + "hash": "49211172b2719cbfd82b5fd04e80da261e7cdfff9e2a66770a84ddae31d1124d", + "kind": "execute_success" + }, + { + "hash": "0d1d542348259bc15153741cdd88cacbf93fd55de2ff302fc63e4284e4dd34e5", + "kind": "execute_success" + }, + { + "hash": "440a5b908ca21ea279d73c15d9cf4ce0b33da24404c5945b4b808b55f0588f7b", + "kind": "execute_success" + }, + { + "hash": "ce3d51cba34a01cbe161719cf7dbe451b661a9a1d555c6b8dcbdf2d015d9348f", + "kind": "execute_success" + }, + { + "hash": "1396cb495d02edd209787c4b0346305026a335be930f10beb14aa456b426b6c4", + "kind": "execute_success" + }, + { + "hash": "a8837e6ae5d34b57ba02663d68a966bf9169a4aeedd984acf915e1b8e41c0b70", + "kind": "execute_success" + }, + { + "hash": "c3c3b770964fc016e049e41bcf3fff0220646554800d444b5c9665da56585a4e", + "kind": "execute_success" + }, + { + "hash": "edd505d65302b04ffacf7094ee9777f8a52570da7a100324855428bcc5e5727b", + "kind": "execute_success" + }, + { + "hash": "b88295e6960e463e83e095acf2be9ce183ec40d5ebd4f3f9578d6fea70c018e6", + "kind": "execute_success" + }, + { + "hash": "b8c9e7ea6758ad8a6ee6dee25f06cce628065663b46c764fb1cf17cd7a1a3595", + "kind": "execute_success" + }, + { + "hash": "c640f8017f6fb0b59aa42727460de41346474ebbd229ea0e79e35b7fc1a681e6", + "kind": "execute_success" + }, + { + "hash": "7ced008107b441f3a64d94e5010de19c5f3707775e85440b690f0aa82659ca39", + "kind": "execute_success" + }, + { + "hash": "91c78e4c9563c61c6c60e1393fd7f235a49556493e4447f00678dd1438f27c22", + "kind": "execute_success" + }, + { + "hash": "234b1d9ad1b79b54603a745f8ebe253f0ed4ea677c6f67bca5fa55d38e5dcec4", + "kind": "execute_success" + }, + { + "hash": "7912040bff6a0bc40e8544a87d0b2ac4c9bc52947fc0951949ee5b6bb2c9f538", + "kind": "execute_success" + }, + { + "hash": "87ff68b61726c2f1cf40f71869dc9e6ecbefcab136ca27130e1f4972a9fcece4", + "kind": "execute_success" + }, + { + "hash": "f8d9a3cebfcb7c6d47a0f9ab77e20548b088d0ec2f151d92182423ca097715af", + "kind": "execute_success" + }, + { + "hash": "520790a1aa521aae44584c5e38d578b1d14011b9d025a5bece5e359bd1ad6941", + "kind": "execute_success" + }, + { + "hash": "518a446a909992d51c075d58d8126182d2ce66f7445017f0a73a174aa203b344", + "kind": "execute_success" + }, + { + "hash": "23f7382b0c716c4fd370ebf675ce15e97cd9c1fb8c0dcc6b3e3529e6cbc1daa9", + "kind": "execute_success" + }, + { + "hash": "fffe99bf4a30fecdea1dc9032f716d00eb0c2feadf66d58850446945dbe27a0d", + "kind": "execute_success" + }, + { + "hash": "cf113161d5ac6b92d7f0a2cb1cd3a5e4a871e4cc71a6850cfeed0abe38260398", + "kind": "execute_success" + }, + { + "hash": "b7ff8370664d9386d2042129f18438955e1bf97a41329b93821ca81115b768fe", + "kind": "execute_success" + }, + { + "hash": "8323ec666a9ab9f1c17dbb2053d05cf2db0ca384934971d5c86654fbe25e513d", + "kind": "execute_success" + }, + { + "hash": "1fb5411505acc370b085aebff707ce18595ae69fa181974437149dec7f935e64", + "kind": "execute_success" + }, + { + "hash": "6f79173ee0214de2f973f24b243cce177a7e3739b7c37b07a8903192f0a7e483", + "kind": "execute_success" + }, + { + "hash": "856e5351ba6cfd612765a5f2e31fe2a4a08821686c0ebc7ada2a77c79414feaa", + "kind": "execute_success" + }, + { + "hash": "5f84b3f5f2b1a4ec79d957c579849079ca40e57563298e93e0b19ddd93cbf060", + "kind": "execute_success" + }, + { + "hash": "f5543a67a94e17a193dff6300f36ade7a8c0f751925d0fcc9fc4471a9c447e8c", + "kind": "execute_success" + }, + { + "hash": "4f1cc43363cac79e72a0e0d0bed14604ce59d8aeae05316b80ba67658a449ef6", + "kind": "execute_success" + }, + { + "hash": "692ea87cd29b39995f984efba1028bbe1fa31cfea0b9599349399739fdd8acbf", + "kind": "execute_success" + }, + { + "hash": "ca1c46c63ea7f88ce711dd6fdcb85c7e5166d45c363fe5d944499f0af517b218", + "kind": "execute_success" + }, + { + "hash": "84d2e8cd9d20fe7d4c801bfa705cd5905733c0046277b47aa2b78c3f0d626148", + "kind": "execute_success" + }, + { + "hash": "6e77bb464a71d266165667aa155577f7a1512cab2bd2a9575f269a6c04780d8d", + "kind": "execute_success" + }, + { + "hash": "ad7a05c62e85411d29a4fd7add3d7d56cf1c60a86135d5b9423e9f5f9c4b2522", + "kind": "execute_success" + }, + { + "hash": "e51010c066309262d979236f63ee6df732e7b9c6e8c469e13fc4b02029da95cd", + "kind": "execute_success" + }, + { + "hash": "184e12a92de73f3f5615e8b11260dd425b0df8ecaf57628141522fd61e01ecfa", + "kind": "execute_success" + }, + { + "hash": "cbad9ec4de1e0e2496ed0517cc625914bd9d9373fb0f3e5da1ba7c070d9781d5", + "kind": "execute_success" + }, + { + "hash": "9208b37cdecc695e1614cdf85fb6d508cb79f7f0ca256ebc50cfd6fef393092a", + "kind": "execute_success" + }, + { + "hash": "699288b94ad996403933a9664911606e9684f85accdf7050bf04fd5a1fcee7cf", + "kind": "execute_success" + }, + { + "hash": "5fe6d8afc11faa8e8281770fd9b32af5112939b319b40c31a3ff01016ea2d54c", + "kind": "execute_success" + }, + { + "hash": "14d141867ac254da39ea33040b9be1c501e417ec342d04fdb07f6658861eef0d", + "kind": "execute_success" + }, + { + "hash": "7389ec25c42ce83515d04e7f9cfa3027b4da0224a9cf27a0cd03aa19e92eb3f9", + "kind": "execute_success" + }, + { + "hash": "920383954433e1cd591abf222cbf867e0bfd289195df4167e6f37661fadb6921", + "kind": "execute_success" + }, + { + "hash": "f921d923ce1b9c5ecd070f647aac9314c636d2e06af47fed695b1f16319eb9b7", + "kind": "execute_success" + }, + { + "hash": "bd7061866312cd613ac6abcb78d02f9401d2e5ffed0962fbc9a123055d32cc51", + "kind": "execute_success" + }, + { + "hash": "a22989df4d75b1d818635f57f78f54f9edf1f3326f12060ee5e50b2bd15f5889", + "kind": "execute_success" + }, + { + "hash": "037c3bea475f1db3ec8f15b8b9aa27caa5fe896dd95f5daa345b13bb22b958ff", + "kind": "execute_success" + }, + { + "hash": "853d43d9c8b6007b112e1b960da6a5a856661537a97a0e7027bb45bf57c3469e", + "kind": "execute_success" + }, + { + "hash": "51285696ce6050a028d4301a9c0e384fbfd6c1fbe14cc1461298c360bf6d0d8b", + "kind": "execute_success" + }, + { + "hash": "ff1e97888638901a8a1e849a88710b5b9d1a5b54fa39a0f8b36a3dccf82cf84f", + "kind": "execute_success" + }, + { + "hash": "11a3a6e7ec50ccc516260c7667e6790a864bfc552734dad8b16f671577fe06e6", + "kind": "execute_success" + }, + { + "hash": "a4b1b36289f1e46e374da85d120a46d92d308e457c5e6820dee7a342a5c297a3", + "kind": "execute_success" + }, + { + "hash": "9b193c2aa3915e6632b43a4137435f9139173f9f59b610907272d99525a9b39b", + "kind": "execute_success" + }, + { + "hash": "dd532a84d89c6919e9843feb510926e82f7082429e769a1a7b3a5b71ca0e924a", + "kind": "execute_success" + }, + { + "hash": "5e7f7cd1597f8c9a21640de3598dd7c5405186207fe2ded31d7a18d668996166", + "kind": "execute_success" + }, + { + "hash": "8e176b24595e58f1da71a22e2caaa56c05b2eb0af0e9d983865128e32c1a6aee", + "kind": "execute_success" + }, + { + "hash": "96b77b96c90ad39e59089463bcd90538edcedb6f131d94f34cb0973956c03d87", + "kind": "execute_success" + }, + { + "hash": "a2ae8f3b43d67ea854c80ff7f9377a1e5fd65a3179637a7c96161fa0daf57afd", + "kind": "execute_success" + }, + { + "hash": "c99defed574a53fee6efe9cd552c42b136e8ff44e252a3dbeb4186f02f4751ee", + "kind": "execute_success" + }, + { + "hash": "d8d71018ba5b3b76dce33dce48311cf0be49c920d34143fcadbb3e1a5133a0ea", + "kind": "execute_success" + }, + { + "hash": "267f3df5c59314c7d1338a342a5d7446f23a2976cbaba3cc557f03e68e179bd3", + "kind": "execute_success" + }, + { + "hash": "3d0035be64dbe34c1e47e4c3654eaca23e3c8d296ebe665fdac119099e253464", + "kind": "execute_success" + }, + { + "hash": "0aa9be4070bf52a7212428bff62534e04011ddf52478efc91974b7be0586849c", + "kind": "execute_success" + }, + { + "hash": "8826ae0775f6109c732f6b3c5cafb8809ad00202f500540be75a7e33a62a111e", + "kind": "execute_success" + }, + { + "hash": "ab49d8c98503ae63cd17e1ad1d9eab0c2458cf36c71dc22e06ba8391fae71066", + "kind": "execute_success" + }, + { + "hash": "225754f540d3e0535c35b5b6e5ac23054aca0ea905e06482734e7e532f5ad466", + "kind": "execute_success" + }, + { + "hash": "1d559e179c5b52521b0d91355501a3d2c1b7c76f7a486eafae5644086db5de81", + "kind": "execute_success" + }, + { + "hash": "9099b8858afa1b14bea1148529c73f56371fc862bd70546e9741a7b598503516", + "kind": "execute_success" + }, + { + "hash": "4854ba83e3b8ec0f8d06d8efe6562b4cc387e401e1182056e21891aa775f6f9d", + "kind": "execute_success" + }, + { + "hash": "67256be803dfc2dde6967902193d2cec908314a6f16572a1c9f5e4c3bdaf2ecd", + "kind": "execute_success" + }, + { + "hash": "6084f142c5cf8b8f526d9a2badafeb5880acaa819d44bfe39ba3cb3800a403e0", + "kind": "execute_success" + }, + { + "hash": "8c95106dff601d25c88695b0e07c1357119789b9cc8a26fb785160622d506c22", + "kind": "execute_success" + }, + { + "hash": "d10c8ee0847b624c688fc8c564f0021fe249f49d4e1d849332b4a8734a66cbae", + "kind": "execute_success" + }, + { + "hash": "84eed5c9fdb94be2d49ce8da92b90c7316c177a81ce0c38cd3eece13095762cf", + "kind": "execute_success" + }, + { + "hash": "99753271d30ae21cb5187551549b61e9e37d9df0678564f36fb57669eba26f6a", + "kind": "execute_success" + }, + { + "hash": "1366cbf2dc7b3cda6f6b688655175f584bed412253efdf3e2d9f3bd20f06392c", + "kind": "execute_success" + }, + { + "hash": "2eacf6effb7eff3d7a4e28d8dba8d4122cd24b84ff1d0ee62628356d8acc4bb1", + "kind": "execute_success" + }, + { + "hash": "0751b500ab6a7e9da4cd78c07744e752a6f47b02a734c2eb6aaf9c3def4ce0f9", + "kind": "execute_success" + }, + { + "hash": "da7929029dc1e031210a8a2034934038e8ee1dc30ff47ec2a02e4a61b0ad9b36", + "kind": "execute_success" + }, + { + "hash": "725886f6ee3c8d957b2b5a51b552fcd30df54f0c4c49ebfd21d3eec8e06e0da7", + "kind": "execute_success" + }, + { + "hash": "ac6fecef971446770cc240320ad49c01c4c56641fcca9ef764469640d604c871", + "kind": "execute_success" + }, + { + "hash": "9fbd9b98d7fd71264f853cc298312c8eee3273264bb1c3bd8aa84669a8ff6b17", + "kind": "execute_success" + }, + { + "hash": "4967f3e6f54b3d3b5a716be60d9a091bf48b9da5357800896c6d1de970a85b59", + "kind": "execute_success" + }, + { + "hash": "ded88d03a7d8681cc502d7f2a542e10ebb927d2427847bb92f6a2df6f618d8ba", + "kind": "execute_success" + }, + { + "hash": "6bf0a734ecf2909155e55509d69f76474d42d950c4e1c2cf0d3b945e436b376f", + "kind": "execute_success" + }, + { + "hash": "7e9de591968679298f4dc4f76af03e0a0524f1a8ce391fdd517d02a520d9b462", + "kind": "execute_success" + }, + { + "hash": "80833b921d919728a9db59bd28817f2d6c7f0aa0e80f6fc50dc0d200a1be4ef2", + "kind": "execute_success" + }, + { + "hash": "9661b6651a7431f62c845cd69492306b41ce7a0b51db8191a39f79f8da6af1b3", + "kind": "execute_success" + }, + { + "hash": "12827356113e7f55dfe8b7dc1889eb327b613142b697b7077153e86558db0aac", + "kind": "execute_success" + }, + { + "hash": "317647239147c14d26de9a35590a55ce9411e58707c2e99abb8d0dfe949ee25d", + "kind": "execute_success" + }, + { + "hash": "12e02d9dd6d9f734e94088997aba59527a694c1ecdd147762559654aebb2a8d3", + "kind": "execute_success" + }, + { + "hash": "9acaf44306bc81ab799e3f15cef131c6757164843a25912cd8f030f95eaffc45", + "kind": "execute_success" + }, + { + "hash": "fc0b99f0aba40cfce7ef72840e38efcb3d6c85fff0387497f2b459a5da422ad5", + "kind": "execute_success" + }, + { + "hash": "8f52b44cb7ee2664fb099c9fad7e664c8666e07e838adf109020c180c92aab50", + "kind": "execute_success" + }, + { + "hash": "6ac2b2cc5a344df7a76fbe5c2c33c348e791e830b0749af530ee5ea1578dbca7", + "kind": "execute_success" + }, + { + "hash": "d0f119cd014f9c8f60b70191a3db1cda3f34c1706be62d2b56a643415848ea45", + "kind": "execute_success" + }, + { + "hash": "aee9a5999ca287ae979c920165830e4b7bac8f3dc563b82c3f855c93087c82fe", + "kind": "execute_success" + }, + { + "hash": "01f31420f861910c38222af742e289224cfd6fdebd9af99cbb791c7483aff7bf", + "kind": "execute_success" + }, + { + "hash": "6f9b83f2d9c855e716afeed8b86d9999b571cc577b36d1ce4c03f4ee4f349bc4", + "kind": "execute_success" + }, + { + "hash": "f10e2f60cb185c8e896541b0eca888d17e28e570333b47283f6d74a54348404e", + "kind": "execute_success" + }, + { + "hash": "22ba322e69b32ac79ff618e348d1ca03ab9891c7bfbdce427e538f0d8c0f9be6", + "kind": "execute_success" + }, + { + "hash": "ae904f40b2a329c5193a48ded1953a6227da85ac31e16894564c77617d4c20e7", + "kind": "execute_success" + }, + { + "hash": "ded8ec07d50df7e8f882492c0525c65dc32cec8906db28f614da203894936cd1", + "kind": "execute_success" + }, + { + "hash": "c049fe78cdd4c8eea49df720d22d0a2f90d9775493b577a04cd3252809583f98", + "kind": "execute_success" + }, + { + "hash": "0b9217ad0ef6fc30be62d28cd0e0431f1ff5844472a5f102b9e8672f05d1db6b", + "kind": "execute_success" + }, + { + "hash": "204f58fd4c7508869645a4ca7185fd9615f6d4b574051e1dd19b9e1c66e69d75", + "kind": "execute_success" + }, + { + "hash": "7f95c6cfe61f84db903a73f18342973072afbf1eb3d73cef3fca451960397451", + "kind": "execute_success" + }, + { + "hash": "17c99ae757775f5b303d0c8ece38cfacef0a99aa49092a03edb3f5177a0232d4", + "kind": "execute_success" + }, + { + "hash": "82f64ad681bfa11b0f6c4f34a3f2670901bd9290e4e635c0812c7faf2c033e51", + "kind": "execute_success" + }, + { + "hash": "998205d38ac6cf708cac963eaf06f9bef3280484137ad182e372c7be121a4200", + "kind": "execute_success" + }, + { + "hash": "fb62960425e6c94d6e74606748336aab84902fd1bb4789844e42571636c32f37", + "kind": "execute_success" + }, + { + "hash": "0cc177a90b9702f97695ab1c95fe83ea7536a537219f577a30dd3df663222e43", + "kind": "execute_success" + }, + { + "hash": "962f7363ef217cb9e4876db5622fe47df7bfaf0f0045dd708ef0c00ef5d9a8ee", + "kind": "execute_success" + }, + { + "hash": "1fc733164667c2e47beddf2ee0d93c4af955dbc7c56eb2255769546f0caacb1e", + "kind": "execute_success" + }, + { + "hash": "d2ec6076e60dc4fb1c1f63e331300dd94d409c37ece6280e8bac41e174653d31", + "kind": "execute_success" + }, + { + "hash": "509f40ec17323e45d2849ebc742b26547155d92c0ed8decc19cd4985c8d99298", + "kind": "execute_success" + }, + { + "hash": "e412ac9d29dbcef26a3ddfb640ce52e609c54288e3cd08da829c90b2b37f0762", + "kind": "execute_success" + }, + { + "hash": "465bfc18410945e625e2425dcf4c306b75b0fea9ba940061d4b3f4dc2dd4b51f", + "kind": "execute_success" + }, + { + "hash": "6a947cc911f9a91a67740d28f8cbbe59d3829a857fd050e696ab92f22249ec37", + "kind": "execute_success" + }, + { + "hash": "ead6c60c217812700caf907f07c072c2f2711184543be3737f1eeead57bf8f2e", + "kind": "execute_success" + }, + { + "hash": "9ea3d988bcff081942af4295866a7bc6c386b410db54f4478d44f2f29ec601fd", + "kind": "execute_success" + }, + { + "hash": "639563b1d7c0e4cdfc16f6a15ba3001289faac08867cd5391d64a85d0c293d26", + "kind": "execute_success" + }, + { + "hash": "2c19e19cdddfd7118181d9f62537612bf2e0822baedfd20d63e858de6bda649e", + "kind": "execute_success" + }, + { + "hash": "bcd8d72d8d00c86e023ee257c5eb5e904a809aa1319f2032c9648137531cf03f", + "kind": "execute_success" + }, + { + "hash": "9eabe94f1b4c043e6b028e23f1854574ecad9bf59f89e86cb7ba6d04a7ab9510", + "kind": "execute_success" + }, + { + "hash": "84b78423640ec193d4021c24a57e001dca5dc7674ed33b1e7e12a7bf1f47889f", + "kind": "execute_success" + }, + { + "hash": "208bbb86cb672983fa9f81e3a29e38f77a5b2ab75064b179166799aa2378b127", + "kind": "execute_success" + }, + { + "hash": "08dec5ed46d198b7dbad8a5707126869950b09b84482a05a566ea4d4bcbd908e", + "kind": "execute_success" + }, + { + "hash": "46314e4ccd6e4faad065f2a2a699914749925443970173fa8c4f5b682e55b9b4", + "kind": "execute_success" + }, + { + "hash": "6816b5345b332f8e5680f28b4bb81b201496ba16ccd21f964f75f0f8cd537dad", + "kind": "execute_success" + }, + { + "hash": "841d8832f1126f65a674e167f03496beb3d804ff29d5acac84ce525a5da9aaf3", + "kind": "execute_success" + }, + { + "hash": "09ca32ba6347d989a10a5f885b8142e05d4ea164c80675f3e25f68ddf5bb77ae", + "kind": "execute_success" + }, + { + "hash": "f419daaa6488401c7816497c5aa7a8ef38f848dec3de9af3ff2ebff7c30ba505", + "kind": "execute_success" + }, + { + "hash": "9cf980902a6fb3bc932358ff290785b0930bdaee045f42a9c7ef77671ca873aa", + "kind": "execute_success" + }, + { + "hash": "46b0c40248cbb1282dd9cd0c769fea0ddce180ccbf53be68a15cdd1dc1e4e305", + "kind": "execute_success" + }, + { + "hash": "15aa8ac789b6a75c21e7fd1a4e4f2b86bd8a5cee821e4819d995e1c8f6294998", + "kind": "execute_success" + }, + { + "hash": "1bdc68fe8f5ce657179057140277a03504f2d78714575668ee633dc1a9673fe1", + "kind": "execute_success" + }, + { + "hash": "ef15dfb8042f872fe11f04334c9308fe8d174d7d1ef4f9fdf93aac520bcdff85", + "kind": "execute_success" + }, + { + "hash": "f1f8ca3a155959e70f84e92439aff8c016012ff8901ec5374b6505a4fc7135c7", + "kind": "execute_success" + }, + { + "hash": "927cd155b2eb13830d5bfb2d68326f63091374f0b605e576cff735faec671fef", + "kind": "execute_success" + }, + { + "hash": "2031f4b91918c7e7105f3be661a7b574fffbb6c9ee3636542a418a2073b8e1a1", + "kind": "execute_success" + }, + { + "hash": "5c4a11c51aa443a930a40f013a853decb8603f7734c671760d526a9fef1bc184", + "kind": "execute_success" + }, + { + "hash": "d94b0b39654e6b917c9f3e95a2aebbd8c0312b7b302a1f325429c6944742bdf0", + "kind": "execute_success" + }, + { + "hash": "39538dd665aa1b2d26b0cb5b3ec6a1de5eb56a6694816d2e3ed82647b527fdcd", + "kind": "execute_success" + }, + { + "hash": "cdab9030af12f70a46e93991e5b6844b7475a8de73dce1936a12647eb8384018", + "kind": "execute_success" + }, + { + "hash": "44cf9af767a5a7d36affc9b8f2ca1cb7114e8d044900e03befabfc2fa7c68092", + "kind": "execute_success" + }, + { + "hash": "4097c8f955059a052479a89f0152d7b0bec5c074fd531becefb658f9b6743da1", + "kind": "execute_success" + }, + { + "hash": "a8e18073c7ec1f1383d1c9d3a7474fd8229bf1d868dacf23bcf2eae3dbfab4cc", + "kind": "execute_success" + }, + { + "hash": "58d0e7be0b6f3e3ac5bdf02ecbc7e87062f801b0ecee2aaba53b292b73efeeaa", + "kind": "execute_success" + }, + { + "hash": "fb5a8d0395f48f800a0182d88890ef44b959f583e3dc96499ba96992c4701053", + "kind": "execute_success" + }, + { + "hash": "102b2842e2935d64a1a9825748d108a8286df2ad5acbe2e22fb78c6ae540d80e", + "kind": "execute_success" + }, + { + "hash": "b7b28b1c9fe37e3d826cfae57f9a36caa1ca4687866e2e74d0ad7aed134ad28d", + "kind": "execute_success" + }, + { + "hash": "c930abd1a462b23c443f700aa6c904dd85fea3e01ecb7ffe9bb925b3480fabad", + "kind": "execute_success" + }, + { + "hash": "4d2db893aa487c19afba95bf7d8986be59c32f60a05fedf85169fdef009323f7", + "kind": "execute_success" + }, + { + "hash": "e801068d2d14e19c88bdd12e448750c625fe09ccbb4ce59babb0a7da870645df", + "kind": "execute_success" + }, + { + "hash": "f9946092db4a197e6b2b82bec889774ba151739452df7203f53e19c91798a20c", + "kind": "execute_success" + }, + { + "hash": "8d2f192139ae71d61ef4951198d469b1f093899385551bc2cde0d581ef9b1fb8", + "kind": "execute_success" + }, + { + "hash": "85aa43da57e2fe1ca7a281a32c8e5f673f28cf59c5c44accf924f69cd4933f2d", + "kind": "execute_success" + }, + { + "hash": "57cf594e2435981b07092612f9a310528fc21ed1030bc3acfd4a496de9a390cd", + "kind": "execute_success" + }, + { + "hash": "9908776dee7aafa946f8080ef961ef2e7da89e6d971765c5f3191283db5c32e2", + "kind": "execute_success" + }, + { + "hash": "b5a238e14f3709432f8feba3db1defaacfe1e986db2ced5184f24c7b1ef0ae60", + "kind": "execute_success" + }, + { + "hash": "1b579c591a1eb65e16cecc8bce08779cfb221bb169abf6544a630aa6ed6ab90f", + "kind": "execute_success" + }, + { + "hash": "bb617e4c753e19bfbb736e17cb0894a8ff1ad35d65eacd08e9d35e4a687b680e", + "kind": "execute_success" + }, + { + "hash": "6dde1388d2595f886cd3682a628d12ac6e958ad186464ca68f621c9bc06a244b", + "kind": "execute_success" + }, + { + "hash": "fa037a8291e81cd741f3d3050dd0509fc84d6d2c25ca0288159b132dfe5d38a3", + "kind": "execute_success" + }, + { + "hash": "33d7de658a56eddb40a4b9768ad15daaee8c42226e5c8b267fcc07695da21e03", + "kind": "execute_success" + }, + { + "hash": "2f9e39943937ee26f5a43f1d9256f4f829f02fa01e5f78402c873fcd6020dd19", + "kind": "execute_success" + }, + { + "hash": "8d95a0b8545068db7da4b2361b6cf6bec7f7015d69b85a4a8a0eb28d4b5eaa69", + "kind": "execute_success" + }, + { + "hash": "fb7b5ba4489ebeab3099d0d168411c0f8d37e61c4518f96134e0972b5d08b81e", + "kind": "execute_success" + }, + { + "hash": "9f495a3c70f51bc2e353850e857d7b2d12b341b653b8c0d4be671fcd8998bcd0", + "kind": "execute_success" + }, + { + "hash": "4bde8c35db8c55b1715d0f81113e4982e635bf64bea73eb5a5fd112338045e22", + "kind": "execute_success" + }, + { + "hash": "a3783be8539c95a532db05c649edf42e13b9f6dce0d9a303d6961b318abd3756", + "kind": "execute_success" + }, + { + "hash": "02bc72feabca752a7fa96201fd25aba86b92b129b1b72c168725c7354f14e8d6", + "kind": "execute_success" + }, + { + "hash": "231089fbe646d9e3d2c18dbd4a153aa73aa77e78e79638e4427d50fc9a121edf", + "kind": "execute_success" + }, + { + "hash": "da01b719b563f4f80c967fa44715f02b3b815696ca5f22d60012cb43b440b99b", + "kind": "execute_success" + }, + { + "hash": "3a126809e4c85a0f85a9d778ddcbee6f96f210313791dfebde13c71cb2889250", + "kind": "execute_success" + }, + { + "hash": "bc6d1410419a9acdaebff6c0c522dde50bdbf4c2d3452cd0ad4fc972543d7b98", + "kind": "execute_success" + }, + { + "hash": "c5abaa50b377a2ddb58ec049f3864d3e66577adf1ea1f17687b0282ac1d4e6e1", + "kind": "execute_success" + }, + { + "hash": "ca76e5c014d9fcb304790ed1e192bb12630dbcae53179697a0c19ba1d195a823", + "kind": "execute_success" + }, + { + "hash": "e8ca115b2163376a0dc074e73013012cd026275f481fe8e1004c43222724aef1", + "kind": "execute_success" + }, + { + "hash": "7612652776cea551f7755f2e11b042c945ecaa5a342cd81033a6751e11165cb7", + "kind": "execute_success" + }, + { + "hash": "43b9c772c2f944c830a4fd8ad07209a79b680786d81c2cd3af75041b1c28659d", + "kind": "execute_success" + }, + { + "hash": "a3a0f596436bd2872f1dc2302bf20d35c3b42dae8e448908933468e39cd1c298", + "kind": "execute_success" + }, + { + "hash": "14cf4daa1a44ade401b360bc615486b58e44e54300766bdfd8196e836f57714f", + "kind": "execute_success" + }, + { + "hash": "fc9ebc881fa74aa7a1f3a88b0903e5d51057f4fa309958fb395bf9f0ecc55fdc", + "kind": "execute_success" + }, + { + "hash": "e9b0c822bf142bea3b7b87415e7705f163437eb1a1f1560380b3a7357b1eb9a9", + "kind": "execute_success" + }, + { + "hash": "458c753639948cdeb72f0b445a06f724df30ca989e8f8eee74bf81d8addc691d", + "kind": "execute_success" + }, + { + "hash": "df1cda7753276d601db680e6f47ace122c37d2ea2005eaa587f19701fb7dfb8e", + "kind": "execute_success" + }, + { + "hash": "90919de1295673b194ee7be3ad5f7d3bb6077c4fa653fa7eb398ea6a74986ca3", + "kind": "execute_success" + }, + { + "hash": "125724d7413a6c2f4f603f2120575a385410258650ce7cf01a4f717c9b274682", + "kind": "execute_success" + }, + { + "hash": "11cac22cd3bf76b0c28737d4a97935e88f359b8ba140d99805f85e1abd44036f", + "kind": "execute_success" + }, + { + "hash": "97d7760df5952e2e4b7464a60310b6c92f30144a2e0e2f4652f8511e98b63175", + "kind": "execute_success" + }, + { + "hash": "c2e11f452513e00ecfc78aa935191f0ef9e853913230f1fc34413a059d461c74", + "kind": "execute_success" + }, + { + "hash": "60a0c91c48c595bc66ddf5478af3aff95ce7612deb15006648b39a358d83306d", + "kind": "execute_success" + }, + { + "hash": "99be64d31da1919fa8538fd9ae1245a0c8a928c93077ef257b4690b057fb1f36", + "kind": "execute_success" + }, + { + "hash": "0389574c3a2200dfebbecb2f3ca1f471f0d794088dc136aa49b82eae2e957c44", + "kind": "execute_success" + }, + { + "hash": "2882764f68379a45fb37a3af84dafb0d2a5359d48518a975c28c260f7cd60094", + "kind": "execute_success" + }, + { + "hash": "e771ff38c68ca1bc174de3407e7238e59bbccdb26a9ae9da442dda1576b1d80c", + "kind": "transfer_execute_error" + }, + { + "hash": "7dab019cf1889e8b74a1290da91f6718b34b07023732cee95bc20735c4f58fb0", + "kind": "transfer_execute_error" + }, + { + "hash": "df06fb0ec6edd644f4ff7a4d521532e15a8dcb8579e0ac48c57db2ac7bbeb2aa", + "kind": "transfer_execute_error" + }, + { + "hash": "464eaff02d5c59b96024bc0313366ef8755f2a8b749394fbff696c6a768bad44", + "kind": "transfer_execute_error" + }, + { + "hash": "0c6591569ab4d58e21eb32e88dd11f076e3b8f16705ceb5731e77c10c7285a17", + "kind": "transfer_execute_error" + }, + { + "hash": "1847c5bcc2f897f088959cdd44c1fe9ed7f7b7f687f09734144a61f6a12b545a", + "kind": "transfer_execute_error" + }, + { + "hash": "c2faf8a694c50fa436fdad6df35b3e5b41161c1ac5924923aae74b6774c0f5b8", + "kind": "transfer_execute_error" + }, + { + "hash": "214309173c687c093b29c93dd26e06cf8203a38eaa40c8cb7cbe1d429a9ef861", + "kind": "transfer_execute_error" + }, + { + "hash": "1e0c780d04acaea325e1700e244989816fe97f819b6d59c3ed1f4ccca0909005", + "kind": "transfer_execute_error" + }, + { + "hash": "497f3c0bc83f449934c5f6d27f3d6ffa5ca4052df73b96d950942cb4c9fc36ae", + "kind": "transfer_execute_error" + }, + { + "hash": "35e15668aabb562e92243c9195a69240339f2a90a39d4e0ff7916f02ee9325a4", + "kind": "transfer_execute_error" + }, + { + "hash": "86be010ab6922970832cace656aa90687ef24feaec8b8e2a432b9746a14ac3cb", + "kind": "transfer_execute_error" + }, + { + "hash": "363c37ecc86f758d33fe29f08d0feb04b5c194e40334d3f5e03231ae5c9ce94c", + "kind": "transfer_execute_error" + }, + { + "hash": "75fe8f706d73a8db4cf7b5ea63c771f16f2c15b3f9c15f23291d472c0d9d5bad", + "kind": "transfer_execute_error" + }, + { + "hash": "2a64caa54530ad14cfc5b7aa02c5c6bca7ad4389771cef315538c9ac68e02d83", + "kind": "transfer_execute_error" + }, + { + "hash": "1615a2cdb634a8d5a43dd52054d7b491ed219047c3a58ce1256d27a981a9387b", + "kind": "transfer_execute_error" + }, + { + "hash": "eb0b83aba35161521027fd525f1f60400a78af05de2f6561345f89b67dd26255", + "kind": "transfer_execute_error" + }, + { + "hash": "4055548c87f5865ee06c540d8e85bee0205c31259b5a944ed899a335d0539d29", + "kind": "transfer_execute_error" + }, + { + "hash": "542f1f3c5ed5d47c894220cb2e45b3599c9e65b9f3b2414bafb13916913a9527", + "kind": "transfer_execute_error" + }, + { + "hash": "77e44a654c45e46d6b9491b2a1c18cef44be53f7ffaee39cd6d9de862ad38bfe", + "kind": "transfer_execute_error" + }, + { + "hash": "d815e7bde4e1774886009692a1c2d92c25c8c9c2a7d6a711677fe11298313887", + "kind": "transfer_execute_error" + }, + { + "hash": "f9500483fbc9b4520acdc9e1a7f36fa63746c475b2f4001d91296ee1c5b0ad72", + "kind": "transfer_execute_error" + }, + { + "hash": "5a3e25777291543b2e437b1ac8ba9b667a42dd71936137239baf37edc9494647", + "kind": "transfer_execute_error" + }, + { + "hash": "8c17f79b4a2a1b44476546f225536a1d77f18000e17ddbacb5fd015d33eaa45a", + "kind": "transfer_execute_error" + }, + { + "hash": "05164157ff10aaefe941acb42ea08f27a88cd200925b052d33dcbdae086c18cd", + "kind": "transfer_execute_error" + }, + { + "hash": "48055f7974a3fa1c8c98551caa21ea1861a200964a772012b07e357ba406fd02", + "kind": "transfer_execute_error" + }, + { + "hash": "b3111c3c794fa98cff161442068de2be88b600b1b68e9c75fb2a74b128c08b9a", + "kind": "transfer_execute_error" + }, + { + "hash": "1115321328dec39aebb3fbce1a6614a66d4a4449abc6e88bc1716571bbd3fb36", + "kind": "transfer_execute_error" + }, + { + "hash": "6ba2cd0213960b4be4982a7ce425a86e73f85827fc41c13415850ed4ae0a4e90", + "kind": "transfer_execute_error" + }, + { + "hash": "4ab60d57a9bb93c9f8b246436107bb4de75d680c026cc5fc737e6cd6de4b4423", + "kind": "transfer_execute_error" + }, + { + "hash": "072efd29bc10b419be0c8ed7511ca2af822a07dd73845ee2c836c35e3468965a", + "kind": "transfer_execute_error" + }, + { + "hash": "80940d21289ad350876a09dd5d16114a345f726b54fa327864a4d168ac1cd08a", + "kind": "transfer_execute_error" + }, + { + "hash": "18c7637df2b6e82a770b19fb574a0220cb37fd2cb05069721306c5b573f3230c", + "kind": "transfer_execute_error" + }, + { + "hash": "a35d2cd2d22f32d0c70d616fc76c57e559f728e4c5bb70d62aef4cc3e54444dd", + "kind": "transfer_execute_error" + }, + { + "hash": "32c1353b386fec17716b368a7914f69e12b7859a5d861a3a5209eb3cc71a95fc", + "kind": "transfer_execute_error" + }, + { + "hash": "cc68284f250aa26ce06f000e771327d864a7fab2784043b522d83bb753e907ef", + "kind": "transfer_execute_error" + }, + { + "hash": "17d4a956ce5138249e3992912b554bd468cee4312b5dfe5016ab3b6305cbb80e", + "kind": "transfer_execute_error" + }, + { + "hash": "3a80361b1f7bad7394b770831adb148a27e16fe325a7e5774db488aceb52cbba", + "kind": "transfer_execute_error" + }, + { + "hash": "0be26632ec0d99deea4eadb246487c57a913beb7f780fa6938901cd8dd8f142c", + "kind": "transfer_execute_error" + }, + { + "hash": "847f0055d46716582ec6682ec7756efe3f466c09715ce8d805ebdd3370e303ef", + "kind": "transfer_execute_error" + }, + { + "hash": "1c3748728176ae920fe0f4d173163ab7312ca0c2ceb14aadd0984ce40ece30f7", + "kind": "transfer_execute_error" + }, + { + "hash": "01aef10a774f2e127b773ede4946639026c10394087eaf87f9394710151da4c2", + "kind": "transfer_execute_error" + }, + { + "hash": "7295a22c075b13f68c7b36a35c4f8d50adc49afd6c20dafcd5d7ab384d2c0a6f", + "kind": "transfer_execute_error" + }, + { + "hash": "4779e595def48c6aba1aa8f1af31dc36ee0dd4b36aa5fa68af72aa8dbb2db496", + "kind": "transfer_execute_error" + }, + { + "hash": "ca67ad2c4254f0e1a2679c2a54f0be99df665d5f61acd16ed7f15a7af5cf414c", + "kind": "transfer_execute_error" + }, + { + "hash": "1cc3d28e300176b9ae019757ae7e90c8197308ed81432754a70af77526cbde44", + "kind": "transfer_execute_error" + }, + { + "hash": "84e0a1764e4d5ca0845939192925f8a6feb958271368788462f5a2ec24cf7e56", + "kind": "transfer_execute_error" + }, + { + "hash": "b2b2cc8341a30ae750fbc00de6f282d8fb9bd670f2c1e29e3384781aa8cbfc8f", + "kind": "transfer_execute_error" + }, + { + "hash": "a42ded352e1639c1de9afdc3f7a1107a607c8fbb5059d05594719c437e4fc53a", + "kind": "transfer_execute_error" + }, + { + "hash": "1b3d07cd6dbe182703eee4c7af353b2af75a9d5aeac06d8a7737738120c9a255", + "kind": "transfer_execute_error" + }, + { + "hash": "729396ea0749d5611a5aaf93c9f9c9b44e6f39b896f0487fd19b87ef478217e0", + "kind": "transfer_execute_error" + }, + { + "hash": "145dfe6ca88e22c01950537dd2a64374d659d9d628a69ad346087a284602bf8e", + "kind": "transfer_execute_error" + }, + { + "hash": "d25593c277db2c1b43638ab403daf78c515b3d1bcc377fcb1238be47b93f3d2b", + "kind": "transfer_execute_error" + }, + { + "hash": "11bc95c1e1567095393b3e823399d53f1607ed823f60e7972f45e31224d0a1ad", + "kind": "transfer_execute_error" + }, + { + "hash": "0d911370b0d90a58c618b7f84dd8f168afe34e0b920de93d55af4976f6b965d0", + "kind": "transfer_execute_error" + }, + { + "hash": "a325c9be14c9243efbe849dde4f8d46a14ca573a1546b5162763bb8ffe4e7551", + "kind": "transfer_execute_error" + }, + { + "hash": "d3224e14c161d5f1b617441ec49c2937190da2a71fb24854d6df3345272ec9b8", + "kind": "transfer_execute_error" + }, + { + "hash": "2dc8ff0f993a105cfd17395cf1fb48776f8ee5d81d335c9ceaafea7963c0934e", + "kind": "transfer_execute_error" + }, + { + "hash": "2c419e9088d4e5edebe05b9319a1352f948821446784b2db3f11535b244e6cbe", + "kind": "transfer_execute_error" + }, + { + "hash": "edaa73e055a5164198153ae79b509a280fc8c86ac63e299bb819cb5c16ea77a9", + "kind": "transfer_execute_error" + }, + { + "hash": "036945479cf593412a6926837e0a719c7650f0e9443f1c53285450bcbd0fedde", + "kind": "transfer_execute_error" + }, + { + "hash": "21ab4e2550108e996055c286e97aca73ddd70c1b7dd026716e1c725cfe142053", + "kind": "transfer_execute_error" + }, + { + "hash": "e1829f5ab0355761158d19772b420b144dcf4f887cae9fa78825f1b84c6985b3", + "kind": "transfer_execute_error" + }, + { + "hash": "29e6b96dff6065d867f81c755961f0fd5774593e59282f5eee5b69bc002aaf85", + "kind": "transfer_execute_error" + }, + { + "hash": "18a72662a657dd10805d618d38e4365414c3fde6a6f15ee10a76e0866b5577e9", + "kind": "transfer_execute_error" + }, + { + "hash": "34b73f9ddd19e5db4e99bdddbb57416f4c9463c0f1515959740e26ff45869f7b", + "kind": "transfer_execute_error" + }, + { + "hash": "8693f97dd7d435f5237a6b8f4acbf2077ef8da9029ed1ed6ead95d06412eb8e8", + "kind": "transfer_execute_error" + }, + { + "hash": "fc72fb486c4d853ad1e84002a5d724286e6737f94e78ece4b8263b907aa49237", + "kind": "relayed_success" + }, + { + "hash": "e3aa8f86a391d143f3369433c2323886350cdcb9885c0595d4a3c9deab4699e0", + "kind": "relayed_success" + }, + { + "hash": "e65404fa7485397be9f882458e2c252194a17699015dc1104f1bd6399760c126", + "kind": "relayed_success" + }, + { + "hash": "a019f0e00f9ddbdd21667ee10effedd3071e32584bfb6e2021fe49c5a0308808", + "kind": "relayed_success" + }, + { + "hash": "67063bba38d67622463c435c238f686bdf57cf1b67168784a54e9db2bb28ddf6", + "kind": "relayed_success" + }, + { + "hash": "e147f2873881d375894abba391c9427bca8615bd6a55116f1c82f15c3b782632", + "kind": "relayed_success" + }, + { + "hash": "f0c9c3b2a6b89feae2a1a6af30ae9b688523ff660a6813839e1c53a3fff32c97", + "kind": "relayed_success" + }, + { + "hash": "e39fe0f204fc92070e780f0e4c148310ff174d9e4994e5a5f79ada5e2b7bb56f", + "kind": "relayed_success" + }, + { + "hash": "a2765478d558d84eb6cb6bd70cef1f19fc6df8506f60654bc2f19d01f54fe3b3", + "kind": "relayed_success" + }, + { + "hash": "230d6117f14b13f2a8123e0e9d71fa9650dd1860391640278e086cdd605404d3", + "kind": "relayed_success" + }, + { + "hash": "a5c740fef53b5171d236502495967b22a0160034f64b286747f44b3a55b08d9a", + "kind": "relayed_success" + }, + { + "hash": "58d6aa1c8380e8a7eeba87182a91349e7f73df14267baec7b99cce374667cf84", + "kind": "relayed_success" + }, + { + "hash": "4d68d3565dc8c3b0273057a7ad7315489969765faea8cd850867ae9244c527d7", + "kind": "relayed_success" + }, + { + "hash": "abf613ccf96f5d5be8eb397641ab14811920b2520a47bc69ced36c3c0b8e5422", + "kind": "relayed_success" + }, + { + "hash": "1af100c24e7020f2de08e7b499e3d5dcf1780b5ae4ed99ef6ab0d1440fda8417", + "kind": "relayed_success" + }, + { + "hash": "1f0195eb548d15103cac95f39a9eabfe262ed72d2be31acb0a0e0989751e8dac", + "kind": "relayed_success" + }, + { + "hash": "0026fbcd73c8070055e0eaf4c60620ed72c0654f7176b1529b08c086c88562c8", + "kind": "relayed_success" + }, + { + "hash": "f23223e81e710b06adc1f834c3d07d94f9b142282a11bbe52972a69bb068026d", + "kind": "relayed_success" + }, + { + "hash": "987552808e62a9d425a31b1ca7219d33b1889810ad4d59f423e0d868d8df675b", + "kind": "relayed_success" + }, + { + "hash": "6fe119e33bdb5bda974af41dc81eb27604e24d4153f9e73f0b570a89c5625608", + "kind": "relayed_success" + }, + { + "hash": "ade508fa7c63ec8be23510b6413c72e259f65586e479bc48104aebe2e1a610f0", + "kind": "relayed_success" + }, + { + "hash": "f23f3f3e0dee8227bf980c816694c8d540b99e02a15b72b814b5d175915985ee", + "kind": "relayed_success" + }, + { + "hash": "809169382b86753192aa65ec05f9aa233e2870344f2c90ebcb8b389a9bf74063", + "kind": "relayed_success" + }, + { + "hash": "05c42d10f315b72fc256a64901d16abe418e8734265b6fdc366085ae7173835b", + "kind": "relayed_success" + }, + { + "hash": "67cfc6a788d0db4b4fa5e6cd54598903130e7359d80850c901f4f4829252fd3f", + "kind": "relayed_success" + }, + { + "hash": "0aa05e872b2bd5b66573f5c4736e8ad6339ae0853ecb9b59365dccc49519b3f7", + "kind": "relayed_success" + }, + { + "hash": "5efd39f70bb0b4f28c687d36789eb5394b0980c016c884cb2db2af0be957bfe8", + "kind": "relayed_success" + }, + { + "hash": "4e81d2c973b9312c34fd1cd9accdd6971e8b4e47ee185c6a53112fd07bc97722", + "kind": "relayed_success" + }, + { + "hash": "f4f716264c38c0a92d877a4048bf5920f391a12990a9bf0649299b16b35b38a6", + "kind": "relayed_success" + }, + { + "hash": "0b5da1e8846036c1b675d99aa0ea22079a21f1376704d7289f136b2d221f2f9d", + "kind": "relayed_success" + }, + { + "hash": "763bff18415369a67848c93baa4096df99ddbf40f6ba8d18cd42d195b572e979", + "kind": "relayed_success" + }, + { + "hash": "49589905e79224d84e83ee1de9a5171ab6975abf560f332710524fbcb34be1ec", + "kind": "relayed_success" + }, + { + "hash": "fd80a8ed81cbbb77190dd8f864b78fa58fcee2f9b1b1de7f588b7bec9955a82b", + "kind": "relayed_success" + }, + { + "hash": "6478c206b6cb507773a5ba950b460d4e6e4e4a61e27b054e7a0842fabead77b0", + "kind": "relayed_success" + }, + { + "hash": "77570e866090af0aad89e81a748e090790d68a8d54128f1b0fa8da6c23ebfd3e", + "kind": "relayed_success" + }, + { + "hash": "e92e95a12fc66057ce13b7759d0a5a7fc9ba2d6e86a8ca2ed1b667c78b46cce4", + "kind": "relayed_success" + }, + { + "hash": "cac6d26cc0c5d75e52c5bf44c431a3e0aac293812696735e968d8322f622c1a4", + "kind": "relayed_success" + }, + { + "hash": "e820de636cbaea5bb83714f0640e897643b023591262dec79cb0682ef21f7983", + "kind": "relayed_success" + }, + { + "hash": "f9a57fa485ab562c00ed7059b5a5cc9b80e8760c5ecf6419c288a11d545d5f93", + "kind": "relayed_success" + }, + { + "hash": "9b8b88d7dda4b14bbe56529b4515cc33720e1acce37319574bb7794af8f1307a", + "kind": "relayed_success" + }, + { + "hash": "48f4a68ae596917ef48fc15cf2ff5407922449918cd66356d2cd94686f84a2be", + "kind": "relayed_success" + }, + { + "hash": "e1b311befa36d689dfdefa071013d6c6a4b7beadcc8d28c9dddeec472044f210", + "kind": "relayed_success" + }, + { + "hash": "54f1cd16561adf8b948fddd790d2cbfe4bc92cb7092fa91ed2da4ca96f1b1f9a", + "kind": "relayed_success" + }, + { + "hash": "eaca9a37acb2d1bab91f3e778a2abb50d845de93d55082e446abc63e19f553e4", + "kind": "relayed_success" + }, + { + "hash": "d0af37fb8940fb8093e231dfd2262c974c024832dad16866991a72be6c05b5a8", + "kind": "relayed_success" + }, + { + "hash": "810b125aa7122b96e55a82bac9393f8d0ed67afd6df5f69533469f84f6e4441b", + "kind": "relayed_success" + }, + { + "hash": "dd7e3f14d0ee9ad409a44a461b069b67760f62a9fdb8088ec3c239de24b7fae5", + "kind": "relayed_success" + }, + { + "hash": "9551ff32ae46243e7ca9911755a6141b6fef407a11a9fed4ad3a615158adc2ec", + "kind": "relayed_success" + }, + { + "hash": "2553712a7b9588ee3ddce638b532c8ad1d4ea696be067baed62ff6b2bd10b543", + "kind": "relayed_success" + }, + { + "hash": "e832eea5e2e113ee6d2bb52ca64dcc2c62388ba32ded73d7e9672a95dd7a292c", + "kind": "relayed_success" + }, + { + "hash": "afa29b4e64f242c50aa1039995927daa440ada1f7add54e1e1374d4ffe27ab5a", + "kind": "transfer_execute_success" + }, + { + "hash": "f13eca4579906121bd1f42f9af156f8d6c1f3b298c0fe9c2741dd55bd6b50fc2", + "kind": "transfer_execute_success" + }, + { + "hash": "304cb2910d0bc42e4e54f478e89889a3ae604fe801528273ba57d32e2c146234", + "kind": "transfer_execute_success" + }, + { + "hash": "82f22abd9f870267d93920453c98215e554f64b0d0c75079dffb7a2b500ba2ae", + "kind": "transfer_execute_success" + }, + { + "hash": "dc37c539aa41ceae817f7c94447af6a1f14bb1d13e89fc017b0b8079cbd18a5b", + "kind": "transfer_execute_success" + }, + { + "hash": "186619587dcdb13d8e59c1be35feaf21172c48573d46c9476a3a0046db1ef416", + "kind": "transfer_execute_success" + }, + { + "hash": "88b79025ce5ef9e1819285ec7cac4474410d5d254b25a56659de73ecf214ade9", + "kind": "transfer_execute_success" + }, + { + "hash": "15735d390ac560399cc1955fa5f46e86da8cee5330c6ada4b5913b8a137380b2", + "kind": "transfer_execute_success" + }, + { + "hash": "30c8fc8761fafa5ee56ecbbaf7237858cc1d9817f6fab91b4d7aac4b7b13d60a", + "kind": "transfer_execute_success" + }, + { + "hash": "b367de607022ff07edd59ac9b30e641612f0f847351864da5b5608fb90cbb94b", + "kind": "transfer_execute_success" + }, + { + "hash": "7bdc382b80fec6a27755a659972915c51b221adbc3f180ac8286eb751aded42f", + "kind": "transfer_execute_success" + }, + { + "hash": "bec3ec3fc9ffe1ea6012472e5e72bb96019a94d8724ff7f1c697961aacd9d8c3", + "kind": "transfer_execute_success" + }, + { + "hash": "1e230e3d957d211b2ad6cdd0be3e851621a410785212be0911cf90ea48a3ce0b", + "kind": "transfer_execute_success" + }, + { + "hash": "8e273bf2fc937c1ee2a109c4152bcc03cd632a378e3013ba81c33b6a7be030bc", + "kind": "transfer_execute_success" + }, + { + "hash": "6fea466831b9453dc933dcc069042cfb30b5f98d13133c92021e9c74a2319d02", + "kind": "transfer_execute_success" + }, + { + "hash": "407916af02376dfd8571f50f10a563a9695bfca9c280905079680e41c7c1d35a", + "kind": "transfer_execute_success" + }, + { + "hash": "570139259e016ddedc2f2af2ec31ef144bc6bccdf21d673fda5f930813d09757", + "kind": "transfer_execute_success" + }, + { + "hash": "4aeb9d3c0f6384ba7965cee7d755920cff076b74a9d182cc1c98814280e93787", + "kind": "transfer_execute_success" + }, + { + "hash": "aefc8131ba26be3ec9ff944ef553134975027ca9201a8b2558b51fbd584ab0fb", + "kind": "transfer_execute_success" + }, + { + "hash": "dcb675493227af7e8312e8db59dd0fef882116132feb70e4003f3451825ce2b3", + "kind": "transfer_execute_success" + }, + { + "hash": "3df55b3110be43767f617657f6bf31a4774e39098f772f783f2ee57da899f025", + "kind": "transfer_execute_success" + }, + { + "hash": "3dd9ccecf3a19bdd5d7fb1e0e7a5a6dc0cca6fe932eaed8fa296d738666cab46", + "kind": "transfer_execute_success" + }, + { + "hash": "85e690a45cba87bd62a1963789135efc539942d4af0d99e685ef3388bc917f8a", + "kind": "transfer_execute_success" + }, + { + "hash": "b72dc665dab6781de93542694ffb37fb30364b2b879aeb26ca2f95fb3cf1020a", + "kind": "transfer_execute_success" + }, + { + "hash": "7ae20145382a8d6df31a110b6818c0120a43d3f7ce6b3860c436740455e034b9", + "kind": "transfer_execute_success" + }, + { + "hash": "141eaa1edc46471e83fe0a8b19c1f48d2f1824b2015897e9c36423584b401457", + "kind": "transfer_execute_success" + }, + { + "hash": "7479d7a75569d16eab319269e1fd10d58543606d00c131ca55e394d6cc4737e0", + "kind": "transfer_execute_success" + }, + { + "hash": "84c0586c551fbe82a6a5735d865821aa11ea4d4b8ab90a8c8737a72917b29ed5", + "kind": "transfer_execute_success" + }, + { + "hash": "fa47dcfa27822d363f4656f22c97c4177bbd9c33228c9ddb528e7b1167655e22", + "kind": "transfer_execute_success" + }, + { + "hash": "4749575a8a2a46c8ccbf74baff77ff85537f05ff51831a1e2b374be00348e490", + "kind": "transfer_execute_success" + }, + { + "hash": "c742033e774147d7e6e5165d8e862a006791ec68a1a5598f96947b59efb0509a", + "kind": "transfer_execute_success" + }, + { + "hash": "487234b0e43b1e361d66803e13fc57d1a4773a4f5a9db55f3db89fdc5a1bbc37", + "kind": "transfer_execute_success" + }, + { + "hash": "c4f756399df877f4e43e5a939b78ddf882e6744c40630c78bb3e2609fcbf7be2", + "kind": "transfer_execute_success" + }, + { + "hash": "8fed71b824c92f58e32aeaeef39136cfda940efa8dcb3d9d52503eb13261022a", + "kind": "transfer_execute_success" + }, + { + "hash": "4622adc78d0f8f15c519eb2814950a83d41065226b1595f7f73113f749203508", + "kind": "transfer_execute_success" + }, + { + "hash": "c27647311a0031c05cc08d53f5388415691825cdf593f7b003d2527576883cd4", + "kind": "transfer_execute_success" + }, + { + "hash": "69add25526e62a8f518cf837818aa521aa7052af46ef7195fdcb3b806a665c79", + "kind": "transfer_execute_success" + }, + { + "hash": "5c23427ec6046ce79525c435b00bdd5c3f8d2e547000264332eded84213514d9", + "kind": "transfer_execute_success" + }, + { + "hash": "b62111e2cb2beb2fea62538ccddb4da80186cf37e5998ec077d35f2a077081a5", + "kind": "transfer_execute_success" + }, + { + "hash": "80c4a359f2fe7a8dbf23b4c04f1035b757a76453cd8041aa9ed8f8027a1d30a1", + "kind": "transfer_execute_success" + }, + { + "hash": "ee41498d67f73c8abe15a95a6d2dd6f363250535cc85e915cbca257d6c37784f", + "kind": "transfer_execute_success" + }, + { + "hash": "c8fd4e9edbbe4677c31eba222f3955d156719ce12732a811d6ef29107a71c4a5", + "kind": "transfer_execute_success" + }, + { + "hash": "98403bf1daa512099cd9106550a8b5a946b584fce33aa9f7184be9a745540fa8", + "kind": "transfer_execute_success" + }, + { + "hash": "a90bdcb531c49872259f1927e096435adfbf41b239a02215c552e18d26c96d5d", + "kind": "transfer_execute_success" + }, + { + "hash": "2f3af71830d2097469325dd3109cb55c7a0bcb39a60c8c75257871a247f10aed", + "kind": "transfer_execute_success" + }, + { + "hash": "39ba5f7180d65f063403d9c7f47ecd5a356ba1f8217c657cf15c28e50e523edd", + "kind": "transfer_execute_success" + }, + { + "hash": "6b7b4f83e6c99497c6a9dc4e313604bfd72eada23c705f889e22917c64ffbb8e", + "kind": "transfer_execute_success" + }, + { + "hash": "825d25f2bc1ac0fbcbc10fb81d2daac4f21612ba0b106210f83945d031e49a67", + "kind": "transfer_execute_success" + }, + { + "hash": "75ddc3d419886b90b6eb34b4c4d76d6e9dbfcf4f04dc8e896061a66bad4a3261", + "kind": "transfer_execute_success" + }, + { + "hash": "61cab6cef1ff0c6b96f3ac660417ee4f83cba985e6a6473bce7b6dae66693c07", + "kind": "transfer_execute_success" + }, + { + "hash": "437458b82aa32ef9ddf7d28227740343e4566d9ca5560f398b3815a607aa4586", + "kind": "transfer_execute_success" + }, + { + "hash": "95fb8bbf220442d6ac05a6c76d36778bc0856fd30caaaeda848f73d6493d7df0", + "kind": "transfer_execute_success" + }, + { + "hash": "df8382f94aaad84d2d7cde8938e33e664900f1eaebd40c480e141f506c01d034", + "kind": "transfer_execute_success" + }, + { + "hash": "2df7f0a541e19a4f42d53a3f1337be4f7eb493df1674728516cfd96be3d78f42", + "kind": "transfer_execute_success" + }, + { + "hash": "fb218d4fa05463abd7e43570a79a08e7717f88916befba19063b499d0084917d", + "kind": "transfer_execute_success" + }, + { + "hash": "c81b5d4bf27eda41fa63ce0d67fa7af0852e97a6ce8193e3ab8187a43e8967f1", + "kind": "transfer_execute_success" + }, + { + "hash": "296c4902cdaa7e283ae5e9dcb10addf8ff27bfef899f4af5f94fefcc49a12d1c", + "kind": "transfer_execute_success" + }, + { + "hash": "9d7db557e988185cc8dd64d8d0300ba4683b1e22605de3f676297ca8f136b71a", + "kind": "transfer_execute_success" + }, + { + "hash": "c170b379e783e7e44ff1a9188af3e4c079a6bc4933c28d600291c0fc39c912fb", + "kind": "transfer_execute_success" + }, + { + "hash": "172282bea32db61a51d56fc7dfba62190ce81be8038a1b03151f48b3e6e84ef4", + "kind": "transfer_execute_success" + }, + { + "hash": "748b627fb59762fa4c21474a8b6728e0421d48d8908d302237eaba7610fc1c53", + "kind": "transfer_execute_success" + }, + { + "hash": "ad19d0d3093d401bef62e845ab8b03b0472384e8282278136c76884c5cda6b8f", + "kind": "transfer_execute_success" + }, + { + "hash": "07001cb143996a90806725f3687e9fa8f010d70998a488176db37a0649376984", + "kind": "transfer_execute_success" + }, + { + "hash": "53bcdacc7196049352f1405ca516e72bf9731aa04e41e09c040495b714b6f5b0", + "kind": "transfer_execute_success" + }, + { + "hash": "7d6b331bb9f4b52f57bda19ee5e41f8e3cbb9cdb60c6ab061d7cdc6ddf67d2e7", + "kind": "transfer_execute_success" + }, + { + "hash": "455bb22379ff7967798d279179ce5d19e803ad0d4144e0dd2f68690c96651177", + "kind": "transfer_execute_success" + }, + { + "hash": "ae563492c8bc02bbebcd02351a1a96f5e9bb3fc471e5cd4cbed85ca5451e9b01", + "kind": "transfer_execute_success" + }, + { + "hash": "955a101267eb8e1f4066fa3ec101d4329311c2e062d9eb1dc1acd9413f622eea", + "kind": "transfer_execute_success" + }, + { + "hash": "b0f17987cd21e4ac419e12e0b1797e56a4eb82e016b71608ab57993bb9daf31b", + "kind": "transfer_execute_success" + }, + { + "hash": "11967382b5568d8a7af01a0c8f721d32d5c591342cb5b8e98096e7c4c0495858", + "kind": "transfer_execute_success" + }, + { + "hash": "ac3c292c02059183bfba3552fd659468cd28ceb0da4de8c650bca6e798fe424e", + "kind": "transfer_execute_success" + }, + { + "hash": "9d39266989f694d284861918df639db8e6b10b4651bb38fd67444f81f6c71147", + "kind": "transfer_execute_success" + }, + { + "hash": "df017e65e4810f7e0ed05a98f754de084233b5e49e45ec28289134e1e9aab145", + "kind": "transfer_execute_success" + }, + { + "hash": "b1c5753e2f658d02e4a6d09f31bf4203482f73a6810d7d8e532fd67d70ac7e2d", + "kind": "transfer_execute_success" + }, + { + "hash": "bc45c97be73665a3a268c7561747cedfc7d8349cb19bbd74a113306e4ee73037", + "kind": "transfer_execute_success" + }, + { + "hash": "e5565920175ac964c7f18b096299951effe2fb4f6a0c3c4172f8cf0f25c2ae8a", + "kind": "transfer_execute_success" + }, + { + "hash": "c121c680d17777facd60947215bf10753b74e71771e410b94d842293675fe1b9", + "kind": "transfer_execute_success" + }, + { + "hash": "c17414ea761a83929c9d66474364295f563278458f865e8e677deca8f2565529", + "kind": "transfer_execute_success" + }, + { + "hash": "dc0d86f3eaa88e64f179d7f452d5174e1003f4b9639b3b359f2ff5fb24ad6788", + "kind": "transfer_execute_success" + }, + { + "hash": "e6450a680db1102b2fcd7814cdf0b39107cd5637cad0a7d05697dc7e8cafe76d", + "kind": "transfer_execute_success" + }, + { + "hash": "2ea597d0628eaa1cca03097a1141cc8ebe6601c90c0b715886fb2b9de0d7c29c", + "kind": "transfer_execute_success" + }, + { + "hash": "37680a62e1d5b9c68c1c7620ca2455731830f5570c6532acb8b33bb414b39339", + "kind": "transfer_execute_success" + }, + { + "hash": "6d0939cef5dfd0d2584f5887ac45010322fcbaffdb7f92fa045712bfbf426db1", + "kind": "transfer_execute_success" + }, + { + "hash": "77b5451ea9959b33341e57d424981cf4c13b5786f31a57457b72885f4893c11b", + "kind": "transfer_execute_success" + }, + { + "hash": "5e9496622d28a6e13ffe1f444c4a960b501e5c79d1242a24a496211de61d643c", + "kind": "transfer_execute_success" + }, + { + "hash": "aff1fbd29d3b4f87a4b88f6c14031c1d774f4bc703a4aec8dfa0bd5fd11a0109", + "kind": "transfer_execute_success" + }, + { + "hash": "87b9c25ee008456c239fe7620514093b6caf16686042ae655e51856fbf9ea8a2", + "kind": "transfer_execute_success" + }, + { + "hash": "bb19350763bcd9b83b57355c988e4a14c1bcc6ec5743fbcb96b8c6e0b24ca447", + "kind": "transfer_execute_success" + }, + { + "hash": "793eef2d1d7b2f26992758c6846cb63e99b5220308f8e49478410829d1fe0985", + "kind": "transfer_execute_success" + }, + { + "hash": "125be7fa4169ab94f7b97f2575501bc930bb3d47759b13e3142d8c0ad9127c5e", + "kind": "transfer_execute_success" + }, + { + "hash": "70f45dbbd5a322bbc1f577a077a356d80f00a3771895379be317d757c0a101ca", + "kind": "transfer_execute_success" + }, + { + "hash": "d6a32ab7b545d9c52342382bb92d465dc65d6bccd99cbb240ec4ebbf2d8fea76", + "kind": "transfer_execute_success" + }, + { + "hash": "bd0596cdec747a1ed37cddb9bbe1e69224c4be81ce931fdacaaee3bc191c96bd", + "kind": "transfer_execute_success" + }, + { + "hash": "644e036382be944f0a64f602eb264ed74ccd5c0a5f5f9ad9fbad604fca90dcaa", + "kind": "transfer_execute_success" + }, + { + "hash": "ed1280f0cea4d359535e4af274eb144a1fe27f364ea4b2a2da2c3a9307bc9541", + "kind": "transfer_execute_success" + }, + { + "hash": "3d1bfb0e1d184a12c03c4acca217f780f6e9f94a6d97d37e6b33ab6bea0d2b94", + "kind": "transfer_execute_success" + }, + { + "hash": "b0e5b1c02235dd29d44f38c63f318c55abc5522a2f337e7dd80880783f404225", + "kind": "transfer_execute_success" + }, + { + "hash": "8b23c43cfb9d7d5bed3901f9a7b7607f1f1b2dd1b2a3d2e2bf88fa9e289adb73", + "kind": "transfer_execute_success" + }, + { + "hash": "95c7dc6093c12eada0c262f7ce0445d7913dc2fc3129a5048976a8d84626e051", + "kind": "transfer_execute_success" + }, + { + "hash": "7d7337c92eecfab18477a70044373a53ba18778c0cdc396ac6fd535d5dc8cfb3", + "kind": "transfer_execute_success" + }, + { + "hash": "4fe94181e3b71afaf323e9b3dacb38ae674e7d2bdc64d6739d06946ad3b95bf2", + "kind": "transfer_execute_success" + }, + { + "hash": "5b8e3035da5542e8293df37b405e9b88435a2bb493351db8a2fd7be5efff21e5", + "kind": "transfer_execute_success" + }, + { + "hash": "ab1998020be593bc06985cda431fe98dee778d424de51f5fa5f4272d002e6749", + "kind": "transfer_execute_success" + }, + { + "hash": "2c049d926d321d516ce2fc3d8fe119d9c14866b8c8dd36c144725b36ba388a91", + "kind": "transfer_execute_success" + }, + { + "hash": "90a634bc44c04131908128db4e2696a4876e25f4dd3f6990748d656e538eaff3", + "kind": "transfer_execute_success" + }, + { + "hash": "10d3bd1bfb52880852941e0b813fc51797695e90cae0e77795fe7f76d868dd33", + "kind": "transfer_execute_success" + }, + { + "hash": "c91b4b6d3fdc60b75f02d86ae2fd830d194bd92cffde2e7838d8f9082064f8b8", + "kind": "transfer_execute_success" + }, + { + "hash": "17fa5372aace8b62973141646c4e17e391c59c63c43d1ca57388c06617aadf87", + "kind": "transfer_execute_success" + }, + { + "hash": "f691d889472ec35e45a9ecb15c07996f539d30afa68551fa8ce649dd4e192116", + "kind": "transfer_execute_success" + }, + { + "hash": "a3e5d2efa3fea3c56038e77009d4524a4fa1a62ed4eb4d64b9187c046613043e", + "kind": "transfer_execute_success" + }, + { + "hash": "9ac63193efffd8c856f1d49893e690b31ad5e0eda6c5b5816d1d48c8ca22435e", + "kind": "transfer_execute_success" + }, + { + "hash": "ef1dc7b1df7bc173e64f803ce1a0950e79396121bb59741beb287139513cd32e", + "kind": "transfer_execute_success" + }, + { + "hash": "90c43ff94bfece21131fdbd473a0bc4937166480442fd46dc4ef64855323b0f4", + "kind": "transfer_execute_success" + }, + { + "hash": "87cfef085488420d791b3ff9b5fb445af87b28306093d0e21afc0693b0627bee", + "kind": "transfer_execute_success" + }, + { + "hash": "f681c3fef82f22b01ff085c4c4cb87ffa59ede891d05091fb38d1f0298523a3b", + "kind": "transfer_execute_success" + }, + { + "hash": "3a3b4f32b76b4abff0863f31901844c5b5bbcd008b8c047220776988b1a3e594", + "kind": "transfer_execute_success" + }, + { + "hash": "86f886846de01a34d95db3d8db2c0f11d875d8611df8206a7990455450839e58", + "kind": "transfer_execute_success" + }, + { + "hash": "ffe144c59d64ad606b97163e86ae46f5ea73f5ff92c097c52249113f48547320", + "kind": "transfer_execute_success" + }, + { + "hash": "5ae11eb075539e7e082475f6529542729e3577a8392669701619a943e476a044", + "kind": "transfer_execute_success" + }, + { + "hash": "0fa43cb150354d676489eb2cdb0c2da432b1ae4f77bb97b9d029e93c997f2ca7", + "kind": "transfer_execute_success" + }, + { + "hash": "1b67c46a5d3652b0631bcb9c44d0d61b58084ff896e285798c49fcf28f95312e", + "kind": "transfer_execute_success" + }, + { + "hash": "a10806b3b975644d7ad39f93c0348895e9f75525d51df49a0bb9d935c8bbf4d2", + "kind": "transfer_execute_success" + }, + { + "hash": "7b6d73f7411ff64d10ee6e573163d0d1d2f794808555aecf2987f3c0b6e9dd94", + "kind": "transfer_execute_success" + }, + { + "hash": "6059fb13065259950724fdbbbd01b88acec79c6739a171d687c39a3cf762d405", + "kind": "transfer_execute_success" + }, + { + "hash": "0fce4fc98f42e0751137395563143bb64b62dfc57893b705be4c35611dfed7d4", + "kind": "transfer_execute_success" + }, + { + "hash": "e6a25c6ce50ca9d36e9c71bdd9705b68e96e25a61fbd57cf042e44ab71363017", + "kind": "transfer_execute_success" + }, + { + "hash": "96a777e0760c2d9a557f8ff14ef562d59cc1ae1fbe5a1b72554c8ad658f76d27", + "kind": "transfer_execute_success" + }, + { + "hash": "c76ecc812724f097d15a7c08b468f0f1cd4e89f0f6ef4b85d5326ace475358a2", + "kind": "transfer_execute_success" + }, + { + "hash": "a97c5ec5049ed629162e7b2946c8f77476f747d5db978fe86408070125c4b6bd", + "kind": "transfer_execute_success" + }, + { + "hash": "38ad61d299e68c77a52ac7b4104c1d95cc9f5989246732e628849ce4072c403c", + "kind": "transfer_execute_success" + }, + { + "hash": "c8deab216ae508a01f92f34b79f93df5d24922eb34b7339d2cdb927aab11aeda", + "kind": "transfer_execute_success" + }, + { + "hash": "fa12f3fd2c4696795d31364c2245a1279623cb26a84735446a8bea6775976b04", + "kind": "transfer_execute_success" + }, + { + "hash": "084e8695a3b30f31fdceb5655b9cace3c1d5c61db6ac63a1549e4a224c9cfbad", + "kind": "transfer_execute_success" + }, + { + "hash": "7b58c4e89ba3dfad4879057737948b127d13e44b109301398b69e5c565c3a6b8", + "kind": "transfer_execute_success" + }, + { + "hash": "29a11438d13d4f2fcc104dfcafc730f56764641405beaf8a263dd3b33f9e6645", + "kind": "transfer_execute_success" + }, + { + "hash": "0d9587d3bfa11bd54e7e323ebce8476f0a767f97b58b059fbe1760680d6c0ebf", + "kind": "transfer_execute_success" + }, + { + "hash": "10cee1d272509f304a0ec7b00722004076e1dcd5c90fddeaa9b7594be99a472c", + "kind": "transfer_execute_success" + }, + { + "hash": "ad33bbc595127828f1fb995cf43d749a1d6638e4337e1106c249b76800f3ade0", + "kind": "transfer_execute_success" + }, + { + "hash": "aa42a5a9b36cbc148719e2f474c8df970bbc96ffa3c2615b9a78ad27927f74a2", + "kind": "transfer_execute_success" + }, + { + "hash": "c14c3faeef4346c5adb8977c73807cfea13af5281f439a925e05115b7166a220", + "kind": "transfer_execute_success" + }, + { + "hash": "d4e010f09124bd5da35a148569d2adf82a22e2bc8a00eb8650401c97110bf178", + "kind": "transfer_execute_success" + }, + { + "hash": "a4d4140e59739af3827d6ddd9ca76b15b10b75a57b584117a127a442d59c47a3", + "kind": "transfer_execute_success" + }, + { + "hash": "480b6710f88331f204fec4377b751e4f657d75e9683bd69be4fe3bebbd5f6cef", + "kind": "transfer_execute_success" + }, + { + "hash": "734be56b54d9df8bb74a6cef6c7b61ff08b05b414618d68770e315809a0ea554", + "kind": "transfer_execute_success" + }, + { + "hash": "fee79b52cd29261c54e9ae99fc96f462cfdbe4466b4d4149219675e168bd9190", + "kind": "transfer_execute_success" + }, + { + "hash": "069f704f9e002ab1e179abde21cdecdcea462f226c8d93b75c3c53d1e76609e6", + "kind": "transfer_execute_success" + }, + { + "hash": "f6327fe6774f6d44c9737f0aa39aca2fbd67b572dd5fa396217bd676d11d442a", + "kind": "transfer_execute_success" + }, + { + "hash": "cae5ca1a3d74ecfd23766ebf6cf3a1feab31fd952a9f8efbb1067def26f2fb80", + "kind": "transfer_execute_success" + }, + { + "hash": "4e0befe2b16795777582d9f23b8945a2bcf1fbb260f4a97b863bffc5cabe8929", + "kind": "transfer_execute_success" + }, + { + "hash": "1003e2120318eae1464b8fd7c1836efd1a363d829beaff884f8a6aabf34da177", + "kind": "transfer_execute_success" + }, + { + "hash": "32ba5f0a2e5d4967e0eea80e05754a16007f9bcf5c1d422cd96cc384879659f4", + "kind": "transfer_execute_success" + }, + { + "hash": "1118a51e42f39e50bbd9ca0fcb494eca7fef99d418b40baacae4f62cf7624f7a", + "kind": "transfer_execute_success" + }, + { + "hash": "4da1478ea31b931df66fa869841ef76cddd66984d0315f913e6d4828d7614f89", + "kind": "transfer_execute_success" + }, + { + "hash": "dc68e815e493b44946ffacc9564192fd4a05adcb7604c88742adf974ff60c8fb", + "kind": "transfer_execute_success" + }, + { + "hash": "1d25f0ff2bbe6dcb4fb542cbca68af8d81187b19ea20008c894ca81137df830b", + "kind": "transfer_execute_success" + }, + { + "hash": "24e895ac19d2f44820d6e880c34bba3320fb0ccaffe334f8bcb2c709edb51f4e", + "kind": "transfer_execute_success" + }, + { + "hash": "2101b9819eaf779361958af61b5f6f8d5285eb99f8248ec9c729f6e1d5810a71", + "kind": "transfer_execute_success" + }, + { + "hash": "ffdeab1663b99539d6cbf0a3ce76b3077c27da7ccb7fe330e9c2440e2e75b6f2", + "kind": "transfer_execute_success" + }, + { + "hash": "8e9041c7066a1fb5ac3156e6adb523f410e330290c1f3969b53682c470424be4", + "kind": "transfer_execute_success" + }, + { + "hash": "6a54955d285418c61c1713751bdf5a76244ce3d0d075f5a95b82af0a2889b109", + "kind": "transfer_execute_success" + }, + { + "hash": "4fc3a5f99c5f89b448f67c8b862d30a72bb2c43f8fea1791531d439fd7093ef9", + "kind": "transfer_execute_success" + }, + { + "hash": "127799f8a5d9420ce94aff9701cc1b335b900c1ac491868b0b8302d31f44b7ea", + "kind": "transfer_execute_success" + }, + { + "hash": "cc877d83f44b693ec4f16929a3ef39b64254663e7c8d3d3c1bbea2ddedb0ff00", + "kind": "transfer_execute_success" + }, + { + "hash": "c08c3ca0cf2b7406dcb71c5c2305d19bcdaed34e946478c0dbb10050efb38c5e", + "kind": "transfer_execute_success" + }, + { + "hash": "2db289ae91cff778a0380604003fd1de594190d2b838008b830c3ffc8228554e", + "kind": "transfer_execute_success" + }, + { + "hash": "968a6c4c6eb129be594d111df4afa821acd0f1e34e438bb96256f4791380b0fb", + "kind": "transfer_execute_success" + }, + { + "hash": "5c7c5ed9716aea8dcb5dea9068ce6300e8aec59da849553649c03a9bf6a54679", + "kind": "transfer_execute_success" + }, + { + "hash": "b7636b0d3fd4d181ffdeff1e4eb3dee60b1264695d361dbe54c535a8e4010e37", + "kind": "transfer_execute_success" + }, + { + "hash": "6c2d2d58ffb1ddef75d7059ccc5da5644c43abc01031cb56802d8f30785db1b7", + "kind": "transfer_execute_success" + }, + { + "hash": "d77622cda28f39a7352d2ab799554e8108c20c18636edbd04f1d022fb91a6bea", + "kind": "transfer_execute_success" + }, + { + "hash": "0d189b97a7a98747a660d3be1756b0be27326fd6badfd55b1bc94216785fcf6b", + "kind": "transfer_execute_success" + }, + { + "hash": "8a176e096c309b32281a62969631b7d2ad460b99ee96056827d5bacc2b68f050", + "kind": "transfer_execute_success" + }, + { + "hash": "9c0d7fb15dcf287ee0695259dac7fe5f4e42ee94cb49151944aabfa90eb2ac74", + "kind": "transfer_execute_success" + }, + { + "hash": "a88c3005447818cdc7428a98c42ca51e3c4e524db107344a2c9e8aa2f8233d0c", + "kind": "transfer_execute_success" + }, + { + "hash": "a6a795a69592446056d07d40aa53646eae6108038a65aab99816ac7643913097", + "kind": "transfer_execute_success" + }, + { + "hash": "fad3f52e851b9b50b5482c16fb4d7bc18963144c3b89a8241dca4db349f3789d", + "kind": "transfer_execute_success" + }, + { + "hash": "116084fce944794f07866169201101688abe1011a053fb1a477e7165f02905cb", + "kind": "transfer_execute_success" + }, + { + "hash": "e60379a6205622e448a259646b46658a5367bc28939b56415209c90a9b557b94", + "kind": "transfer_execute_success" + }, + { + "hash": "37f9f0d351b0508d6094e8b5b935ad35bf96bbb802a6d252b5bfdb3c1ec17d5e", + "kind": "transfer_execute_success" + }, + { + "hash": "95d92ce1563303baeecb405190e28f032a366094ee63f545d279d47b7bdbb243", + "kind": "transfer_execute_success" + }, + { + "hash": "3142212f48e093588468d5c8d6b03f2d679f394671d245bd69121d821d15de58", + "kind": "transfer_execute_success" + }, + { + "hash": "68dfb693be58e0eb545987b0fb30cf53cc61d9e4e8830675fe6946ac3468d15a", + "kind": "transfer_execute_success" + }, + { + "hash": "8dca01debb925969a2f5ba3db8d429d2d96e49a07cd57ed8ecbbe3565245d45d", + "kind": "transfer_execute_success" + }, + { + "hash": "0adcf3b94fcdc0b0d5ce03635f525446519191d7d8fe9d89d7afc5b0f6ae35ae", + "kind": "transfer_execute_success" + }, + { + "hash": "6b2e48975369bbca7629759ab1417a1975a5efeb89fac44b04c7ac132e37461f", + "kind": "transfer_execute_success" + }, + { + "hash": "362ad9fa03d045298611d4c1bba03a2ce952ab3fe14d507b4074a8f6265b6f1b", + "kind": "transfer_execute_success" + }, + { + "hash": "8c5c56f2b409c5f4ddcd1dd65495e3cd424564832b74c7ae7680df95fae0ace4", + "kind": "transfer_execute_success" + }, + { + "hash": "9d9526dc5e254122f7e7a81a0679a7ac637f3df85759b1f209e4da3ea80a5aa9", + "kind": "transfer_execute_success" + }, + { + "hash": "c021c3faacf18b24e6953a0b4b4d65cd1e416d4254413c6d999821026c1adbe0", + "kind": "transfer_execute_success" + }, + { + "hash": "cce6dbcaf604e9029c0b0f2273831e1545c3cdb6dcf773e869100b16de1f4754", + "kind": "transfer_execute_success" + }, + { + "hash": "53e5e447d3d280ec9f3b92e48d1ed66c16f544fe41f55723c85b9b5f57885a5a", + "kind": "transfer_execute_success" + }, + { + "hash": "0037eafb93670f1f7afa9d1463b0f93b58955297e40e0633c70b82f0098fcb5a", + "kind": "transfer_execute_success" + }, + { + "hash": "61a012746700111c9d0686015d3146b36f865542583be70890939daf305be3a1", + "kind": "transfer_execute_success" + }, + { + "hash": "6e2341a97035cbb2c4ddfe937e71f537d5561e473dc9850761b78f69125f2d85", + "kind": "transfer_execute_success" + }, + { + "hash": "6f67b34ab6adc411032b2f3e303b27b068f197d571006d517d862e3ab02401b7", + "kind": "transfer_execute_success" + }, + { + "hash": "37b685d0dc489a9312ad87f81309df5c4fc822e1aaeba933d1b06f609ee20b63", + "kind": "transfer_execute_success" + }, + { + "hash": "ba672dcc47cb81d641a55107ebc6bac80c576702d70149e727216e077f3165a7", + "kind": "transfer_execute_success" + }, + { + "hash": "18786a7f8c2cbaad512c49c95691e72f33ca16837f44b720041a495d0af00c5c", + "kind": "transfer_execute_success" + }, + { + "hash": "dc1397647b059462066259db535dfcd1d70671ebb3854aa088dffa16b884decc", + "kind": "transfer_execute_success" + }, + { + "hash": "d59654438526cfaa630e28c8c0765a9eab6f4347436f092f72f2e276378d86f5", + "kind": "transfer_execute_success" + }, + { + "hash": "218ed9eb73e39a6c1718331d2d1a5feac781d8b7e169c39936bc539085b37f12", + "kind": "transfer_execute_success" + }, + { + "hash": "3ae4ffa0af72dd200d999d459f3ea33a98263c8dbe4226f81dd30d4ae88cea14", + "kind": "transfer_execute_success" + }, + { + "hash": "ca8f2c0331be82aff61a73567762324a9d1d5f7a9726ce448cb4c618428a0505", + "kind": "transfer_execute_success" + }, + { + "hash": "16e5ab3b06c1dffbcee256751f5a0e09bc9eb20d0594a71966385a0d7254aa2e", + "kind": "transfer_execute_success" + }, + { + "hash": "ae013ff00fd10540b4d5ca3c7d445c84b549dd3adb811ab35684b5ba4abe6724", + "kind": "transfer_execute_success" + }, + { + "hash": "6aba5598a2bf010c0d16a09a3a4957e156f676623580d11dbe1b869b9688a8e6", + "kind": "transfer_execute_success" + }, + { + "hash": "eb43c2993a005f270e089c8ee7f247e093677bfca56060a757d2c34421992d7a", + "kind": "transfer_execute_success" + }, + { + "hash": "a63163a1ea09c52f3bdeaeab437dd24eef7ca3301c4fde5e16fa23435c0d3b7c", + "kind": "transfer_execute_success" + }, + { + "hash": "9551849a34af5275ba3e88d5b90548914ecec6fd7f02c0a0318c8da07e636592", + "kind": "transfer_execute_success" + }, + { + "hash": "2d93e49b643dd28fb5c4f4b49e2daef84a54d45e7063de680f82a3122657e7ca", + "kind": "transfer_execute_success" + }, + { + "hash": "dba657c7885a727ee7b878764c5447296381f98bd4b64b4a00079b11844fecd3", + "kind": "transfer_execute_success" + }, + { + "hash": "470e2b87786c04cae3502a4e7a5070ed39c46e68d6f554ddfe1f9ae15fac0f9f", + "kind": "transfer_execute_success" + }, + { + "hash": "5d22cd6352511c4b17f539e4f4b2b1397445467f66702937b1ff561360f9e0b2", + "kind": "transfer_execute_success" + }, + { + "hash": "6c861081cbdd8230c6c6a1e858cf57b984680e0a380046a61dc8e47777b183eb", + "kind": "transfer_execute_success" + }, + { + "hash": "5f044ec6069832331a0bf08b6d20572a6ebc65dd2b6a55760c32eccf7a60c93c", + "kind": "transfer_execute_success" + }, + { + "hash": "6bbb2c533b4acd4a7c22a1438f8dfee57dc67502e044f7c1210ee788e3e3b9eb", + "kind": "transfer_execute_success" + }, + { + "hash": "ff29253c715049a89a0a33d68306e7bf0be47f566035b0ff1c87f81b1c2bedac", + "kind": "transfer_execute_success" + }, + { + "hash": "40f99b2a18dad3da6194c9b0f39798762d98feccb877de7a206f11e105705a58", + "kind": "transfer_execute_success" + }, + { + "hash": "f4064ae3a8f0b018ebcedf0a5df1ab361de1138e92ad4db572f573ec14d5bad8", + "kind": "transfer_execute_success" + }, + { + "hash": "d49144bc0f1b964000486a1f482d2569caa1a0a6b40347926b5ea30b4d69dc78", + "kind": "transfer_execute_success" + }, + { + "hash": "607a3460bff406e94a70670d9858895e84348e7e4308bcec93df06904bbeff35", + "kind": "transfer_execute_success" + }, + { + "hash": "ddd6453c309922ad9e54b015ff0c2ef90a2d57e10e7275d49b0fa0865c9078f9", + "kind": "transfer_execute_success" + }, + { + "hash": "b009e4c010b0c54f0f8b3cf4723a8db5fe1769781e941ab7f34d26ecc71986b1", + "kind": "transfer_execute_success" + }, + { + "hash": "a10ef8ea28650954286f5d4df6a564393b1abf5fa4d3fcd962bb679b5b01a61d", + "kind": "transfer_execute_success" + }, + { + "hash": "04b94d1b0c5947878cf51a56517dac9ba681bde3ac62c60c1bf8c75812a25d8b", + "kind": "transfer_execute_success" + }, + { + "hash": "0251885a39ef55e72ff872f188b0272a5db4aebbd7f5c78342847faac808c9d6", + "kind": "transfer_execute_success" + }, + { + "hash": "fb0bda5809d50cb9aea0cf56409a1d4c7afb67f91254c2acc2a66f1bd97f4519", + "kind": "transfer_execute_success" + }, + { + "hash": "58410c45403118051fb4c991a8b45cad34e2bd6f75f70a018cf7ec3a002d0745", + "kind": "transfer_execute_success" + }, + { + "hash": "3fde10e2366fee4c47b0673fac7a45185a83303abda8c2403a17ab1004c96e2a", + "kind": "transfer_execute_success" + }, + { + "hash": "3ee7be994cfdc3ff0e535a69e8bc77e1ad50ac1235a5656b92885d713cfd128e", + "kind": "transfer_execute_success" + }, + { + "hash": "f98502104d9f3b36a09084d8ca1915fbf01e9de13e625536e5d83318440cb9d4", + "kind": "transfer_execute_success" + }, + { + "hash": "35addf220ae683500d958f56d5691b0c02d996b11ea443198cdfaeb96170ce13", + "kind": "transfer_execute_success" + }, + { + "hash": "d570d7e8ffd32c99f01a5d03615aed4fe770b3698b1c6015dd7a30bde2468de3", + "kind": "transfer_execute_success" + }, + { + "hash": "47b0151e5f54b1ea48861a045e34eae3d672bf901c65e7ec486004306ba792d3", + "kind": "transfer_execute_success" + }, + { + "hash": "1e892bc41229f014554659bbd55ad1b95c2235cff3ab8fea23aa054aab820c8d", + "kind": "transfer_execute_success" + }, + { + "hash": "0f698b3be05123146472921ee80cf033cd08147c38eebeee8d4d47ef6080c8bf", + "kind": "transfer_execute_success" + }, + { + "hash": "319ac4481f0b03d45651920a8a32343c365c086a9f29f520c38829ea14258bd9", + "kind": "transfer_execute_success" + }, + { + "hash": "bbbc39b5ad66059db15a8d1d42828ccd9af0ced4b006c5fc4fa40ef65eb82fad", + "kind": "transfer_execute_success" + }, + { + "hash": "c96e29a9fec94aaa9a41aa66a803221d7b7d58e8c4519c819f96a4b8d213f8be", + "kind": "transfer_execute_success" + }, + { + "hash": "62384d45867c3f6f1bf44354bb578224fdbee7d0294365e3e1be4fd7e5886ff4", + "kind": "transfer_execute_success" + }, + { + "hash": "136eabe9e7b952bd266f41e7e8f6852295900f2611c0cea2956feb5f1b96a86c", + "kind": "transfer_execute_success" + }, + { + "hash": "4297591108e67705850f8748319d45818ce196f418429cd977e3e86237790b59", + "kind": "transfer_execute_success" + }, + { + "hash": "fcaa7e3ce96c72483b60d9f18a85fd6d014100054b4ad7133808f126648fb9c2", + "kind": "transfer_execute_success" + }, + { + "hash": "21b9cde2a605da17df33b4d85bef27640ee8a5ee70b0b3b6550ccba5c916b5b4", + "kind": "transfer_execute_success" + }, + { + "hash": "e5f081b4e101f4e951946cb1efb01c0625c1366eecc28ae290054e583989b2ae", + "kind": "transfer_execute_success" + }, + { + "hash": "af1f0df364ad7e02bf0be79b230e2e4af698708764cf80b8813e990155c0b5f0", + "kind": "transfer_execute_success" + }, + { + "hash": "a77fb15cd5f3dbf864b82bb32be245def675461e19b5020707c9501d327b1cb7", + "kind": "transfer_execute_success" + }, + { + "hash": "f29024f7b3a8dcb5ec481e913fc17ffa9fffb1a98aecd4bb40358b1f41790026", + "kind": "transfer_execute_success" + }, + { + "hash": "88ecd846125815772a814daa840cba0c406d730b06fd0c5682600aa47aa99bf5", + "kind": "transfer_execute_success" + }, + { + "hash": "488249db7d4b9502f4f7378d834ea1f9304f3183deb9cc086f4c1feeae87a7a5", + "kind": "transfer_execute_success" + }, + { + "hash": "a3df0a654b6d5df8dea1be35489cfec948a6d271ceadd4d5b2555be0c6bb6260", + "kind": "execute_success" + }, + { + "hash": "c82aa637a78c2f95618b8288385c5d58aa5d5b1944236f65543254e3e40ccba9", + "kind": "execute_success" + }, + { + "hash": "5b146e05952df48b1ce091211462095e40822c52525b03125de1c82c0399fb7b", + "kind": "execute_success" + }, + { + "hash": "9711b43beb163f5c2a72ff14390069cf990dafa01418088b4e3f8cc77a3894e7", + "kind": "execute_success" + }, + { + "hash": "7cb1a42a1fa98d3402ca66d7d1634d2543f821b890b60177f63ccbab20d29fc2", + "kind": "execute_success" + }, + { + "hash": "fecd7ea205e1d24b804f33146d1c07d07530203c88b24e2b03597163a3229f22", + "kind": "execute_success" + }, + { + "hash": "90dc88159733d504ceea6b0c1f89ee69a18a4fb7b304d74d28b911e5bcae2ba2", + "kind": "execute_success" + }, + { + "hash": "0c0c5cd7731561a7db12d8c0f1170016adf38e270b70fc0e90d90eff97f0fabf", + "kind": "execute_success" + }, + { + "hash": "fc29e6cddae316b406d25b94d98894bb0997021d96b98ec66104f286e3cce18e", + "kind": "execute_success" + }, + { + "hash": "de1b2b3e85b3613d97e31ec816cd2a1b5565730b22a46b2f5fc0859cd2e1e5e9", + "kind": "execute_success" + }, + { + "hash": "233514cbf89cb12bcbc8f00bffed422919fefe4642ecdd538161f8cbbfd9b837", + "kind": "execute_success" + }, + { + "hash": "45b6fbcf667355ce979739a0e8a6c7819965a27f3a37492f024abe47ce882905", + "kind": "execute_success" + }, + { + "hash": "d7110c06326c177720abdcfe9806d068fcfe08e98252dceb992bc5e644e7bd87", + "kind": "execute_success" + }, + { + "hash": "3a1dfa70d148712f2f9777207a2fed15b091a1a14c251240afffc1358800373a", + "kind": "execute_success" + }, + { + "hash": "7893635cbf4752f151583bc98bcd55be92a657995984ab68924daaebd9c1c056", + "kind": "execute_success" + }, + { + "hash": "28b50c306177a39a586e21bcf6b30a79e697c4055c3f52d17c8f0f29478beade", + "kind": "execute_success" + }, + { + "hash": "a64edcf9c6a5a8beeabc52ae3864621c0aee6fcf6490842a3de592d65a749e15", + "kind": "execute_success" + }, + { + "hash": "6393b00adececf791af6eef9f6b7ff2cb799f8bab5873856790b832e1632de32", + "kind": "execute_success" + }, + { + "hash": "f4cd96e0437edd8bab248dc0ccb6e52719147ceb8bfc9133120d369fb0f1e207", + "kind": "execute_success" + }, + { + "hash": "5980dbc737674f53488c1ea3fc69a2d0fafb9f538bde4fbe22d093e08b68b709", + "kind": "execute_success" + }, + { + "hash": "64ec3e7cdad04a5c1218c0ba91eedcdb33a48a89209a88f2c82b34f6aaf456af", + "kind": "execute_success" + }, + { + "hash": "bb03b5e760e4c9462f23b5d3a246f3734e299be7f7505152c8ae75673aa7bcf2", + "kind": "execute_success" + }, + { + "hash": "6bb2d1264a126cc83b2a076eeff65137639ad670cf8f69053c56f79a17c5fd17", + "kind": "execute_success" + }, + { + "hash": "ca58863c4907659081192b21fe40bffc36ecfef9977d6ac2d243250ba097fb8d", + "kind": "execute_success" + }, + { + "hash": "7f020f40ba432f9c6e54d6da981afd1acb60baf44a712c74ff2721b47a0cd8fa", + "kind": "execute_success" + }, + { + "hash": "6682a5fd46fc13b39474d08adff8ff516cae4c3aebda9e9aa8ef608fe56d69c0", + "kind": "execute_success" + }, + { + "hash": "385f47f5ea0d272d6afecead05e4c4003208a1755d560d61ee6fe862ec6f2188", + "kind": "execute_success" + }, + { + "hash": "f4f07126c4720e331dff16c478649409c3bf680967cb1ce0e1c6f83b5bc2eb22", + "kind": "execute_success" + }, + { + "hash": "cef883925df023ec911bac7d5cedd97afc19870db7a889bad6d5f83e83653ae2", + "kind": "execute_success" + }, + { + "hash": "ca7a2a1cec441e0bd83f76cb009ba23c0290c3252cad793be7cff956dd36d8f5", + "kind": "execute_success" + }, + { + "hash": "aa0b4482baa0380058eddd8892274a417a20c543456174991815ea9a59bd6a1f", + "kind": "execute_success" + }, + { + "hash": "0ca283d62cd3eb71516706dd95bd0d9a1f226a42a1d59a830ae303e16e3b50da", + "kind": "execute_success" + }, + { + "hash": "06dbeab6354e73a7859a6f73bf983b669667be311998d3f4836e5ba27180c4e5", + "kind": "execute_success" + }, + { + "hash": "986a8fcdd67938781ed4ed404448c526e4b4445bfa7b63b6e216fd61141eda36", + "kind": "execute_success" + }, + { + "hash": "e927227594395460d644c1011ee362afba80d83c0df8ec8a380d4c8f3222647b", + "kind": "execute_success" + }, + { + "hash": "6ff16b239528e5ae3233572421c406b79997d6a773ed8e41e21a0b50d6f74781", + "kind": "execute_success" + }, + { + "hash": "e84fcf503b1901a6a7f06e138c7751d3ee49369c2726cd173a1b8da9638d5376", + "kind": "execute_success" + }, + { + "hash": "3fbcc4cfda5f2ff207bb00bd94725cd79ee97fa56001c32355423380aee20000", + "kind": "execute_success" + }, + { + "hash": "db8849ddeeede6019f6cb7282362919de04a534ed588a432d0ad5600026e3703", + "kind": "execute_success" + }, + { + "hash": "ead468a7bb0cde011573f9f1bb6aa86edd6e6ea1cffd64d6142fd61b73efc633", + "kind": "execute_success" + }, + { + "hash": "a3bb26121171553b02879b44b17aeec45094d547feacc30597a16cec30b9fd57", + "kind": "execute_success" + }, + { + "hash": "a5c7aa753c270317b8f1f462a3241abeade7c7413ea2a8bfc05d6fe37fd025f8", + "kind": "execute_success" + }, + { + "hash": "670345ba68116b3a0aaa055e0a2d0eb6c48cb176c7bd0f6939646cb8f60ea290", + "kind": "execute_success" + }, + { + "hash": "3482ec0836d84222fa87aba204ec1f2548164a68230fbcabe0eeb20a18a1ff78", + "kind": "execute_success" + }, + { + "hash": "d7598a6105f3898107cbea2aa08226c2810fa956c960620d43fecfe6941a1def", + "kind": "execute_success" + }, + { + "hash": "7ddd26e7a7947f32a2d2d466572b7b7cd1cf40bf17197cf47c299fb18582e3e4", + "kind": "execute_success" + }, + { + "hash": "1bb45742f4bdbf0bac2fe881d49cb28bc28cc0f72e50c13e653853d9a3395c2e", + "kind": "execute_success" + }, + { + "hash": "959a9ae71a35ec804abe04f5f97f3587b9a53669feffc433b478ea73ce592603", + "kind": "execute_success" + }, + { + "hash": "35d3bf921d075584991eb37e55a81466d5f692f74d0578c683cfcb163a0e3f37", + "kind": "execute_success" + }, + { + "hash": "9178d7923c8cb87892f89389c8469122f1ae972e72a589fa88692483fd2394f3", + "kind": "execute_success" + }, + { + "hash": "c63e28813984cd102ddb8aa4d1265a1f4009ef41078892bfa319a94ff903bfbf", + "kind": "execute_success" + }, + { + "hash": "90d700b2cd677789106c049914e3108509c89c954f4b06b229df14fa5d46cc7b", + "kind": "execute_success" + }, + { + "hash": "8b12eb1788599c27d6df191784d451ac0684f000c9044911db919e074aae4dee", + "kind": "execute_success" + }, + { + "hash": "fae942cffa1014454286002c35da0f2f36a85def34e83b20daec096d0e0b5e10", + "kind": "execute_success" + }, + { + "hash": "a6a25706ce5248f0f29cf55efeaa9cd31edfd1d41446aca56a0e016a2416c098", + "kind": "execute_success" + }, + { + "hash": "3d9118ab7ee49ea0249d609725fd1db167fe6795adfa3343c0c9dc035e305c80", + "kind": "execute_success" + }, + { + "hash": "55e575236c875b26748fd95e2791c0f23d21b4f890efe92fe2dcfa138f68145e", + "kind": "execute_success" + }, + { + "hash": "5f3923d4aaa328aa461d1b238f2c29f2bb14735c1d2bfd71af79ce13e0c7a709", + "kind": "execute_success" + }, + { + "hash": "5c5eccc73c564c839ffc44adc8f52eb3874bc1cc32d2948632b9a0a1e2977161", + "kind": "execute_success" + }, + { + "hash": "c30ed856fe07e3007e47b33e9cf93e4224e63183de916244acb359f69b8b6277", + "kind": "execute_success" + }, + { + "hash": "4a407d3c371a96f12b351b4ee5da9e8f0372241508ae34547d049916bf1a1315", + "kind": "execute_success" + }, + { + "hash": "e3b7d5177c4a76af5d9a1c419f64d4f46c88b6bb811633521ee1b7dd049e9b6e", + "kind": "execute_success" + }, + { + "hash": "01395f8614577785da045d6603cb8343fa6f9e2652a1dca90a9abfd7a438dddc", + "kind": "execute_success" + }, + { + "hash": "aa2f2123ea18dc5867f4c6ce4ae723856f90a3425958b866dd68a96466901a97", + "kind": "execute_success" + }, + { + "hash": "045436b5c9d8df9653bbe64df966aa2755197c4d972ee1045d3ba5c7cff4777d", + "kind": "execute_success" + }, + { + "hash": "bd1f17f803d8bce55bc1e92feb35630c5d0899fbe4fe284bcad050631ef46074", + "kind": "execute_success" + }, + { + "hash": "64ff48b003b65a589794964ec4c2da309f9a135d35e8a2019a369647ad3b194e", + "kind": "execute_success" + }, + { + "hash": "aaf4039e000b13d1ecc7d8aed2353db8ba5b7c451c288dc80fc13b054a71bbd5", + "kind": "execute_success" + }, + { + "hash": "a17a2852353e3e8418abac93105c6d8d03a304d185d4b02aa50d2c3e188b8a5b", + "kind": "execute_success" + }, + { + "hash": "79fe2fc865c7ea090089ba0c819759ab7968226cedc8dff71a7f4c8619f9f547", + "kind": "execute_success" + }, + { + "hash": "2b685220e8029309d94b26fe6a18745b143658447f86af4749f1d1ed7013d26c", + "kind": "execute_success" + }, + { + "hash": "7e08152288f0d549333c084900469419b5569bd7eb21f4caf248d703100a40b1", + "kind": "execute_success" + }, + { + "hash": "aab3e8b129c87dc6eb6468a216fd1f4fdf953598177f30025b61a586fa636e5f", + "kind": "execute_success" + }, + { + "hash": "e9a2ed9e3d6e626047251b3afe77c470b50584b7e143e0226de8d4fcb9c9eb00", + "kind": "execute_success" + }, + { + "hash": "94265b21961ece23db86a99ecedf3702f476c61371acf31de265c0154b09774e", + "kind": "execute_success" + }, + { + "hash": "718994cd6d9fc09769ee31c39e34538c69b5bcee30b0026286c422eeef33acd5", + "kind": "execute_success" + }, + { + "hash": "9fd08ebf530a741dfb010fcbfd0c669d3b9a1860e76a7aa9c9b5156a907b19ac", + "kind": "execute_success" + }, + { + "hash": "52bb02e6c4b6cafea0c59c3e28ecdbd0e4e4b799fbdcc10332d43ca4147edd50", + "kind": "execute_success" + }, + { + "hash": "9ca91b601c5f1d8d7bae01f4fef558a6afab32d4425570139c8656235926b1d8", + "kind": "execute_success" + }, + { + "hash": "18d89ef0155aade7eeff3f6a04e81e34eb88f1e6499b36b94f6eb55644be33cd", + "kind": "execute_success" + }, + { + "hash": "ba918170a6cb2378b22993431f013a84dc2f6b1d9e6dd45ba8e36442f72b9b3d", + "kind": "execute_success" + }, + { + "hash": "ea7983edfedbde8a817b37176a99804b97e9254018629900a6c93f6535f0f91d", + "kind": "execute_success" + }, + { + "hash": "90eec64a0938801c57974f51281f67dcd752e9a8ad03eda76c03848d54ea8992", + "kind": "execute_success" + }, + { + "hash": "8ff4d53f2afea4678f23b2308913750a9c076a4391d2e95d73c44e070bdf09db", + "kind": "execute_success" + }, + { + "hash": "6f19bb774243d1139499167a35860028595f9120725e3d8b0da089320aded3d4", + "kind": "execute_success" + }, + { + "hash": "33fef6b9101cf8885f8bdfb13de29bd70aa593bf783d90774bf0e6f978a03166", + "kind": "execute_success" + }, + { + "hash": "2480bb613500bc75ed9fb65d4e15f0d9aede6c83f3caf3537b5e5d7204689f98", + "kind": "execute_success" + }, + { + "hash": "22c3f1e26f0f9d9b15329243c8f7d48e1c7549a92b09484eea57dca732d79324", + "kind": "execute_success" + }, + { + "hash": "8552f42bbe8df9cde9d96920b082ad2acdbd9eb6edb931361400ba70632ffa5f", + "kind": "execute_success" + }, + { + "hash": "058f0edcaa4b769c984df119310b7d49f69fd6e1ea7f50de834785664366925d", + "kind": "execute_success" + }, + { + "hash": "96efd34dd3b39cc4afa6537b25bdec68342495807ceb461c45358ef2a3ea6f51", + "kind": "execute_success" + }, + { + "hash": "6251b5be9d60dce8938fb1107d6663d8eef9e5a3e3c3688f53469331079cf06b", + "kind": "execute_success" + }, + { + "hash": "91f8ffe69a19d7525288274b7670fe9d1714219a5bc472b5ab7b308a354d7c5e", + "kind": "execute_success" + }, + { + "hash": "2ebe76ead8ab64191d90284012fb2b0256435c5c43e7b5b40cf0269ec571344e", + "kind": "execute_success" + }, + { + "hash": "8789447cc88fab183cf79ca0d30618f91664a0cce35e7eae4f42541217a908a4", + "kind": "execute_success" + }, + { + "hash": "86c884a8df60ed810e21f1c1826f6fbfaf850f4ae038697456d589ca7a98a931", + "kind": "execute_success" + }, + { + "hash": "b757f0be048b94e66c70b5ea1365e8164d468689d3a1cbdf8942ab8fd605b59f", + "kind": "execute_success" + }, + { + "hash": "d0b858f7ddef6f1178ec2f4b32f8bf651c9346ed5fe9ee93d684b6e12eb44fda", + "kind": "execute_success" + }, + { + "hash": "958fd8b7d71bb76c575fd1f31b11700b02806467fdf33329e398a4b7c7ab3273", + "kind": "execute_success" + }, + { + "hash": "ff88d9a4a2e634325e78758a490553103e277e0ea49d497bea1c8202da6d70ba", + "kind": "execute_success" + }, + { + "hash": "1f00f4d543607dd73575808f841b14ea12aafaa9c17cdfd8b7dfd64b01701859", + "kind": "execute_success" + }, + { + "hash": "efdf956a4da61e16130d1df9ad08fec29bdbd18e1bf72e49b3b97578d5fb9bc9", + "kind": "execute_success" + }, + { + "hash": "4ca07b23a57a2f03b0cb48beaae9f93135df91592fc4a71119ed74415af9c6f6", + "kind": "execute_success" + }, + { + "hash": "c135b5296128b97c3c09e825debf776c8122b67c4563cfa6785260970a25c0d5", + "kind": "execute_success" + }, + { + "hash": "026240eef3378be5f8b18f26890d6e03266037a57698eda8da1362017c942bea", + "kind": "execute_success" + }, + { + "hash": "d4d46326e91c96b83f5f46e3ea1120e74e5b38c046fd9078aa7fe987d9f811a1", + "kind": "execute_success" + }, + { + "hash": "f2387255db48f696c66ba2689d4892c7f772424d4ca79b00b7c97750b97ec87c", + "kind": "execute_success" + }, + { + "hash": "ae3645192fd0533a073175ac8ed4580cc36e5401dcd1922a9de8a10254626426", + "kind": "execute_success" + }, + { + "hash": "38937f7bf7a69ff760d085dc9b2618983a2614d55bac39d81750e41cd552484c", + "kind": "execute_success" + }, + { + "hash": "fc0f440fe0fcffd3467dc9075f2c8c91fdeb8fc8d7426bd21fde169ffa76e3e3", + "kind": "execute_success" + }, + { + "hash": "88f02f011e65ec7a3908d2f01ab07316a3c25a23b0133896652d75c9f3ba8804", + "kind": "execute_success" + }, + { + "hash": "405c97266df25ce3716ce6113f02f002b9f1e9937b6452332db4dd161156469f", + "kind": "execute_success" + }, + { + "hash": "b5652fdb0fdd19595ab60d0a7ecc03e843928b989104e567f6da1f6b9b757260", + "kind": "execute_success" + }, + { + "hash": "7fd820db59e20979e1acbef514c7f76aef961f633e7cb329d0ebce3821d85c55", + "kind": "execute_success" + }, + { + "hash": "68e2f9248f7296b4ef96381fc584f0dd5385891533b38bb96fc759c46f384932", + "kind": "execute_success" + }, + { + "hash": "ab412894d3aa0ef53d578ca4f6829e52de4df3fc5069b89c4e0108bb35c14270", + "kind": "execute_success" + }, + { + "hash": "ac3f163951797161a96786829d9cd025f00c90d035095c7742fb64b9434398ec", + "kind": "execute_success" + }, + { + "hash": "511a745b0a7d57e01c78a43e90393b65e64847a83c5e52e3ea317eca9e587d59", + "kind": "execute_success" + }, + { + "hash": "b580daefb1a494b69176b8744c645527c631ae0cab0cddec8d0a5fd8429d95c4", + "kind": "execute_success" + }, + { + "hash": "b1ee0f588c14f6fcaa04bf1a07d956d481fd417cb6b3850636f48537e3a572be", + "kind": "execute_success" + }, + { + "hash": "6e51d3cb99dc893b48290541c064137ddeca0f8f6ca031e009cbe14246317197", + "kind": "execute_success" + }, + { + "hash": "6d5d98a8c5971bee2dde7b54d9eb0306a016d40622d5d3066a1e52fdded7b577", + "kind": "execute_success" + }, + { + "hash": "9708980683cc9d4d462b5b9c9865cda261bc68cc9ae6584a76c3d97383160220", + "kind": "execute_success" + }, + { + "hash": "cf40331b8e88013133ce2b8400d7ae20204dcaa955c65d77d3df5caecd05139e", + "kind": "execute_success" + }, + { + "hash": "71eb3f1c17fb4f315d066352cf7b0a4e7b14b85dbeadeb17ae5a8040b2f52991", + "kind": "execute_success" + }, + { + "hash": "39be34fffd261e97b5ff16085723b4cadefebe3e53a34687496d9e31973c88ef", + "kind": "execute_success" + }, + { + "hash": "9f44f3dad01c6baff40aa4ef4a11f814e96f51059290b2710a1c846ac8cc5eef", + "kind": "execute_success" + }, + { + "hash": "2a5e4c5845259673aba5d1b68745d092d47e8ab8c3475b1843129f24669c4523", + "kind": "execute_success" + }, + { + "hash": "3f9a7fb22147e3973b94545790ec3d03b708a127d9ac6bbde8a2219038aa26c3", + "kind": "execute_success" + }, + { + "hash": "45f6f44d683dc4836b465a837289e0e03daadc659657f6d43a9ed849816b320e", + "kind": "execute_success" + }, + { + "hash": "e0b517731baf3599ce34990a98b6cbb4de0d6f2aa87f5464ab8d1ad08d5a444c", + "kind": "execute_success" + }, + { + "hash": "49cf4125cd7f542f5da6e427b65f4055bf258a4222b53f4fd5b8c9d35d43cc85", + "kind": "execute_success" + }, + { + "hash": "c07f18953f2f969a13a5960a980a478de38375fd37ba121b8e392a6231251361", + "kind": "execute_success" + }, + { + "hash": "3cc2dc3054a830703b17a82923ed7944132c333d95fa0ed75454fb2386775370", + "kind": "execute_success" + }, + { + "hash": "910d42d09c35cae7f80724abb1ba7bf44428cf5449c5670060742d7883f77ad3", + "kind": "execute_success" + }, + { + "hash": "ef9e277012dc073d3cae3f138fe4e6e59305c7432e129ed6542b1aa939ea4ba6", + "kind": "execute_success" + }, + { + "hash": "aaee792148138d79cf6b9c8674e83cd1a4d8ae62efaac000d9b0817aafe9cae4", + "kind": "execute_success" + }, + { + "hash": "6893aa54dd2e3708dc6d78b38508e35259f820d8260994e4d8cdf2ddeba94666", + "kind": "execute_success" + }, + { + "hash": "97f3aa712f84f5aaa9a5fe25cffa2ce13a603a4d456e045834498e962578fda0", + "kind": "execute_success" + }, + { + "hash": "90d5cd485cc6a300f28b91a54966df2f81023837dfe21acf724dbc35f9f3219a", + "kind": "execute_success" + }, + { + "hash": "6abfb3d2c135e366b5569cf2f218efa2840c4faa28e172cc3e818aea3f21d9a7", + "kind": "execute_success" + }, + { + "hash": "b6467958f8f0b4f7bbf13fae0364b4909e29a764ace7bce4219637039acab744", + "kind": "execute_success" + }, + { + "hash": "f2789201264134b88d0473d6871ddd5ae93b532a5bfc0e304f80d81e439bf1f4", + "kind": "execute_success" + }, + { + "hash": "9c3bc33857fb8693bdf1aaa11dfde34598407071ddd22a4ed6a07896f5200f51", + "kind": "execute_success" + }, + { + "hash": "2a551a3a3a391fb11dd73bc4457b3ad24325a394723007f5fce7056b2bc7e88c", + "kind": "execute_success" + }, + { + "hash": "b0a8eca8907d1056f79bad72f7ae65872bf32008cfe5081751d5df4c4de53a2d", + "kind": "execute_success" + }, + { + "hash": "067b45d381e67c27f6c6b5c63f8d35ec2662612401bbff01a06c949b432ac4d8", + "kind": "execute_success" + }, + { + "hash": "c3087230fcaef017b462a9b0922853f09fea93a42498c3f9dbc212785afdb7d1", + "kind": "execute_success" + }, + { + "hash": "9985ccb90a66e1c7d31bc2ea5abc60873ee49badd679755ab7093fef44775725", + "kind": "execute_success" + }, + { + "hash": "2ee302d643b86bbad21e684523391c3f38a76795e13ff188d9906e15aa7af1d5", + "kind": "execute_success" + }, + { + "hash": "5c5bff02cc9a8173b3da4a8ed7470007022f95707e02ad65da6a2277ea273295", + "kind": "execute_success" + }, + { + "hash": "bf0202be83b7016799e09b992542ea683e40fbb2c671ad966f7efe75250a1b61", + "kind": "execute_success" + }, + { + "hash": "b771517a16c98630e4684218186b7f539f8aea3543b7b5e73f91c68f47363047", + "kind": "execute_success" + }, + { + "hash": "5c0317aae887b4bf241e3a8f73c0a46c1bd5914ad35b8ecd774ba16bb561718e", + "kind": "execute_success" + }, + { + "hash": "661fb50109685054f6824e6a60461bce66aa5f5055fc5910fa800c9f43798ba8", + "kind": "execute_success" + }, + { + "hash": "0bf07ab590fdd890b107f469836e3a6f9faf81b2753cce8e53dffb8d57d683f4", + "kind": "execute_success" + }, + { + "hash": "be11d245644d1cf2806f6e6d9c5e9d5412a73e0c48d4d6413b2f1c130614acc5", + "kind": "execute_success" + }, + { + "hash": "bb40033f807bfcb1bd70e5b01b6a5f44a1c119095dbc56255807d61acf1e9faf", + "kind": "execute_success" + }, + { + "hash": "01d105fd147697ce23aab2c9d50c3d6ab4b054ea4a71a35c89d1fffabeef9674", + "kind": "execute_success" + }, + { + "hash": "ba6473afeba86956113579b1a2eb891520a6e44b13f2dd840f76e0fa4f26e2f6", + "kind": "execute_success" + }, + { + "hash": "ab264e5aabddd3ffce2db7cda1a8f3d07b13a872d6aae7eefd0b9c10bbd3da00", + "kind": "execute_success" + }, + { + "hash": "743eeddde0bdd5676823e23b4ad0541c5d1b33af7aa2c2cc1c4bad1cc120a1fa", + "kind": "execute_success" + }, + { + "hash": "a8bb481e6b9d34676f2f14f4c59ee8cfdd38646fbe522a2747b70fe6df136b95", + "kind": "execute_success" + }, + { + "hash": "6341433eea0c69bde4f730d182b774d4b8ad1cb334f4284d4532a632c2363809", + "kind": "execute_success" + }, + { + "hash": "e6f51ac6e6dadc0674e394bc6dbf590b1e879a7cfee9e42873833d97df72b3fb", + "kind": "execute_success" + }, + { + "hash": "44f7ac0b5fc96d5078d033d955723229696fb4009c9cecb854e679cff63ed55b", + "kind": "execute_success" + }, + { + "hash": "802a3b55a2439ba9efe262c0bc31c43df3d26a22a1c20b0089971fd8235455ea", + "kind": "execute_success" + }, + { + "hash": "ed7ee82eb323fede26ee1d9503c714fc50ba2a617b6c0fb37fb983ec67f9f4ab", + "kind": "execute_success" + }, + { + "hash": "e6e5f9715f13edb3af9e5accf3b2daf137dc345383674c144acc31ce6883dea8", + "kind": "execute_success" + }, + { + "hash": "f9b1edd57ce065eca69b38486d4868ba423aa3332ceabfb9c943418b001032bb", + "kind": "execute_success" + }, + { + "hash": "b5d5b6827db204d0ca11ed3e25a06c7fd17b3bf1b64df21afdb2b2b96d6e0b01", + "kind": "execute_success" + }, + { + "hash": "760ca5b441510620338831923bcf2b242cef5dbd256fdb29f6dba44cad2f2675", + "kind": "execute_success" + }, + { + "hash": "69689198a435c3137aa783e3dfc6aae6f18d3d3f8dd7203b49f510caff4a6886", + "kind": "execute_success" + }, + { + "hash": "69ec0bca0c3037726a12ab780339f88957e348df3e9b92a6cdf216df52637dd8", + "kind": "execute_success" + }, + { + "hash": "44c929e132318feecc79f6ea15609516eb1538710a378f8e10041d2549aff0a0", + "kind": "execute_success" + }, + { + "hash": "a0c21f28b35e218e10e30a7d2a382f9cd9921ac76d3d1fcbf9e6b98f341a2ae3", + "kind": "execute_success" + }, + { + "hash": "2cccce1004721360964de7638fbece121bce7f7d81e87905cc8830f9795866b7", + "kind": "execute_success" + }, + { + "hash": "cb23f8b5255824b8eaf03ac13f6034ab37643787392158e64be123f9eb33863c", + "kind": "execute_success" + }, + { + "hash": "950f71a7471a2faed0f3e57600679bfd3e0ca74ff45f4d0881e3f7425f93d1cb", + "kind": "execute_success" + }, + { + "hash": "f00192bc9590bc6fb25d85c9685babe3f609b5c7bd918085ed73bc65537de6f9", + "kind": "execute_success" + }, + { + "hash": "be9df22c6ebfaa952e607d6b1ba0daaf284aa41b18b81909b8f699d3163c4329", + "kind": "execute_success" + }, + { + "hash": "cf2020d23ae00ac131e2aa8e49fa4f49c5f0087138607d735017251afeebb74a", + "kind": "execute_success" + }, + { + "hash": "6d91c4ee77c673b09f1a8fab159f97a2c3998e388a66426abf57d5c89a78d8ea", + "kind": "execute_success" + }, + { + "hash": "000d41710d4a0e1366b2ae11e86e26e4d67ae292c34aace6e9ce956e2b65bd39", + "kind": "execute_success" + }, + { + "hash": "c86ca41ef37117786ce454b433ecedbb37197463606b8b32c50e62cc3841709d", + "kind": "execute_success" + }, + { + "hash": "9976c3bf693ecf76357a185308f24534d4bce69ea037677a8eb40cd1855ada5c", + "kind": "execute_success" + }, + { + "hash": "221abaab36e896902f06551184088ca3a3bff9b11e4c7302f941773e870eb7dc", + "kind": "execute_success" + }, + { + "hash": "766a659db087e135897bb7e6684209f9f6278a6324dcfddab9aba385bced45cb", + "kind": "execute_success" + }, + { + "hash": "c131e3c171a6593da044279108c8663a3c5184de85d6cad72db31e378801dc73", + "kind": "execute_success" + }, + { + "hash": "7a5dee65e5bead7c967378b41127da8a4a1f87b2b75461b52869a3c66cab2c1a", + "kind": "execute_success" + }, + { + "hash": "8f04e30fa97fc3e509fe9dc9e47049e5de186c2d05c2eafcb07417dfdfbfa3e5", + "kind": "execute_success" + }, + { + "hash": "35188ec1fd69a52ba80ccc58549c5f2e325aa49ccaba228a03a2b5121c331cf3", + "kind": "execute_success" + }, + { + "hash": "d129416da0d5d7c81721d7fced7831d696c67edac9cb96224fcffc63b30668cb", + "kind": "execute_success" + }, + { + "hash": "b88315cfe3ee22c3c06ab1542964dc883631916eeeaac9171aa4642a76af0118", + "kind": "execute_success" + }, + { + "hash": "4a4002faaddcb3ad2d4705a90677cbdb5062badd56f56f090614441178e0a333", + "kind": "execute_success" + }, + { + "hash": "d6d24f03a129dc564bfd10b7b8f3b63d826d61f1a2ecfc817532446942828eb0", + "kind": "execute_success" + }, + { + "hash": "5b9bb9d346af504b2b1009972832d288ee397fd1125e3c19d346db914d24b538", + "kind": "execute_success" + }, + { + "hash": "dab289fb534fc3f5cc20b3419f3baa940ce0d70c145634ff60f20bb533df242d", + "kind": "execute_success" + }, + { + "hash": "7e91e39651be568701ee3271a9d8bda26336d098df3e9b10877262bd6b467538", + "kind": "execute_success" + }, + { + "hash": "271868afbbfce36b39ca108843119354c80ef38bc1fc9f490d703f94b7b26a95", + "kind": "execute_success" + }, + { + "hash": "8e5172fd7ea4bc8015d63c216926026bb26daf0f22a9f1dce1681ae95e2c0caa", + "kind": "execute_success" + }, + { + "hash": "d1dcef6d862ff7daedc71ed2ec675be2a13c3c0f3c17a5a412d40f6d3bbcc15a", + "kind": "execute_success" + }, + { + "hash": "faf69718dd53dbc2173e5ad26264d6c75d24c12da62262377b92aa105d00e87f", + "kind": "execute_success" + }, + { + "hash": "ceea98858734e8f7f84d6e7aa7102dbc0b0a6b12ba7b87146b7fcbcb18107f48", + "kind": "execute_success" + }, + { + "hash": "0498d255598d3f008de0ebac1187cf9fec14e93732fa9295fd4365a5c964e0de", + "kind": "execute_success" + }, + { + "hash": "190668fdfb7330444eae23fa57f8a3ff249fe0969b294519035e09372631b70d", + "kind": "execute_success" + }, + { + "hash": "06ef386d6ab174b9316e89602c9f4f2b1d191af18036da62e9de37dd7a0b85ba", + "kind": "execute_success" + }, + { + "hash": "0fd44cc86b9e03c59dcded7edc756ab110bda122e7eba26f30b47076a6d1ed35", + "kind": "execute_success" + }, + { + "hash": "807c99ccabd76718e793fa67b92a0c59b29525f2c4a9ade302454e2a57be2144", + "kind": "execute_success" + }, + { + "hash": "d84fe05bf13a0291f8f160a9953020216cf1609b7757e8ae2b67f74aea94dda4", + "kind": "execute_success" + }, + { + "hash": "afa9417ad0afb8d580b08a1b5099a25aebcee86ab3522df5fb15b9ae0a6cdf70", + "kind": "execute_success" + }, + { + "hash": "e242e73e6bbf6601058ced7a451ba6b0aa4f0e95638dc5d0660bd50662320fe4", + "kind": "execute_success" + }, + { + "hash": "df56c7636b3be1197b11f696627cc99c51a47c8fec76ef6a09b4adcf65d48c4a", + "kind": "execute_success" + }, + { + "hash": "1b9099be1fbf3653a8a2fadf334c263ee17aff2934ad89fd0870776a201b2d8b", + "kind": "execute_success" + }, + { + "hash": "9767d0ee961673394ff05619f2dfaccdeb236b0a2454396d98c969d462371ec4", + "kind": "execute_success" + }, + { + "hash": "3523fb9e52c5b84e7f183184f31a091538d4d8c8ec5c7214b21e02f28ee04b5e", + "kind": "execute_success" + }, + { + "hash": "56537625edd114e24ae383842633052003c2c4de0e34f6b40a9e067e51ac8d44", + "kind": "execute_success" + }, + { + "hash": "a80522559fff04872f2e2549374812374165502f0bd55c24c4b8c572a71c3076", + "kind": "execute_success" + }, + { + "hash": "7afa119943502a1b145d1b3786ce1d9a9115af9b4710cf73129145155bd16755", + "kind": "execute_success" + }, + { + "hash": "eeb61cc8b44f82565a855bda98365604d3f05854969a5b4b5a39a0ca597e180a", + "kind": "execute_success" + }, + { + "hash": "8ea4d1f4690a58a1b18d52eab0ebf761e2ee13a0dd1eb3b3741167ba08fee1d5", + "kind": "execute_success" + }, + { + "hash": "ed0be54c4106a3a75951e01eb120e19e6418411c8ffde2045f6828bd699bb212", + "kind": "execute_success" + }, + { + "hash": "e215ff1dd269b7cdf1a30ed3f934e7776fe11b173e0b6d0401ac93c80a8a66a6", + "kind": "execute_success" + }, + { + "hash": "52bab72dbbad6ee184e634ba862f3cb287245ca1a15e1f8184d8f465901ea421", + "kind": "execute_success" + }, + { + "hash": "8fa79ba0301693f25132af0d472db101f0cd355706576b4df3edc0142f6a7bc3", + "kind": "execute_success" + }, + { + "hash": "5e2fb2a3487e0c9040240b0e7897948603e1048ca9a4db56c8400339984fcc01", + "kind": "execute_success" + }, + { + "hash": "5db6d4d931976de724bc1ef5a19a2b07db56c444a9d6624e3e925300738f0c7d", + "kind": "execute_success" + }, + { + "hash": "8b26dade9e8e672c40032e17ccf59f18e42300cff0506c21898204e31b0e6da9", + "kind": "execute_success" + }, + { + "hash": "0895b58db52b3a6d053e53a44917d67de9acefd30e7dd48ea898ebc199529b4d", + "kind": "execute_success" + }, + { + "hash": "75908a7cb3b1878465fbfa835df5650279db6e4ecd9d31a0dc4b74b0d59b8ec0", + "kind": "execute_success" + }, + { + "hash": "8625fd25d3efa607cacf9ca5b2a4dd5f2e75afc0f38e1580d0c5fff726951fab", + "kind": "execute_success" + }, + { + "hash": "dc2bb896e883f140788307217324c9a819f879e0b1b391e901fd6f3320f6bc4d", + "kind": "execute_success" + }, + { + "hash": "d7c1519c321aefb0ae760c4ef661d1ec37803d50dee5a00d8814d0302c9a457d", + "kind": "execute_success" + }, + { + "hash": "65a4672f173b2b81b835bdd7b1ba160730e03233983f04562de846603c3dd382", + "kind": "execute_success" + }, + { + "hash": "7718c33bf9324ddf758e80b117400eaed13b8e970f0865f6387491e9c27f20a6", + "kind": "execute_success" + }, + { + "hash": "21316825360d04bf72494a83dd53646453d660d4713d95fd5290e71a98be0a12", + "kind": "execute_success" + }, + { + "hash": "9a38879467eb249a4003b6eadd9ef379dfd3a4cbecb7646e8938b3d766a8c912", + "kind": "execute_success" + }, + { + "hash": "e30b401eca28d6bbb03d9bec41686059755fef54122082c03e6fc7f9d2b21907", + "kind": "execute_success" + }, + { + "hash": "04a0786b7b56dd5c2a387c16ca7fa9671b14942b68fcb43cea3dd8f88525571b", + "kind": "execute_success" + }, + { + "hash": "7710de836128cb20c65cf5050c20b36e99a2c5c9432a8769d8bbb54dee41d4d2", + "kind": "execute_success" + }, + { + "hash": "149c96113e5e0f37a9962342bfbe91d838e5be818a51da7629a358dc3bd8c94f", + "kind": "execute_success" + }, + { + "hash": "c5c1d6a0e9e581a4fe0ac71a1060debba068de1cab3bd01ebbdbf2ea21b52f85", + "kind": "execute_success" + }, + { + "hash": "f21124957a1ebbb046667bfc0bd08a229ebc47e8d70ac83169c3855fb2af06ea", + "kind": "execute_success" + }, + { + "hash": "7a120f1a20569db4266478e036d93b3bb1c851ff732a93aacb1155b97960dc31", + "kind": "execute_success" + }, + { + "hash": "fcd8f87d70b9e090e5e83daed84ee899d955d4cda7644efe8d81e2a7cbdcebd2", + "kind": "execute_success" + }, + { + "hash": "3f94886c463f246cb23799fedaa405821252b17a82c2635dcbea181469a3ab18", + "kind": "execute_success" + }, + { + "hash": "9ca5b87fb8439bd5edbac0b1d80a78092b9fc3355e2b6b2f922bd9a824eeb908", + "kind": "execute_success" + }, + { + "hash": "f284576ee00cfe7311d5775ffe8655469f09b334977ac90a297daa253765baa4", + "kind": "execute_success" + }, + { + "hash": "e753d42897d7c698e469bb3b1cc127c61c065d41744a8ba489d2f8123c81255d", + "kind": "execute_success" + }, + { + "hash": "01da4b54e94296e411f0618393e33f917aafc86209c57236f97a4c073fe35d67", + "kind": "execute_success" + }, + { + "hash": "594d50402a5a9b023c8caaa4515c2feb435f66946ad9a52bb9385b4d139764ef", + "kind": "relayed_error" + }, + { + "hash": "177176fcea8ea370687914f61fe40c06c1685a9db6ed5fe705c79711b13435fa", + "kind": "relayed_error" + }, + { + "hash": "5bc8f3cdc8afb830d93ec6d1c0b218dc45925247dcb7fbdcfe4eab7ace410ebb", + "kind": "relayed_error" + }, + { + "hash": "ec82a5610b816b9af5eab17bc735456dafc6301cc9a594b7270f4d25d1c0185f", + "kind": "relayed_error" + }, + { + "hash": "49481d82403dc57e369032e913085b5404b92e4315e71a169fff09377843d70b", + "kind": "relayed_error" + }, + { + "hash": "a668adff12551e9333e92885d27bbd87260e1c37876b6f6fe6bff0136b7e3099", + "kind": "relayed_error" + }, + { + "hash": "17f474733ef9f8669f6c404bd9231e4f0c60a66874354ce913c95dbee95309cd", + "kind": "relayed_error" + }, + { + "hash": "07ed7e82fb9246a2a5dce205b2a196d5ae2416bfe7d5efd55aee389f6a9d2e6e", + "kind": "relayed_error" + }, + { + "hash": "fffeb20fc894418491157fd0d686d4d93693f4296d97ff18b40df7cf7cc7278d", + "kind": "relayed_error" + }, + { + "hash": "b78fcc53c31f13e4eba8630ea79dd7a4e29bcec2bc957a7706bfe3edbcb54386", + "kind": "relayed_error" + }, + { + "hash": "8e0643dfba8111efc5a558f16815598814109ecf5990e9d411f5fc0d303381b0", + "kind": "relayed_error" + }, + { + "hash": "d203c9af8b496b9b6c3e8ec7c354a4797a1b09b61c03c0900b5b78ea1a58a0ed", + "kind": "relayed_error" + }, + { + "hash": "231a52889ba4f35dc0da7193fbd8fd60ed24f0e02f51a845b9900d2de7ec6037", + "kind": "relayed_error" + }, + { + "hash": "7e96e79610a959e6d9bc7f96020c02ecc5cbf814b3e66522106e5b2fa3ddabf7", + "kind": "relayed_error" + }, + { + "hash": "2abe8b101287e559ef0cf110385b040da24228c276935cceb941003e76eda0fd", + "kind": "relayed_error" + }, + { + "hash": "a24c0690795db0bec07de54b0550ad839309fbb6f848ce625ea960307db4e688", + "kind": "relayed_error" + }, + { + "hash": "9fe23777d62dbe1c7239cb4d1c604a42f5ab556dd02b23ac2a733444c82115ce", + "kind": "relayed_error" + }, + { + "hash": "a8c65c9fb2de37e87befd18a91fad19c58ec6312e1a7e2213e471b0a52160b9b", + "kind": "relayed_error" + }, + { + "hash": "494b20b716236042bca009dfeeafc340f7792d4bbfad3023901de329733a823c", + "kind": "relayed_error" + }, + { + "hash": "b9f6f68ef852bfaa741905dd85d7335622485cc6542a0c3af5a32afdebe41154", + "kind": "relayed_error" + }, + { + "hash": "eee785ce0a793e4f05c8b9071f38e6e2a137643f8586d98e8d7dee7623cdcef3", + "kind": "relayed_error" + }, + { + "hash": "4f50b4d356745a6534a63bed9acf15238ed291a89a979910140d35c545b73d75", + "kind": "relayed_error" + }, + { + "hash": "e91e4640cecb86f0a77d7568b72640a29185ed4d99e925dc291f74339d77d661", + "kind": "relayed_error" + }, + { + "hash": "fe1aaefaab26ba9b9df8e6b16de8b0b54f8c51a7603d6ce492fd0318c79468fd", + "kind": "relayed_error" + }, + { + "hash": "0d0044498045f2279c84de64ea3b7b16831340c14c832ff2aedde1cce1c0f66a", + "kind": "relayed_error" + }, + { + "hash": "eb2e2503bdf945a99097fd1e2cdc820cf092ffd9d0493e43966442eff43eb681", + "kind": "relayed_error" + }, + { + "hash": "2a06d64db1e767471429fe2df72e2a4f28c4880d5e8bcf47009e393f50691b25", + "kind": "relayed_error" + }, + { + "hash": "34dc68aa82ce64e7b7485529e85df13e642e8cc75500ff12b1d1c5c54adb93c9", + "kind": "relayed_error" + }, + { + "hash": "685e36f9d5da363e653eb7513edb4c3dab79d9f63ef8f8e1697f3aafac2265c1", + "kind": "relayed_error" + }, + { + "hash": "3f51414b076be62c9c1ac2745ba18ee91a5d113e4da81404e0a86bef28c294d1", + "kind": "relayed_error" + }, + { + "hash": "59fbcaa3f62c6785d04e9e630c8addae6ac6361aad0652698ab392764d0572c9", + "kind": "relayed_error" + }, + { + "hash": "5fde3bd3c253195c1a4f0179106ef36bb423cd621e1429235e0b809d0245af5f", + "kind": "relayed_error" + }, + { + "hash": "fa290fb7784d5a564a6e5fbea3a7cd935a41b7d99768587ee5b517e8139c5fe8", + "kind": "relayed_error" + }, + { + "hash": "4f86a59dcd2c994b0c007916910a124e81ce820405917cb6186eee9230193f48", + "kind": "relayed_error" + }, + { + "hash": "e489352a48ccc196ef933b19f7096fe95283ab777ae00db09e36909a9fe549dc", + "kind": "relayed_error" + }, + { + "hash": "904928b693dc3750071fbbb51881c6068a75e2869fdf440e432279060b720e42", + "kind": "relayed_error" + }, + { + "hash": "15a30e3d69b06c4d8c04a18783859c0016d621aaed46467befea344cc1d73759", + "kind": "relayed_error" + }, + { + "hash": "a86c960fcb51e72a3abbc93d088d92d6f06843c21fd75d07e2b9e25dc9ea3dc3", + "kind": "relayed_error" + }, + { + "hash": "e0e25a51fdddba951e015c3674726f0f3a0a4ca3ae419c5d9a5101e5cdd48ecf", + "kind": "relayed_error" + }, + { + "hash": "a1a50692da1c951f8e04fb4464a2e9a5de36993061975c8e1527dbcb39c0a5e3", + "kind": "relayed_error" + }, + { + "hash": "fb974f799d66cc5e06e4c9407a55ccf2cfcd9f6d9f85d2a780338426cb3deebc", + "kind": "relayed_error" + }, + { + "hash": "2716c7d7d8a2e84291e5079da0b843d4efa688ab24fc55eee604d17b69c12c66", + "kind": "relayed_error" + }, + { + "hash": "decb06a828c56baec63315e3c14224310cb77d975b2cb3515ccacf6dc93c80e0", + "kind": "relayed_error" + }, + { + "hash": "23e52140112f294d40523071baef64090966c4990f7685b68b250eebe63f418f", + "kind": "relayed_error" + }, + { + "hash": "ba2500c6a18d8acbc672b3f164933e1cb1042a5a9480a89a0f69e8f2b22c95b2", + "kind": "relayed_error" + }, + { + "hash": "73baaaebb044ad79c188bef3fb307d5dacf061e583c813ca188e529fd83a5f34", + "kind": "relayed_error" + }, + { + "hash": "e199735f5dffa06113e706b81ba60dcd232132681856c3c55d9b661265a47a24", + "kind": "transfer_execute_error" + }, + { + "hash": "a7806f527c753930709451735ace13d33a6ae8dea6ab3cd35607997d220cb6a6", + "kind": "transfer_execute_error" + }, + { + "hash": "5ba19842696abb440bc65372100ec8412d943ad52a7047781946535271e9bec8", + "kind": "transfer_execute_error" + }, + { + "hash": "1300565ac341d0d6b1864d6530eb95f2084c693f3a9a3b81155c7c579ac28c79", + "kind": "transfer_execute_error" + }, + { + "hash": "432418c5c169b3fc00e3b970e4ed0f7e9dcea97f5785934bac0daff0aed405ed", + "kind": "transfer_execute_error" + }, + { + "hash": "4f33cd583a568ba8641fb6e3ecba33fee35df544eebe6fad4547925a1ea56d0d", + "kind": "transfer_execute_error" + }, + { + "hash": "7d12e48a0bb3f95bc79aa61c2a768e3ea48f5aaecd22256d3d5d00d32e7d8ad7", + "kind": "transfer_execute_error" + }, + { + "hash": "4d3875c86f4a1c767964766a980ea58797b612667a07b86b375f24845b477d12", + "kind": "transfer_execute_error" + }, + { + "hash": "9974784f5240e32cf45052f54559323acf51e2e682fec8048c08bcd2e751b94f", + "kind": "transfer_execute_error" + }, + { + "hash": "41ce18715ce6e01b688db86ca0c26a906562c3b6193947f1989cebd002116209", + "kind": "transfer_execute_error" + }, + { + "hash": "92d5dd891cf676ff75a919c0e216fbf7b54696459d7ad2199ec659efc520842a", + "kind": "transfer_execute_error" + }, + { + "hash": "838b5a1482ff3bfd18f6010f9340d86eb619bc662cf2e6d9155ff37c9696ca5b", + "kind": "transfer_execute_error" + }, + { + "hash": "4dcfe210a10bdda0015ddb61462fb2fca6ba49640f426cf8ba9dd51695114a79", + "kind": "transfer_execute_error" + }, + { + "hash": "555e015b6abde8a0c3ec5d627e98f08fb1cfc1ef25973d354a2d701e7d8853ca", + "kind": "transfer_execute_error" + }, + { + "hash": "6cfb5ec647dccc73a1e65744491f070d2a051c575949ecbfe6d262a272ec46b6", + "kind": "transfer_execute_error" + }, + { + "hash": "5fa1f3c6adff1f258c2dacf5559c72ee2bd11a065891abe9f9e8dedfdcd53bc6", + "kind": "transfer_execute_error" + }, + { + "hash": "8cc835136222b1eecda7bb18372ae40c7bc8aa0ace702ea23d295fc9a39cfb75", + "kind": "transfer_execute_error" + }, + { + "hash": "bae1030571bc9bf99409fb3bf6d6ede6a892cf6d51d66d89af1b042741411ad4", + "kind": "transfer_execute_error" + }, + { + "hash": "6da45162d8bbc38c46c15938b0e6816178facf2ceb4ed9a794d581286dda746c", + "kind": "transfer_execute_error" + }, + { + "hash": "0d1efe38a87451ab1d323d6a81cbb120d508a072ef8f9227db529ad03ae1b82c", + "kind": "transfer_execute_error" + }, + { + "hash": "e588057a0dc601848c33a58526eec1208bea081f415827ae87aa8b623f2dbc26", + "kind": "transfer_execute_error" + }, + { + "hash": "f8c24c3ed2fc865b6a47b7c5bd0c3e92b5ac4103f41b1f4494285dc37698e411", + "kind": "transfer_execute_error" + }, + { + "hash": "ce63d0e11a8fbc61dbca2f61a701abf7b50b9d7c451c6580af443c3b55d6fb66", + "kind": "transfer_execute_error" + }, + { + "hash": "cd1911170ef69b6d68beea92fba854e0bb293f1768e3369924daad417e2c5a92", + "kind": "transfer_execute_error" + }, + { + "hash": "245801a0e76b4dee6e455e5d04c79646d776ce1cf7922c28c96faa00391b2f9e", + "kind": "transfer_execute_error" + }, + { + "hash": "6c27647dedd879c6d3411bfc893c5dcd92a4b650eabdcbf243380d7face42733", + "kind": "transfer_execute_error" + }, + { + "hash": "731df0d9f1722ec61ecfb1ab1e8b178071434372b5d632b22680706882b1505f", + "kind": "transfer_execute_error" + }, + { + "hash": "7240b2f6379138b285f23da9528fe6fb5b31f23f403e49dd7c5c393f7316a401", + "kind": "transfer_execute_error" + }, + { + "hash": "8fe13352cdc3f2b2b99090a215c17da923289706868448433c2b7449b7283af4", + "kind": "transfer_execute_error" + }, + { + "hash": "7e227c71709885496e1c8c65f578ba50ed73fea19837023dd3ce5cf3b04a7074", + "kind": "transfer_execute_error" + }, + { + "hash": "ae605452722ec43c0184fdaaaba63640c09c18606c78c55182d4d739df0049ac", + "kind": "transfer_execute_error" + }, + { + "hash": "27272da00b5b121b3da50a31b4f3337ff8fb9d6186b418149ff93c5679c74318", + "kind": "transfer_execute_error" + }, + { + "hash": "db1bce4bdeb3325121188812e3f40569a70af24799cd59c8a062047c2d25d848", + "kind": "transfer_execute_error" + }, + { + "hash": "5b28c1e180b6203aa34c7a1c52c470bc6f9926de24dad49a4768a11bf021c4d0", + "kind": "transfer_execute_error" + }, + { + "hash": "b8725acea8cd32ce57c0a44d0a4bff3a2f9c4fe33eb5f5d25a01c60c22ca1660", + "kind": "transfer_execute_error" + }, + { + "hash": "4578b2c23f5a4a0dd9d747bbf02a65d1f087108de8ef8e6b9e67427c5607615c", + "kind": "transfer_execute_error" + }, + { + "hash": "bf8a7d6657251185759d7b9496ac2e6a5ace5fc0fe48090c842654182cf9b12b", + "kind": "transfer_execute_error" + }, + { + "hash": "241e35f7ce76eb1f4915208a3981be659c4ccd01ecf655b90a93a8620a44e509", + "kind": "transfer_execute_error" + }, + { + "hash": "f440fbff5159bb35538467d57c5fd55a32778f73c79d2cd7d98b39515d6ca77f", + "kind": "transfer_execute_error" + }, + { + "hash": "8ced64566375d387193371db4a820cd72ff77897cba974de610c6488e7510e35", + "kind": "transfer_execute_error" + }, + { + "hash": "9857c8b1d86a04f5cbb2314562af9156b8adb58e1c20c29cb399528c35dda4de", + "kind": "transfer_execute_error" + }, + { + "hash": "e24905990e739366d08dafbbcb28d6492f70ad7072f27df2ef9bfd380e66f194", + "kind": "transfer_execute_error" + }, + { + "hash": "aec5865d9d56077d355fdf2ced37db63b93d4cbff0335ebc16146ef6e2769a62", + "kind": "transfer_execute_error" + }, + { + "hash": "0de5299d4400b220924b2acbf1f563e79416cc2956790d97c540599adcb3de15", + "kind": "transfer_execute_error" + }, + { + "hash": "b7a57096e29006060f31063fc5b4ed1e5bd1ad6489d45bb83f1562f20ad93569", + "kind": "transfer_execute_error" + }, + { + "hash": "df2f1e501003977b05e752b12e45f29b9405e96dc70826d1a487fbfb7e277eb9", + "kind": "transfer_execute_error" + }, + { + "hash": "04fe980c0c5199e0500d2e38a274db61a7ccc01246dc76de812f1ab0ec22341c", + "kind": "transfer_execute_error" + }, + { + "hash": "106794236b282aaa9be098e7f77c5fa03706ec34f311a2d66ad9b249798eefe4", + "kind": "transfer_execute_error" + }, + { + "hash": "b1597212830e12bdbb4cb982e4dad16f8edcd486d2daf6b74f3c7070da7d4b92", + "kind": "transfer_execute_error" + }, + { + "hash": "29006653d2b3667285f9f025a2e36186b42bc43bf8f4b584876cd6e583fbfeed", + "kind": "transfer_execute_error" + }, + { + "hash": "bde71fb5bcb6053fb06075751349458eb66e19c3c1125a46f2eb0924be75007c", + "kind": "transfer_execute_error" + }, + { + "hash": "17510fb3145e06854f623b6d1581393b9d346da5312bb0e9591611ffbdda924b", + "kind": "transfer_execute_error" + }, + { + "hash": "0199f4fca008e8809d371fd4ebc80695320e0318ffdd5a65c5dddfba8fb27d7b", + "kind": "transfer_execute_error" + }, + { + "hash": "8f79063f170079a47bd42d4142ecd68199323ce9add6573281e3edaff45853d9", + "kind": "transfer_execute_error" + }, + { + "hash": "7646d573d14caff4f00162b527a67647d394091b9cf29e2f93eeba3b5e9fa83e", + "kind": "transfer_execute_error" + }, + { + "hash": "e5078bc60efaa10d28b9a334925198d8d84452d6b882e066895dade2def53b79", + "kind": "transfer_execute_error" + }, + { + "hash": "00ff560926c5ee3f8988fe5438f032f3c3e15da640fccb76209561c6e813b940", + "kind": "transfer_execute_error" + }, + { + "hash": "f8a5eb2783872fec4a4ee7d55fac9dea7c68e0ec76d6e9a1b78a3ffd49d20b84", + "kind": "transfer_execute_error" + }, + { + "hash": "a6c45391b16cb66d6a1c7529823ddd5918f2b501c853ca174c94846847ebf087", + "kind": "transfer_execute_error" + }, + { + "hash": "cb25439b4fc70c8050db72bf97b318f7390d1d1c06d861fbe61475dcab400c19", + "kind": "transfer_execute_error" + }, + { + "hash": "cbfa422b498daefcc364ad607120683910c809cb4f6b9831f6d3394af31f5e04", + "kind": "transfer_execute_error" + }, + { + "hash": "deb8de1f238cc7325d38b3c4d35197884be85bbe453cce5bdb1600360cf721ce", + "kind": "transfer_execute_error" + }, + { + "hash": "84a0e5952122e172db0204ada29af2f08213d0adac3f0ccbaa838cfb8913021e", + "kind": "transfer_execute_error" + }, + { + "hash": "a16ee2f63a9c0e96a02ae53cd509e546c149c006b8c706df77f331a374f8b313", + "kind": "transfer_execute_error" + }, + { + "hash": "7db0639594b2d80d420e1a07a669ae0503da88ab911852b3d00fc0330ff247c8", + "kind": "transfer_execute_error" + }, + { + "hash": "b545d4be56003bd85729b68eaff21f1ebe164b5baf16345d55224eff5f892f45", + "kind": "transfer_execute_error" + }, + { + "hash": "16eb57904761126ecc7ffd93472467dac5f9349244da9cd1cf546435e7811687", + "kind": "transfer_execute_error" + }, + { + "hash": "a4c75be9679fc491ea19b227e5c8036c87fbb355c422b9978f9d831887f8b64e", + "kind": "transfer_execute_error" + }, + { + "hash": "7737783c398c6e9e00fca7012b9ebfee52bad9efad8e239830a18124293fcdd5", + "kind": "transfer_execute_error" + }, + { + "hash": "1dd0fa287039c22ebd89b9d25f70734449c1d2c538afead8f28ff739148e6c7c", + "kind": "transfer_execute_error" + }, + { + "hash": "89cbd23307845f386e39f2570bd02ad5edb532109308fc210f2c169966aedadf", + "kind": "transfer_execute_error" + }, + { + "hash": "d4ddef4144dc76f10511f5bc6162b848b86883ef5c833eaba91287e0a184d349", + "kind": "transfer_execute_error" + }, + { + "hash": "f5a4d2d86fbc77d27d309d5275db6b2ebe619136240cd5435ec81f01d591230e", + "kind": "transfer_execute_error" + }, + { + "hash": "22ae7310fa9b26f39c438a6744a613fddf9e0bf2a74061712cdcfa1598ac9c15", + "kind": "transfer_execute_error" + }, + { + "hash": "12b84a7907edf002c4dc7a47ae4110b55a7d1712dc0b5af77a3052fc7173877d", + "kind": "transfer_execute_error" + }, + { + "hash": "c9f42ee8568da6659e34dc6c7f4c45f5e4f3d40b00c2f61e29cbdfd48b71eb17", + "kind": "transfer_execute_error" + }, + { + "hash": "eb23df3f07a02c9bd5f9c75f86bc46673a5c2ea25b2e0e2d2471b476733e4536", + "kind": "transfer_execute_error" + }, + { + "hash": "31d72e60b0caca1985af7a018d4981b169761a6061b2c9968b6c42139f0aac35", + "kind": "transfer_execute_error" + }, + { + "hash": "8ec0f6d160608ae1cb9b9125f33a570f892aecf3496edbd4727c381775e16cda", + "kind": "transfer_execute_error" + }, + { + "hash": "897897d8b320cdd320c4141962f326a735278039e0a2408f76b334879c8d9b7b", + "kind": "transfer_execute_error" + }, + { + "hash": "34ac3b53b14a4c329a25f161135d40bd33c85d80e0d3437b021f407a80aebbbb", + "kind": "transfer_execute_error" + }, + { + "hash": "3f6660da305bff514807a5aa42c9e962e32bdda26c246004d15d579548c45c3f", + "kind": "transfer_execute_error" + }, + { + "hash": "81bca924638b6dcd85bd9ee29da0500438a0fa8587dba42b51490ca8aa844154", + "kind": "transfer_execute_error" + }, + { + "hash": "10fd8eedd1f129e12c493f13e738ca0ef477bc0a8e83c81442199bac6c40bbdb", + "kind": "transfer_execute_error" + }, + { + "hash": "6f9d41cc61b47287737418b747261a9c44fdf12bcd3401632ed2cbe786c0da01", + "kind": "transfer_execute_error" + }, + { + "hash": "29a96f55aeb15deeb51542d68caac6d2945a8353243ae92de46237290f7373a5", + "kind": "transfer_execute_error" + }, + { + "hash": "68b05dfc84252490b2a66cd6fefe792462a93cc1055dc471d9330ae57f67480c", + "kind": "transfer_execute_error" + }, + { + "hash": "109eaaf35ec5d7617ee68fb871a32b68f00afc5f72911aba9fe000a4eb4a68a7", + "kind": "transfer_execute_error" + }, + { + "hash": "db22ec307721d755b9a1d8fb1a7057bab4a4ff7752271634833266073144a33d", + "kind": "transfer_execute_error" + }, + { + "hash": "bc5717c7948ff5c1e5825f9873747a98ab97b06e0d486e12f15aef367a9dc541", + "kind": "transfer_execute_error" + }, + { + "hash": "6e8562f8d8b253d01525501b6d18b2d00eff719da761b83a24ad273fcfa88196", + "kind": "transfer_execute_error" + }, + { + "hash": "c29bc214cb8b6c72151e2103cd1ea831d355b16103639c62632b7429b046d7b3", + "kind": "transfer_execute_error" + }, + { + "hash": "a45a9642e60d3875921537a42e367ad3bec852e9b92e9cd9918bcaa694f85ae6", + "kind": "transfer_execute_error" + }, + { + "hash": "eb81d736d14f12b26f3b65278128acff3fe2aee50a5b80bc8a9a69a7bb8d03ac", + "kind": "transfer_execute_error" + }, + { + "hash": "c257b1e47ce85903ef9e362f268ae79eabbdf62903ac0e22a2c2183bad1b3cf4", + "kind": "transfer_execute_error" + }, + { + "hash": "7c97319901b53ebc6b69d44e8acb529967d59b5f253b5cb577c2827041d852a9", + "kind": "transfer_execute_error" + }, + { + "hash": "7d3f7330f0d362c94a2e41cab50e1d077fe514a481ccbde2ac156e900cf34280", + "kind": "transfer_execute_error" + }, + { + "hash": "3d68eeded9220c4d6f5894df1e56e4d2ee80241985a57b35cdaf76eb68a87dc9", + "kind": "transfer_execute_error" + }, + { + "hash": "5cfa274f3e15fb52d78d12f4ddfb0b9cfd2f4d875ab40e8800bad75f318f60ff", + "kind": "transfer_execute_error" + }, + { + "hash": "9ac0592bfe75cab312dc23745d853572cb7b71cc1f9c63341bf4539181c3b66e", + "kind": "transfer_execute_error" + }, + { + "hash": "9a4e4d4d1c4c751db1cc0804ebda5e3171240ad955cc1817b47432460c5d0d43", + "kind": "transfer_execute_error" + }, + { + "hash": "ae06a7f467b6581997b8c5e232f10856a24641bbd6935d9460d707fb835f11c2", + "kind": "transfer_execute_error" + }, + { + "hash": "eea2234b62e83c5a67339b24d5eb757307d57db39f9e9b8fe14b3cab69898bd4", + "kind": "transfer_execute_error" + }, + { + "hash": "a3e0b9c22a6c565bd78536ef6ed6d0f249c6c72a10accd6a17ce97677bf8a5b8", + "kind": "transfer_execute_error" + }, + { + "hash": "34695a5f96ea8c614c71de98ac00cc6cf15ab389d2cc715808eadc589f4e1afd", + "kind": "transfer_execute_error" + }, + { + "hash": "7afbb38086ec156fc23aa544f5f9dbfdf8180975a805174b79e418e096ab83f2", + "kind": "transfer_execute_error" + }, + { + "hash": "dc1e2cb75077088c9799793e7dadc6b4b29a98df74a8ca929ee3f1204c499541", + "kind": "transfer_execute_error" + }, + { + "hash": "721f4cd726d3d90f12dd228400531f14d8f2e06fbde891762376cb3dfde54517", + "kind": "transfer_execute_error" + }, + { + "hash": "541dce9545f414096f31771419179e2cd689f133da8564b59804ad9dc7214a65", + "kind": "transfer_execute_error" + }, + { + "hash": "be69dc1f7dd2b8c6082a01c5b1d3f72e28b9a24344a218e7bdb0f49fe75c7e48", + "kind": "transfer_execute_error" + }, + { + "hash": "ecf9e2a0715a7dae2158b04afa8468aae2639678dbefb3866d33c49b76dc82a6", + "kind": "transfer_execute_error" + }, + { + "hash": "973c2b92b42cc42cbe74f12b8b5e70b4cce5daa421aa513253c1593a05fda709", + "kind": "transfer_execute_error" + }, + { + "hash": "276c1a427ac168adaba175bcc72f05049a34269c50480fa529ee7daa52ee5b76", + "kind": "transfer_execute_error" + }, + { + "hash": "d0b2598232994b36be9eb6d92fba17514ba13bfcbdb095094e5b6d7ad4cfc4c0", + "kind": "transfer_execute_error" + }, + { + "hash": "1196260ea79e491ad1c1f56c05f5993d6c6c7ac7a3e00ed984a0516adfd7d7af", + "kind": "transfer_execute_error" + }, + { + "hash": "415d80fbb1267091c2e57e990b7cfc75fe16afff83a68235caf8f5b4590aafbe", + "kind": "transfer_execute_error" + }, + { + "hash": "aee311773b2173180ee1161d02a7f52b7f5968e09b7cfa178ef4a7235a938771", + "kind": "transfer_execute_error" + }, + { + "hash": "381e10f3d6ae251cdeba7f5c046289e8ca30923d341108650b56d94337016d09", + "kind": "transfer_execute_error" + }, + { + "hash": "84f510c1c6fc6bb5e135418d8a127fc61808fadc25d8c1c644beba357294abe9", + "kind": "transfer_execute_error" + }, + { + "hash": "5044ed8c1f9a182ee15adc46d22a2f7fe3e8654398cc399df0b355644f6bc9a0", + "kind": "transfer_execute_error" + }, + { + "hash": "64a25d27c7bd6bbad7e4bc90ce9115a2f345def6eec5f4e0f125a7ca66124d76", + "kind": "transfer_execute_error" + }, + { + "hash": "ffcc8ea89d03e678b89b9d5e7c8fbab7f1d56feafb28a64672a680304076722a", + "kind": "transfer_execute_error" + }, + { + "hash": "17a5e9d5a9a490ce309c0d28405688e9708e0f76812f772acca7ec937e6e03f9", + "kind": "transfer_execute_error" + }, + { + "hash": "c629cbcf3cacd0fe0fea4f6664f6307865135f1aa8ec7f85b9b3d91f73718b7b", + "kind": "transfer_execute_error" + }, + { + "hash": "b6d7c5859f0f3520da671fb0cd2480009fe5648ab235eb6ec4afc339a994d192", + "kind": "transfer_execute_error" + }, + { + "hash": "e370111c0e9ab78fa91823ff7c8bc0fc7825de5e746a3b38c6604b5fb9f9c48a", + "kind": "transfer_execute_error" + }, + { + "hash": "97246b534e81824bce3ea5a1e3443e63cb0b394549659555a7ac99b7608ccb07", + "kind": "transfer_execute_error" + }, + { + "hash": "8607da423094929f04eae7697a2eae5120ebe6db3660e0a473bd1d21049674df", + "kind": "transfer_execute_error" + }, + { + "hash": "8e79ca1e888b97a8d202d31f38c54894ac6e46a740f81f7fedee66630345d20a", + "kind": "transfer_execute_error" + }, + { + "hash": "fdf8f0fb21715b176ebba0119c554bf8073f717d0c79b8662e3e8cce95ce1396", + "kind": "transfer_execute_error" + }, + { + "hash": "0600aec6199d5c4001572d58833866fc2176df27989fceca68395127b58bb2b9", + "kind": "transfer_execute_error" + }, + { + "hash": "5c9332673076fbb2f6db892f382c693da402383b1cab3e2fae3500e684ec8479", + "kind": "transfer_execute_error" + }, + { + "hash": "c92da43ffea60c40dc53948eac626433382fe6cd50a84e025537bc5db35e2b91", + "kind": "transfer_execute_error" + }, + { + "hash": "cccbdbbdd1a67df4a99689c5a65c7dafdfc65f7b409490cfe6960e77a40c6379", + "kind": "transfer_execute_error" + }, + { + "hash": "c51fdfdd0ef1c097d55e16bf7f0b44ac5df454173eccbb92ab0be256e6747418", + "kind": "transfer_execute_error" + }, + { + "hash": "f81b7e89f22236fc9bd5c816b85588c19584e221f3dd33ff8be81c316e6271f7", + "kind": "transfer_execute_error" + }, + { + "hash": "74b12e362f6d8f8ceed150ff7698b3f92ae67d324f70a7ae4bf32185c2ba7814", + "kind": "transfer_execute_error" + }, + { + "hash": "2941ab564f85b455faba95d6dcecc1c1f6acb0f2ff2145fc8f9a5903cdadfadc", + "kind": "transfer_execute_error" + }, + { + "hash": "a94fd2db8876087172a811be3c9108559effb60e8932f16d8f355cd34baae9d7", + "kind": "transfer_execute_error" + }, + { + "hash": "e6619e7f5ec69e71d25ddbb5f32467abc0113290e1420bd8575a0e2e55aa41e7", + "kind": "transfer_execute_error" + }, + { + "hash": "a3a07daf21160d57b18a47455913c57db86510cb4039bc07ca3489c0a5e88153", + "kind": "transfer_execute_error" + }, + { + "hash": "2060591f7e1584545d9beeede4ca3d3ddfeb0ee65a2d929a197cb311fbd7e63e", + "kind": "transfer_execute_error" + }, + { + "hash": "eb19860eb59a18bf398c6428ed3c33a1297c40189ae4c60a85a8f30f9772671a", + "kind": "transfer_execute_error" + }, + { + "hash": "cbb95bbe13baeab570d263719957c70b0c221e78a8796ab488ad7f7412462a67", + "kind": "transfer_execute_error" + }, + { + "hash": "f511cf45a906afdca1832ff2f015fe3867de48a59c69dda996782cebb4becc4c", + "kind": "transfer_execute_error" + }, + { + "hash": "21f9f758ca1a283a16b16831f18e021b47f5052046e42d463e88e4c622fcd313", + "kind": "transfer_execute_error" + }, + { + "hash": "606bb0003a152e523fa2351121a22065ef86ecf57691d66e9a566bc6a047fbed", + "kind": "transfer_execute_error" + }, + { + "hash": "1cadda0e63dc60c3564c2f2b2a6048c19445d3f694f818ebb487da92c19c39b0", + "kind": "transfer_execute_error" + }, + { + "hash": "1c992069b466072845bf8e4a496a569bae2e9af6be7076d52e988cb906fe5ba5", + "kind": "transfer_execute_error" + }, + { + "hash": "d5e08c6e0c7a8afa10045b22875620f4cef21fada3a9d0440c26477359f04bdc", + "kind": "transfer_execute_error" + }, + { + "hash": "4a4d437740f619107ee19910b22a8b10cbe527277bedabdf6ef42f86d3b277a8", + "kind": "transfer_execute_error" + }, + { + "hash": "2a4204059b5f033237ef0fe42e28f9688da70c6cb5b7a0679f28327f18c3738d", + "kind": "transfer_execute_error" + }, + { + "hash": "8695faebc6e51a3dd901f1c8eb647b9489834fad75b98e762a7f4e75965eb237", + "kind": "transfer_execute_error" + }, + { + "hash": "86893de1dfad0b0630e3f4bc56b1164aa8c347a254bc73b22c6bcc50ffca7ac1", + "kind": "transfer_execute_error" + }, + { + "hash": "d1aaf5168e82db3f2a12acdef601f2d5a0793c7f4305144dc9f671b4cfdce2a7", + "kind": "transfer_execute_error" + }, + { + "hash": "b029a613302fff4f39527bdb3bf24ccb71292132d2901cc25def2464f562a44f", + "kind": "transfer_execute_error" + }, + { + "hash": "c90039390dcb55761c03519e900780bf05ffb55895a73f8e6eff758a8966b34b", + "kind": "transfer_execute_error" + }, + { + "hash": "ec71c6f90047136ca69fb828e969ad9b5094c5c1f324897730cbf9ad480da230", + "kind": "transfer_execute_error" + }, + { + "hash": "34345ab81e15a06032309d513022c0e49bf20c658e11d93638e765b653ed8d79", + "kind": "transfer_execute_error" + }, + { + "hash": "4e830b2460780c49857e68118f10aa9e10c27b60725088b2767c22e09e9f51ac", + "kind": "transfer_execute_error" + }, + { + "hash": "700e7421b9a77cfffe421f9c3f8cdafcaa3d22d9f664cbafe795361b5135f0d5", + "kind": "transfer_execute_error" + }, + { + "hash": "6857fbf00b4ff667040358bf8b3cf475741f57b147a261b9aafdb09973ad8252", + "kind": "transfer_execute_error" + }, + { + "hash": "ce7cf4aa5986f068a699b6ab40f2ac1a43f8b605bebb9fa2fe3090e6624ed6ff", + "kind": "transfer_execute_error" + }, + { + "hash": "8874cd5e55157aded270fd65effb27d958eeb6ff8391561632fe408b9ed36fb2", + "kind": "transfer_execute_error" + }, + { + "hash": "45b63d62035b6f5fa02c252418ee147b56158710291ed5f26e0eecd5390394c6", + "kind": "transfer_execute_error" + }, + { + "hash": "b6a1bdd2c8cdc21bebc2330c307f76df4804ce9e54edf4fd94eb47c95588f48f", + "kind": "transfer_execute_error" + }, + { + "hash": "90eccd8f73650ee194b29d86962ec4dc189b408e417d8eea257f11a05fb6bc8d", + "kind": "transfer_execute_error" + }, + { + "hash": "16e82152f0facfc74f77f4f625f1e8bb4e2502901eb8e0cced7f7d644dd6396e", + "kind": "transfer_execute_error" + }, + { + "hash": "9a9ce52e32ed88e1c27d9dc5446d13cbe3d1f5a07b2217ca717c0db1a375f0e8", + "kind": "transfer_execute_error" + }, + { + "hash": "7c3c3e6cc4ead987f71e93dc2143e30bc01fe1e98bd8acb7c7882be240e4c5b5", + "kind": "transfer_execute_error" + }, + { + "hash": "98cfdf2ae9d183423f3b1c00dc2a1fa88c7c5cd6c431d9806c52b0b9e838b019", + "kind": "transfer_execute_error" + }, + { + "hash": "b2d36145d7ff27aa64745c006e7878b81212b9dd543fad292f25e3015d12b9a8", + "kind": "transfer_execute_error" + }, + { + "hash": "a2f592cbadd6c67bc86cd6aeb4b3b7afcf94a817e369f61211174ce18571a882", + "kind": "transfer_execute_error" + }, + { + "hash": "d553e1c004274870eb0b923521c831e5bcceded5798008b809bb5ff496ef2fc3", + "kind": "transfer_execute_error" + }, + { + "hash": "ac5bd4962fbb0c1d2ce35bab1a0af72891dd0faa118ba354cc2ecdfbc87dadcd", + "kind": "transfer_execute_error" + }, + { + "hash": "ac1f0222feef034e329bf8fcd8aa21685da2a110b0761c42385244867cbd4372", + "kind": "transfer_execute_error" + }, + { + "hash": "dac70de7975425745459b31e112f890ed9ee88a00f84ac55b87637cc2b4b5fcd", + "kind": "transfer_execute_error" + }, + { + "hash": "9ec071367b73540f3ed1676efcaa9561709a387973d94e1d4ed9ee117b09ddea", + "kind": "transfer_execute_error" + }, + { + "hash": "d5a84868f928838be609cda8ddfa1cec82d4f603b0d3c46760433d83c72dc8b3", + "kind": "transfer_execute_error" + }, + { + "hash": "18cedbb72058662b67ab69fb096bfdee3cf057e0ef48a0c4fb0d0f5aae331695", + "kind": "transfer_execute_error" + }, + { + "hash": "ec3ea525685e3741b6b305916f251d7efa0e879cfe7b0aa7aaaefb8e086cc5eb", + "kind": "transfer_execute_error" + }, + { + "hash": "59d21ef4f37be1a594a3386d03c18927f21769eddda94e9f05bae938f0dbddcb", + "kind": "transfer_execute_error" + }, + { + "hash": "bdd617c867a47cd8cc7db687c2931849be985a98c9aacd71f3e323da74dfc267", + "kind": "transfer_execute_error" + }, + { + "hash": "f1f2c44d287178ee59a990d4eaf8d97b72c045c0888d87bae548fa375a3ced7a", + "kind": "transfer_execute_error" + }, + { + "hash": "820b8fc7ae164ca23c748d08a4718c1fbcc6e53fb6b04e3ead344fc47c621bfd", + "kind": "transfer_execute_error" + }, + { + "hash": "ffe9ddac12cca748b3f9ba651e554b104cc7d41ac9a40605d568a7f472f09afe", + "kind": "transfer_execute_error" + }, + { + "hash": "dd9bec9b552ece721a1c60821a604886632a41e540f11d0020d2552e94f45e0b", + "kind": "transfer_execute_error" + }, + { + "hash": "81d323542f96f6cbfcfce8f8c46c7b02e2393b8222373611d2235091d7cbb88f", + "kind": "transfer_execute_error" + }, + { + "hash": "261a54bfa5d2b148c9121ddc110ba1bd66964fb38965bd4bfd842a659c37c204", + "kind": "transfer_execute_error" + }, + { + "hash": "a3aeac4f289571045080ceb9d152a166019efee95550f6e864a637d34d574459", + "kind": "transfer_execute_error" + }, + { + "hash": "9c1578c17455a8b284b561e9897009d8a5d2cdad8121f3e931a3e5ed8ca19b8e", + "kind": "transfer_execute_error" + }, + { + "hash": "3d5a3014de1939afe34fb5cb25d55364884f1b2247e685c45458ff1433d1e9f2", + "kind": "transfer_execute_error" + }, + { + "hash": "1f45a9de622e226c59c4c19b31ea2ee565e387908fe5cf7f89cea062fd28ea91", + "kind": "transfer_execute_error" + }, + { + "hash": "39d4dea54692d9de2aa0c4a547a765af348f0b398b048667db0c227c27de581b", + "kind": "transfer_execute_error" + }, + { + "hash": "b6585cee1a7ae457cdab1aae06fc691af42afae7d8a2b5c71d705fd5ca1b76fb", + "kind": "transfer_execute_error" + }, + { + "hash": "5d0722e97b16b26e8c8e7ec0f5946b2c96aef1f2bf1e4c93215d92a3fdfce4de", + "kind": "transfer_execute_error" + }, + { + "hash": "84584fb71f64d53f7a6bcb5a3c708d7156c72d867043c1e231a5492cca2449fd", + "kind": "transfer_execute_error" + }, + { + "hash": "3acba4e2b1c08abba33c24c33e998490b5c74376c03f9ea6dbe1f449f274a146", + "kind": "transfer_execute_error" + }, + { + "hash": "157775e10857faa93156bf013ab04cff388b9f3c2cc4c6ffb2e883106f4cb692", + "kind": "transfer_execute_error" + }, + { + "hash": "04693d72af80fa98d84a0da373e28c173f445f8d1ba52c41948d5df5c2360a55", + "kind": "transfer_execute_error" + }, + { + "hash": "e5b60a483b76eb42cb4180af5acb68b822d42ec6a1a0bc315ec4d5fc1499ccf3", + "kind": "transfer_execute_error" + }, + { + "hash": "45bcfc1a42178be99e97eebf70b3420516b4b68e819613fa6ee885fe75fff667", + "kind": "transfer_execute_error" + }, + { + "hash": "09143a397efd10b1dbe5c12f2bc6945d048f533a9625b4173bb74affa0b45a7e", + "kind": "transfer_execute_error" + }, + { + "hash": "4e26b1d07c369f5a7af0af6896a8fed373b8fa0e5b9bb65f732853c7c4e2d87a", + "kind": "transfer_execute_error" + }, + { + "hash": "1188c2ebe3ba87bb27212ec045dec4775371be957ac89a4cb45693aa31de961c", + "kind": "transfer_execute_error" + }, + { + "hash": "ea5ae210510c2adbb1d4f28aaf38677b0fbcfbf42d8b2adaa29d2b9d84b07886", + "kind": "transfer_execute_error" + }, + { + "hash": "aa776bc2847aa91bd9a506a8603e2ed5ff98174454df0663f850e3639a22f215", + "kind": "transfer_execute_error" + }, + { + "hash": "89af2bb41d651cef038f53d7f6f23e200bce97f5a8341983893fe7c45e1ea51d", + "kind": "transfer_execute_error" + }, + { + "hash": "7256b86337d3f4f9c101d5a399e123cbb7a240fc2c2af81f0a7304fd4ba0437a", + "kind": "transfer_execute_error" + }, + { + "hash": "289049196ac2a93a7051f21be6439360d97aedc79c8f112f6e1426e1b160486e", + "kind": "transfer_execute_error" + }, + { + "hash": "f4536a54a40fc01d4678b3668f820156588a2f8ebe46d9d9669790d90d3daac7", + "kind": "transfer_execute_error" + }, + { + "hash": "362aec5668fc06d98669040e21d2b619cc248c3c9c4ef101599ac9239894a31b", + "kind": "transfer_execute_error" + }, + { + "hash": "0850e1045049fcbc27ddcd46dc632ce820c45fb8b9220e1324c2fc1a04b59f76", + "kind": "transfer_execute_error" + }, + { + "hash": "5414b2932eda4a66407230f81f992666eb5052cfec1796c9aaac7722551ceffb", + "kind": "transfer_execute_error" + }, + { + "hash": "e17b8db59492823c12de6e366c9a2aa3273a596c83603c1c4b28a1e062a3cf6b", + "kind": "transfer_execute_error" + }, + { + "hash": "c3f2a77b53a13aee059bf331db9280c15ad50754ed71021de734ff941dce694d", + "kind": "transfer_execute_error" + }, + { + "hash": "d9ba7d29ae8361f1983d17ece7ef4911de4228b363b3d4d6089ea4a2562925c1", + "kind": "transfer_execute_error" + }, + { + "hash": "4aa1f8d2ced943fe30f3bbbddedc013c4a7f95246214c5f2c20445e073c2d1c0", + "kind": "transfer_execute_error" + }, + { + "hash": "4acad513deb8f3c804904b3b44baff13fb11e8af06a95358b84e04d3a2704b30", + "kind": "transfer_execute_error" + }, + { + "hash": "c42eb7146b8d1cf5ebd4cc0572cca26f8e6ac52d02f1d6b6a6149eaaed51dd9c", + "kind": "transfer_execute_error" + }, + { + "hash": "d6ae265e22f5c5a67cdaae26b66aafa47079342222cb71fcf4d678a9da9da4ef", + "kind": "transfer_execute_error" + }, + { + "hash": "445ac3e538ad910e422487d51784cd90822f871b90b3a4e605970dc9308c4d32", + "kind": "transfer_execute_error" + }, + { + "hash": "8b3bf8bb304c59bde4bab723e8d7a0d20f13e3311f4b957342fdc08c9f44c835", + "kind": "transfer_execute_error" + }, + { + "hash": "2a573c6e61f125991c2b108507012dd2b645063049e115beda49809dacc017f0", + "kind": "transfer_execute_error" + }, + { + "hash": "8d58ab4e026681e317c24a5867b04e89b15c308ab293bd2e0d0b10b7f183629d", + "kind": "transfer_execute_error" + }, + { + "hash": "bbc2c0e098956669c7fd84fd19ff748243e3ee309a106d447fa9a5f2226838e7", + "kind": "transfer_execute_error" + }, + { + "hash": "62f92c24d132fd817421a52e498c107e8ffb3b3d1a4f152cf3bef4ba6956e2f8", + "kind": "transfer_execute_error" + }, + { + "hash": "c2b37bb746d1dcad210c9d3f5989debc0966e4c84cce7e9a46d709a65221c0f7", + "kind": "transfer_execute_error" + }, + { + "hash": "58b16be44a29e3e62e3ff9dae28d4ebe5923b7900898e75db08eee16932c69df", + "kind": "transfer_execute_error" + }, + { + "hash": "6ab8686abec70d678a1c68db689871f46200fd896953587fe02a098cb5e23a37", + "kind": "transfer_execute_error" + }, + { + "hash": "1cc8851e92d74e9810c47c9a96c1c0483f8ff7f83a43b2e2e775e7fe858b1c9a", + "kind": "transfer_execute_error" + }, + { + "hash": "6b809a7b928a94b71155137f6164042a9d414f9425a25fa0de9c9ac5f02d484b", + "kind": "transfer_execute_error" + }, + { + "hash": "f4e8b1bbba3e9cdbfb51874b6c34958ffa2d7fdcdb7336bba1dbcad7f3162124", + "kind": "transfer_execute_error" + }, + { + "hash": "9cd847b7b020a043fe36da221e2621bd3223df9cb2bdc99177d3d22d8f9b4b8a", + "kind": "transfer_execute_error" + }, + { + "hash": "8b7fe2ffc53d8c8280753e8fd6056f00d0653d9b5f4064557f1a282328e10737", + "kind": "transfer_execute_error" + }, + { + "hash": "b4984b91e4f61d10c20fd49da7d094ba0bc7bac3461dcccee41708dd094df7e3", + "kind": "transfer_execute_error" + }, + { + "hash": "209d9d747b035bda2bf593ff986240b2ae83826877a32b44f7154511528ee667", + "kind": "transfer_execute_error" + }, + { + "hash": "e29f0c791066d0aaceecf55a4f36b482d1f15df995b58be3a76e51b0553c4158", + "kind": "transfer_execute_error" + }, + { + "hash": "56009aa7d54a53ffdf239c6e642855dbd7c0c2f500aae1e923078905c84b6b3e", + "kind": "transfer_execute_error" + }, + { + "hash": "4952eda6518a9d1a2c8a2b29f29a5b907941115bb402413cdae6608b7123ab52", + "kind": "transfer_execute_error" + }, + { + "hash": "2691f4b0f1aa2c97f527d047d4143b98ef9ab47bd0a9543ba743e6f56b4bd3e0", + "kind": "transfer_execute_error" + }, + { + "hash": "24627f377a635014290b6bbf2f1c0a30a58d26d3aac9cfa32e5486e3689c68f1", + "kind": "transfer_execute_error" + }, + { + "hash": "f00ff506cfca97e6620b48a22a21da06935aa9365faf2c1db944dc815aa12162", + "kind": "transfer_execute_error" + }, + { + "hash": "02331102902c4dfb66e7f31e7c486a1ef38e58c4c044f8dd0fefbef64995fa27", + "kind": "transfer_execute_error" + }, + { + "hash": "91e10eed554968ead2da10655ea983f785f328530c02f809f161805af8dcbfcc", + "kind": "transfer_execute_error" + }, + { + "hash": "34d2c68d038e8972199c3e1d7e8783690abcebb74968a1e75b1ae2bb364349ee", + "kind": "transfer_execute_error" + }, + { + "hash": "a79faa7cb2834f03293837f5787856ca1b5e76a0c8b9867934713d08845e74ee", + "kind": "transfer_execute_error" + }, + { + "hash": "9d0980d149f175b7cfb62ed02ad20fc1a9dd981f5ed09495abde9f140c47ea57", + "kind": "transfer_execute_error" + }, + { + "hash": "bf6a37473b0239f05fccb275074b347dae65358fbf96f0db586821f4ab1bc1cd", + "kind": "transfer_execute_error" + }, + { + "hash": "b5438e3a4858ba1379a9cbb76e0a6455ff1602dc4f87d90d0d6905717339272e", + "kind": "transfer_execute_error" + }, + { + "hash": "62af8e62e1cf97bc6e84d9781b90404b72ba72a68ec8950f9a3d2d3638367b60", + "kind": "execute_error" + }, + { + "hash": "7ebb3df4902ae4409ac5e3b69e95c326beed244b4ec225ab67db96104f102d82", + "kind": "execute_error" + }, + { + "hash": "b8171f13e36e7204f532143b020f1b971d4901e8711bef8b92c37ada991a8e99", + "kind": "execute_error" + }, + { + "hash": "65f7b2f1d37f1500d08f5d40ce317d1eef7adcb72d7c40f1420286a31b2dfc61", + "kind": "execute_error" + }, + { + "hash": "e1f1d2bec2d19715d06e6adba9812a4bc91a988c3afa8f6297a065b993f44b90", + "kind": "execute_error" + }, + { + "hash": "d37f9afb23da7daf9b3df0fdb64e319a365d34a5356e6d67df62bfb106256b0f", + "kind": "execute_error" + }, + { + "hash": "acc67e3cbeed8c40f21232cea1bb49b5bf73d15209bc9174f73a946654380a36", + "kind": "execute_error" + }, + { + "hash": "710988bb1e225f486638e02ded6a1ad4eb32e8e316748bcbdcdbfc6faafe3138", + "kind": "execute_error" + }, + { + "hash": "a008a3f7ee0987602f21ad195bde56905c2083f0c8631884148a67b39efb1412", + "kind": "execute_error" + }, + { + "hash": "b386c146e1283e0bf68f970528fd3ebd819f3156eb4807470323283c28a10320", + "kind": "execute_error" + }, + { + "hash": "4a03f0dd9aff71acf2512f4da2518ce5762dae9ab6b96cba05e03fae197a7b02", + "kind": "execute_error" + }, + { + "hash": "0cb4e7f5726bf0ebdca77b446ae9809f8ed67e26d42cc259e9599724f6fc2306", + "kind": "execute_error" + }, + { + "hash": "2dc2509b637cdef3e4f8264ce6bc4b18c54b2f42c6d3d9f8ae135b5a96db6e65", + "kind": "execute_error" + }, + { + "hash": "493ae29df11970e476f66a435d160c5db4a3b6eab09f1aa7a74dd1baa5926f6b", + "kind": "execute_error" + }, + { + "hash": "f9fdb96ab54fc6299979c92bb3adc3007256ced9cb6d3becc8bce68a652a0e71", + "kind": "execute_error" + }, + { + "hash": "2f8ea631672fa749ea7b6bd3fa8b3019106262cc007573981401f3543ecd8674", + "kind": "execute_error" + }, + { + "hash": "8a85919ed97c0beca0e000b331af75655b5f239bfeab31bef09dd8ce37cd1530", + "kind": "execute_error" + }, + { + "hash": "eb432797dde9f068c6b95682dd84e740bfd095865cb1ca5079a963f52f3586e4", + "kind": "execute_error" + }, + { + "hash": "cbdc6b5cef6faa756a74a246cbcf1b7b1107f58a9fd28c24aca501d1d2ade437", + "kind": "execute_error" + }, + { + "hash": "4c913beb9e0946af124abcd8c886a16ef7ba9e54df0da5ec11f1099f06c9bdc5", + "kind": "execute_error" + }, + { + "hash": "8359199049b89edb82276c450a850983bd3ab464027b20ba0e1dea60beed10aa", + "kind": "execute_error" + }, + { + "hash": "2cb4ce6d736d7ad6e33fee0282732e954b3dd5020f5e19294d69b51df8c1dfb1", + "kind": "execute_error" + }, + { + "hash": "4822dc62e14facd8068dd80cdb39e222add95511344736b5aecdbd2f791e32e8", + "kind": "execute_error" + }, + { + "hash": "fa0e1b4f799e079fb7cee6aee8e691e2db01bbe54dc8a3a224618e96ba168d24", + "kind": "execute_error" + }, + { + "hash": "2984ae7250094be414cde907987fd0d9d415dd9f287f54558f0a720f80875050", + "kind": "execute_error" + }, + { + "hash": "157348b6629dfa581faeae5e51ce7eeac12ca1e9b3a688fb71af5039620cc513", + "kind": "execute_error" + }, + { + "hash": "30259b78b73d42b342033d9ee0d369008ec49ba9aaad85418b6e1cc1353797c6", + "kind": "execute_error" + }, + { + "hash": "8ff3de7064157efecd0e951918ed3d04896dbb6d0594feb072ab3799a87028c3", + "kind": "execute_error" + }, + { + "hash": "2cc6da86d01a65e923f8ab72ae81303578fb9ddd723899cdd874a5767fb9422c", + "kind": "execute_error" + }, + { + "hash": "9b4cb383bbbf12566e0285e78ffc791cc21218064b581f760819ae209ef7c326", + "kind": "execute_error" + }, + { + "hash": "a80237fe194872c2174762b6e9a0a67fcad2676441f606975b93d081413a4334", + "kind": "execute_error" + }, + { + "hash": "136b0b74ef864bda02cdf05f0b6eefec4ac9933a301eaa8d8cd0af196d2d0ab8", + "kind": "execute_error" + }, + { + "hash": "9792cce9062113c1bd7118771080d6f2a8c1ddebb54cc8b7624402fc5c9230c3", + "kind": "execute_error" + }, + { + "hash": "de5e34c1418527392a8ffe9adbe0d3d2906c3564dbc23917867f6b6cb64765c2", + "kind": "execute_error" + }, + { + "hash": "e196b33522c0d54684c3dc3e27029422ee7959fe46494950fbc21632697502d2", + "kind": "execute_error" + }, + { + "hash": "6942e159c0687a1f3fe94b184c4e1db0140dd1d772a8d51d6360e706ed0251b0", + "kind": "execute_error" + }, + { + "hash": "e46a0bb083d76a80275b12fed0d1f664d3572f1fd0ffa0cf96d9f99761a221e7", + "kind": "execute_error" + }, + { + "hash": "5f28f7554f431f3c70ef5c7b6f22f5500678e519c1940c5904f95bda8a8c7bbd", + "kind": "execute_error" + }, + { + "hash": "c32ab790255c1a0d9849d26c12b99a5dece9589ff2a39bfef51614db0c245644", + "kind": "execute_error" + }, + { + "hash": "6903df1044de194c2eeb6d900a877229133f495db1a3dd7543838ca4e2fcd736", + "kind": "execute_error" + }, + { + "hash": "047233603524a533aa8a7ae51b8210d1ef80808e073c3364473b20c1eadd92a3", + "kind": "execute_error" + }, + { + "hash": "961f72fd3b968a48106f0085f33ea1495f603a6dc3f599d0d94ffb4e7dde7433", + "kind": "execute_error" + }, + { + "hash": "8e38b1a2b7281688a18dafe222f0acdd319194da0dfb3b8b4f45b7bbce578bc4", + "kind": "execute_error" + }, + { + "hash": "5513e11a454e95167903a82c3f0025840a2d12f6c62b1503dd52731380e7e922", + "kind": "execute_error" + }, + { + "hash": "ef5dc0a9b5ecbc472c7085983666fd9d9d8185a3a3c80aec3507a2720b2540bd", + "kind": "execute_error" + }, + { + "hash": "c4a37ac988c92096fde558679912606660cb855b55e26473fc185297247b570c", + "kind": "execute_error" + }, + { + "hash": "1dff49ecb0b8b51def56635c7182050d13b49b89f270ecb6859cd23e4c55ea22", + "kind": "execute_error" + }, + { + "hash": "ab245795376ea0599eb2ddf81296e2462df9909f7179e594f554bfd145779527", + "kind": "execute_error" + }, + { + "hash": "d1150bcb3a6690892c8f2450aeb1e8cc3e630d7d8e1702a3a76e4aab781c1db0", + "kind": "execute_error" + }, + { + "hash": "289f6fd3ca4614926682b5901a752356e281fd9c0e21ca0636810beb23b1aaf9", + "kind": "execute_error" + }, + { + "hash": "54cafb59aa0a469f251efa9f900dcec564acb89778d547354cdddadf5b03c76a", + "kind": "execute_error" + }, + { + "hash": "523d3aec02d3f84e7ef23b3445471c9a830b5f0bf32f770d7aac49b8e8e729ba", + "kind": "execute_error" + }, + { + "hash": "86953782ac0b1e6446b1e5160cbd6b1854b5ac6892a084e425583cc3fa092aed", + "kind": "execute_error" + }, + { + "hash": "da6affd3278a89b1d9882240b7a2b7dfa388a9201fe1de6a6856719373f01b4d", + "kind": "execute_error" + }, + { + "hash": "bb91cd69926fe694336a281d63d5fd1dc14d7f7d3a97cca5684c30f4f6fa949a", + "kind": "execute_error" + }, + { + "hash": "4a540b860f0ba21f8e09cdbd4fcf5286934d7193b7dd783edd13ca6c375aeabb", + "kind": "execute_error" + }, + { + "hash": "d6b6e89aa665b708635249f8a92bd2b2d4c9e8e06111e86f90008670f2b059c2", + "kind": "execute_error" + }, + { + "hash": "970292106236a258c914ee4f38b8be55513108cd654a909b8c08ba14d6a7dcda", + "kind": "execute_error" + }, + { + "hash": "90e893ae0f5912cca597b9f7386aa07eb62235857eeb173da50d5beb97ac2093", + "kind": "execute_error" + }, + { + "hash": "1a96dd004c2e614a929b18b14fd1c0977759c444f3262f2c0d67a1840398d217", + "kind": "execute_error" + }, + { + "hash": "0af33be1ff802267000209fb574c91e7d71f8f256351657114dedf1b100b855b", + "kind": "execute_error" + }, + { + "hash": "2cad4d436def13048b13bffc7f29629eab7c4e76d59ac160975366ef3be907ee", + "kind": "execute_error" + }, + { + "hash": "377fcb5287051b929e9dac808907f2e1d923243b1d204ab4f06457d716a3693a", + "kind": "execute_error" + }, + { + "hash": "c9b7d74cc80697b29c58e39e46486b5ab198b3431610bf95828af4a003fef776", + "kind": "execute_error" + }, + { + "hash": "e2def5292442e1225ccf8e7e9b9bc2103040f442ac1c305c5aca72651fa3dca5", + "kind": "execute_error" + }, + { + "hash": "48fe8dff5c0bd31e4915cd0b5ee1e07a8677222df1c3df4429c811703b31acd6", + "kind": "execute_error" + }, + { + "hash": "5390a758049cf1c9cf942704369b76b8285a723c2451c28979858017b90069d4", + "kind": "execute_error" + }, + { + "hash": "233769ecaf9b1a3796a360ec94939c432d6ab805573e7e1feb414a5dd0614678", + "kind": "execute_error" + }, + { + "hash": "c35dd410e7e0a5e56328632f851dac0b341912a5a790c05079893e0e91a3054e", + "kind": "execute_error" + }, + { + "hash": "687cb1800210ef1ae6832b68a5e39f13f9a0dec761fd4fcd43057fb52d52638b", + "kind": "execute_error" + }, + { + "hash": "a7ce2406abc5ba7703d3fb22ebd3c1d29d6419a63924ecf7f2ffac67a3a8f204", + "kind": "execute_error" + }, + { + "hash": "75477d97d13ae639670029fc579113abeb56be5bdad8fd839aa34e543ac26a37", + "kind": "execute_error" + }, + { + "hash": "ed97e8c92797f5686de4407a56b1895eb607cef9c9c82776223f07b7bdaca049", + "kind": "execute_error" + }, + { + "hash": "3203e3bd725ec7d3cee2edbb1de03f8f5fe2f8ebc1e8681823095afaefda59fe", + "kind": "execute_error" + }, + { + "hash": "e6c2f6e7b89b8d725ae77d2408371d78bdd3c6f9cf16cf9f259427403e2b5a71", + "kind": "execute_error" + }, + { + "hash": "e47e479cc5317f02b6ff8cd2dde436b08efb51a818d9c71abef322695ab6af20", + "kind": "execute_error" + }, + { + "hash": "6fd603daa41a0f0129b8f5ed4c6b2533aaad25c95fad84ddc5ebc0092d9bd431", + "kind": "execute_error" + }, + { + "hash": "c1fbf35a4f9c5d308531258bfb4ba152062ffe74061fa03ed83d957574b93f7e", + "kind": "execute_error" + }, + { + "hash": "954a94440c6c3abf281fbdbcb4323cdd905d6f52416038436b331f4dfef6fa3e", + "kind": "execute_error" + }, + { + "hash": "d534006d60a5be78e0d1d98c34f5acdd8252704de8a1d1a3568a0898c943cb82", + "kind": "execute_error" + }, + { + "hash": "7bf5b0c0cf8001c727bfa2b1961ef6429ff10bc9f3f6f98b6f5cca7c18f3a1d6", + "kind": "execute_error" + }, + { + "hash": "186c46020318334ce80c15e888ea7990503bde55222ec0545aa3697d003a4fee", + "kind": "execute_error" + }, + { + "hash": "9be2fee3c01450ebc524c274454a50f5318de3a164eec4bc1ba51d2a97b92bf8", + "kind": "execute_error" + }, + { + "hash": "aed29419b43e12913b97e05939480edf9db6bbcdf658e28e0adb6bec7cc1abf7", + "kind": "execute_error" + }, + { + "hash": "13751814bf5f7e01983b4a2482bbb5d68b48ce41fd4e49879e2cf0115c8c6cb9", + "kind": "execute_error" + }, + { + "hash": "51cce4ee7c7201b4282de9f077b6093ec437bb040f91a7c3360df2b083bd1b4e", + "kind": "execute_error" + }, + { + "hash": "c5fd84a3c00ff513285bdf6c533edc5a4de4ab6f45e2acffab1c5c3c4cc2442b", + "kind": "execute_error" + }, + { + "hash": "0a459beb62c96120f1342ee2bac15bc317e4bcfce731e2388af39febc46d9ec8", + "kind": "execute_error" + }, + { + "hash": "7d0e94f575fe564897dda57822b510ca02bfa2e0360c1c29629141b69bba903d", + "kind": "execute_error" + }, + { + "hash": "d3a376d3c615b8c4bf7d290205705e457c5ed8cc8abdddd98ac3aebeaf4b914a", + "kind": "execute_error" + }, + { + "hash": "731f271888281a394363626c5821686f8472fdc3b755e9750a7f31e524d41269", + "kind": "execute_error" + }, + { + "hash": "260c34f333106185feedd0336bb85b71743882ba60d65828f0fbe20d8dc01b8e", + "kind": "execute_error" + }, + { + "hash": "d9960ce308bacf434223bd59c535fd82bb9561418ab15e94c2eb06d649ee3e86", + "kind": "execute_error" + }, + { + "hash": "a6d353ff036fd238a00f236447ff4f6622e15ea41ca62490048f9859803ffa79", + "kind": "execute_error" + }, + { + "hash": "65be249976aa0ea42dd2f0aeff290683d98f001761905ec39fa4ae4453b7ca9b", + "kind": "execute_error" + }, + { + "hash": "a64685dfcf563b003994cb552d79d32313928b4e989d72590c06e9c1cb0bdd54", + "kind": "execute_error" + }, + { + "hash": "9febf40b011594968191436fe1a62172f93fd9e1ce91c3658a19eda08f12a622", + "kind": "execute_error" + }, + { + "hash": "f3e1595d674d9be8c8de8b42b8ad5147cad98c82034dfbbd22a50d1723309d10", + "kind": "execute_error" + }, + { + "hash": "b064edb39a98275614c04ba297a578c248dbb7b281b58147eb98cc7e3ec7e551", + "kind": "execute_error" + }, + { + "hash": "7608a4b2f705751c7530d71cea65485e7cb2b937b3015596cf5c35ce6ddf9650", + "kind": "execute_error" + }, + { + "hash": "3ec25b136ece99a956b6e58e645d9d63af0d4d73106a695508584a278a508346", + "kind": "execute_error" + }, + { + "hash": "3b6ed41332df0876d1a6a91f0431c8efa9438364156fe8c7ff1977ada305ca68", + "kind": "execute_error" + }, + { + "hash": "5946c534bf646859fe9e4868354e4410664371af0702354cd9783a6dd7987d32", + "kind": "execute_error" + }, + { + "hash": "38745c8a9aad4d36b7a5fde6b67641b4dcb815a0b306413bd4598a980e74fda7", + "kind": "execute_error" + }, + { + "hash": "defb50ff05a973d7a7ed94f34b1bf3e378f707cabbf668d9927e551370595016", + "kind": "execute_error" + }, + { + "hash": "518927beef7d4632cb7bb8050bd0f573f10d6a7881ab76ab0a0c0d52dd3dc73e", + "kind": "execute_error" + }, + { + "hash": "1416dc4d4a3f0cfa7091ccd4af159215f60882005f3199e017d451012d7acd9a", + "kind": "execute_error" + }, + { + "hash": "9d8dd87b2773cc471d356f4c79faab34be65f0e0395a8938fc1a85f448ee4aa9", + "kind": "execute_error" + }, + { + "hash": "45c93e1e4dd0341f46b8bda7b24acbb4688f1d3efad5dae0fe3572a53797a9c8", + "kind": "execute_error" + }, + { + "hash": "5edf2295877e7513954b78792f290ff456bf5e564657d1c191ec89f86beaae03", + "kind": "execute_error" + }, + { + "hash": "93a333ef38ec71ffc8fca2fdac974e619eb5266e76b6b0f74595157832ad7206", + "kind": "execute_error" + }, + { + "hash": "e6f61bd50dd645d7b2266f428ba4771b5dafaf0d47a1fa577e78ee6f25cee25a", + "kind": "execute_error" + }, + { + "hash": "f62d5a64ac5f120e3d032415c46a893b7d1dfc143c0ff2ccf2c6f9e779fa3980", + "kind": "execute_error" + }, + { + "hash": "a7416ce86583ba749614e300712442002cf6e7e9a20314af19d3e828b472b2e0", + "kind": "execute_error" + }, + { + "hash": "6d1f5ee187f9af3d279b1658356f3f643af00483d83f65dff5c6ef79299bc6fa", + "kind": "execute_error" + }, + { + "hash": "5f8d7dad42dd0624de213d0155984f8ff708628b0d2aa624ae1a055a44a391f0", + "kind": "execute_error" + }, + { + "hash": "9ca1ea9485d51f8fa2c256fa34737205b35c99e2f8146b94f5f600896f0fa2f6", + "kind": "execute_error" + }, + { + "hash": "2f6f1c6e462c4709d91a442e8e3ec20e2ebf180d15650bae65c354ed394db6ef", + "kind": "execute_error" + }, + { + "hash": "361325595ed1db38195fd9f960884b6fc3341f127a3ee35d81861b81845c0592", + "kind": "execute_error" + }, + { + "hash": "b3f309bd36304836f318e1953c7e582d08865d90df59c301332e2d889d0cf503", + "kind": "execute_error" + }, + { + "hash": "d1fae9325e5c24a266dfd81708381e78413aad7d2aab598401c11624f9cb303d", + "kind": "execute_error" + }, + { + "hash": "a4763f5c2b526bdde6ad40e5e0720cc1249be73d058e9ea2f258f353c6480ec4", + "kind": "execute_error" + }, + { + "hash": "cdafbe209780944eb8976efd25635dbe8f2cdd53ee201994742bf41addd2ebb0", + "kind": "execute_error" + }, + { + "hash": "6eb17c0df5eb7fa64c352db33992ab4e855a39123c85f764569ad5e2bc296429", + "kind": "execute_error" + }, + { + "hash": "5a37938fc2d47b18fe5509f447735b9b924ed9bfc8aea38da8feec358571590f", + "kind": "execute_error" + }, + { + "hash": "1f32e7689f0eeff7d2c9308dd413d593afd0aaa02af58d6270f33bbb8f742eae", + "kind": "execute_error" + }, + { + "hash": "299d2bbc1c9c984324eed7e214f7ac3031a1841b16e51fd13a5625e728aee37d", + "kind": "execute_error" + }, + { + "hash": "bed593fb45564a953de11c6fc071e014b11c84b2032bebc72f7268a7f2dfbcc0", + "kind": "execute_error" + }, + { + "hash": "ff31687d657b2d6846e5d97d32555d2be37d7a300b3862b789841bcf49907534", + "kind": "execute_error" + }, + { + "hash": "e9732abf79c4785d9f7fc57a2c53a369767a9b988a4a0a775f32e97a3a29130d", + "kind": "execute_error" + }, + { + "hash": "1a8faf8c2432e8db8237a124aab5b7645183334f19a23688ed36f3a0c4845bee", + "kind": "execute_error" + }, + { + "hash": "2c4287f3fb2623924ad7221eb01ce77f637598746514f4f6b4de403c84e19c0e", + "kind": "execute_error" + }, + { + "hash": "acedef5ba78526c1014dec2e29304161e26e6f4b8b2b731de0f2e8d3e778c209", + "kind": "execute_error" + }, + { + "hash": "3b44a6d84f2d59a89fc945acda0d2d10eab4bd474bc90d4ec8af5b54e06d976d", + "kind": "execute_error" + }, + { + "hash": "ec710ccf6b4e2f2935ef863d524debd049b90eb1e95440cbdbad2d04a74a8391", + "kind": "execute_error" + }, + { + "hash": "85de5fa5aeb8bdeb8ec99e9390c26f0239146f0e9e88c285fa5951550c7a9b6f", + "kind": "execute_error" + }, + { + "hash": "ae9e4f3beb0b736a0775abd4027f2e4b553fd01b7e6721ff08b742428d0df6d0", + "kind": "execute_error" + }, + { + "hash": "a555a8c303b34103c2819191b259aef80cf6cbda3c1c889a08930dd3e2b91b65", + "kind": "execute_error" + }, + { + "hash": "621358b11692ec4dba23b23a5202755a12bdd7447d3071498490ddae44ca14a2", + "kind": "execute_error" + }, + { + "hash": "6ec3ebc0575b524946dcf0453c6b55ac2959eaca25ecf850efcf1178beee28d1", + "kind": "execute_error" + }, + { + "hash": "912288bdf2fbf96036d9287b227a11d598519dd8cf0f9ff34ecc1d305608e945", + "kind": "execute_error" + }, + { + "hash": "b7b1b9d308b197283508588e93c3bb44b67fda4c9aaf3c60a97028e566d37c6c", + "kind": "execute_error" + }, + { + "hash": "5f548027afeacad4f99c9ca8a91787f4a90ec8aa4b3c2c3dc32202f4c7f1f8b8", + "kind": "execute_error" + }, + { + "hash": "da7bb76c3b41c697a8e8117c3966d13612cd684fdfbe8478754ca08467391409", + "kind": "execute_error" + }, + { + "hash": "580d341c2edd43714fe2c84dfaa7b7000087c99412f356f787cdd1f028c60f14", + "kind": "execute_error" + }, + { + "hash": "3d516e90c8bc0f0422040a0cd2b0d3e6e6fc0a2cbd4c6770ffc6a83b65bc86e1", + "kind": "execute_error" + }, + { + "hash": "9eed47e9ab35e99cb2769356d56cdeafd3ca9008493315036fa8180b16b50451", + "kind": "execute_error" + }, + { + "hash": "26d5185c2d7c3a56950d1e60f9b5363845c6c37745167f520ab72ae20057a07d", + "kind": "execute_error" + }, + { + "hash": "2c999cee62f1b29e445a5e4dcbecb70e8df910287ebc497971872ff9e540904f", + "kind": "execute_error" + }, + { + "hash": "4d9a8e1d77049284b907d5ce910be57cfce1feb92539cf47260f6cec5c7050c4", + "kind": "execute_error" + }, + { + "hash": "9cd1760e9518f1010cfd41bc98c3768336f6bdf9d0912a4ea94db90fe83fc61c", + "kind": "execute_error" + }, + { + "hash": "21c3b033879999ad209204b0aa1f312627cd5cf7fc85e289e06c442218400006", + "kind": "execute_error" + }, + { + "hash": "17bbab1e11d7fb253ed67b2678827e77d5d084f932fc0d66b72b51ad1f2201fc", + "kind": "execute_error" + }, + { + "hash": "298b5eb9f20850952f4a607051f7192f12d848bc54e0eb02ad12532bea856722", + "kind": "execute_error" + }, + { + "hash": "004dc5747e9b14b8d5b93b0d0c98f0bf3754a4663604792b970235abba9298a9", + "kind": "execute_error" + }, + { + "hash": "f6caabc98eddd1348adafb6ebe716696d03ea5c173483690e5c37a326357fd87", + "kind": "execute_error" + }, + { + "hash": "7fe6f4f02deb6184d9e54e62ff3475fdf46d85203c30a624dcfabf72925d6f17", + "kind": "execute_error" + }, + { + "hash": "4e95fc6b44c84d094f92c00a3095867592875ef86e509e3f19dde10b903363a4", + "kind": "execute_error" + }, + { + "hash": "564c4e012b371e045086b225f04d999969107cf5cb8716d45de946e113def182", + "kind": "execute_error" + }, + { + "hash": "cf31c882e3efd41290baea7d3a7dc93bc40d44d06de52d951efa4e0d6b7cc5f2", + "kind": "execute_error" + }, + { + "hash": "f085f5f8425c4f1629e18b8eec662442a435a355b8194659ca0468bdb476254f", + "kind": "execute_error" + }, + { + "hash": "cc7cb9cb6a4a7349f5a18b1090944a5bcb2a23840d87d6cd7721153338abedd0", + "kind": "execute_error" + }, + { + "hash": "da42de3715b9ce69421235f1e9d9895d84ff1cfe2ae03419d5f9abb136d901d3", + "kind": "execute_error" + }, + { + "hash": "66655f817ad8d6c950c3f45faf760b028156e748c8c6142743ed0f4735820f4a", + "kind": "execute_error" + }, + { + "hash": "c62e458c4af1769abe362392999a44f2a1ca37b3d9f2a667d6c709b0992b6ebb", + "kind": "execute_error" + }, + { + "hash": "a6478c3b965b74d4ba543610f8a83cf6cb6c34299836489e9fb1a2bb89112149", + "kind": "execute_error" + }, + { + "hash": "378f2bdd75a9577bbb19dc3b9d8935e9821ab6c9cfbc00f0ffa5832cb254ef92", + "kind": "execute_error" + }, + { + "hash": "33b7da8c1dd8a9210fd957858fc615879e4a42cdedca3bf0d9f565ce4a6b0809", + "kind": "execute_error" + }, + { + "hash": "a1cbaa2cb459ac30707c209654b5c86ac3ca111747fd22aee6008ff5116bb1aa", + "kind": "execute_error" + }, + { + "hash": "e5c7b686dad01ad836b9ebbf53dff1ae9d7d3eea752f1ce8ff647737d41841f0", + "kind": "execute_error" + }, + { + "hash": "798ea9a929ce42622571dc5b8c78c325396d1d5137de635fe1af612a84d993a1", + "kind": "execute_error" + }, + { + "hash": "304c0ebf61c5e4da58df9c083cbdaa736b4edb6d65459db092dbdac20212b08b", + "kind": "execute_error" + }, + { + "hash": "70ee47f35257930d9431809dc19823e20928d95c08f9a51d671197ffe14fddfb", + "kind": "execute_error" + }, + { + "hash": "2ffb996618a2a4fe737866b6dfa67039bc4f6724e7c937dfd19cc9e89bb5badc", + "kind": "execute_error" + }, + { + "hash": "bf1cfbbfa09def4ac1129cfbed9a6b74a5cf33fec0143d38f5c453019fe1a6f5", + "kind": "execute_error" + }, + { + "hash": "8b597214145f423c1e41533ccbc528b63e9c673d56bc8d4360d73008cdfe3aef", + "kind": "execute_error" + }, + { + "hash": "4fb5c2d47d05b994b622f7b2a8688c429b7b7c04f42fcebb45a0ae7ba7caa2ae", + "kind": "execute_error" + }, + { + "hash": "611123a8b6c82354402c0952ebbc39d4829c27c699b34cd6dad9eb9a5fd8be64", + "kind": "execute_error" + }, + { + "hash": "ec6a393dd75f9d4fc3b2a90afe2dd4d185ec10a0cdaa31586a147f335abc3c9f", + "kind": "execute_error" + }, + { + "hash": "17072bff50d0b3ec69525c700eab9f41807eb29871185593cedc6cf37eefbc80", + "kind": "execute_error" + }, + { + "hash": "b1c5e1a0fdfd41ded4835d2b10d3659bde0a1a4c1f4b64c4ad92c228d6e38edd", + "kind": "execute_error" + }, + { + "hash": "b97bbdcf4a56bd1274c11f4544ab551bacb0c5cf9ef08f5f917156490ef43914", + "kind": "execute_error" + }, + { + "hash": "7aa5478068b0c473750e9f13bce1e66ab0435e4a8cd55b4c6d678c48abc08397", + "kind": "execute_error" + }, + { + "hash": "5db642f69832ac0daa454d28ad90c31778a1b79ebb1e2228548f47d65078b61c", + "kind": "execute_error" + }, + { + "hash": "8d2a74d1bb47cae86e9a0a9252208d9e09bbefd479248e9eff811a1c02bbc077", + "kind": "execute_error" + }, + { + "hash": "ddf0b3b8b21cba80aaa3198bf8e2659ff3981a963ed44097ecd805363b416afd", + "kind": "execute_error" + }, + { + "hash": "60c50ebe26c4839d09982aef4e8512a80d0663d68040a36d4e74fd97df2424a7", + "kind": "execute_error" + }, + { + "hash": "f46f252529c3fb9e2e95950bfebd5dafb499470a8257832fcf0d84b91c42efc2", + "kind": "execute_error" + }, + { + "hash": "1de425fa976087a00396397919136690d3df67b3ed5cfc682668c13da8249c41", + "kind": "execute_error" + }, + { + "hash": "b370d2ac93e186d6246c0b07b0b0d8add1aed38c4adc838e6f86bccf0d82e947", + "kind": "execute_error" + }, + { + "hash": "8243524ff80bfa02ccbd4b6f8a38a0e5c1ce35ebbb614f165fd124e6536b2247", + "kind": "execute_error" + }, + { + "hash": "211089f27196763126b0eecbcaa27e6f683efa0568d3a7462e6965102ed58635", + "kind": "execute_error" + }, + { + "hash": "91d862a6c1979a7acde1fe9aa15b84bb7ff2bb283c50eb53495f1ddd229a02f0", + "kind": "execute_error" + }, + { + "hash": "68bc856063cc1219feda235e568455dd08cf24df9adee7e970e027e60432f61a", + "kind": "execute_error" + }, + { + "hash": "dbecca74a4d912a1a41af37d8d21f5c97032195c820eeea186038e972028da43", + "kind": "execute_error" + }, + { + "hash": "2f27ef1a179e27e28ea30bce62e3affab425d09502a55334d291364ff5f59338", + "kind": "execute_error" + }, + { + "hash": "9802899b469bbdc5d205d40188e5f2393f201c946ebdd117d08c76f609d38a79", + "kind": "execute_error" + }, + { + "hash": "5ceb065bb64a17aa00414eda758a79ec7c34c366ebd70c2a01697ff7546c4fe7", + "kind": "execute_error" + }, + { + "hash": "5a5c9ecdeddff57ac29214360c6a4619d57cabc7d642e869b384384fdcb47a9c", + "kind": "execute_error" + }, + { + "hash": "4c384df917bdc1b668df048bfcce9e799256677cdaae8f4702dde37c517c551b", + "kind": "execute_error" + }, + { + "hash": "22f1a60c97f65f41596309ed2cb025147dce0e08cb2a5cf925378e1ab65272f3", + "kind": "execute_error" + }, + { + "hash": "102aa05c9be8937ac5e48fa6db48c66836531d364a2895f3dbaf4fd502416fc5", + "kind": "execute_error" + }, + { + "hash": "bc02c9e0420e2d7b80c40253ddeeebcf1608a5cbd047e1717d988b227f122667", + "kind": "execute_error" + }, + { + "hash": "b0ff97e992f59dcb15f03e65d539af79354cb74a23061c58ca0f982ff930a4b5", + "kind": "execute_error" + }, + { + "hash": "e0d0c8a55dcf08998ad230c23ecc581a1777ad60f7e33c7d378a95936362c2f9", + "kind": "execute_error" + }, + { + "hash": "848e5b2e6f9f9eaff4a1e3477b63a78e856510bb4843c286efd92dab8ee7b4c3", + "kind": "execute_error" + }, + { + "hash": "2774cad9b69fc9afa70d928d8a4b325e77419653342f1cee06126c1cc427d393", + "kind": "execute_error" + }, + { + "hash": "a91d2ee431a7ef6cb51742c02b9ed89a987609e85d1e928e89eb6b8d4e96aa3b", + "kind": "execute_error" + }, + { + "hash": "d0bff3ee603e4081e1fe94ec1f42e1ae893040db09eee2af703b8f549b2c7370", + "kind": "execute_error" + }, + { + "hash": "b884f04aefcf95d97915d074543ea65eafc27928406cd5e22d1bf759b9628471", + "kind": "execute_error" + }, + { + "hash": "879f7ef2dd5bab902c63e84064cf078d4d4bc6f79867f99952cf6ae6a8681898", + "kind": "execute_error" + }, + { + "hash": "1a779fab9a0167181816e6f797a301904090b517eb78c3420c857dc37b8cfc84", + "kind": "execute_error" + }, + { + "hash": "c9c42c51468b0626e8230074638c4a69fa2f332a210f9f5e1342848a51f4a6cd", + "kind": "execute_error" + }, + { + "hash": "3e220e7829b4220c1518bae57e89bb4cb3910a2997b0ae5cf2b43ab2ed6ab846", + "kind": "execute_error" + }, + { + "hash": "088509d08fccb04392333c2ada4d8f56f30e35252395c292a2226bb028777931", + "kind": "execute_error" + }, + { + "hash": "8b77f088b8a1082b6d2130e2565ed65924e557b6da08e32fd9611bb81003a9c6", + "kind": "execute_error" + }, + { + "hash": "26e2784750b7e50893f5d5a46d3f1eab9132ae081e8fe097b896a65e6858d632", + "kind": "execute_error" + }, + { + "hash": "e4b286a1c1f38ed21f0f073e1b2e902a45780cb30e2fed3b953422dd63e982b9", + "kind": "execute_error" + }, + { + "hash": "007e32c6256ebcf2b0736bf61fe82ec14b1a55b81fed304223d8cb8ffb4a6c9c", + "kind": "execute_error" + }, + { + "hash": "209ce6cba27c4ab60fc392c318d1cb58f2da6ab677ed066857cc2d8648a7f4db", + "kind": "execute_error" + }, + { + "hash": "e1bd6154c2db92d97e8efe8e7954acaeab917ef361ac2cec6f813fcada414799", + "kind": "execute_error" + }, + { + "hash": "7cd81eda70b34e54b41dce79c1a7320c4a129e31281c6d7e5d0db070ed656b0e", + "kind": "execute_error" + }, + { + "hash": "4a369e9b551669212077b46caa83ed6e369eeb6db8d9ab6275d4bb4833df0f2e", + "kind": "execute_error" + }, + { + "hash": "2519e44ab13a53593b10a0782889fe270a6f3a6985e387e21321ae43d8330547", + "kind": "execute_error" + }, + { + "hash": "f206fd88b7e95e6c3df06671d8dc5ee848349ee392f3b8efd61d46269c04095e", + "kind": "execute_error" + }, + { + "hash": "0ece71bf1b55094daa73c2e16411da5a0627090cf57a6af0f04041273dd7c0a2", + "kind": "execute_error" + }, + { + "hash": "2745734967b2398467739e2e9f5e14d70b09cfb562c0019ba87dd55a6d6df8cc", + "kind": "execute_error" + }, + { + "hash": "0bdf44ab808dafac0f6b0a2672db12508fd9ad5d7510f055da370d715fe18d2c", + "kind": "execute_error" + }, + { + "hash": "44d388406337d81856aa8786711e76215c90c4a6e4a2bfc25df28288d6a5068a", + "kind": "execute_error" + }, + { + "hash": "cf67c3dcc04c88559a03adcccf5e0340eaf73f5e97a46d2848d9b7a54ba7bbb1", + "kind": "execute_error" + }, + { + "hash": "f038e6882a463f326d7762b5cf29a67a1d20137a9b9337a94a7c92812bd7237a", + "kind": "execute_error" + }, + { + "hash": "5de1f901c7d927c9864b2558386427efd35299fdda98c295d40948792bcdf9d9", + "kind": "execute_error" + }, + { + "hash": "2aa0dda50085180850a9d6ff8a02b74741824d924877b3cdc84b43b258e87faf", + "kind": "execute_error" + }, + { + "hash": "5979d0c1b480f94a699b0cf3e1ff3006c86d5159a925e9fa047a72083b7c9cb5", + "kind": "execute_error" + }, + { + "hash": "0b6b282a552de3f41079d75b2b65fe04b8ded1042bfb5783a54ac79c9aa46556", + "kind": "execute_error" + }, + { + "hash": "b88a3e58ecc4513d0204620f8f5d3052a6ba5c3b0ec2c610fd87a66198373e9f", + "kind": "execute_error" + }, + { + "hash": "186bebc82c3b124e8cd429342da77c17ee9e402df6572e9a69882abfc8511ba5", + "kind": "execute_error" + }, + { + "hash": "77b023fb3dd14b70e9167d2ccd72425daa2c1913b5600fe2011099c97d46bea2", + "kind": "execute_error" + }, + { + "hash": "d86ac2d071a34f828eb86799d1b31ae1c9f630c59c33b2f0c0cd632111bd3ff2", + "kind": "execute_error" + }, + { + "hash": "475f0f62362493a19e30da4a3f3d239c5ad45aec33c7036039daa61a04c6e3e1", + "kind": "execute_error" + }, + { + "hash": "a84ed4795cd27384238023a839a12beadbdb0c95de391685725e4ad3e3075929", + "kind": "execute_error" + }, + { + "hash": "bc16d78f86abed62220a44a45f27c7aea3835403c10d67d5f5849571666fe26d", + "kind": "execute_error" + }, + { + "hash": "d39ff653491f5006651bf8bc49ee58253d0581a14ce6692f4357936c7f076ee1", + "kind": "execute_error" + }, + { + "hash": "6923dbde99abbe39e2b772f026f53d69a9f4e10c87ae54a4beb20bd7725c926a", + "kind": "execute_error" + }, + { + "hash": "9299302891390190518756c36e31a7c855e3f6d0446da24c31c96636d9534009", + "kind": "execute_error" + }, + { + "hash": "25497522ee2bd1cae9a1c129f53f72b22e198c0e923b9dbf82c63f62d863fa85", + "kind": "execute_error" + }, + { + "hash": "47e2d49140527febf743f879a5b8914e4168f3dd34a5cd03f34b6e5f5088560a", + "kind": "execute_error" + }, + { + "hash": "5b56b48992e67e52ae0ed5eab5b4383e54ce818d8a990d00f6c5cd9f93255565", + "kind": "relayed_success" + }, + { + "hash": "cf8f934b442fa1b9ea809e5d8639ace625c16615a2ec8839bab7483023e7687d", + "kind": "relayed_success" + }, + { + "hash": "932baaece613c5be32813e2ff6b04da0f21b67e3386398454747eb64aa0d6c51", + "kind": "relayed_success" + }, + { + "hash": "830d45ad8b48a3cab84a676f3d13250e8a928532dabd61464e9da7fbeaad54ec", + "kind": "relayed_success" + }, + { + "hash": "65af16f3130617c0568b7b120554b7e12619b1012bcc64f8c9bc3861625120aa", + "kind": "relayed_success" + }, + { + "hash": "0275497dc183428f25fb61b8539991278d9e531a8f9a3e3e2879890ada4e54e0", + "kind": "relayed_success" + }, + { + "hash": "4614747e597ac48636565066904a04ee0ab8eded7196d7f4210add2601545e1e", + "kind": "relayed_success" + }, + { + "hash": "f4a15fbe726ac1c9061c71c3f2630d2cf1354211446baee5bf6905184a088511", + "kind": "relayed_success" + }, + { + "hash": "3b66dcf0b6f922a666d961c9c2df465260291b174269fb7e7510f7befa95c24e", + "kind": "relayed_success" + }, + { + "hash": "72500bb6e8b388f006e0b12178f1db93b53314238aa0e5f3090c04a82023cd3f", + "kind": "relayed_success" + }, + { + "hash": "46ed0b9f4be4c5d81e962054cbf52847c353793ed084a6e2285378ba13af5f94", + "kind": "relayed_success" + }, + { + "hash": "366864b03d63eddec7c9461f53aa4deaa3ce8d7f14317af571a5765099e16f93", + "kind": "relayed_success" + }, + { + "hash": "104bb60336c0672853d5a19ec3ad1777613833282a0bc9eced9d833f17670791", + "kind": "relayed_success" + }, + { + "hash": "885d3a103e4219bc972969016e42efb9e9cfa9e5ab5399a7d9a438005902beea", + "kind": "relayed_success" + }, + { + "hash": "141b28e4f64dd2f8445e48288d3ffa0d9b317f075c71d467842126ce57b6d7b2", + "kind": "relayed_success" + }, + { + "hash": "3b64bfad76cc47d7711b88cf8b119c1af721919878c4b2b5651e4dbb99825f16", + "kind": "relayed_success" + }, + { + "hash": "16913a2dc9fa77d0c6ccafc3a7583e9161078c58a228a2e7a895d9ad1554fa28", + "kind": "relayed_success" + }, + { + "hash": "7f0abffd18496292c7eaed14018b62269dfc2d14a77dc0914e7270097724cc30", + "kind": "relayed_success" + }, + { + "hash": "272e535c70e5d22a98ff8df17abdd4cda8cd5f4090ff28efe4cdfb110934a0f2", + "kind": "relayed_success" + }, + { + "hash": "bd14766d52c5b5138f3bbe86ee298bb66d2501c3429bb986509d8dfc5d4c1fc3", + "kind": "relayed_success" + }, + { + "hash": "b21fe5407554294c7306ec47798c571d4366a03850f09cc8058e8eb403f725ca", + "kind": "relayed_success" + }, + { + "hash": "5c338f6c39364e9c9bd2d1a7b155aa6ec017c7d21f541c7abc86cf33735ad98a", + "kind": "relayed_success" + }, + { + "hash": "01ccecd437e731947b1fd235458d374853da115150c2d6339d77f6f3ac2467b9", + "kind": "relayed_success" + }, + { + "hash": "2ae2432710aa4c289fb7649e82197b60fe55e8cc348f97903c4ee5ef07d0f8ba", + "kind": "relayed_success" + }, + { + "hash": "941ef0fe0940dd5e3bb9a7b378dee9793d8e9a5e839460eed26bf418857a5e2d", + "kind": "relayed_success" + }, + { + "hash": "49cef7570a51e6017b6343f5e1fa5784c92444b9177058c42b58cffe2a7ab88d", + "kind": "relayed_success" + }, + { + "hash": "89a0d16e22d3e1a1b17d05350577596b35ecd3b480016d2c9418bde2a5ab4101", + "kind": "relayed_success" + }, + { + "hash": "2ab1b33ca63aee64e78d13e5a7498107b136b397ffec84200c2d28ce96a3d54e", + "kind": "relayed_success" + }, + { + "hash": "f5014ee0e780ebd35c5a7f90365c8518939911071a8e148ebf02eedc40b90bb7", + "kind": "relayed_success" + }, + { + "hash": "e4c0793b03a93748c7f81a79f3de3094b707fe0ce49d78d11faa2dcbc10e3781", + "kind": "relayed_success" + }, + { + "hash": "aa76c5bf5a72206ec818471b77bc42ae3a72cd54f73b98970b0361570c0747b7", + "kind": "relayed_success" + }, + { + "hash": "c5c51dbe8ca78aa42f39e4fd3941db23259d4cc1c75ae290d305565a7ce3006d", + "kind": "relayed_success" + }, + { + "hash": "d2a3702695ed4a83d0ca60994c7226750f77663b7aa4771dac611ba1dc9f5084", + "kind": "relayed_success" + }, + { + "hash": "e7b973f0245ce7d1f62aa7c83962d0d2129048962bf2b57e81bf52371656f6f2", + "kind": "relayed_success" + }, + { + "hash": "dafef1be36853378d6c067b6394e4aa6f458e9309cb5f0ad723b795a1b8656ce", + "kind": "relayed_success" + }, + { + "hash": "6a1ba5f6c8c88823fdfcd9ab9295917c1b161d3354dc7b1153a5825091d6ca0a", + "kind": "relayed_success" + }, + { + "hash": "5db1a32f06696a86b1abc8c7fd9f513693aad5896933ea93faa188954e4fcd2c", + "kind": "relayed_success" + }, + { + "hash": "15834ab5682fa54101e94a8615fa8172ae1c3f14524e6a327647a68f01ec46da", + "kind": "relayed_success" + }, + { + "hash": "ef3525d1f92da0936504266654b1378cff6ecf331f551fb7205ba16e1ca9340f", + "kind": "relayed_success" + }, + { + "hash": "3c8e16f8bd623b940bbde0f08055e2d01b76eb1447582674233ac4559e3cbcd5", + "kind": "relayed_success" + }, + { + "hash": "960872f4c68faf5be019aa1f973246158aa0637f76319c9b297f57f8004f0cc0", + "kind": "relayed_success" + }, + { + "hash": "0d3b8396c9f68a59f45b6fa3a32cc595dd37dadf3461d9acc24d9762bda64bf8", + "kind": "relayed_success" + }, + { + "hash": "97bb022d794282be1c98c8cc78d19883023b9bf75c7e140e6f31df5bce9e9068", + "kind": "relayed_success" + }, + { + "hash": "41250e35dcef601c7a31ac3fe880eeea1589746baa610f1e6f8da26254966332", + "kind": "relayed_success" + }, + { + "hash": "a17f1ecaa3033e1d91fa2f8642887d5c7d4fceb9876453d92fcc905ab10915c1", + "kind": "relayed_success" + }, + { + "hash": "372fd74991e5f09c3aeb724e8bf2963fde81f4048ac38d525fc649c810572cc7", + "kind": "relayed_success" + }, + { + "hash": "d549628eaaa9b22e8516ce819602ce9dd7295b3b12bc419c2707b597e5be8bec", + "kind": "relayed_success" + }, + { + "hash": "2bf855eb147faa30cf1e501da80af2829bf32d4775c48de7fee365b08a4c76f3", + "kind": "relayed_success" + }, + { + "hash": "2851a64f97401b76211c687bba76b539c331fcb8d3ff3bfd5411791ed330b6d7", + "kind": "relayed_success" + }, + { + "hash": "3f5333d802601b10d5567203c629341e17bc87727d6cf57e0506ebc532f81b70", + "kind": "relayed_success" + }, + { + "hash": "7c139b1da1bfd0776bfc73158eb2083f5dc89187590f1701db89210e2f6982be", + "kind": "transfer_execute_error" + }, + { + "hash": "b7a70fe4ee207f01c0ac13458c7377da71c13f065bf944f2d95ea832561c10bd", + "kind": "transfer_execute_error" + }, + { + "hash": "cf04bbe11bf44f03be25a01dd574e243e560c5cebe7f2418fb5ad626d6ba767f", + "kind": "transfer_execute_error" + }, + { + "hash": "03f0b5b53e1ef5ef212928eb9a5e83b97f64254a62adee067a8c439ddde20fcd", + "kind": "transfer_execute_error" + }, + { + "hash": "bfe45b34b29bd911a05d55ea58cf919a91b34f10318c0d2bfd4a7f50df86fc53", + "kind": "transfer_execute_error" + }, + { + "hash": "4a4fb60f766305c398fca44f50b63eb95a7606fd172f0b3844b331a8a0008d1c", + "kind": "transfer_execute_error" + }, + { + "hash": "b50889e334c69b4b2c85eb067ee0f96a24308e0333ae677c7a343f1a3c849775", + "kind": "transfer_execute_error" + }, + { + "hash": "98f4005fccfa7380f49b846413c80b78d2246d179a62afdae5ae6749fd545646", + "kind": "transfer_execute_error" + }, + { + "hash": "81284bc4ae84e69823f71897da0b71677a1a6112b19105d7182de7fd75f624b0", + "kind": "transfer_execute_error" + }, + { + "hash": "00f5d03703ccc37e1873ea18ec3bf0cb46840dd854a6cee9a6af795df6fd6cd7", + "kind": "transfer_execute_error" + }, + { + "hash": "78caa86d8e3d47bbc6c228ae0d49a1c276fc153c51326ec7ddc974913d8bae38", + "kind": "transfer_execute_error" + }, + { + "hash": "6284a701095ff12cbaf59d3756590d1784ec3a4dcf32c814b6c0ec58b7c90f4c", + "kind": "transfer_execute_error" + }, + { + "hash": "f85c6ec11bf660318278248addab6228b11641d06ab4fa4c22b5d650716db47a", + "kind": "transfer_execute_error" + }, + { + "hash": "2bc660a9b28d81045391426d8cbc7a436ca257f9834d2adc630e68e7362b2c4c", + "kind": "transfer_execute_error" + }, + { + "hash": "4482034f2491a8dcd47a992969f6e87a84d97de5a2547e2f87c63f4ccc794340", + "kind": "transfer_execute_error" + }, + { + "hash": "d7d909a3db2eb17b0eda7cfd462612bbf3294ee493e5eeb118a756394c3503f7", + "kind": "transfer_execute_error" + }, + { + "hash": "a4edd2d072c6d0531e33c10e56e032dba172abfc168a5f232ab6ea71bf32ff99", + "kind": "transfer_execute_error" + }, + { + "hash": "c52f6b03471bd6858ad484b0edf22d006797934e908d5188f0f727c01738cf16", + "kind": "transfer_execute_error" + }, + { + "hash": "93a618d10563e1eecaa7f3f9e40a81967a80745dc95e763129b293e8ba7734d3", + "kind": "transfer_execute_error" + }, + { + "hash": "7d403b35a3e2520c208ced77f8dec978e541197bac2c12416c3bb29f11313eb4", + "kind": "transfer_execute_error" + }, + { + "hash": "ac007aea6d9458dd85db096103e251d76402b7be4203ed7a20389da9b86afd95", + "kind": "transfer_execute_error" + }, + { + "hash": "55c5574a7d4989ae4e8d293106f0eeebe1f96ff736f99ee0fd87569dd3ebc2b5", + "kind": "transfer_execute_error" + }, + { + "hash": "22544866fe78d81ed53c898cd5f3af0ba807c824a2b7314e8457d933cd6d846e", + "kind": "transfer_execute_error" + }, + { + "hash": "2dbaf86fb711e920b1452498c0eedbd59eff25174a2ac7fd1c1b1e1a84c0b4d6", + "kind": "transfer_execute_error" + }, + { + "hash": "092d3eff6ca730d180886921f2393dd170fd44dc8cd0ba6203af664c93df6354", + "kind": "transfer_execute_error" + }, + { + "hash": "560951af904fb0779f19b9ac6058201dd253579222f4c03cc1a0ac50cb1b7568", + "kind": "transfer_execute_error" + }, + { + "hash": "2c4715787d744c3dffa6cd1b9988d92c209644064af4ad9c7796c011c44f0e45", + "kind": "transfer_execute_error" + }, + { + "hash": "ad6ee6fce42b0d231caf3754d5891394e6bc28ca1ee6f310426cd0ff39de1dc9", + "kind": "transfer_execute_error" + }, + { + "hash": "807378015edba61b3e3f239d44822072d4ee5b34d21490c294106b4662942887", + "kind": "transfer_execute_error" + }, + { + "hash": "0c57be0e61002dea89cc8bd7c9a533521f19370edde34f2d0c97e4c006de51fa", + "kind": "transfer_execute_error" + }, + { + "hash": "1fa9c74847abe3a65e41cf589528c9e8800e5b3ac07ab2193ab82c522f339584", + "kind": "transfer_execute_error" + }, + { + "hash": "f4a9ff0f4ca36694fb840476b99743a3d978baac688ec04adafe85b185436a8e", + "kind": "transfer_execute_error" + }, + { + "hash": "177ed1477d0126b0f3445673e12116ce4ab5d4c0f3d1400778f1941b320e8865", + "kind": "transfer_execute_error" + }, + { + "hash": "2bba138516b1af9a6e9ec0e3f61d02f3f3014ad203911bd7c3cbb0179fe1a400", + "kind": "transfer_execute_error" + }, + { + "hash": "337764b0d49af4229a633b316302af27f9661a25b61fb460c7ae94492783596c", + "kind": "transfer_execute_error" + }, + { + "hash": "a7e469cfe3588acb10968f04a27542c4e5096a1f4cf1534ef4f982127943fbc2", + "kind": "transfer_execute_error" + }, + { + "hash": "b649c7ac4158d9fc5d3901ec390fa6c0e0b0359f6bf1357fb2e97a39965ba1d8", + "kind": "transfer_execute_error" + }, + { + "hash": "6f9181e78777d8f37fd41ff32f2fa525ea32f0ddb567039dd256987df018064c", + "kind": "transfer_execute_error" + }, + { + "hash": "fcf10fbae51edb51037bf8ffb04a2dc7d0d9ecf67c85095f79ed0c46eac922d4", + "kind": "transfer_execute_error" + }, + { + "hash": "b951dc6e3cf9477f210585d8de2fec89a71ee110d5e81f30da0c5a20082254d2", + "kind": "transfer_execute_error" + }, + { + "hash": "93f4e23c17e7cf5a916c4e125443558c67a5ff8f42c85870716a133231f87c71", + "kind": "transfer_execute_error" + }, + { + "hash": "d9ac5e5d342f8d49bbed01e6bba184eeac02011168ca79d13b635f9d42cf1bbf", + "kind": "transfer_execute_error" + }, + { + "hash": "debe4af855384580cf2297d1f2c2a504b668afd4b62b6d512e4c3c6e0d8ac842", + "kind": "transfer_execute_error" + }, + { + "hash": "8bbf5c19cc2923fc1a9e27bb35f284f9c1ecb73d1c7b355a598f55e5285d60d6", + "kind": "transfer_execute_error" + }, + { + "hash": "4dab6d7ea56872ec41dd211bf8d432516beadbe82b510ef912af4fc91a63657d", + "kind": "transfer_execute_error" + }, + { + "hash": "b45277ca50cfbeee162542763cd1a67f19b0836bf4f7e56751c7e9b700e8ee20", + "kind": "transfer_execute_error" + }, + { + "hash": "b22f878903128d5f057641c930c013a89b972a577c8a1fff7a4d1834fa6a9a72", + "kind": "transfer_execute_error" + }, + { + "hash": "8b3e7b51c63eea2e2b8a0194bbf1731387f50b20c7e5ecf5c316a9d635443dec", + "kind": "transfer_execute_error" + }, + { + "hash": "17c9fa44b76a3cf6f2841720e2ee6ede73a772ea31616c9951569b273dceb172", + "kind": "transfer_execute_error" + }, + { + "hash": "ffe039ecfe3c424a11a2e2134405752cc8a6692065ed828e882de0af9a0ed117", + "kind": "transfer_execute_error" + }, + { + "hash": "5548bacf85bd373700f855e66816535485411594deca8bab174e6ab5ec447af1", + "kind": "transfer_execute_error" + }, + { + "hash": "57280d425e2151d3135792cb58282eb2ab27718832412b681bd7624e5862886e", + "kind": "transfer_execute_error" + }, + { + "hash": "960470fe55e796b357ff679c532612be7091d9e563bf769db523b818a3828f11", + "kind": "transfer_execute_error" + }, + { + "hash": "e5f76318d1213157a97879d72f56ebdc5b5926ffe6d9a7c88cef06178c5525ad", + "kind": "transfer_execute_error" + }, + { + "hash": "1172ea424b26b94ffeffb3c089d27d2a011fd2fd021359c456bca65746150de7", + "kind": "transfer_execute_error" + }, + { + "hash": "8a8941b687cfae5843a1e9d437ed8d200bbc04249788985bd34e300e0f5fc811", + "kind": "transfer_execute_error" + }, + { + "hash": "5314d49e6d3472804a79e632f4adc2311a61a9f7c70ac2165997f9b0ddeff3aa", + "kind": "transfer_execute_error" + }, + { + "hash": "1ada50c36429b34d46c83193ea8215121a1f149a1b6289984a23dff0a38f051b", + "kind": "transfer_execute_error" + }, + { + "hash": "fdab2b6ee33feb793fb9bd22cc6298ab5428826dd011a3500db56effdd0809e2", + "kind": "transfer_execute_error" + }, + { + "hash": "248f451807677734fa9e2899de7b25f8033f57ebbe5e8eacc54be00301c403ce", + "kind": "transfer_execute_error" + }, + { + "hash": "c7c193cf0a79f2537fcc9a90ed8c29652c283345236a5a76d7b03e32ccd64115", + "kind": "transfer_execute_error" + }, + { + "hash": "06cc5111ed6bef61f769d9c07ab7d60a8c7589132eae1e679651105f57db34b7", + "kind": "transfer_execute_error" + }, + { + "hash": "9a5c97baa979d1c38adb3669b48b49a173a666b896dbebe1804af1c2a63f6ff5", + "kind": "transfer_execute_error" + }, + { + "hash": "a2b4cffc693685759f4972b1eda87495877541065b55c8aa5df970b7ffbc3b15", + "kind": "transfer_execute_error" + }, + { + "hash": "14e012a4a6727e6f8b42813b60983fa19d0096ace2d10ea1689b4fe9c500c2d3", + "kind": "transfer_execute_error" + }, + { + "hash": "0077383488f23b386182ffdb5f344a6e0e26b9aaa7b725085b7e9601a0e6499e", + "kind": "transfer_execute_error" + }, + { + "hash": "a37cb6e0ed79fa114a7ff8abdeff72c425550cefd8f25673db6d4bb2901f5ee7", + "kind": "transfer_execute_error" + }, + { + "hash": "de456297df9eed381c0bb5d6eb2b8f7ba0a9d0ce006a10cce46debaf6ae0ef7a", + "kind": "transfer_execute_error" + }, + { + "hash": "3518e2cd6b7ae3711cb118af5a12498a72f6a4249316e4c7a72c7ee1668915cd", + "kind": "transfer_execute_error" + }, + { + "hash": "5928d134d04b25520708be6574080ee56bdeb93eb63123d8bc7b14c0598e1cf2", + "kind": "transfer_execute_error" + }, + { + "hash": "334bf1eb2855faba2622cfc4076027408d46c221f9c5cc098bffeb1ca2725f50", + "kind": "transfer_execute_error" + }, + { + "hash": "d3b24ad71940607b7b34da90d910abc054516480dbfb39226a629e81ab0b98bc", + "kind": "transfer_execute_error" + }, + { + "hash": "9ddd2359a9d76509cda1c85965372e3cd03c839dbb166c7825f833798b0da204", + "kind": "transfer_execute_error" + }, + { + "hash": "b44ae09f74b72f3bf379707a5ae361c9197fdfe0ccb97b61912f1e5136bbadba", + "kind": "transfer_execute_error" + }, + { + "hash": "40b1ce35fc0f1def62c14931d05cb220b29b3a500c355801e349011aa8841c96", + "kind": "transfer_execute_error" + }, + { + "hash": "98585d5cced3c8d3536e84fe839714fa21faebd1d125d5dfe3c9700fd91e5b20", + "kind": "transfer_execute_error" + }, + { + "hash": "5d907b715e56ec6e12d281b0968bce4e67ea1c5989c0f12b256462a1c699895c", + "kind": "transfer_execute_error" + }, + { + "hash": "e53b0fe1c169b45bc01fcd8c8bf1430173ffe1bf96709c523979f327ff263c40", + "kind": "transfer_execute_error" + }, + { + "hash": "bc585f09315b8fb8a9fecb455757990a537e897585db9e1cd14f005d551f13c8", + "kind": "transfer_execute_error" + }, + { + "hash": "4118f7a71958d8a5a46c0ac856cbcb081a29005d9236b6651429a74e279962f8", + "kind": "transfer_execute_error" + }, + { + "hash": "3f613fab92cca386c05b424605974ce6685c6a147e322899ef68865ce87d671d", + "kind": "transfer_execute_error" + }, + { + "hash": "dcde222340ff545bfb7358a7ec1ac1ee479bb720ba9bcd994b442a15db5fa48c", + "kind": "transfer_execute_error" + }, + { + "hash": "c51ae7b16fd2c1907db2444bb909eda951b78464070c778a7e89b20d1012b5fa", + "kind": "transfer_execute_error" + }, + { + "hash": "39970aee39776c18eb9619110e4bae5bc9c50d901d5b6cc7274c470a61858d37", + "kind": "transfer_execute_error" + }, + { + "hash": "6b5b6f86bc9fc0b66001a7d6e46ba2f967f0b3f50bd650c5e8b13988ff254fa1", + "kind": "transfer_execute_error" + }, + { + "hash": "9c40a763226dfff48e2e3885e6684b838a899a1e671316c58c66d7025e852415", + "kind": "transfer_execute_error" + }, + { + "hash": "13895ca1fa9ab2b8286d1bf17bc1a3dd2796f866e033c32ab8e9b8ffef66da3a", + "kind": "transfer_execute_error" + }, + { + "hash": "6bd79bf8c0e91fd6e58e2c37b0f083f54d8b2e30556245e0e63a0f04c6e5e9f3", + "kind": "transfer_execute_error" + }, + { + "hash": "5aeaae1ed1224e8541a7f0d2632d283d857447fc78eeb2ddb2fe3b1d9dd692c6", + "kind": "transfer_execute_error" + }, + { + "hash": "ea1db9afa6d8b4d515e06b588ddb803fea54dcfda2647b559a86f27280d76cf7", + "kind": "transfer_execute_error" + }, + { + "hash": "ca716a663b85f9ccef5a261ea15e051460061222ab3adb59e93bd0c971502c96", + "kind": "transfer_execute_error" + }, + { + "hash": "0b7f7a62e40a6c8cfb080a23c441d4b3f46689e5a18f6bff16322049cab6f15d", + "kind": "transfer_execute_error" + }, + { + "hash": "48522e6c18a191c49ec014efb08265424ca6c12b9fe2b79fd0f006f414b726b8", + "kind": "transfer_execute_error" + }, + { + "hash": "23c94d7f27dbb90ac55cd86fd769c4cdbba3e82097d6a5567686e3870ce58c1f", + "kind": "transfer_execute_error" + }, + { + "hash": "c5aa580c3ba411385c01ee4673cbdc42956f7812020f436b21271087fe53c374", + "kind": "transfer_execute_error" + }, + { + "hash": "a2fb7a614e1cd96361e3d13cc4387a0116a6087209f7d818a7b5861c30dd747d", + "kind": "transfer_execute_error" + }, + { + "hash": "65fb642310c83943ed83363324a802c460286b33263dfd2f6ed3e7ef191c1253", + "kind": "transfer_execute_error" + }, + { + "hash": "0834de989c0354b21abd9de85fc341f1ae136fb8182a61031eb7ef36a2d37ca8", + "kind": "transfer_execute_error" + }, + { + "hash": "549262d0257617a0e78d1fae3b8b3c6e41fc0fd833d82ec74ec959c797ec4ef1", + "kind": "transfer_execute_error" + }, + { + "hash": "6fd9dd82d186bae62cd9e4afff7d7597644607a8dc3086d95198398aca0ab605", + "kind": "transfer_execute_error" + }, + { + "hash": "0d4f968618646d863341042175f0913d7f91e2601e2691484323d422d2555394", + "kind": "transfer_execute_error" + }, + { + "hash": "717f8dcdf261ccd395ec9f4accefdf7e1c7e7648d824a1447ad94279efbed537", + "kind": "transfer_execute_error" + }, + { + "hash": "a79c67cacfcab7fb936c394f583366e6188e076f2727296399284cbec2b54bdc", + "kind": "transfer_execute_error" + }, + { + "hash": "2defe97dd76e5da389db9b9ed63c5d86ab84d180ed0695f6446095fd14575f38", + "kind": "transfer_execute_error" + }, + { + "hash": "21f8cf276036aa6e49f54da1647ffcc71199b8df95780cae0ea972f31f0dec4d", + "kind": "transfer_execute_error" + }, + { + "hash": "0df34a893403023c8f5db68de92d0a80b1fafb397fc24831d55ff06e7c4c4839", + "kind": "transfer_execute_error" + }, + { + "hash": "e8264fe06854275b0284ff3741fd44e54590eb8c4f297cd5dc3dc8550a21cc3d", + "kind": "transfer_execute_error" + }, + { + "hash": "2369cda83e0474d0fd2d5c2a2becfd282f3bf9e2beecefbb0b9f8c158ff866d5", + "kind": "transfer_execute_error" + }, + { + "hash": "d373195b4add24505bda023b1d787fb68a6eaa718619e386b1900ea93a74c9df", + "kind": "transfer_execute_error" + }, + { + "hash": "181ee75f22cd7b39983070771c0c5a8c64f78002d2947a47dc9beb0e9cdf7d55", + "kind": "transfer_execute_error" + }, + { + "hash": "387be97e9874b7e1a5ce84dd58163214dda16fe18a42b9418db51e6f0709ea6e", + "kind": "transfer_execute_error" + }, + { + "hash": "2948360f67501920e9162f962c7b2c166314a6a1c971975fc18749e15450c395", + "kind": "transfer_execute_error" + }, + { + "hash": "08142717ad761d82a922a55843b4658720877de55f8d0d6df098f36ca9e6cfad", + "kind": "transfer_execute_error" + }, + { + "hash": "b6a7e5fbfd015f28f48d42c8e90b60346a4b2f27892acde6d29d0c2e635c43da", + "kind": "transfer_execute_error" + }, + { + "hash": "53386ea46af9d521c61d0364b1aa1d388a836725669c30905e4035e2ae910314", + "kind": "transfer_execute_error" + }, + { + "hash": "5f89c9e40703b4735854c913dd5de99f5c898b0a53109b19d401dc24d1759a83", + "kind": "transfer_execute_error" + }, + { + "hash": "928b5c29a237a1b05c8d8978d7e1cc88331c3576df076284fbda9dbf299fca94", + "kind": "transfer_execute_error" + }, + { + "hash": "ab313ee14aa5c6266f2dd49e7294818397c99928225f58955fc4a2791a56c396", + "kind": "transfer_execute_error" + }, + { + "hash": "c30d8965e31a078ae5cd7c1d0a7213cc51dd3bbf3b8bf2f341ccff2267969d0f", + "kind": "transfer_execute_error" + }, + { + "hash": "8eec59e7a1ee92fc61a474575f4117ce6668bec9344f59a0b90c960f9c5099f5", + "kind": "transfer_execute_error" + }, + { + "hash": "8db3c586c7d00dd4fb98c59313355a1c4e8e5dfe70fb076a6d3deb4e038cbdc1", + "kind": "transfer_execute_error" + }, + { + "hash": "e7ed817aa49ed94e3c572b4b37098a460eae4a07bc374961b5337bf0a55833fa", + "kind": "transfer_execute_error" + }, + { + "hash": "05715c2b29cef78ac54f1897972c9cd780ea25f2ba941955c872a22120d9ce49", + "kind": "transfer_execute_error" + }, + { + "hash": "5e3f5b6dc93180448cca56dcb95869f8d9c88c23f5c60bd2d3327323de9f5480", + "kind": "transfer_execute_error" + }, + { + "hash": "eaeeffb167095dcaa5ff0a1287835951c17a4a95922b5a60aab39fcfc593fa08", + "kind": "transfer_execute_error" + }, + { + "hash": "c1915e7755f070beeb02ceb2e52d909330a9455a87e367fcc98511798a906847", + "kind": "transfer_execute_error" + }, + { + "hash": "4ec62236d37e4f546d908f6467a71be8004ed9c5990727072dc795ddfbbc0bfe", + "kind": "transfer_execute_error" + }, + { + "hash": "42ace5a672d208dcc07ef73558dc7fa6d436b571bfd795835d2141cbc601ab4b", + "kind": "transfer_execute_error" + }, + { + "hash": "50fc7997847145fb54a13c7083384bb81b99a9c5b5211f9486a9e88b119df4b8", + "kind": "transfer_execute_error" + }, + { + "hash": "a61e1d5cf37a4db4cb5c84cbf36fd6f45c0e15d5cf94c4f68d7469959bbee84b", + "kind": "transfer_execute_error" + }, + { + "hash": "1438fee8fa499c8110748c4cd03bf43f50bbfd7eae18725b019228a208fe7184", + "kind": "transfer_execute_error" + }, + { + "hash": "e32ca1c07997a593663ac824627cc2e27f668ec1b6c1babd756a6931d8884b52", + "kind": "transfer_execute_error" + }, + { + "hash": "0b9aab1556995f846215e444b882c4f122ff30ee96ff3e994bae8dd37db93e34", + "kind": "transfer_execute_error" + }, + { + "hash": "526f9db74b15c832a5b9088f13810aa0dbbdf0a2c81b257420cbfa93b651f743", + "kind": "transfer_execute_error" + }, + { + "hash": "4ce8cd009766e4e283680714a8673e20cef88efe82acfd45a33e1e4503e88be9", + "kind": "transfer_execute_error" + }, + { + "hash": "da51a57a794d3fadd15b04bbf29ccc5e82a1b7c7785469ede0a971ead967e40c", + "kind": "transfer_execute_error" + }, + { + "hash": "aee888ce7f0f21fda9b64955d959ad05f9cef23bfbcc72f3105c04a8b00ba9e4", + "kind": "transfer_execute_error" + }, + { + "hash": "c5ae6cb56e18c4b1da7614c41f7a6c60afb9d820a64a62b3eeee02558ba4d336", + "kind": "transfer_execute_error" + }, + { + "hash": "8337a9e167a726f468babd5d03013e1668a9b46c346b9a8f48d918d285b4e2e0", + "kind": "transfer_execute_error" + }, + { + "hash": "d57f26875f8b2954c433ce9a1e0f32392e950007441cf8c460604bcb7e5fd664", + "kind": "transfer_execute_error" + }, + { + "hash": "01d6e35285c97fa71cf97000fc2129c80f4eaccf4c992b49f1babef7e23e3e6c", + "kind": "transfer_execute_error" + }, + { + "hash": "bd74589dc94f23108a59cc3849f1f4a101f3963d8339760beacaf7cec23c3a53", + "kind": "transfer_execute_error" + }, + { + "hash": "e22cf66a1c0174b435ff1133b8818dfade5e7225bfe13f7d8ed684445ea61802", + "kind": "transfer_execute_error" + }, + { + "hash": "9f734def3629bd07f51b5dfcd7761c36b3fc3d01fc6902f1d839916521a6db4e", + "kind": "transfer_execute_error" + }, + { + "hash": "d5aa13ccda6071695726053acfb956578813fcd4797641eea2ae6765c3a37b19", + "kind": "transfer_execute_error" + }, + { + "hash": "42a621c64a45e4886f0d7b3250b0fed095c5d23d69466b1e59e6c8beb9ca23bd", + "kind": "transfer_execute_error" + }, + { + "hash": "19642a4048ba848ca2339efdeb43fda9ad30bbcd15e920b190d5d6e1a02ebdba", + "kind": "transfer_execute_error" + }, + { + "hash": "36e282b8a8632a6ba5dd6dd6a616a34195e8cb5637cf0577fce83f4386fa8f91", + "kind": "transfer_execute_error" + }, + { + "hash": "4002b30a9ac3a593f41aef68868b0df6d297f2eb7e29e8e96f3182b6bd438f81", + "kind": "transfer_execute_error" + }, + { + "hash": "d4cdc1fceb648a3ff9bfa456218abfe0950b4fd6cefcc346581cfb0cdee73aa9", + "kind": "transfer_execute_error" + }, + { + "hash": "39dbbdd03c0a31e285450d50001561ed61b7c8e647c94d0a59f9b9a0ca1d0635", + "kind": "transfer_execute_error" + }, + { + "hash": "f2440dac98b14f602013056599aca5bd8da4123843bb198d4d9d89f482dc9bb2", + "kind": "transfer_execute_error" + }, + { + "hash": "bbd182f4b620917aa1d8c2d7ef03e7574a4f92e7a7ce9d14e5a568e65055027a", + "kind": "transfer_execute_error" + }, + { + "hash": "611a72d874b17d5cd41f92f61f40549e6463e0eed2f3b1e31aba49c6fca3ea8e", + "kind": "transfer_execute_error" + }, + { + "hash": "ebcac7cf482e07512f3c62ac8bf1d0d38858996823c28f11739c3f787946d43b", + "kind": "transfer_execute_error" + }, + { + "hash": "63f03f4bac736428cd14b24a4a8a7d1d7af533872e0bb7f3c5e1b8ae04439483", + "kind": "transfer_execute_error" + }, + { + "hash": "5607e6870ed0aee9b472f50e02d09f93b25352663d650cbcc989bd2275ce1d89", + "kind": "transfer_execute_error" + }, + { + "hash": "5448a5a1b16e8c73a63b27bfde88810f11438c49f2353579745e981d36508014", + "kind": "transfer_execute_error" + }, + { + "hash": "c2d1639821549e16ce7fed67516228af221aa4a4fd292537969c2b5bf541b57c", + "kind": "transfer_execute_error" + }, + { + "hash": "901b0f9a613de9e245fcbd96092eedc6e974d9f82eec4c6c1f010e29082d0d41", + "kind": "transfer_execute_error" + }, + { + "hash": "1724c437da3125f5e375e9e19420bed15ad8f70e14712d53760f0bde70df1d34", + "kind": "transfer_execute_error" + }, + { + "hash": "548397c8439375a7fa9768e1bcf6c96087c873ab6fb8d913806d883a2c0f60bd", + "kind": "transfer_execute_error" + }, + { + "hash": "690d3425c2c8a9aba1e3782bdb89d4033fc0e27cab216c46f6a59a9c84de6c71", + "kind": "transfer_execute_error" + }, + { + "hash": "a2646857f2766e293367bae4231c35a0ddce293ae36c9434e1851d16d2af492a", + "kind": "transfer_execute_error" + }, + { + "hash": "2386f5685cad48e414f8a109524ea560597a1f06c19765f3caed2bf8ae83bd5b", + "kind": "transfer_execute_error" + }, + { + "hash": "d376ce529ad413470141c369d9ade3ec6a9c773bcd4cb984d3eddf03b20bfcfc", + "kind": "transfer_execute_error" + }, + { + "hash": "346b9a513511d752e3c76ca549131ea857de4ada2f7908c0083de529aaa32e85", + "kind": "transfer_execute_error" + }, + { + "hash": "111bd202fe7bd05caaafae0f7f79d2bdfb8d67976823af226f4453ac4c61eea2", + "kind": "transfer_execute_error" + }, + { + "hash": "15e46838bd867bf7809e7e425c8f3beee5f75e2981c088afa74c8f3f2205a46f", + "kind": "transfer_execute_error" + }, + { + "hash": "bb8cf27afea029b58dbdd28b733a961b8c404ee0914f2517c8b4349aa2e80f53", + "kind": "transfer_execute_error" + }, + { + "hash": "0635c9d179d9d256f632a3ecd7c38a5b0021c0bd55bd61864e2b0a03038fd5eb", + "kind": "transfer_execute_error" + }, + { + "hash": "a159186a65511f06e32ed60ecf2b246e6cdc6c020cefb1cd0c926860a844557f", + "kind": "transfer_execute_error" + }, + { + "hash": "b9e05f9f61831d2e5e46f6b4ca5ac51c7616792c36fcf30c9fcf3b98a4df21f4", + "kind": "transfer_execute_error" + }, + { + "hash": "237b281e2ffcc2919c5e34468998e5c51f8d64062650aba2d101aac8630aa015", + "kind": "transfer_execute_error" + }, + { + "hash": "337eec82f1a363eaec2f4b5775dacbc1ae56270b8c73bb53ae7a25543fb051aa", + "kind": "transfer_execute_error" + }, + { + "hash": "7ea4454cd7b21fd24c1de7409220127b7b0af816d9d9d842daecb77c0293d154", + "kind": "transfer_execute_error" + }, + { + "hash": "6f5e6948c7cdfdb1d73bd157f62ffaa61cfa14829d1c186bdf74670c7119891f", + "kind": "transfer_execute_error" + }, + { + "hash": "c21c3b0acc97bbebeadd9b147713e7696bdefc6136823285754b5797262155c2", + "kind": "transfer_execute_error" + }, + { + "hash": "242b73a67751e1a0cadd5765539f9147bfd46ccd2e14e35e67a0997e653b4f4d", + "kind": "transfer_execute_error" + }, + { + "hash": "f189eda08a6ace7c98a8d305f6aec1864ff05c09f738a8aeecbd6a90f35d55c3", + "kind": "transfer_execute_error" + }, + { + "hash": "d7a41d980144581c92379fb23f18b9a14ae2fce179ab176c8658d841354e2963", + "kind": "transfer_execute_error" + }, + { + "hash": "557e99150ca929cfc03791efcb8ab682c1efc4fd7e2bfd4826d54085778711f4", + "kind": "transfer_execute_error" + }, + { + "hash": "d14ba38d730b04af25426a44d5c963954b5ac2f5c86fe445d25432e5026f53dc", + "kind": "transfer_execute_error" + }, + { + "hash": "cdc07581de1c910c3b99ea0aa4171a4c97831ff1ff58c1b1564e5532752d7141", + "kind": "transfer_execute_error" + }, + { + "hash": "830fb04d94902725c4b3b25b2209d20a6080a3507d8514c50b67f4fcc2713739", + "kind": "transfer_execute_error" + }, + { + "hash": "8fb64217ee33de4317edf55af76b5a0840bb4d0251a56c4eeec99ea8db2ef95d", + "kind": "transfer_execute_error" + }, + { + "hash": "3f64a000e27f5ee31c5643139f9d80539a7ef7cc88e652c546bfb949df9d4949", + "kind": "transfer_execute_error" + }, + { + "hash": "834fdcda6f7745f3992dc18d7531e840e5f3efb6183047ab89c8da07bc25d7ff", + "kind": "transfer_execute_error" + }, + { + "hash": "14742dbc129842230480560704a846d1bb5967229c7fb81fb8d7628e9508eb35", + "kind": "transfer_execute_error" + }, + { + "hash": "fab7cead06c2887af7e3d42855cc1c8f5801b239de3c16cb1013f29926ece111", + "kind": "transfer_execute_error" + }, + { + "hash": "47806753023f87c70c97b28c3f5984877db125cec8d02e53493bfb943df92818", + "kind": "transfer_execute_error" + }, + { + "hash": "011957d69771d5b66427c666c438450ce01e36f2f93f1f0611e375b05929e9a6", + "kind": "transfer_execute_error" + }, + { + "hash": "67b9b4b754fd7ea72aff07fbe15f5215896187a8e532c494c0af648cb8dc3932", + "kind": "transfer_execute_error" + }, + { + "hash": "a42ba8083654f55884daa38afd70c024d6fa46c387ad34045225721ee82d1cfa", + "kind": "transfer_execute_error" + }, + { + "hash": "d04035afa860ead10930ecfcc2b7589aa41132b32ac2cc596a5fad7662fd9043", + "kind": "transfer_execute_error" + }, + { + "hash": "5c220ecb23aa9d151315de919c72720f15fde69b5ae3779d886cf0170e534688", + "kind": "transfer_execute_error" + }, + { + "hash": "05e29ac552a2e1a13e84f56495d86c7b3d17cdce12441ff94e14181744c57739", + "kind": "transfer_execute_error" + }, + { + "hash": "78fad424876bc82a378d8cf34a7add1a24dd55436bd5e43b6f7a283ac8a6d913", + "kind": "transfer_execute_error" + }, + { + "hash": "87d859080dcdb40624ffc9ba7a0506ae4986802ee784508e29591fdcf894b147", + "kind": "transfer_execute_error" + }, + { + "hash": "0668f3912876995825852f917a44c61d2aa19250324fe350dab46e2f49edd98b", + "kind": "transfer_execute_error" + }, + { + "hash": "68c906d321c0bf102b3879a00ad290d4f82ffdc5b50c8c8c959777544ead00a1", + "kind": "transfer_execute_error" + }, + { + "hash": "c3e7d0e06dbbc7eacb84ae84281ca73f8b723184ff7fdec22219fde790c80c65", + "kind": "transfer_execute_error" + }, + { + "hash": "072d9bb81f6c68c9e87456fa0761246a1f7442b31e50b48a3c157bddbc68a020", + "kind": "transfer_execute_error" + }, + { + "hash": "3f55bb4449e910edbf65d717621eb49b2042fefa2dbf74472cdd09c43c2c3108", + "kind": "transfer_execute_error" + }, + { + "hash": "33e1e3c638dc7bc2801f93c57cc795a00f894e71e38795bb9b2893c10e04ebc1", + "kind": "transfer_execute_error" + }, + { + "hash": "937f81d40db7d2cbde8c56a58a588c7bb47f8f88383c461d53c640045f660001", + "kind": "transfer_execute_error" + }, + { + "hash": "c49872772f2d30d0a7522a7dd32000e5c9805c0793da5c219601f365b9f44c5c", + "kind": "transfer_execute_error" + }, + { + "hash": "983b3dc07e096c11513da7e447f55c86b729a96a0906f2836535b4fcc9725d62", + "kind": "transfer_execute_error" + }, + { + "hash": "9bd3f3794b42f7f82078e523f6106831d1bbe4b3f80329b84640f69107e230d2", + "kind": "transfer_execute_error" + }, + { + "hash": "bddeb6aa29ea0b33149aadba16558f2ac16b116362e9ffa210a96e86f7a82e63", + "kind": "transfer_execute_error" + }, + { + "hash": "6feaef22bdce8150b132c8ecfb09ab863b27394cbd5efc3106032528c1d5577f", + "kind": "transfer_execute_error" + }, + { + "hash": "2e35f4e3d0fe3e3ded447feea19e5258e36be2e4007ddfcbb95d880abc202356", + "kind": "transfer_execute_error" + }, + { + "hash": "3300f20f2d38658dc31e144a46e81c3d8c26b658ecaf37de052f06fd87be8869", + "kind": "transfer_execute_error" + }, + { + "hash": "5a8a1aae01e86bb048ff0f64b0ef8d5db2d230ad9ec295370ca04f2889356fe5", + "kind": "transfer_execute_error" + }, + { + "hash": "8ef659797948371d222f0529e7ad1c5e058c8d647edd12153233fe3681f26979", + "kind": "transfer_execute_error" + }, + { + "hash": "0d27986ef7ba2336c5a58c457605474eeaa548bd0fe38477e81b50b511608741", + "kind": "transfer_execute_error" + }, + { + "hash": "b0feeb0d90e884b7d0c5d653be57d7741c982b0e0c6df815847511ce62bd3f6a", + "kind": "transfer_execute_error" + }, + { + "hash": "f0ebd52fed839f494d2c615b24ba1454336048fd93fdfd6682e0a2214ab8e3c0", + "kind": "transfer_execute_error" + }, + { + "hash": "6c8a2682413f80e575499d4821e808ddf4e23c8d4f7939125ef4795837620385", + "kind": "transfer_execute_error" + }, + { + "hash": "bd79bf6d4bcaf70b5ab53d6bf4b019487e0e9c67f5b983e29d5ff7ed8d9336b0", + "kind": "transfer_execute_error" + }, + { + "hash": "8c8e0fca43b661c2f79d05bf6d68899f451157d08ba58348b7d23e11d058ea34", + "kind": "transfer_execute_error" + }, + { + "hash": "e3f70d2f3580cb779d5690ee4075c28c0dccd31461a4ef09321804b30d86b2a6", + "kind": "transfer_execute_error" + }, + { + "hash": "832a4c30e7a65912e61ab8e1e97bf17cbad42f0f3da5aac5b31be4aa8b57298f", + "kind": "transfer_execute_error" + }, + { + "hash": "044655a39f69a137b83e55ccaac7af1ee355e150084f439a0644cdff56d09f4d", + "kind": "transfer_execute_error" + }, + { + "hash": "2515a98447eabd245b513d708d143e657156981bf627fe9475a80f25ec363511", + "kind": "transfer_execute_error" + }, + { + "hash": "229e864d65db9818d5df8254b7a7f91859364441b683f5b04ba43c9a3b2d3b67", + "kind": "transfer_execute_error" + }, + { + "hash": "96c352860256995c35b147b5f24ac0b6bc00f6f1fe26880a716e65a6c73925d7", + "kind": "transfer_execute_error" + }, + { + "hash": "f64b53a4fdbf1b5fb94b713e23781708643c05d52d31a8be272c168202cff2b9", + "kind": "transfer_execute_error" + }, + { + "hash": "747a4ab528c40fe8889bf2713e077f39d3b7f3b4f4a517fc6e720c16c5148d21", + "kind": "transfer_execute_error" + }, + { + "hash": "0f4f03715120f792f775365d7cc6980ed1497b0274e4c2d6b228ca9eb4bc5c3d", + "kind": "transfer_execute_error" + }, + { + "hash": "c7ca065940bf6677e909642e3cc0a098aaa51d2bec749931bcb3f783669ceee4", + "kind": "transfer_execute_error" + }, + { + "hash": "b3ae5a1f4920255322782f8cb49f0d77b7632e1dcbaf1e6f9e83f10ffca6644d", + "kind": "transfer_execute_error" + }, + { + "hash": "69a2a835b35c23ae8fe497ea85c21049e8af626a0135bf5c5f321fd3019f4944", + "kind": "transfer_execute_error" + }, + { + "hash": "dd6e02dffac7aad1780d4b2a7e39628053d1c2b7f4652fb38d389290dbfa71fb", + "kind": "transfer_execute_error" + }, + { + "hash": "a4707812175113cfe58ea4b97d1c2c58d38fcfd3f26693b07a6f225dadc81abe", + "kind": "transfer_execute_error" + }, + { + "hash": "22f8f774325322dfd91acbd987a086f313437409cbb9ed5c5e9aed3af9f89c31", + "kind": "transfer_execute_error" + }, + { + "hash": "06d1101cc1444c79d39fb53eab40764d2dff5cb1e073daba15a275006484c053", + "kind": "transfer_execute_error" + }, + { + "hash": "77a4b5bfdd045e4e16836bf460f8e5eb36748b3cb65426720d1ff451ecbfb0db", + "kind": "transfer_execute_error" + }, + { + "hash": "807b2818f73ca71a9848c529cd0e84272424abce073427df24af4aea71ce4301", + "kind": "transfer_execute_error" + }, + { + "hash": "f6a1d336565c7a4ef9d9ef1393f4a64585a602958ad61ba0816118ca1973cd23", + "kind": "transfer_execute_error" + }, + { + "hash": "2ca486621ce98c4d1e723e7157dcde63dee34db6c41f66d924cf9fe0e222810f", + "kind": "transfer_execute_error" + }, + { + "hash": "c088c3d564f246415cd850820552813672137d5314baec91610538cab4f3708c", + "kind": "transfer_execute_error" + }, + { + "hash": "6640e74c57f0452886565e09fa3b8ba7868d8b888c864c913fa296dcc92ac015", + "kind": "transfer_execute_error" + }, + { + "hash": "60b475a2480a33c696ac802412c4dcbb735a5b658a890c7037891aa2b5dedd8f", + "kind": "transfer_execute_error" + }, + { + "hash": "7b77090eb8b70dc67cadf06706ad1252a9e4da95e4e38b90e0e3fe92ce9488f9", + "kind": "transfer_execute_error" + }, + { + "hash": "1b9a9bb6ea73a715c943e477982dd698904ba93a75240c6f705c0f530a53de62", + "kind": "transfer_execute_error" + }, + { + "hash": "87aee3be9ed9d6bb87d4d153fb0b0b1ac84499b30a503ce099f0e74219796579", + "kind": "transfer_execute_error" + }, + { + "hash": "f5eb83a49ba5cd55c49b8c5effe6a749f3bb795748934e178c74a6bead1bd222", + "kind": "transfer_execute_error" + }, + { + "hash": "2fc1aac8ad48c92ebccf147c70302562242a031f8689502a9509f1d6f119f296", + "kind": "transfer_execute_error" + }, + { + "hash": "d9da60ea44b3a14730a7d79a4b85c3d114acce4efc24fed743832a9f0f1e65cd", + "kind": "transfer_execute_error" + }, + { + "hash": "f51a3362a01f94c2b3e976cc9667c3a68800bdc9bb5dc641b47273ce45079c52", + "kind": "transfer_execute_success" + }, + { + "hash": "df5d195ada6922aee05a7dd5ec27d553d507a9d79e55241953876868b51c57e2", + "kind": "transfer_execute_success" + }, + { + "hash": "ae5f0ebfa89afbaca1280805ed4fcef4ff209b13160abb8603eb0a78bb1e7da8", + "kind": "transfer_execute_success" + }, + { + "hash": "5a564df5119ed5de369cb89024c1ae8f0ac8f618e3124da19f2367576f185284", + "kind": "transfer_execute_success" + }, + { + "hash": "5a0ae85285a9182f647403a93546b266bbac7bcb076eeafaf39295147e230bcd", + "kind": "transfer_execute_success" + }, + { + "hash": "b208e301cff8fbc1458c80582d97e4652d4c07f47efb4eae5c89108cebead1b3", + "kind": "transfer_execute_success" + }, + { + "hash": "312f201f85988ed6572344cbefa2e3e1b53fd840399056e88c42c2d3663d565e", + "kind": "transfer_execute_success" + }, + { + "hash": "7c0f6e2e7ae8bd9ab686b0819fe9ea3895334406db65f6d806f4dc3098bf14ad", + "kind": "transfer_execute_success" + }, + { + "hash": "5136bdd25578ad6a7eaf679d50d7e3363ada85698532b21e8c48fa24fd7e13d3", + "kind": "transfer_execute_success" + }, + { + "hash": "6ffcd2232ffe2baca86f3d84f83584e46c66ea1985e09b80fa02ed2e5a37aefb", + "kind": "transfer_execute_success" + }, + { + "hash": "2ee6c86b06259125271a8a3ba92beadee031f2478f328d694dd7f42b93b53fac", + "kind": "transfer_execute_success" + }, + { + "hash": "5ff5b1150adc3807397bd7f5dc61a801753aaeee57e9878154a29be22dac5700", + "kind": "transfer_execute_success" + }, + { + "hash": "ebcedc97a81c79197af257ebad46fd4c6018e5fd5c64487463c62006bc499741", + "kind": "transfer_execute_success" + }, + { + "hash": "b9476cb7746094c197ab3a02c48171b4899632ab0d582ac9c257048c0abd05ed", + "kind": "transfer_execute_success" + }, + { + "hash": "56ef5c0d9f38f9a93d59d65fe7cc255840c6173e6bfe0cadc107ecd56863ce73", + "kind": "transfer_execute_success" + }, + { + "hash": "c2f5da62abc98d4a92af32829c277a0a942dd94cf6d1dd794b9f78803211f0e8", + "kind": "transfer_execute_success" + }, + { + "hash": "ed1d3df0715475d7ea78dcd91635a7dd669f1917800f8d84285671c00b8fd9ab", + "kind": "transfer_execute_success" + }, + { + "hash": "b4cf2df38520e861bab98bc86a75ea383e50554f4e99558df6ffed4b05028545", + "kind": "transfer_execute_success" + }, + { + "hash": "561af5b619fc439805fe6009ce3badc9937a85662b93d2777ae24d1659f5aa0e", + "kind": "transfer_execute_success" + }, + { + "hash": "4dc14668621d39dd073eed5db06dfe10472f23d8bf5700b81358deb062e17a0b", + "kind": "transfer_execute_success" + }, + { + "hash": "4090c5f307e9fa1ff45cc4f6b19295f57ee4905560203971444c696cb8b03a9e", + "kind": "transfer_execute_success" + }, + { + "hash": "223381ab010f3be74dfcda2af181e177e2cbed934ca1846b7814f70760719407", + "kind": "transfer_execute_success" + }, + { + "hash": "f36d24d967b79bd5c844d82a781f0b3f1245a377a94e1a8c4a32959d7c68acc4", + "kind": "transfer_execute_success" + }, + { + "hash": "1fc5cb62378db1243dd192e4fcd99407efb4e36f6b64f81aa4959bb411737110", + "kind": "transfer_execute_success" + }, + { + "hash": "9029b93ad87a45db15688e6ff9fa547724649212309bcf9784782c1ba41eef04", + "kind": "transfer_execute_success" + }, + { + "hash": "0c1c01de5c8b31950d2c9ed784a5b287d4efb3866a91e71a632b5151ffad9660", + "kind": "transfer_execute_success" + }, + { + "hash": "c6563a1aeca87a7600f7c9c5d14da0e5eb8c5127ec488af0157ba23982f5aa20", + "kind": "transfer_execute_success" + }, + { + "hash": "ef0508bd473e32f02bef9cc1b99e5895046683ff42e8fc77b2372ec514d11bb5", + "kind": "transfer_execute_success" + }, + { + "hash": "6db91c29fffb95a4bd81927c823a81fd3d09c57658d26eb8f33da2541517ba5d", + "kind": "transfer_execute_success" + }, + { + "hash": "b2d63090d3615e971e835e4874123dcdfe699e809634a6bac7dac2232fcae115", + "kind": "transfer_execute_success" + }, + { + "hash": "2922522390bea4c9f31c90c2754f3a6d0d870de25f1d1c04e7231889d35a04ce", + "kind": "transfer_execute_success" + }, + { + "hash": "3e8b72fc1b7f722c4bb2f41311651452c50b8e0940e06ed87331e126a86b4a1f", + "kind": "transfer_execute_success" + }, + { + "hash": "8f6e7c13fcb826f12a0836b897ee4bed8a6eb18d66d48d80dba84cef71023c0a", + "kind": "transfer_execute_success" + }, + { + "hash": "eb2968188203451092186dc64177df9fb3e0285b1e10d7d9465debf1a3102e75", + "kind": "transfer_execute_success" + }, + { + "hash": "02ce5b3a0f38e0c4f279144f1225e338439a7b0789df34c4b0f2d40392f0a1a7", + "kind": "transfer_execute_success" + }, + { + "hash": "3d7c37f9172e38b63b256deafe7b55306cecd1fd95b3cd16b942c9b0938461ae", + "kind": "transfer_execute_success" + }, + { + "hash": "3029c4422237da47f28c73ffdde7a139733f204ed0579546ebbbee850e9b5941", + "kind": "transfer_execute_success" + }, + { + "hash": "9bda939bfcc7f90f1589da8a0c17709aa89d38bb78c52a546e10b7466980c8f4", + "kind": "transfer_execute_success" + }, + { + "hash": "183a896c5b63221701ec9de34d9eb8e0d318315252ab3e32ef7d131a5055d59c", + "kind": "transfer_execute_success" + }, + { + "hash": "8031466a958f7a670abd9979e4e53893daca0c3245f53ce6dbd5541ca0369c38", + "kind": "transfer_execute_success" + }, + { + "hash": "c1bda326c10ad30b0a836366ca45ff12a70f996dbad500a0918ef57001069141", + "kind": "transfer_execute_success" + }, + { + "hash": "443e70fbf6ed0b23b1250fea98c5194e036134cd9c511556317fbaee47895387", + "kind": "transfer_execute_success" + }, + { + "hash": "a211130740b2a35321bf692cdc387831d636e05567ca69a4713fd2bca6098562", + "kind": "transfer_execute_success" + }, + { + "hash": "d710e4db927a8aa36ab666c456842216fa50c4d2cf5e38c90cb64f5c7afe1a75", + "kind": "transfer_execute_success" + }, + { + "hash": "1eccf8d9f3eb6d0988cb3d027a828f2d3d71d3c3632a08a92abb34975953b5e0", + "kind": "transfer_execute_success" + }, + { + "hash": "6db7c3df13a357e234f1ade685d806628ed224c6748daad7a5d0987467039622", + "kind": "transfer_execute_success" + }, + { + "hash": "3caf9c18fa918ffc8d58a599ff8a970e29d7b1fa4845800e808b5ebe0284a102", + "kind": "transfer_execute_success" + }, + { + "hash": "142b1ea7f35afdeb0e7fae38e34dcf82e066b7ea0b3a67b65f89065c83164c43", + "kind": "transfer_execute_success" + }, + { + "hash": "5318069b45cded622e352af71781cf593e159c60e68c70887e542512b5effcce", + "kind": "transfer_execute_success" + }, + { + "hash": "90d1ce511e23145cd3d7a273884b4f3f04f7b7449a6abdca56c39ac3ca64cd8f", + "kind": "transfer_execute_success" + }, + { + "hash": "3d1400776cb61bee691e0ae0e52b654f39dc3b0ddda381e49e1a5d3c2fa1cde2", + "kind": "transfer_execute_success" + }, + { + "hash": "851f727184079e8df78051461f3626d881468ddc2a5674467313873db1090b2e", + "kind": "transfer_execute_success" + }, + { + "hash": "24e43c6bd9bd91d9ba6c2b9b8517052b22bbfc6e493a2f5da9d2bd808e2b663b", + "kind": "transfer_execute_success" + }, + { + "hash": "60580ccb7da03e9bf42337880509b742e274b4bf3a210a0114c1d9e280b37003", + "kind": "transfer_execute_success" + }, + { + "hash": "eba2faaf42145a0d21d9c55ddd7f86c193d3c8aecf1048ddd88f43a5bbac7dd5", + "kind": "transfer_execute_success" + }, + { + "hash": "92285778a6d1824cd6edf8cc873ba5217cb0e9ed1d9fd657c3bbba78c92886e3", + "kind": "transfer_execute_success" + }, + { + "hash": "ed2485e665556e23752ae1af22ce39aed4c0179abf8d2f8911f06dadf904d131", + "kind": "transfer_execute_success" + }, + { + "hash": "0fa31768994bf7e552071899133b9d97541d0163bef4774e584d990a732f5059", + "kind": "transfer_execute_success" + }, + { + "hash": "383a1eff65fcf474061b334587edffc6a8384ee217844233704c790a70ce400f", + "kind": "transfer_execute_success" + }, + { + "hash": "3f62222c4bf5d29a1a2838a6b0d8d4358509667de4b17f8a3323577d69c43dc1", + "kind": "transfer_execute_success" + }, + { + "hash": "f5cf8686bbd01e2f7c1932c81e4b38bc9577ff94080abbf784e8e0ad7d5b805c", + "kind": "transfer_execute_success" + }, + { + "hash": "66ba1a2accc640c785a342e53610f199795283bead27f48db90aea172981e7db", + "kind": "transfer_execute_success" + }, + { + "hash": "a5d00985e073a3555f58c2fc8aa8ec4b422165c947ad5961834941784192c8d5", + "kind": "transfer_execute_success" + }, + { + "hash": "03c987b0ec3df318a354eb391bba80618ba106d8f4cb858ef7226a9b4e170eb9", + "kind": "transfer_execute_success" + }, + { + "hash": "f0f3009862e902b8f6ce4db3de21dbb9af83cd6ad0828518a7689d02445e1d70", + "kind": "transfer_execute_success" + }, + { + "hash": "edfa004b812d76a5b13123b02e01642cc5221639a4b4637c8b8faca916340a5c", + "kind": "transfer_execute_success" + }, + { + "hash": "614b1fb5e9d714f1ee4bf5a4593dd6af07cecbfb775cf6426bb220e43104c98e", + "kind": "transfer_execute_success" + }, + { + "hash": "6e9ae2d58b6bbf8748beb687a7de622f549a9430dccdda9860f8f6f093c1316a", + "kind": "transfer_execute_success" + }, + { + "hash": "f5f65d100fe9e09847319d10db05450a17600527c8f5dc38de42c12053209e75", + "kind": "transfer_execute_success" + }, + { + "hash": "78822fc96fc6eff34d2916fc63bd60f9f43e285983d307c27681e688184c7f3a", + "kind": "transfer_execute_success" + }, + { + "hash": "8a61b9539a694ab6d3a97fee08144778071427f68b24c2742ef10b73b58b255d", + "kind": "transfer_execute_success" + }, + { + "hash": "71375a210f957d12b023e2ba431f3e10bbc990d64e91e9ab8cd4ea0d8e822dc4", + "kind": "transfer_execute_success" + }, + { + "hash": "5d915ebf29c079b84d6a406bf099c50608a0edc6f520f6f185984a49be9e656f", + "kind": "transfer_execute_success" + }, + { + "hash": "22594c7185d653a620a3246664d331fce2d0ea124176d02b31bbc10da404571b", + "kind": "transfer_execute_success" + }, + { + "hash": "ca83500a16e94343cce16f454626dc1f292205ba8fec04845707fd72bd4a6c9c", + "kind": "transfer_execute_success" + }, + { + "hash": "ad077407ac53f1d83463d662deb12bd09a6c5262860ac1db47630861cb891239", + "kind": "transfer_execute_success" + }, + { + "hash": "eb1554cc3f87c48d8f71e935b919df55a591c50539e8be57e7f9ca991ece2be0", + "kind": "transfer_execute_success" + }, + { + "hash": "d6f8543e457af5b80fa0fae42cf6f49cd50b1df2d14948196e1c2ccfba618d3a", + "kind": "transfer_execute_success" + }, + { + "hash": "89955489f08300a1aef1bd820c46a1827145d1411e7591dffe1b1670621d077e", + "kind": "transfer_execute_success" + }, + { + "hash": "370267acbf6d05afd42908c1de3e9ba0be6a61b6713c16cb46a82c52a9e59e26", + "kind": "transfer_execute_success" + }, + { + "hash": "5b4891bb15d30206da98ac85ce2c5672dd85a317ac6b1f63e46f2f576ebcb5ec", + "kind": "transfer_execute_success" + }, + { + "hash": "4afd81023d9bf5367ae11ace56286fe3ac1100d36455f4c4123f3e28bacde120", + "kind": "transfer_execute_success" + }, + { + "hash": "0487bc9555948e2ee33b4018b33108443ef811cf9d82115f1766b4bc9718c664", + "kind": "transfer_execute_success" + }, + { + "hash": "ac06ac122ef7d518534bdab6a2abb74af509a40735fa95038c789a3cba9d1064", + "kind": "transfer_execute_success" + }, + { + "hash": "9fd15ea4a4c009e3dca2a2b918f12844e7efcb9bf8c824fc439c2c846d0f0806", + "kind": "transfer_execute_success" + }, + { + "hash": "862ab4eb810f1e278521fc4ecfe9f6267b713f17fee19a3f159e837063db314a", + "kind": "transfer_execute_success" + }, + { + "hash": "a9f8bebbb9a8f271919fb6792edc1260f7f83aeefc6e1a62f4ef8cb0e894b85a", + "kind": "transfer_execute_success" + }, + { + "hash": "fefda9ae8911938ffbdc93c610f4db8eb9d4a2be1db7ff79cdc299a8361dd158", + "kind": "transfer_execute_success" + }, + { + "hash": "4c8cbd9a006a0f1d1d1dcc9f0d20734cc2ac2c6c398453e2e4c68086b243db2f", + "kind": "transfer_execute_success" + }, + { + "hash": "76ef4a2fe0d7fb550aefcaadc8f2356f74ab2ebc6e264f136fa646a6cc21638d", + "kind": "transfer_execute_success" + }, + { + "hash": "b77dd06e3f426e9d10b3053b2e35502cbaf1fcf84b617ee906598607e1cc0ec3", + "kind": "transfer_execute_success" + }, + { + "hash": "52c1855504a257da4348847cae96b079e901de92a4a1a2139adc9202ec70ec36", + "kind": "transfer_execute_success" + }, + { + "hash": "48278a2bf171c35e58b422c433dfdeb8c6bc896dbf51ba29e8d7f5bb1db710b4", + "kind": "transfer_execute_success" + }, + { + "hash": "209e68fbd94423135e0e1464e6968dd860fe4b1a23db23548b0ff34b05032804", + "kind": "transfer_execute_success" + }, + { + "hash": "77c379ddcc59c5bd4ba50f0f3351f8e34597e3d067481843e10e977a26e87e2b", + "kind": "transfer_execute_success" + }, + { + "hash": "9a5b8a46a2bcc217b97998daf3bfd1201ccc31ea2aa5a80166307abadcbf51b1", + "kind": "transfer_execute_success" + }, + { + "hash": "69d70e40ea74dce57b41a86817cf0713536dc0f4af067e5d6d619d109eb42731", + "kind": "transfer_execute_success" + }, + { + "hash": "67ec7b0f7a1e15a40cc189d79a72660f08550883ab544f063a516555b3631d5b", + "kind": "transfer_execute_success" + }, + { + "hash": "982fef35d1cc7df4054564bae87f832d5491b15b51459498f510c92b47a33347", + "kind": "transfer_execute_success" + }, + { + "hash": "266abbebe8f21ec90b69df2bdbd17ed5271651ac5b4358dac7ced1ccea337417", + "kind": "transfer_execute_success" + }, + { + "hash": "0a6a1a6af97691d19294ce8b70ffe95c6e7a66eb1f41eab77cb65df0c01d88a0", + "kind": "transfer_execute_success" + }, + { + "hash": "4a396c8341521b37f9dd4e656e601ff53da90cccd25919d5395272b6b998c35f", + "kind": "transfer_execute_success" + }, + { + "hash": "344329916e280499fd1703f139de26c2e1e91091aaeee3d4d0b13af7eb167423", + "kind": "transfer_execute_success" + }, + { + "hash": "73532c820d8785aaf35acb454cfd404c6cd6b522f9b7676f6e27918dfeb6b97c", + "kind": "transfer_execute_success" + }, + { + "hash": "3f8cad8f9b493e3ca26108da23804164c7e56c842b0d8a1ab3c109614ceda45b", + "kind": "transfer_execute_success" + }, + { + "hash": "b61a5ca595eee2c7b579b251af97db4477f13196696dbc8bbd88cde32bbe2610", + "kind": "transfer_execute_success" + }, + { + "hash": "7a2c6bc43fa69aba57057a93e8f3ce2ede0739c030e8f46f2d75eddfed680457", + "kind": "transfer_execute_success" + }, + { + "hash": "d911c72f73b06d240e1115f0f41df787119632547828ca5a0d084877642e6750", + "kind": "transfer_execute_success" + }, + { + "hash": "d10dc081fd6efcccfa5733a7b0357667c105e26bb643eda2fe100ed5c601e09a", + "kind": "transfer_execute_success" + }, + { + "hash": "e5b2e7f733f709b3f0b7dee3531c54d93f342290219df0dd11b1f68da53ffc4e", + "kind": "transfer_execute_success" + }, + { + "hash": "fc43d360efa5225a34b8e0ad021e3dd5505db9ae877200125c65e14d4984ce59", + "kind": "transfer_execute_success" + }, + { + "hash": "987d4c081b0f6c59f6af550a23b9345fb0a16d8ac815ad0dcf49660d0f0ed93b", + "kind": "transfer_execute_success" + }, + { + "hash": "37b90b0ff943bda6b21155e2b8bd14569a91993aff3acad3bd9756e2ef82d607", + "kind": "transfer_execute_success" + }, + { + "hash": "ff83bf05f14bd75c0e68fb28c81c26a34da2eca29c2d2ad3bb0fd5920ce109af", + "kind": "transfer_execute_success" + }, + { + "hash": "2a195fe7d0df5ceed8de6af16abd76c555b6325d45289e8cb2d86faec7bc4a8f", + "kind": "transfer_execute_success" + }, + { + "hash": "b6bdf01fbb8b8f3f0597c61b29027c7d0c1afa21fda68ef461d30ace6239e26c", + "kind": "transfer_execute_success" + }, + { + "hash": "aa56f40b46d0102de915f2cd585a9b09e407dae2555a7b4fb6710e0e5e631c23", + "kind": "transfer_execute_success" + }, + { + "hash": "87875f000557534d55eefbcb92b5a764afaaaf9e2cce03d38068a73f448155d7", + "kind": "transfer_execute_success" + }, + { + "hash": "66fe45abc44747f1ea131ba6e7b53109bbf01e9c5096e7d9bd98aaa095277586", + "kind": "transfer_execute_success" + }, + { + "hash": "48b175c17cd359bb03fe21d4c115de4031bb0e9b9d12c3c568b1fbd753985735", + "kind": "transfer_execute_success" + }, + { + "hash": "e6d61fabebd29c9c2d504186a520d241e48ce713b80eb61e92020d3ddf95fcb4", + "kind": "transfer_execute_success" + }, + { + "hash": "59bfa47f8e267a7c9b947fc8db8f18af79031bf7003490db68c32f5a05d844c3", + "kind": "transfer_execute_success" + }, + { + "hash": "86a5ee174050ede9b2252a63894b0b84131859f7493aa1dd759beade3326059a", + "kind": "transfer_execute_success" + }, + { + "hash": "55e05156eaac4f665f9a480b174fddc6197128af1b3b8c00ddc295837c6628b2", + "kind": "transfer_execute_success" + }, + { + "hash": "782ae359cab3e6fe6b4e588b36232d281df62d9be0d4f0ec3a93919bb4958c7f", + "kind": "transfer_execute_success" + }, + { + "hash": "195a3b6778d0cf237906a14efe929ef531c6d98af69f0af907c1e2b2b8956fb9", + "kind": "transfer_execute_success" + }, + { + "hash": "eeb549374f598e39808ba7f906ce39c076ce98b3df06db89dbe3a447b07a386c", + "kind": "transfer_execute_success" + }, + { + "hash": "dea502404ba0f6b4acf04d6236d30e004662e5f6b66bcca8a9542abd66b92f77", + "kind": "transfer_execute_success" + }, + { + "hash": "1969fc94a5c3e6aab0e475299c3685968b17397641c588173039a1eb4e193fbe", + "kind": "transfer_execute_success" + }, + { + "hash": "717fa9b4aca70b9b077a8046adcf5ab1b0bd546cd56074822e98573d9c5a0395", + "kind": "transfer_execute_success" + }, + { + "hash": "16892d1ca7d2122e710a3c691399dbd5debec33cb48c012d5391c1f5b3a5909b", + "kind": "transfer_execute_success" + }, + { + "hash": "0caa8afd916d452a2b426e4a6f9c56d14549dc474f8b9a38951d8275baaafd89", + "kind": "transfer_execute_success" + }, + { + "hash": "aeb059dc660dbc569f2cf01c6fb16acbcaecb403869a6c8a81f2fd9eda570e34", + "kind": "transfer_execute_success" + }, + { + "hash": "b131a8e5235df61d76d69117588374735dcd11d04ce931ee4d0791c289d018c1", + "kind": "transfer_execute_success" + }, + { + "hash": "1c2ccba614226a460a0bcfbdff54a3f593df4a01a9a9a6bbd79f5d74b46b7e2d", + "kind": "transfer_execute_success" + }, + { + "hash": "7f7b617ca11dcdbb8d6e8a1cedc26f048864bc596d764d3811352070e163a1c3", + "kind": "transfer_execute_success" + }, + { + "hash": "1bec291d368dbfb48e0c44c8b553fbfcd91c5f2350545218a5757d029c0f0bbc", + "kind": "transfer_execute_success" + }, + { + "hash": "894fbda7848f9e25aa505aaedcf837eb3f986508789fb848f5f2a58ffb3b04ab", + "kind": "transfer_execute_success" + }, + { + "hash": "63830fac0cde2be9c9143d9cd72f21ed276fdcd9918787709be9ecabca5823ff", + "kind": "transfer_execute_success" + }, + { + "hash": "1956d1d37f10beb32ff4af308733f0c523036000f4026e18b84742f6f8cdb595", + "kind": "transfer_execute_success" + }, + { + "hash": "2043951aa93516cbe1a564256e079489fb4471a0f383f87db029a7ce2f3f87bc", + "kind": "transfer_execute_success" + }, + { + "hash": "f69aca9dbeadfd23f8c4e82a606b38f8369a4411935293222b678cc4ad1cc955", + "kind": "transfer_execute_success" + }, + { + "hash": "cab3601be8c7501fa7de29ed7d8a8aeb085dd781d531eda2c6dd3b7edc207e12", + "kind": "transfer_execute_success" + }, + { + "hash": "b3a66a2c7d9eef22b3eb00885b25970b1d1ecee17e5a39e2fa3e33b254cf23dd", + "kind": "transfer_execute_success" + }, + { + "hash": "595671e7e1f1d06fb515b125a33e3d730e0801fb63cde5bd4a860dd61994e974", + "kind": "transfer_execute_success" + }, + { + "hash": "20e69d3f639bc5f9b459166bfcb0a750a4abf3ade4c43fc3538d1f48bdcc5db7", + "kind": "transfer_execute_success" + }, + { + "hash": "7eb86ca532f73875dcdbfa03c72fd628b638141e9c0117d894b15b16668b7fe8", + "kind": "transfer_execute_success" + }, + { + "hash": "253e62409b24d6cae2d315bcad7dded79fa219e78580e28584916d6df1276b36", + "kind": "transfer_execute_success" + }, + { + "hash": "9e9221206607ccb977964b937a110cf32a46d521b407f23536010c49905682bc", + "kind": "transfer_execute_success" + }, + { + "hash": "ad4ae9a09343229edce64fd0ea430f5c7bf750f21fa1d3c6d523a8bb3a8e3c52", + "kind": "transfer_execute_success" + }, + { + "hash": "7fe8a87fc295fe36748d9ccb9ff13510a7805b166a7fe6376b83f30011275c46", + "kind": "transfer_execute_success" + }, + { + "hash": "1824b2e8f5ff7a913ff7f06acbc595096cac615a52babc1309934500cec7d265", + "kind": "transfer_execute_success" + }, + { + "hash": "ca3eb85e2d07e793b5d46446c7502eacf1d5996b045978b8526b75684c241c7a", + "kind": "transfer_execute_success" + }, + { + "hash": "59308ca3062859322de930c92fb8a46c35c5999839f655155e8fe44d74d23b84", + "kind": "transfer_execute_success" + }, + { + "hash": "365bd3de882c50ea4c7f445efd14ba43a5ee2629a22bfcf633a51cb233bc1f39", + "kind": "transfer_execute_success" + }, + { + "hash": "a4c7079eb98d762b7fb521b4e4f0fa5db59d71efb6568e82c3268bb4daad5025", + "kind": "transfer_execute_success" + }, + { + "hash": "433c9159042bf9d9d6bd27d3137d6c48eec05f6e07373a5f31cc62e4a49c59d5", + "kind": "transfer_execute_success" + }, + { + "hash": "e4f2f678fb3a84712ecc1615215f47f3e5206502e619a2868cb68a9c25d60a29", + "kind": "transfer_execute_success" + }, + { + "hash": "235b2b65d4f476d99b0d6191cb5ea20e9a8058b932e2d8ab30597ea292d1618f", + "kind": "transfer_execute_success" + }, + { + "hash": "4ff60b18894fe240b45fa9dc043fb06e1a88b8c8f761c5efc024b995c7ceb789", + "kind": "transfer_execute_success" + }, + { + "hash": "376a80e0d24254cb4f731381d0b5d5a9f252e3dd01fe7c74e1490dd9e13db5ef", + "kind": "transfer_execute_success" + }, + { + "hash": "da0ddb4e10720876038015d14b6514efa6f0d8297231d55db959ef1b27918bb1", + "kind": "transfer_execute_success" + }, + { + "hash": "01b6f00e5107f9b4c54b2d68eda2cdd2d1be39adbf03af8ecc8e8f68f3c607cf", + "kind": "transfer_execute_success" + }, + { + "hash": "a9568da392edc49ca2676cf426f0d7b3de1bae66c87b3c82f9177fffac17058c", + "kind": "transfer_execute_success" + }, + { + "hash": "89326bbc771ee4bbd9a359a870346df67c3ca3d22a981d10c15cbaadc97e5a39", + "kind": "transfer_execute_success" + }, + { + "hash": "a50fcae4be05a175eb54959aa42c7324c20f0e5aeaf88fdeb4eb57685cb09e73", + "kind": "transfer_execute_success" + }, + { + "hash": "bf76a997587d48b491984f3c06b9dba8056f489d8782bdf437c0e05150ddd799", + "kind": "transfer_execute_success" + }, + { + "hash": "ad46443d3209d3a27b62d88285f3c334d5ec9a22b1e467831c2e35482d2c5880", + "kind": "transfer_execute_success" + }, + { + "hash": "7a836bc9e65f5afcb1054f895d1abb89481158428bb1e19f3f533a73c8696dbd", + "kind": "transfer_execute_success" + }, + { + "hash": "e7d4a38fd94c82161afa3028f607538745c6866b7f73e8c88b5a87677994f96d", + "kind": "transfer_execute_success" + }, + { + "hash": "f270024c2b677f29aa112660116c7669b2fd2663624edb1099aad0c73e1b624c", + "kind": "transfer_execute_success" + }, + { + "hash": "fa0379fb60371fe8a0e5c4d4b9b8a100ce3e834622fcb6575188bcab6f89625d", + "kind": "transfer_execute_success" + }, + { + "hash": "2119f19ae9427a790d01a217e3cd55f5234872d42d133c3d5ec25b16c456830d", + "kind": "transfer_execute_success" + }, + { + "hash": "24caee35f18f3534f068fedae70782b8132441490ba5c36796d3d195a5f23c30", + "kind": "transfer_execute_success" + }, + { + "hash": "9bc946a09df901ef9664f4929855e23b87bf420edaf5d13dbc4b1671b880c75a", + "kind": "transfer_execute_success" + }, + { + "hash": "3b261612de3eaeb7315a4313b5085235c736582b52e976de1f7c012357169603", + "kind": "transfer_execute_success" + }, + { + "hash": "9272425a057efee37a6cbfed383405e4966b92a432bd255a69580a115da889d2", + "kind": "transfer_execute_success" + }, + { + "hash": "ec68871e569179c2f0d523ba4b5c83fa88f05de4360d5134493e6bb4eb5974ba", + "kind": "transfer_execute_success" + }, + { + "hash": "a365cb0a4b223113eed502a77f1512fbcf7cdfeb61631b31faa01cba5ea6c8ea", + "kind": "transfer_execute_success" + }, + { + "hash": "8817d88b85d4bba0b8cfc927704587124b412989feb3193484c3242570a4f00d", + "kind": "transfer_execute_success" + }, + { + "hash": "13fda3a3e678feed9f26bddcb641f7a40eb6fe3ad7763b026d4835f052533f4f", + "kind": "transfer_execute_success" + }, + { + "hash": "0578477427e088b8f6cd5b24916d4fcf624e743daaac50a5640ab55a8bb3b638", + "kind": "transfer_execute_success" + }, + { + "hash": "cf1919624c9b93e2baf3e51580167e37e03dde4f9dbddfbfb4b4096264818455", + "kind": "transfer_execute_success" + }, + { + "hash": "531d32c6cb31d58955d1bb8100e549f040b20b7e34ce0bca5419dbffc6f60d35", + "kind": "transfer_execute_success" + }, + { + "hash": "63854c46d12d3ba71d92e5062b8d9bd19da5d61276a853e19de1cf93baf786d4", + "kind": "transfer_execute_success" + }, + { + "hash": "70cb6872cec49c40290f4354d4c681177e205777569eac8c55f2d0cee760083f", + "kind": "transfer_execute_success" + }, + { + "hash": "8734afee3c518a4e993b5c27fd0b0cb34c6f58ae973e45e6b80d5d924daba092", + "kind": "transfer_execute_success" + }, + { + "hash": "3f1c245a2afc0a1400a92c27c63129af2249cab58c98a881bdc2fce360f43eb2", + "kind": "transfer_execute_success" + }, + { + "hash": "d5969d57069456fda4bb03a025dcfbc7714091db90b3fdd57a128c6f268ef062", + "kind": "transfer_execute_success" + }, + { + "hash": "8ab665dabe3db269657f19d49edb2565bc93288208d913f49d02dbc08dcd3eba", + "kind": "transfer_execute_success" + }, + { + "hash": "3c8605de609da07dfae8d3d072882eecb4941690e942219c672fa62abc5cd73f", + "kind": "transfer_execute_success" + }, + { + "hash": "84062e9e9075ef8f584383453c141e730831a5a10f815422a83a4a333c673029", + "kind": "transfer_execute_success" + }, + { + "hash": "407e001c2c7ae4d38bc8377cb20f59cc32eb747bee0d277cf997b70ff382a2ba", + "kind": "transfer_execute_success" + }, + { + "hash": "fa50a5eb4fb770b5a526760503a903f5bf5fc1c1d63407ac66d81d20f3d07af6", + "kind": "transfer_execute_success" + }, + { + "hash": "ada193c741400d8039af43e033ed394659abd17da0dd9c6c96271fe57a191d11", + "kind": "transfer_execute_success" + }, + { + "hash": "26cc3303c902f62f7dbf2185584cdaacd5cec9fec5416306cdce21778fb536b6", + "kind": "transfer_execute_success" + }, + { + "hash": "b0bf8f37644128f2cf8a54842125e73aedf83d366de1dc42b916174b46ceeef6", + "kind": "transfer_execute_success" + }, + { + "hash": "caa54ac3862ef40b047fd73b675b539bc390bc8e9bd2313991e4f9b6a6aa33e3", + "kind": "transfer_execute_success" + }, + { + "hash": "cfec17b67e248d9c554023dd6710e84125d938e7b05f69031344fd5f352712f9", + "kind": "transfer_execute_success" + }, + { + "hash": "202deeaca74d9fa1d2bd3456d7b9d3d5fb3582ec64209109d2d953aa05fc9aaa", + "kind": "transfer_execute_success" + }, + { + "hash": "24945b9c8133df249f07c185b6b3e3f194400e11b1f9d29581d5316a21da42f0", + "kind": "transfer_execute_success" + }, + { + "hash": "a40c27058f98e869c6eb50fd6222910514f539cdd24d53d45e6b5fc0e9c62cec", + "kind": "transfer_execute_success" + }, + { + "hash": "e853eabcd29a159a68b3873d883c38fe92beef6cb38134ec9a4e54e615357f5c", + "kind": "transfer_execute_success" + }, + { + "hash": "e83a4296841b7f6cc26c0fbd8af28493d19178203bc3b91b4efbe06f9db5dbba", + "kind": "transfer_execute_success" + }, + { + "hash": "2c3526d8c074c77af07e0b0e3da79a8bdd7794ebb78f18b4e6c8d8e165564d65", + "kind": "transfer_execute_success" + }, + { + "hash": "f265bfd44b95d673b33e4f7b34c4f35b83aa1b679a5a7e8c00882d87a1e87916", + "kind": "transfer_execute_success" + }, + { + "hash": "dd14ec88c1767cecec9047148daa3ffc5970ceaed338bf592ac436f9db9b9419", + "kind": "transfer_execute_success" + }, + { + "hash": "a90bd0715a66d6ac83915ffbd9196c70b1def675995fcd386ce2597710ec6ad4", + "kind": "transfer_execute_success" + }, + { + "hash": "69d7e6eaf9f1d5ac18ff59a2ef0ccbe1f4c1c6c83027cc4b52c2374087eb93c1", + "kind": "transfer_execute_success" + }, + { + "hash": "8f04085eb08ae64bb17d25aec0e51ac22b25b8ae06d6b208aa875d4d8cf4ef9e", + "kind": "transfer_execute_success" + }, + { + "hash": "c574d609f6df48c654c7f40073a3131cc5111d4192072c438e85bb8b4c7d2439", + "kind": "transfer_execute_success" + }, + { + "hash": "4ce68229d24145bedbfbd53a8f52c602c0eaa3b824eee00f6dedbc186e478119", + "kind": "transfer_execute_success" + }, + { + "hash": "35120a1ed5f4989207f75ae6536ada627b905afa46c8518d8d397ada6e8e6431", + "kind": "transfer_execute_success" + }, + { + "hash": "ccac7f9fe72faba6f45a9c4673ad92f227299a830b717e1cd2e69e6c513bbcf3", + "kind": "transfer_execute_success" + }, + { + "hash": "d53ea47b923a470d2d81bf038ace429df7c3e64ac399d634041874e27ee61b91", + "kind": "transfer_execute_success" + }, + { + "hash": "4a6bacc1a4227241c6fe24a4f449809249b726b647cbe626821f7cec415b1b15", + "kind": "transfer_execute_success" + }, + { + "hash": "e04e000f3f634dd08c128ef0b7e1accc0a5e1181fc1a85bf57988a403850a415", + "kind": "transfer_execute_success" + }, + { + "hash": "3c2a0066551b6e2a5ba1b689ef08a9067d255d675d4e4897d61351ba5284e0a7", + "kind": "transfer_execute_success" + }, + { + "hash": "705d241e9c9c3122901b06a9a57df9b36e8f8d092631b931951965df27ddc047", + "kind": "transfer_execute_success" + }, + { + "hash": "448972cb66c260529023316ee97fb95f8c3c124a1316ec83704bed465f390720", + "kind": "transfer_execute_success" + }, + { + "hash": "fd0a48a5a24da2c1c29652f21d89e0808c1332dd9d3cceaa072985da0bc8d283", + "kind": "transfer_execute_success" + }, + { + "hash": "4a372653dff0d775aa998ce693b69fefbeb11834fffa984bc1a14976cf34760a", + "kind": "transfer_execute_success" + }, + { + "hash": "872c66d38dd8322c55ead91fd8651cdd759ddc27a7880ccb032210b4b904acaf", + "kind": "transfer_execute_success" + }, + { + "hash": "30249b939ce82f2e0aa4d797ed3f5113a3be57eb0ee64daf1e354baf86cd34df", + "kind": "transfer_execute_success" + }, + { + "hash": "fa6dfda23d809e18e2452d3e978a6377edcf6c225ca7bdb075307c04076e0ced", + "kind": "transfer_execute_success" + }, + { + "hash": "4e95a8f7373fc3d7388ba69b2cfed50b1b38b8a5879b9fe644cc72e0427ccde8", + "kind": "transfer_execute_success" + }, + { + "hash": "955548dc49dc4efb6f317a2ccd93ed06caee41bc11fe383a6d6202bba3d741db", + "kind": "transfer_execute_success" + }, + { + "hash": "7044f0777ae8546f443bf6e37d9fdefcb488f265d1ed3985a2f3eebb6bc209a5", + "kind": "transfer_execute_success" + }, + { + "hash": "0bd4eb59ec10408f79f9b92b57f21952bc428e477ea431b93bfb57e2d2e52d21", + "kind": "transfer_execute_success" + }, + { + "hash": "1b69ad73f2be7d1de635430e87cd54c8d2d9db6d3926c18eb833e6389c2d934b", + "kind": "transfer_execute_success" + }, + { + "hash": "e6b51fc24e7d57f1d0998994a0e9b6a6a918d66967b0bec929482fbcc37a0e42", + "kind": "transfer_execute_success" + }, + { + "hash": "4aaeffb317022784168d72408c298ae5572924e129465d269d88e349325c2402", + "kind": "transfer_execute_success" + }, + { + "hash": "518ee2389987a182f98e96b8d4e17dd80829e06a170272ad2f79a551b40a1d33", + "kind": "transfer_execute_success" + }, + { + "hash": "99772e9551d82ab068cf14158d2fb92494ae133cfb8360dac179822a34834450", + "kind": "transfer_execute_success" + }, + { + "hash": "3da8ccf979a006f6c4a9d31c58b4140e2455dc786ea33c2e9de0e03fe582828f", + "kind": "transfer_execute_success" + }, + { + "hash": "46c0cc4b0476932c50190ff1c4570a71f3af0fff77fbd83acf9b64101247c367", + "kind": "transfer_execute_success" + }, + { + "hash": "fbe792aed214d89d988f51b769729209f55a0365794e6d4303d85e95f5b46050", + "kind": "transfer_execute_success" + }, + { + "hash": "aeb4445990fe90dc94451a47603e4d127b7a3276de3fd613af504857927fd31a", + "kind": "transfer_execute_success" + }, + { + "hash": "636c643d57ceba5cd4249f4d670ec849bab5aed870b74ca02858a530022f9fb9", + "kind": "transfer_execute_success" + }, + { + "hash": "b0767863b48a07517eb3212222abb64bc86ec531170778e75b507a404ccd72d2", + "kind": "transfer_execute_success" + }, + { + "hash": "98a4868436430a7f281d78d9b7126b5a5f8b326e721a1cf93b947f347a695ae8", + "kind": "transfer_execute_success" + }, + { + "hash": "76b6051fa68384c3359665a05e03fa051a0155ab9f7bab94373a3e23d9743666", + "kind": "transfer_execute_success" + }, + { + "hash": "8bb000a0a875121dbccd652565fa5fe1139860d9c6b343c3a9cfc047aa2fa430", + "kind": "transfer_execute_success" + }, + { + "hash": "5ba568fa068a97b19d089f22e45635902695c00fd717258580e71a83ba03b3f8", + "kind": "transfer_execute_success" + }, + { + "hash": "50a2106f5b7f107cfdd1be365a9ff9b9951d61091f4d2a806c210107b379e5a0", + "kind": "transfer_execute_success" + }, + { + "hash": "92d3f22ebfed18feec9bb54c8ffc7ae258eae133becd5f421e6f05d145391e36", + "kind": "transfer_execute_success" + }, + { + "hash": "cb66a8c38e91fc9fcfd811e987fc2ae31379de5321e11cfa9cdb77f036634b67", + "kind": "transfer_execute_success" + }, + { + "hash": "4480566a5396251437262e7b79edec3218c3b480b957fb4ac090a4b3d9dc7d19", + "kind": "transfer_execute_success" + }, + { + "hash": "63655681a5256e1548f9d49582a42198dabde81e58ac9ca8febe34c8905b0b01", + "kind": "transfer_execute_success" + }, + { + "hash": "875962d55654e23de6d6f0b16b5ab14b5e92e9368cff4abbbaaff9914fc97adf", + "kind": "transfer_execute_success" + }, + { + "hash": "f36190da315425f1cb15c90c7882a351e3a4da522814a9091cf1b7c683e5d52e", + "kind": "execute_error" + }, + { + "hash": "f02c967c92c6fe4b051ba20726819a045d649e10bb5e7fa4cb83a46ac8efad2f", + "kind": "execute_error" + }, + { + "hash": "f898230055e71069dec147d8be5ebded5aa120b4f9c06fab088dd4d827862643", + "kind": "execute_error" + }, + { + "hash": "06d34e19d07bcbd3a0ef7cd94be50efd68a62710ffd69f0040b86957fadb202e", + "kind": "execute_error" + }, + { + "hash": "b87e43b706cf2fe4960c6c754eace481bdb6988c96b51f3efa8d8ebb167cb683", + "kind": "execute_error" + }, + { + "hash": "5b0fbced32f0af3a1b9a32e9ded96198ecde102840aa4ca2243e24dc9b9758e2", + "kind": "execute_error" + }, + { + "hash": "51d49507882a583b68e8f557bbfc70549e9267e1e1f7421684e76fbb1dbbaf15", + "kind": "execute_error" + }, + { + "hash": "83202b1f151e8a7eb5c4e63cb52f00a7c5d8bcc9d1ced072adea4e0c0f67a605", + "kind": "execute_error" + }, + { + "hash": "08c6c251c8cb668242172b77b9784ca95ecd8c9ca6db7c1b7a84a00ee61fc632", + "kind": "execute_error" + }, + { + "hash": "626c06ad0629ec752f1b05107f2eced52a55910c63edde334556345049d729fd", + "kind": "execute_error" + }, + { + "hash": "945c65e08b83f3870d4854da4c86f938501c5bd783abf736519a15ca84c9dea9", + "kind": "execute_error" + }, + { + "hash": "21c55ade52e43d23294d4c5874977a10a5aa13ae5b8e21d09a43c8ae7de76b85", + "kind": "execute_error" + }, + { + "hash": "689c6ace9666e33d1791fae357a2b19b199fc7211d1d5307e784fd7227654372", + "kind": "execute_error" + }, + { + "hash": "7ff1ae359a7bd0d357d3259fd37d7396d52847aa2486d95808bfee2a37d8ddfa", + "kind": "execute_error" + }, + { + "hash": "3a0fccb802cf0b9508fc3bdef373685eae8db078b713b3859c375619b49314ab", + "kind": "execute_error" + }, + { + "hash": "04f1c969c2be1a4820c459b1956bc1273697094e35f52659643c04122c0cdf8d", + "kind": "execute_error" + }, + { + "hash": "370451414b4868c111d64ea1209d8afb3d0660be1b69b096e1809c1141d8bb2c", + "kind": "execute_error" + }, + { + "hash": "28c86585b61cacfbc41e2774386b05004e3b387e5bd5bb91bf2a072e54684bd3", + "kind": "execute_error" + }, + { + "hash": "43852358f1e21aa800ce35ea00e41edfa83481ab4aa47a90dfe993a1b484b3f1", + "kind": "execute_error" + }, + { + "hash": "034e97ecc8088dac827d73f5f7dfc8faef54e20bd29bd592528335d28fc88cbd", + "kind": "execute_error" + }, + { + "hash": "0a074db830cbf7d7a68bab54d50d1e60d36bba250f9121ef9d5ee1bc0a8ecf59", + "kind": "execute_error" + }, + { + "hash": "1e2777c895810a3ecea15f4d713f61ba5d5500f62d3c563148d50c4d04653842", + "kind": "execute_error" + }, + { + "hash": "cf4bd70751505d749aaf331108655035efa1964ef699bcb29105b489c60369de", + "kind": "execute_error" + }, + { + "hash": "0cf6cea8e948eea23c29dbaeb79e852df5a0c750def4d7d4589ab9faff5785ba", + "kind": "execute_error" + }, + { + "hash": "e9c6496ad54ac0a3d8648820f002cfd2d9427cdba30ea787e9cbf01abc2234da", + "kind": "execute_error" + }, + { + "hash": "a2245bf15fbf9188814d178cdc86c29a2e99c81b2368af9f6e8977f50be7fa7b", + "kind": "execute_error" + }, + { + "hash": "e364c5f960a3d73eee333b39bce57f8358c49ed715a4cefd0c27017ea46b8c95", + "kind": "execute_error" + }, + { + "hash": "ee17320005e2217156ed07e52a43d909a4b6d202efb82842c917a7f65e0eb3ca", + "kind": "execute_error" + }, + { + "hash": "c8bb825916db716e472310cadc3983be18332d445cd9dcea4abfe3ee73f601d0", + "kind": "execute_error" + }, + { + "hash": "b9004ba721a73242f8bc6268981da184ae390072beed7fda74a6de963f996322", + "kind": "execute_error" + }, + { + "hash": "c7c18bf9ea8a926414e9a7135d7ae6cb31e835a1ebc719e7b3bc485a0fc4c21b", + "kind": "execute_error" + }, + { + "hash": "94d81c6b471b3e9a232de3051fbd951db79e535283197f3524a8993a3c4ae384", + "kind": "execute_error" + }, + { + "hash": "ed2292d2a751601f0bc73686966b9cabbfe461f0f5f912d98fb973e0643f9ebe", + "kind": "execute_error" + }, + { + "hash": "6c9b32bb1adff13d384c3ee43f06c34a15a4a9b3791c92927fa8bafd3758e4be", + "kind": "execute_error" + }, + { + "hash": "a4d5b5c8dec0257b7d4bb90bb93d4c2ec12b204d28672f76c5265a7faa6e08d3", + "kind": "execute_error" + }, + { + "hash": "cd42bda9255b6ec02a1e442b4676fcf57c28754036e32e760d4b3bac70b1a9ca", + "kind": "execute_error" + }, + { + "hash": "d101fe73fd3f2785d46191b1ffaef656b97ae9d71e524abcda04d0784bc99719", + "kind": "execute_error" + }, + { + "hash": "0b59142a8c6cc1362e74f91ec53139908d68325d6f0d137f1f6a0f0d55e8bd9c", + "kind": "execute_error" + }, + { + "hash": "2888c44fa427aef1d8dacaf80f39cd7e74b5384f38e690d23d6a5702684085d8", + "kind": "execute_error" + }, + { + "hash": "e7a513e83a9c4827dbb920034a4b9bf16c45c9ec0c185446d8e62610f60781e5", + "kind": "execute_error" + }, + { + "hash": "32c458c0b032b97e23b3c783e22dd0f7a90b4318026417e5c33f31d5983a7a20", + "kind": "execute_error" + }, + { + "hash": "086d2237b9ffd71e37bba9bec822935dd1c301a4d3022b299a65c5e4ed1ab088", + "kind": "execute_error" + }, + { + "hash": "19aa4d01a9ee13ce69043279176808ef7ad49a14c578d03f8b4de5197831788f", + "kind": "execute_error" + }, + { + "hash": "b27c1aab4315971b0f3273f8dccc23d998d8345d6b0c06694c650b0a43b26b29", + "kind": "execute_error" + }, + { + "hash": "798f6ce71cba391221ef632f31db7ce91931532132b83292542a44a658543829", + "kind": "execute_error" + }, + { + "hash": "1db86ba4aaa5b3bab21d35733166836ff1b1ad4007c7c473f7d3fa3bd7be2b8e", + "kind": "execute_error" + }, + { + "hash": "5417afbcfa5771c822d1d7fe3ba19047f11dae2ac1e48e7cae67d1da9fe41a5a", + "kind": "execute_error" + }, + { + "hash": "3639a7c45221f035f42f34e9aa55a813b84616d6b10b80d5ff68d59ee7d558db", + "kind": "execute_error" + }, + { + "hash": "e9902c73b1ac9340b5e6025013d840753f73393b5f678db58929d828c7034903", + "kind": "execute_error" + }, + { + "hash": "9f03e1e76f2257b4f199a1ed39be0dd859e7e870b591ff396a474d02b9422ca1", + "kind": "execute_error" + }, + { + "hash": "8bd21d6554c4c95282d32e12f0427717a349f3d0fe4e9bdf0570200682ae4971", + "kind": "execute_error" + }, + { + "hash": "1ba5b4744b71767810b3c7887efdcbd3d3a45b4a7ca3818b87f635127b77f64d", + "kind": "execute_error" + }, + { + "hash": "c55516109aa1f58043483d57cf94d41a3bd7062dc625c4de572e84cef0e250ed", + "kind": "execute_error" + }, + { + "hash": "4a11556c84125f5f4adc23d683d54e6deac656ab6f576089aa8436a52be275ff", + "kind": "execute_error" + }, + { + "hash": "6894a16d42b73311b1a8eb8d91c5e1ccf1eb32be7702741247227881b08fd598", + "kind": "execute_error" + }, + { + "hash": "55a6b4ffdb98c21cba10c21a100b9703118ac8bfce2c0d404cf711cba6592d1e", + "kind": "execute_error" + }, + { + "hash": "091f6fb19afd97cec476e845ace0d515a8fb26c806387821cfca01652c3dc085", + "kind": "execute_error" + }, + { + "hash": "469f0f24a80bbf7769cff83d0431b6d140f4502f24df7d1efc147b8175272018", + "kind": "execute_error" + }, + { + "hash": "f263dcafe964418e6ef75ef6b3f75959c842810f19728b8608d49183a90cdfd7", + "kind": "execute_error" + }, + { + "hash": "bf54cf384f446c1bb49a93ee55b04359bf28e5d028829d1ba518fb3d51893206", + "kind": "execute_error" + }, + { + "hash": "d9b9ebe2ffc7767a9d5ac6c143c6598208d43581fef3d90609a2b7f9e7e0531b", + "kind": "execute_error" + }, + { + "hash": "a3b65179dadc8cfaa991479a8a4b032e83ba3473e759b18e914c628320423559", + "kind": "execute_error" + }, + { + "hash": "6995c5cb168970710fdaad21e9b8f455ba4a214d63f6d93f17d755063c5929ac", + "kind": "execute_error" + }, + { + "hash": "396666d87aa5e63ea1d2e8450501cc6927defccb0b3eaa5d5b2b8b4b3fee3202", + "kind": "execute_error" + }, + { + "hash": "62e3f14ef8974939a6f69691d36bb1e2697ac09b4986d0a8c0a17d8fa74d8f45", + "kind": "execute_error" + }, + { + "hash": "2abfa70b9ceac81fba61aeba7cd9b03dec9711ec882852aef373625886eaab78", + "kind": "execute_error" + }, + { + "hash": "66875a9d6559c65366e30e1fbaf85a1274d59d456534176799856a217d48c889", + "kind": "execute_error" + }, + { + "hash": "e27c31989a3b460f2e19b4a0f58d4180476d00d9a84cb2654e66da4fae139272", + "kind": "execute_error" + }, + { + "hash": "b1bc70f4052386a3b783f0fe3d7b5dfadd00b08bbca7012e3182c790f0bde9ca", + "kind": "execute_error" + }, + { + "hash": "56e4ad5e75a7975e097a18f4b5676044618fb4cb4abaeb9fc7b034db6e439d3b", + "kind": "execute_error" + }, + { + "hash": "0aa154f1f61e9bbbf247439fb81936b01bca5e80f255969fe1fc505ab1a847d9", + "kind": "execute_error" + }, + { + "hash": "f268404be1f8b0fb851b810ff9e89aa4dc275eb451f8c0383698987f10e44218", + "kind": "execute_error" + }, + { + "hash": "c3bdb0d22f1336b4ebe2d9b509f843266c730f0c94a5c7f3d3eeb429a99560fc", + "kind": "execute_error" + }, + { + "hash": "0fef12dff078c3d5c4b1f7793d3ce43249861ff0a2f9565c570f1ccafc6e45b0", + "kind": "execute_error" + }, + { + "hash": "70438d344cdbd5a9688b38016eb6c1664f2748be0abe887f8dceb7412c6c354c", + "kind": "execute_error" + }, + { + "hash": "dc1804979ef7c1ab7a6021910ef28f751a75299244975d186bec0fa3cb18c25e", + "kind": "execute_error" + }, + { + "hash": "999ebcc072d4b5d34e1d8fa3c841ce08a14bb8297a9728d7986f0490561fc552", + "kind": "execute_error" + }, + { + "hash": "389225e2dea4bf42bc20460e24707f9964f95796a1e2ac949e5d1787520c7282", + "kind": "execute_error" + }, + { + "hash": "19a0cc2591685ad5a398229b8a405cce309e76dbfac92a2e5706e1f68e4e2495", + "kind": "execute_error" + }, + { + "hash": "d4b15ba24cfa0eca7be9f48c00c7cd0ef02ebc60b5f1d4acfd0c3682ea2ff231", + "kind": "execute_error" + }, + { + "hash": "0fbbc25d7fd1b2ebcf1e66e85afed1114a3767e96e1509ae9b53ce0dfb90b26b", + "kind": "execute_error" + }, + { + "hash": "95a1e35266e7ec1cd85e919fd25b2aa716440cf16c50aba2926c1363665b6341", + "kind": "execute_error" + }, + { + "hash": "2ef694de887030e2ab8167ab566f3515d54a365cfa68e076e0e637b7f69ee688", + "kind": "execute_error" + }, + { + "hash": "cae0303bb5b73fe34df2a3252e7483bb13766fba09ad03e09d67eabe05ea2a6e", + "kind": "execute_error" + }, + { + "hash": "bdae787acf18c87515cc14013033500be4d781d29c71a4b9072695fc0c57a831", + "kind": "execute_error" + }, + { + "hash": "46caf13d5aae5bb0eb6fe32f4a801e23090725e6afe8d173f0a4ea5b8913cea5", + "kind": "execute_error" + }, + { + "hash": "a95281405a274eda5a724ce917130e52cc58416028212f82881f2e76f3e03e4e", + "kind": "execute_error" + }, + { + "hash": "c011c5888086a432335250def85646b85469d93c77bd621bdf9159c182ea465a", + "kind": "execute_error" + }, + { + "hash": "64a08bc64f025907b98aba9e4eaeb998c28f15990f3707d9ec097d6079fc515b", + "kind": "execute_error" + }, + { + "hash": "f19662a73a71cada09c1adfd07cbb211cb0a69c686462ab0eb2935abb9c70b5f", + "kind": "execute_error" + }, + { + "hash": "0f5f8154f1f6a72dedfe05e0424442b99139c1bfb1c8534e25e675f7a6a0d00d", + "kind": "execute_error" + }, + { + "hash": "d9eff48e1ec24549c214408504e10519de9282d43fdb93d64311563380c105a7", + "kind": "execute_error" + }, + { + "hash": "160ca3d3846b66e5611388b5ad41ebb0d3d61b0c94042f58cc17f970867f59b3", + "kind": "execute_error" + }, + { + "hash": "5c6b0bb830e2f05ac73b1771ed47ea56591fc04a8698ceb7cb5faa5c439ee1ba", + "kind": "execute_error" + }, + { + "hash": "20bc30fc73a43a9d569d5a99c7c4d0b84ed055c5ac6e8d2af893b5e1fe3769b2", + "kind": "execute_error" + }, + { + "hash": "c482bdfa730f4a0a2a2bb6358467532a453c382991f034fb0f1173d4c15591bc", + "kind": "execute_error" + }, + { + "hash": "078c5a780b884d3397e9d2abd2e3fcb6c50538996263b148624506ab54b6213b", + "kind": "execute_error" + }, + { + "hash": "654aa84a6596c8d93bccc354fe8a1ce0ef1db3170a48f1dc513ce00e5bc88a36", + "kind": "execute_error" + }, + { + "hash": "7def7983777417b34efeea7c202def7bca16408f77d1002f242b1ed5a8cae43e", + "kind": "execute_error" + }, + { + "hash": "c7240d81d400d8a9d823e26b1f9d93c3251200e13f1e63cdfba000478dfe36e2", + "kind": "execute_error" + }, + { + "hash": "c4b330da247b41c12cf0a2cde568ebea3d98b45a2cd1cc61dc6d558649b50db0", + "kind": "execute_error" + }, + { + "hash": "5a337a7bc8b499c13d4ca9163c7e5865bc31872a3a6ed6ca688fe15a35577c18", + "kind": "execute_error" + }, + { + "hash": "d1b46e8ad3af4b20d1ef6d078f6e89a5d13d2e1af09e4b765798f935591d7137", + "kind": "execute_error" + }, + { + "hash": "c780f04fb6df3b50dc0eff3320c37165ec57aa7cfca4de7f4923ceed36bf0408", + "kind": "execute_error" + }, + { + "hash": "4d71d8949ab39601283e10274b72dc424d43e509d33935c375a94a9e3f098d5a", + "kind": "execute_error" + }, + { + "hash": "59d78df91769137ae71e9db13f10ed0cf8ccc3cfb622cce1d89f74007cc1bd4c", + "kind": "execute_error" + }, + { + "hash": "b6b56b75d2b6f4eff0ff58be5291c726fcfc3d0c9427a9ed746bbf94884386c2", + "kind": "execute_error" + }, + { + "hash": "3307bfc8a797901f7d0bcd258cbb9b0cf8e3ff912eab66609f3a3b55dcc27c3d", + "kind": "execute_error" + }, + { + "hash": "0f825bd58a331542fd3fe75b5edef66a3dae93780efc599c94b9def733cd92b3", + "kind": "execute_error" + }, + { + "hash": "675baf18ed7e175f6fbf94d326a99f73bab128bf063b87dbeb686ea95038031a", + "kind": "execute_error" + }, + { + "hash": "4d959090d90bfb1eb91962752552e18c832e25bdfe50844d4e3b589a0260f6f4", + "kind": "execute_error" + }, + { + "hash": "23547300993a916db2497ab2326aefc44b02b091c4cedceee667ad86882ff634", + "kind": "execute_error" + }, + { + "hash": "946377de081184a2d3bee164f3202647e0b3f238b6e4ddf192aaba0868ba4e1a", + "kind": "execute_error" + }, + { + "hash": "00c93455daf39876bcd385e1b0a58c1fb8ef0ab25be020d47bbce280de90cfa8", + "kind": "execute_error" + }, + { + "hash": "3908976b87c6c4e892dc8676550419e208ace18cbd3d8725e750ca7ae5d43244", + "kind": "execute_error" + }, + { + "hash": "53a7ac026e39ebf7a32fb262fefea838b4d5e7f73fe8ca4638400474d53430f1", + "kind": "execute_error" + }, + { + "hash": "de4b8ceb43faf637ac17d72038d29bef9b055a243dc53d9102e82cbe91c7a5f2", + "kind": "execute_error" + }, + { + "hash": "e5c808700f84a84e864db9abb1c8ea78b30814839b60671c6fc1d5c0a4782668", + "kind": "execute_error" + }, + { + "hash": "49777eed509e50b59467a77cd9044c2ed770eb68499a454dd26170e5cd9344a9", + "kind": "execute_error" + }, + { + "hash": "fccd83aaeb96b54b3579095bb579e59d5c747f2df4131e7925295bdcbf2f212d", + "kind": "execute_error" + }, + { + "hash": "036d8b86ee50cb7b4f0fa4a9c34e711966c0c4cca7e42d3babb713bdd567613c", + "kind": "execute_error" + }, + { + "hash": "67f5d04a943a67aafc74b7dc071aeb3b0837aeb50d18e48ba36f2e9bd8971c4c", + "kind": "execute_error" + }, + { + "hash": "d8ea7863b88427d66ca45110fa74634df643630b39abc034031c0bb77106f284", + "kind": "execute_error" + }, + { + "hash": "0ee3ac77fffc1ee6ceee4323743fa70892d7447208dd5a67df50858b41f4272a", + "kind": "execute_error" + }, + { + "hash": "b24d14569f9f1730f1040a41cab3c373827ae8ece9bbb6d3dceddc696cb35f31", + "kind": "execute_error" + }, + { + "hash": "5fd2505c02dadd74d5b1ed23ffedfee9ab45d045bd6e8cb52abf2697d62443c7", + "kind": "execute_error" + }, + { + "hash": "c478c339ff1e63bf01ed171bcb290a24b36b24fb4e23eb71d15805010a93cc3d", + "kind": "execute_error" + }, + { + "hash": "83d18d10f67e65641d0867ceac4227e40bf635846da3b9d58fa961efdde1f307", + "kind": "execute_error" + }, + { + "hash": "60d1692a4e9907b4936ebedf11703df3ef49e69f308bf30de187c594d5dd1197", + "kind": "execute_error" + }, + { + "hash": "5d4a049e53d891638a1330c024b068605e4c1d56b0b75c9b403df665afe2937c", + "kind": "execute_error" + }, + { + "hash": "260c0fcca5d752a62192b34cec4aea0f276b8d28dd02807758ddeafd079a02ff", + "kind": "execute_error" + }, + { + "hash": "8f9dbcb19cb84b6a238ff9dec7abf76b1c33ea2bdbd1402b4c0b6fe315ff0c5c", + "kind": "execute_error" + }, + { + "hash": "91eede53206af982a9bce1c480b9415255cd9e732090e2d9ed216664ef3f6ee4", + "kind": "execute_error" + }, + { + "hash": "4c4134b9f5746a3fd84da7e559ae1ed7367d5883970368bc28475813789250b1", + "kind": "execute_error" + }, + { + "hash": "40c5fbc669b814c98a305c68c89011a657d0100e3f0faabb13f1199414c9bbbe", + "kind": "execute_error" + }, + { + "hash": "8be64b11b6dfbc04b04d3c44c490b809828e3c0f93b4e7117c773c68c4f668c5", + "kind": "execute_error" + }, + { + "hash": "054c56b41802c07cf1ec516c9839fea005202115929f949d787cdfe1e6d6d639", + "kind": "execute_error" + }, + { + "hash": "0e6dbf4d96e2f04a24b66d47c8e50a3edc02c98c03f43fc20f29a475c6f5b095", + "kind": "execute_error" + }, + { + "hash": "cc84eb1f9cab1a602aae75a5892c45df4c13c363943090da11d3f909a8478253", + "kind": "execute_error" + }, + { + "hash": "13dee71855177dd0ff5da71892e6b59de7537148cee0c0af10a27b9cbca8afc7", + "kind": "execute_error" + }, + { + "hash": "b41b0e8335afc15b06418a2227ca7f62aa6db2af7693edfdfd8c5e170c264bf5", + "kind": "execute_error" + }, + { + "hash": "05372ca38cb1859844dd9ff34fd287b1a1406807812c074727d9e8d2aecc849a", + "kind": "execute_error" + }, + { + "hash": "0b6e103e8ee21533d001a8cd20df7a2f75d389b4d7bfa4c1d128a726f96ec2a6", + "kind": "execute_error" + }, + { + "hash": "e984067e01e9e28a89b51af92e0761b162de79f7d4f3e4694cb4cfb450586e51", + "kind": "execute_error" + }, + { + "hash": "bbdf1921647896e6fc2044d9f826fca3062a03ab0e21ea6c7f08709ca9739d3e", + "kind": "execute_error" + }, + { + "hash": "0daad94e38b55ee6238fad611337312a16f9c688e4492414195a961aebf09a8e", + "kind": "execute_error" + }, + { + "hash": "ce5b4a9331fa53f108d9fd439ed6b41502aa780a9ac464369224d83436d40843", + "kind": "execute_error" + }, + { + "hash": "1543f347583f18d2267d080680ab6dcb3494b38fa9de6c64568eb0ec31dddedb", + "kind": "execute_error" + }, + { + "hash": "9f6d450923e539bcffecc5044e9a7032815290f7e1708de3e34dd0217fc5e974", + "kind": "execute_error" + }, + { + "hash": "3816fa7621b7574e8cd05e01057e1f14290589354a7196540fc981523cf2e8cc", + "kind": "execute_error" + }, + { + "hash": "c025df1c818035275ddcf3d53fc757d8072d16ba9d268582746e9851ae7e4891", + "kind": "execute_error" + }, + { + "hash": "724cfe998d1925f350552c261a01cf1f06854dec11222f5763987b55f40cb838", + "kind": "execute_error" + }, + { + "hash": "3871f507308c13bfc62a663c880555c983f1141dee59e4e0b8d7f5e2a4b4b0ea", + "kind": "execute_error" + }, + { + "hash": "69ae18718434009c7d903756fca8f3e68482a0dd3d35c3e4fc1c713e4a4ff639", + "kind": "execute_error" + }, + { + "hash": "07de23387cc4ca94f2c269bdef0cca549ffb14498a798cc5c457562b316bb838", + "kind": "execute_error" + }, + { + "hash": "a90dde65d0855e30a373b2caec32ffb7433dbc2f46f6f3ad952c26f238d68c35", + "kind": "execute_error" + }, + { + "hash": "590e0ae91be8bbf4cea87fbe719c4a8ababb5440389a469a9cf1312e21033455", + "kind": "execute_error" + }, + { + "hash": "2a451c25c89a9c4783da3ab141c7a2c64fa4147a28bc8106987ea2e306bed26f", + "kind": "execute_error" + }, + { + "hash": "6388d179dccf4412b96cc45c858cd2e0342310a804320856b6ccbacb2eabb3e7", + "kind": "execute_error" + }, + { + "hash": "820b8c03de9d797dc47ab27be0e1b40cc23e06fff3a6f0db6ee05364c0bbc6f2", + "kind": "execute_error" + }, + { + "hash": "cba2908ce6c64be54efd686f5da25814c329f1f5ed0a0dcae349143112332b4d", + "kind": "execute_error" + }, + { + "hash": "1bbb846dfe23751fc09bd1aede19de6c174a3420e033ddafe89287fee2f9f5be", + "kind": "execute_error" + }, + { + "hash": "8d0f18f388243b928c6e56eb4ca068032aa2b620dd530f42f6142c4c415c8ecb", + "kind": "execute_error" + }, + { + "hash": "d255339dd954acf78ff57edbd4986b71fb67898a193573989e31fe5f24b0a7e9", + "kind": "execute_error" + }, + { + "hash": "d6c689d5c6652909f5a780dbdb6b3b62f372891ab052019b887b500033ff4d82", + "kind": "execute_error" + }, + { + "hash": "7b01aa05b659f4853b400f1e235e4e286910a8c4bc38d8c85f25a9fb40f30b42", + "kind": "execute_error" + }, + { + "hash": "ef600b94978099faeceea9e6d6b403bed8e7a990125a39407b7f63f5ae77d488", + "kind": "execute_error" + }, + { + "hash": "e76a4604746c1476dcb2369d9b076cabfe0f9a0eaaa5900deb03693e6abf24bb", + "kind": "execute_error" + }, + { + "hash": "945ccc641e777edbd1dd1a9bcb2fa3145b65409f7d01a865e87413d8db3b0eae", + "kind": "execute_error" + }, + { + "hash": "b5e46875d3205f3d99752c7fbec3fe5fbb7a0f21c16cbe6dbe5c8ce7579d5718", + "kind": "execute_error" + }, + { + "hash": "c30130adc0323c5a0b4a305e37b16e4d84761c7d1d706a1d30b5004266ab717d", + "kind": "execute_error" + }, + { + "hash": "41444b193e877fbc01a0a1a82583d5be9cb5be35a08de4e5e8d8801e39917e29", + "kind": "execute_error" + }, + { + "hash": "c7ac7942800eb7830cb6a0ff7110c6db828879cda37f58836872755c2a85581f", + "kind": "execute_error" + }, + { + "hash": "a8526a7b4c36dc68c852a4b9e5ae7de4a8f1a113d7244ec70f9781a4fc908312", + "kind": "execute_error" + }, + { + "hash": "7202c4f00ce70ce1d18e74b10274f42c50944bee022fda3efb215dea95d5571a", + "kind": "execute_error" + }, + { + "hash": "63835d65610f69ac2e1c2f0b022e4725abcc9152413b1e6692f726cfb8293f34", + "kind": "execute_error" + }, + { + "hash": "8756ddf51d460f0a1fb484b8840b6cab3fde99e9f24525cdcc8df9f05d1bc0fe", + "kind": "execute_error" + }, + { + "hash": "ad895037d57def1c7bebd3100e98a73623f00349c147e73cedf95b66831bf6eb", + "kind": "execute_error" + }, + { + "hash": "d1277ebe5b0c96fcbaccd8e9bfcb45ee9624996c13db91b1a15e93bdc078c870", + "kind": "execute_error" + }, + { + "hash": "8533541d4e4c99ed311b5fdb235cb80f8324173d5d01e642f1ef5a7bcfe0d2b9", + "kind": "execute_error" + }, + { + "hash": "a67ecbfdf90e64349dfbf14ce665a47634f9ff5ae3a17a6be34053a246c6bb6b", + "kind": "execute_error" + }, + { + "hash": "58d847b2cefd9a46c476185c1027d97f2362251b5f7e8d3f899ad7456e973dba", + "kind": "execute_error" + }, + { + "hash": "e9b806dfd06f8ab55f7ccc48e733118e1bbfdc7a24eb3ec17bbcce0d8ab6a95b", + "kind": "execute_error" + }, + { + "hash": "418e6e93ca6cacfd2f1df0b4ace055bc5c4a52a437277a2ccd0873531e216983", + "kind": "execute_error" + }, + { + "hash": "255fdc73ede50cd9df839f27fc0d30244eb60c7868e3277654da3e50037f11e9", + "kind": "execute_error" + }, + { + "hash": "daf3fe7d91fd22254f5fc76b70ea98389e8bb524fc7d908511de7c073301e7f7", + "kind": "execute_error" + }, + { + "hash": "47f2cad3b4f15b3a4df8afa15ca50da389a187d4a8d2d39b6a4ec2a531158bd8", + "kind": "execute_error" + }, + { + "hash": "5f8ebc1149aaad044dfca4c11be60febde1b625d4e5d8539221abca0d84d1242", + "kind": "execute_error" + }, + { + "hash": "0adbd419f24ad8edcb4d9abe8bf68f5d69b8b02054ce3ea3ff5d1d64d38ec624", + "kind": "execute_error" + }, + { + "hash": "0dda89aba769b2957855057ca1dbe6905645f8b42d257ef604297b161e4791c6", + "kind": "execute_error" + }, + { + "hash": "578cf695df2aabeb4a92e28a501779b58f1559cc4bb27f639fe2c03da61ce0c0", + "kind": "execute_error" + }, + { + "hash": "3f22cf58c99337ba2e86b0770fc7119f9c5acdfee9154b048c9b8f26cc8a30ee", + "kind": "execute_error" + }, + { + "hash": "15d8d4010c18ca31e6fd84ab77389d85b0d7acaf64bb1dff15d4df6408c79b9d", + "kind": "execute_error" + }, + { + "hash": "d4a7e227770f8942add6863d2a643b419f287ddecc3ac1e11bc6b70e8e3cbc6b", + "kind": "execute_error" + }, + { + "hash": "e31512457dfbc88eddf8fe09b1a69663358d330baa56c6215cdee5d4854ad8c4", + "kind": "execute_error" + }, + { + "hash": "82484f818903fabfd2f9d8b6d89a5fd4c45e180a04c4efcbd364958a11799e7c", + "kind": "execute_error" + }, + { + "hash": "2f36a1a5f8ba96c2f8ee9ec17935bad939f9037baceea07c06e1300215633945", + "kind": "execute_error" + }, + { + "hash": "cc1e30897e595dc42f430b422892536e6ccea9227089eabbd45ce8479987921b", + "kind": "execute_error" + }, + { + "hash": "2974511a06291671eb8509c141f065e4de807bcf87dd9bf739d0043a0d484a8e", + "kind": "execute_error" + }, + { + "hash": "90cc5be03cec9ffafa92dccbd7591e94810b9c1a7e017d1dcb5ad086628856c1", + "kind": "execute_error" + }, + { + "hash": "2effeac97fd4c81cd397ba38a3dadc34a6d642d2e8707fac14985bc000685143", + "kind": "execute_error" + }, + { + "hash": "16c8af6eff8eb5593cef4d28052966f274fc88d5cb4da4fd6992ff3722de68b6", + "kind": "execute_error" + }, + { + "hash": "e9e154362376018f460311f63d027c7590016440bccd4118633dab6a815b1ec2", + "kind": "execute_error" + }, + { + "hash": "f93b30c157adba19fd0307c50fcd239b6b0e7337eb9e8191bab2a881279c6cfe", + "kind": "execute_error" + }, + { + "hash": "e51f8baf2b5ff6dfed325c8bba7206d3e6515d51f495ccee629d7390f4b03b1b", + "kind": "execute_error" + }, + { + "hash": "6595da49aad2b428293f7e09e1e1ca0c7cc2cb3295409c3b51c9b1c552cef72e", + "kind": "execute_error" + }, + { + "hash": "0699dc90c1b91be92ee6fabe516cc740bdac542b526556f703df24296a6cbb21", + "kind": "execute_error" + }, + { + "hash": "0c02cd8b744d38492173ed6255d1102c36a6ae47ff2b0e645fc7425efcd47841", + "kind": "execute_error" + }, + { + "hash": "a59399d116de5f383b65e358ea64711f4e225ca213ef38550797d5c6d5a2c76d", + "kind": "execute_error" + }, + { + "hash": "c3aa624a54a909a2b22e397a864628cd4dc8d0728802e9fc654055dcacacd98b", + "kind": "execute_error" + }, + { + "hash": "222908e95c75aaa782ff3ae379da8a9b504ca8a936859649842abc584d852579", + "kind": "execute_error" + }, + { + "hash": "bf4f0edb0df2b5077e9e154af4f28ba9d8d61a6142f203670546969f54b0ad2f", + "kind": "execute_error" + }, + { + "hash": "a45300be51b311ef862423dc882666e74306137b117308a15f4af7461be8e32c", + "kind": "execute_error" + }, + { + "hash": "af4b7c643fa6debedf99566664a5dc0e43f69d3adc37cef067ec73281be9d77a", + "kind": "execute_error" + }, + { + "hash": "4fd42081f9fe6d455a03d65eac4d4e1d7598dd2513380d96c5319710fb93b600", + "kind": "execute_error" + }, + { + "hash": "af555c317d10ad669c8f8e4e05b901e4adc916c63c90ac628a705c74a5570f69", + "kind": "execute_error" + }, + { + "hash": "0d6e89726d17811dcad1ef4fa1deb64f71e9e16c5aa45847389adc9c8afbb4e4", + "kind": "execute_error" + }, + { + "hash": "c3705c2783a8ffc8b1c5aff138f65521a2007fe93faa1a6538628efe9da586c0", + "kind": "execute_error" + }, + { + "hash": "020f089347939a097a4bd27c673e3967c1164138dfaf51d86e7082d175030b62", + "kind": "execute_error" + }, + { + "hash": "5b21cc1bdf44d15ad290edace46ea314f4092e9071bdd46ac85dbb3bb55b6e94", + "kind": "execute_error" + }, + { + "hash": "0e60f1df40ae925cb00d660b4d0926325f2381076827928ccea1c16fc21e02f2", + "kind": "execute_error" + }, + { + "hash": "40eb3bd53dd4c90316550f87c36cce38e935fb553381727bf2fd13ae606cfb60", + "kind": "execute_error" + }, + { + "hash": "41ada59d3718601b938ab29e70216cf95aab6db15dbc410a5a30158aa6347530", + "kind": "execute_error" + }, + { + "hash": "0705f9246c2207cb4d79b0e6a73c0a9fb0194ad57ce53a5da443a68b22c069ba", + "kind": "execute_error" + }, + { + "hash": "e1a7e8f9c3a0850a4c55ff19990620146764c2c4e76d5a167086c97ecaca378f", + "kind": "execute_error" + }, + { + "hash": "9cb11e07890f332d4853aaa8165ef9a531a3756e35030ec076d7a9c8e6b235b5", + "kind": "execute_error" + }, + { + "hash": "201bce06e19e88644dfcabbf9aadcc8fcb7910573c878465c05591c13464c741", + "kind": "execute_error" + }, + { + "hash": "999dcced8baa4f04242643faaf0f1576de4b7b21cedbbd213d5a588f3d568516", + "kind": "execute_error" + }, + { + "hash": "661b317a780835778bc959eac74a976ff3adbf008473c74bc9e0207de317a812", + "kind": "execute_error" + }, + { + "hash": "bf628fb7245057789363a8363077717f1c64dc7839c38441e223376d1f3c2d32", + "kind": "execute_error" + }, + { + "hash": "b841c0bc85372861cc7142ce64ed9eaeb4a3600b85486bb6f0c9494be2bfe4e5", + "kind": "execute_error" + }, + { + "hash": "9ee2a006fa2a563ca7a2bceec19ccbbf1b29c19448a7f5846d051a1de41e0ee9", + "kind": "execute_error" + }, + { + "hash": "f7db33e9dc41cf96d57f68e62d58a5c4035ce1de861f5c78d6c1ded2e027a671", + "kind": "execute_error" + }, + { + "hash": "84c7823be9e84f8543d47b57fd544acdadbe9363f3c83dccec759db448adca57", + "kind": "execute_error" + }, + { + "hash": "4f478dbc1dfdbc51748dfe43c12afb1a552e6fc5507690fa28b93391be1f25b8", + "kind": "execute_error" + }, + { + "hash": "e944ae041257f585dbf976600f9fe198036802c6514b1da501c31adbf279328c", + "kind": "execute_error" + }, + { + "hash": "975233ca4787bb8d42420250d97114e5878434977578bd97d979c9b4b4ff8712", + "kind": "execute_error" + }, + { + "hash": "3844e23ab9aa1752fbf2ad27f86d46e4e8317b7de41e00f30e18e0668d31c607", + "kind": "execute_error" + }, + { + "hash": "93b796e778bca39ba22c2ececf69da93195a5b61b441b5fb0b751f677d98f8d1", + "kind": "execute_error" + }, + { + "hash": "11b9f58d51c888c2fa66f4ae83b07d2af22f634e94fdaa4510e08c75e457a0c1", + "kind": "execute_error" + }, + { + "hash": "01492c4947c66da9aacac1577186cd826061b60a8675b3bb42c981998dfa7894", + "kind": "execute_error" + }, + { + "hash": "86b885b072c815352fcb061410f41c711f7bfc3f9810e94f72c7cab6624bdfb8", + "kind": "execute_error" + }, + { + "hash": "9f6bfda975c0c7378fdedfc27d142b0bf80a9a93a94d10503c6ab0ca6373cf2f", + "kind": "execute_error" + }, + { + "hash": "16c3effc5f8abe72e61a7921ed4f78cc5118c8565859a900de01e5daba69ec03", + "kind": "execute_error" + }, + { + "hash": "538c5aae2d6f53fdd044f12c98517517e0e4f8fea3eabd9799ed29c9d4ddb714", + "kind": "execute_error" + }, + { + "hash": "1121581c0f2823f5455773b2e3a95ce464675f90531442dde81215eb16d42d32", + "kind": "execute_error" + }, + { + "hash": "d17e2771089f26f468424e1109d1894e40d3462ae356534a5cc5e1567b1f0863", + "kind": "execute_error" + }, + { + "hash": "c67007a4196741aab93bd6636ca263ca6ad818839a157a70013eb8de7b0d6dba", + "kind": "execute_error" + }, + { + "hash": "df05f5b2d64adf552b2ced4cc96d1e6849fe6f33ed1591041ba56acf4bef1b48", + "kind": "execute_success" + }, + { + "hash": "c2ecf12affc4bc76b9f22b53dfac99e2cd95396db58fa5121644ba242268651d", + "kind": "execute_success" + }, + { + "hash": "360e1c7d00eec1a50f4351e88b42c9d0a852588138df92c98ecb347ef296344d", + "kind": "execute_success" + }, + { + "hash": "706159d767032bf836a22b5131cace0324f145a9ee284f054c21da2d2a25f203", + "kind": "execute_success" + }, + { + "hash": "0a234553ab2280d23bb547424dda88fbf5a4c55f4cea2dd03569bf75b61f5986", + "kind": "execute_success" + }, + { + "hash": "8ec432a909a887283d859c8c89dbce192c5ddfcd82134651c54c028ab185a932", + "kind": "execute_success" + }, + { + "hash": "a870f3112fa9a8395ccbd00c60a798e9f07b7b27c76a50d3b02e3945ee881ce0", + "kind": "execute_success" + }, + { + "hash": "27d3f78db23abe412b5dd1d1acef10b895713bec735e3d6ebdf6fcc51733099c", + "kind": "execute_success" + }, + { + "hash": "9b60eed6de2972287577e83e5d72c2a411fb434544050dc5b5fc8f90e5553282", + "kind": "execute_success" + }, + { + "hash": "edc85dc0b70d4ec31241c554ef5ce5b6a9662bb54897220f3e608696452ed44f", + "kind": "execute_success" + }, + { + "hash": "42180269e0d6264399838a3f4921be3fd6a01c78accca73a4055a85a196fd4f8", + "kind": "execute_success" + }, + { + "hash": "364c27c954bb021001cd5030a1cedcd599813648c22e6aa52a14e883f35d7dbe", + "kind": "execute_success" + }, + { + "hash": "7a24596e5a0c0bc0efb8409a3332d1694f8965b21da208e30ddc582569c4605b", + "kind": "execute_success" + }, + { + "hash": "7e9c2f54e00aae887172feaa06449d1d660f0a509d12da4377b87febe74b9e5e", + "kind": "execute_success" + }, + { + "hash": "6e4cf787b8de5067c7fc455e89c5097406c3949424fcc0eca7be718e091827ea", + "kind": "execute_success" + }, + { + "hash": "594d3b61b8eb89bc08cc6473fbc6f14c841564011da3c4bc0c5b629230335de0", + "kind": "execute_success" + }, + { + "hash": "1cd28dd097ded397b5ef9b6c1fdc8c6fda70d982388e059fefef027286fd6fb8", + "kind": "execute_success" + }, + { + "hash": "d7d405a7342c4b69acfdf23f047be3fde247929a8f07c046dc93ab5155c7e1ae", + "kind": "execute_success" + }, + { + "hash": "ed06417c60950bc79c225ca42684f11df68a6731ba70d2dac196abcd19f0d54e", + "kind": "execute_success" + }, + { + "hash": "1c0e7138bd664a5e3d2d7b43d79f6889e83aa2e0f06ed2f4846901cb3f07cbb4", + "kind": "execute_success" + }, + { + "hash": "61825310d540c16aeacd189d1daec058f415d928a1f1200ec1e976d275854606", + "kind": "execute_success" + }, + { + "hash": "b111336d5cb85625e1814a6d3c45416afbda29732779188d3514482a433dce0e", + "kind": "execute_success" + }, + { + "hash": "374ae8291a78acf906465627e8ddb87217fbbdcbefbb88c7af96ca22d883fd01", + "kind": "execute_success" + }, + { + "hash": "205aaa423528ddbf5da746d6f3aeb3b2b6d76551528c70574387720a76ffc2c5", + "kind": "execute_success" + }, + { + "hash": "5d5f709b83fcb72554bd65b778902f3efcf6e784f471c3997cb21db4935425a4", + "kind": "execute_success" + }, + { + "hash": "85de0d2c5e6470f28deef21fda4d58846ad737d1f036dd224eb58520d8b8d86a", + "kind": "execute_success" + }, + { + "hash": "2281440b1ead62eacc014e9b65c581cc5bd725e48bc767e1184afe28565f2a9a", + "kind": "execute_success" + }, + { + "hash": "94d12a1eaa9e90e59a0c783a3fc54d7eca782e6fb290b65c4031fccbbd791f91", + "kind": "execute_success" + }, + { + "hash": "26f9d72cb295ef99564c3fd9ca7bc0c68ccb42b913573ec737bf4528bdd04b70", + "kind": "execute_success" + }, + { + "hash": "6959963dbe87358dfd626df4491dc20c6a530ff751f1a4e33088005b7a9b8113", + "kind": "execute_success" + }, + { + "hash": "41b5a4d57dadc163589a9d9d337ada891b82a1990b88b5d91392b1363a12e0bf", + "kind": "execute_success" + }, + { + "hash": "92cd54ce7a32576fa0b3c2b2f434b303ecd5ab5d9f165d4c14ccc5bdf9ca5a33", + "kind": "execute_success" + }, + { + "hash": "812d87b0a0f8b0b5e4a238c93bdc092483462a2fe026b2f619dbeea763c1f3cb", + "kind": "execute_success" + }, + { + "hash": "62bd26dad6dcd1f6819c71526dcc002f820b6d6809d0b688acfc28e5caa7a7e7", + "kind": "execute_success" + }, + { + "hash": "2d8dced5f40343678d1dab342d9d731f7a5a5f7df4b9ec5c3e8b7202885c0b15", + "kind": "execute_success" + }, + { + "hash": "e9a9bcdbd0e3f2edfd1c7fc4ca340de87a53eb9f65ca5032b281c7d8c52665b6", + "kind": "execute_success" + }, + { + "hash": "25b2bc58dc803a372a5944683a2316130606f8963fddd0c36d07f7c5304b531b", + "kind": "execute_success" + }, + { + "hash": "b30bf6bdb41aa6b914276f86ede06c114e10ea874a6113819abfe5bd11c803b8", + "kind": "execute_success" + }, + { + "hash": "6afbe78ffad9709116a3c13b866f9ac1abf2c1fb63becfac61508fe944edbf2a", + "kind": "execute_success" + }, + { + "hash": "3db15eee449a6b75e3a6d0a067e28e6f9dade8af61deee56cdfeadd83fecbb61", + "kind": "execute_success" + }, + { + "hash": "c2e56f7dfd4a0cffbc2acc8644c3addaf84930827a2c7ab5e4d51750470fd04c", + "kind": "execute_success" + }, + { + "hash": "4080aaa1d077cee69736171bad4fb330f30a5add4e4cf43719a574cdbb79ad54", + "kind": "execute_success" + }, + { + "hash": "ad18f41dff7343f0d4c040107e68302246c96347bd98ca2b6242523b5707ba5a", + "kind": "execute_success" + }, + { + "hash": "65a4681c196fdb0a81618cf8d8ae0641eb728a35899230b28a7875ee5af7364a", + "kind": "execute_success" + }, + { + "hash": "8481b9987c68dd2f65383330726fe25af7cb894cd038897e55764b624892338a", + "kind": "execute_success" + }, + { + "hash": "87ca54604ef50e981212399cc83b24437e827f116435c09e8e661451fee6f0c6", + "kind": "execute_success" + }, + { + "hash": "4cf1f3abc348c26fbd96d15295d5fad9157ffa905003f58dd9fe7d2128bd2c15", + "kind": "execute_success" + }, + { + "hash": "9d7031736f887bbd8f4aa959be59248fa199562cad42ef4f5ab40f5ecac26c40", + "kind": "execute_success" + }, + { + "hash": "499c80016698de1d66b02384c7bb830c64d2b5f0195fbd43303122541d33624d", + "kind": "execute_success" + }, + { + "hash": "31e045caeab51cff766e9d8121f84070be18edd13e90c944106520ad306b94cc", + "kind": "execute_success" + }, + { + "hash": "693ff7fb69efd5a6c757c3eb3474f3fdb34c693d0196f5a90a6c7755febc9d40", + "kind": "execute_success" + }, + { + "hash": "15066c6efbf3e736693a19be8602d865711230b5ce345bca87044c4637b0e896", + "kind": "execute_success" + }, + { + "hash": "2f9302a04aab8e163c80e8384338db91282be36fb69496578a1ae3e2be821375", + "kind": "execute_success" + }, + { + "hash": "4fc6162f7fc7ab33945abae1ab35b963e0ec42aa17a571b88161bee0272966da", + "kind": "execute_success" + }, + { + "hash": "73f97df9ca521c3b5e33c0eef3a42b4a505d83d6f95bdb4490ee48b473deb54d", + "kind": "execute_success" + }, + { + "hash": "2a5b691fbd502dbc6f464662ec5c6e85e11d7c17f2e4d7b6903b727a54b5f755", + "kind": "execute_success" + }, + { + "hash": "21b49da95473b9eee8475f2248881e42bdba61eccd1542c4a224d71e71f6c100", + "kind": "execute_success" + }, + { + "hash": "de2295442a923d4eac54645565c8888e7547a8d75419c485cc8090c1a378f179", + "kind": "execute_success" + }, + { + "hash": "81b79bf2c5ac00239e538b690cc859dc1b30d44c9e973615bfdb917b4b941b92", + "kind": "execute_success" + }, + { + "hash": "88c4310be85184a7ff92e77a85a2ec572eec3f89cd2e0e94a633fd5c4281ebd1", + "kind": "execute_success" + }, + { + "hash": "f36a2856354e3f5b1a0d53c0a90febc4d834ea3f9c42823c00703150dfcb7d07", + "kind": "execute_success" + }, + { + "hash": "457c9bccf7a469ba3ac12c44ae6f2db19bace39aef2cbf488a6d86870ce18a81", + "kind": "execute_success" + }, + { + "hash": "a44d892ba39984cf7bb1d4e7377e5319c3f3d96ee84767ad64efebaadf0108a4", + "kind": "execute_success" + }, + { + "hash": "3369d0756e8f664de73fc294594ed28687bdbd6e1f5a5ef4bc8d6241a4ff6864", + "kind": "execute_success" + }, + { + "hash": "e7b67eaacd91beab8ea5321cf34e0cacb386ff71377253980d62863d0f62714a", + "kind": "execute_success" + }, + { + "hash": "5adf85873e15aebfd1e20949ce465154f228e0aed62278aa7cd69502c6c4cdcf", + "kind": "execute_success" + }, + { + "hash": "2288e05c9df53577df01cf89f31b221bd6665352ad2c9f18c2af66caac69819c", + "kind": "execute_success" + }, + { + "hash": "d11b1afe4ff0695e43fa4fc51e815f5dcba2ec6c37cf12c44e09eea031498f5c", + "kind": "execute_success" + }, + { + "hash": "2c9ec1066510a0c2faa8101e88d3ffcdf90a01630262f202bc546e45fee034ad", + "kind": "execute_success" + }, + { + "hash": "5c9fdfdeadb58a1631ea6911811011de62730400ea06aa89ebd23b5414728944", + "kind": "execute_success" + }, + { + "hash": "7dbcbb198c58ada892e7046749227447ee0289f6acbbc74f2b9ff85d455dbe16", + "kind": "execute_success" + }, + { + "hash": "13e8e0752b96abf4bd1add3bcd9fd0b89e6d2fe99b0d5f1914b2ee66b81e363c", + "kind": "execute_success" + }, + { + "hash": "8073a2f1fd4bf0c0c0ce0d2655a2289fae4ba53866754dfb4e983397c5cf484c", + "kind": "execute_success" + }, + { + "hash": "0bcec673ab2ba90899e288a932120436158448325fb395315e4a75f7332a7337", + "kind": "execute_success" + }, + { + "hash": "8ab459321d3a89e9e2bd0024a385873a7084a4834f1c61a23b87025f9ca7021c", + "kind": "execute_success" + }, + { + "hash": "4fab1a539f1a5ef1a414f0720d30571a115478e0d2d55d7bc03ee3b5e13fa524", + "kind": "execute_success" + }, + { + "hash": "e898110254e82d5cef61c4670ae01e1fb5e99158c2da43d83c8c42550cb84b26", + "kind": "execute_success" + }, + { + "hash": "04649c059699e238afa1c5e6067149a211520dcbd756faf6dc9a1c9fd1eb7d9f", + "kind": "execute_success" + }, + { + "hash": "095499040a44daf1691cd7c2b825d423c154fd6286e0130d8688b48d9fc23b93", + "kind": "execute_success" + }, + { + "hash": "ce7a7e464265dd9f27cba0dfa4b76e04e8c6c6f9135b87425cedab244a4b61d9", + "kind": "execute_success" + }, + { + "hash": "7bc788aa7bacd1a90db7a0d73846a9f913c51a4302dfb2283ff547e1744c33b6", + "kind": "execute_success" + }, + { + "hash": "91a36beadc46adbdf2ad936c0505c9c6b7f80b153d7047945be18dc30ce2baf5", + "kind": "execute_success" + }, + { + "hash": "1f43d4c66a74b8b45e0101787ea222cb5f55e3a717a795df3ba191e207d05fe7", + "kind": "execute_success" + }, + { + "hash": "5d1d3bd5f3a6227514afd936d4b5c183643e033d7e44408d77ff7ab7f3b67ab7", + "kind": "execute_success" + }, + { + "hash": "17c19878986d10810abf36dd66f4dbbf45a448bb8b79c3aa4ca940769056063d", + "kind": "execute_success" + }, + { + "hash": "1ffd7e1b03cea649054b5cf87ed0eaab26e67f43070fd336f40de702332768b9", + "kind": "execute_success" + }, + { + "hash": "0cccf65f432e81b5e5661ac20d55193035fd967feb56c75371ff3a3dc7342699", + "kind": "execute_success" + }, + { + "hash": "31a898505869c454e02a74757027e272d6a78d36ef0ac145243da9332abcdb45", + "kind": "execute_success" + }, + { + "hash": "564705d7a68226cbfd673aa0e405947b186c6e9dd63e1febc325247fb0d9ae44", + "kind": "execute_success" + }, + { + "hash": "1d3430c826526f2039d1b2713a026a3c744bd8798bc99a00843d0cef076a221e", + "kind": "execute_success" + }, + { + "hash": "1d4bc3b67a8cd3a98f8bcad61d43e7594f199ce24202adf2772406949667c963", + "kind": "execute_success" + }, + { + "hash": "b32a34df553cab7dc53258e8ccc5a9de80ddb70798b856869cced8945b9970ca", + "kind": "execute_success" + }, + { + "hash": "47646e316f0921c059e653530e0b0f2b16393408e32cdee177a04e7e67029b77", + "kind": "execute_success" + }, + { + "hash": "e6bb28603850430eab3c3374a5669760cc2beca60aa47329655f198adbecbd8f", + "kind": "execute_success" + }, + { + "hash": "511dcc34751c5a77e3fcfcceafa7bbd1a2987aea9c80275547b498df4d191519", + "kind": "execute_success" + }, + { + "hash": "16c8e35894f150e77062157f21a8a59841ca568e7d7eee119a9e4aea935050ed", + "kind": "execute_success" + }, + { + "hash": "9b3fc383028dfe8e7aea15177c390e9e6271f728c926ccd59d276aa73a31ee29", + "kind": "execute_success" + }, + { + "hash": "30b8c7d22bafb98ccb18a887d8db306708779c2e50514aa9ff8ab10ef7bde4d2", + "kind": "execute_success" + }, + { + "hash": "8b36a0544f327e661ceaab5bd67f6a0e50b2963193056c657a06a32cc1b4d0b1", + "kind": "execute_success" + }, + { + "hash": "4945e3163500fe0e07fdd6ca13737e59b5e5ec7a79828a243dc6516b7ef54b5b", + "kind": "execute_success" + }, + { + "hash": "0ce28aca02381c518b0689073d0941fadd7319b2c28a1bd5f3ff24be5cc3950d", + "kind": "execute_success" + }, + { + "hash": "5d0a2d10853d81dd32d4e1d9961b04ad23f900031519eedde152b6a204c41311", + "kind": "execute_success" + }, + { + "hash": "3c930bc5829e278ad62af484ab61840dadd16897a73b6a0fb530491cf2ffbb89", + "kind": "execute_success" + }, + { + "hash": "ee8a0325b5cd8514971e1ec538efb13edd5c429a3fff4ac0efac5dd887f58e67", + "kind": "execute_success" + }, + { + "hash": "4581c4d92d9276647ca370a1c3e050ce1bdedb7cabb87f713cadcb206356ab47", + "kind": "execute_success" + }, + { + "hash": "b7afcbf345acf717341223e7910e30af90ed25be643d1407aba1be5e17f2736f", + "kind": "execute_success" + }, + { + "hash": "36039bfbc97ae9c2cc7da8e2b547a7664761f1403dc4fc2c2560e50f49ed5c5b", + "kind": "execute_success" + }, + { + "hash": "006cd26b543f2cf28c21141861b23a0bbfdc59b86ef280e4760fc957331866f1", + "kind": "execute_success" + }, + { + "hash": "044a03f7564aa59e6698cba636207df2a0431dca7c2be38bb9f89182c8a7a8c4", + "kind": "execute_success" + }, + { + "hash": "ab02b362b639a403d204af10df9772e022b884c1a87a22e52a1cb25be0ca7694", + "kind": "execute_success" + }, + { + "hash": "d499c65f320d5eb866c0e170aab97640b6c7137599d337497cfa835cd0690b53", + "kind": "execute_success" + }, + { + "hash": "a941a95f8e8dbe2ae5e8bc654be778d871dceae0143b3f598bbbf780185fce9f", + "kind": "execute_success" + }, + { + "hash": "b4d1531e2e2a881bc01dab795e81d69fbf09963cdc309c9a64774b1234795d64", + "kind": "execute_success" + }, + { + "hash": "141ef8f6b3eb6a3568917304a7da9aa0651738a0180e1eeb517690f89f3fb101", + "kind": "execute_success" + }, + { + "hash": "0bd43cf36031100a25589496c832cfc8f97fd1058295f99f7dae4c2fe06a9578", + "kind": "execute_success" + }, + { + "hash": "ae2cfe022d49e74e999cb09f0fc21326ae374419f5eef2be4101e852afba2942", + "kind": "execute_success" + }, + { + "hash": "0f635385443a3b8e063f1e3c6ab0e022b98408291c641907e1f08f45483841ee", + "kind": "execute_success" + }, + { + "hash": "312c2e9769cfde2b2d87e649db62dd0838a3259e276d22b7e0627613d684a286", + "kind": "execute_success" + }, + { + "hash": "2e79d801f82ff552ab9b907f4be18a79c3a631fb20cd21e96efbd7df61ce9d33", + "kind": "execute_success" + }, + { + "hash": "31f857deb336177870d348f988ca9ce08443f6676f9c12bf70804cb3e8ffbc1a", + "kind": "execute_success" + }, + { + "hash": "2c77d5694dae4693d48373e44a1b54069801c74fbecc1a92e1c772dac65ae192", + "kind": "execute_success" + }, + { + "hash": "bd97b0b021cd43e3f3b17b46c7bbc91941922576d6a0035c56f485f8dca673a0", + "kind": "execute_success" + }, + { + "hash": "71ef247248beb54e052d470a67cf0466f915659645fa0b88ffc883bc6cc7d348", + "kind": "execute_success" + }, + { + "hash": "a9893551d99634e82c6b292aa3ea1d296f3ecbe3e46dbd6a040baad43bc79ea1", + "kind": "execute_success" + }, + { + "hash": "dab652178d7ce38eeb27f9597ef9196f00ddb1e6f589c1a1b88b1c62526065a4", + "kind": "execute_success" + }, + { + "hash": "7c4cb7403f20d45d8b696110b406691c57d03cd4380340b38d19c7c6f3842bba", + "kind": "execute_success" + }, + { + "hash": "8ce35601a5863b6dc9d57e8b11ecfd776181392208d752e0ab9ec4dd57d8d5ba", + "kind": "execute_success" + }, + { + "hash": "14c74f2fac56db3241fb9a83ea45828ca0b437c6ca7962896111a7e309bfefa6", + "kind": "execute_success" + }, + { + "hash": "6f8cfbbbfb3fd1b0d060c5825f804bb5daaf0dc06407fc2fec82e24666fd79af", + "kind": "execute_success" + }, + { + "hash": "3bc9485dd306dfa916b85e24fa8d654237afe1db49296412681c2cfabfe08451", + "kind": "execute_success" + }, + { + "hash": "05973e08f327b7dc89dcea8f3bf8c8f0f62d89cc4d9dcbff6f9411d9b875ccd8", + "kind": "execute_success" + }, + { + "hash": "3cd5fb2a9a1b9c712eb5d6a2360258c7b0d2ae1a7d854e5bd77e24ea286d74cd", + "kind": "execute_success" + }, + { + "hash": "44b87f2434c2710d16fa39d33bbe1b85acb24c148b3c3ed98e2b433b954e7e70", + "kind": "execute_success" + }, + { + "hash": "1f646da048ae6feb8fd103c1abc690928a5fc6cb55b9ec153254e0171ad924ec", + "kind": "execute_success" + }, + { + "hash": "042130ba29710fa5f7a333474ab5a1c002a04623dc1b48a0d7a676a30f9c0ab2", + "kind": "execute_success" + }, + { + "hash": "0411d97571bd190f42a8e4805ea69d0de86d45a61e4b4616116b1510125d5678", + "kind": "execute_success" + }, + { + "hash": "4d763596acfc877e1ad180d6dc5cf8ec3e48339008f7c635b2cefe55f48788f6", + "kind": "execute_success" + }, + { + "hash": "0ae8b8dad22b8d248d77760b76e4ff37827fface6421e4e3a53c8839e5919f50", + "kind": "execute_success" + }, + { + "hash": "c7767113bbaf453a1a272332abe65d898820ba8ebf539bdda914107f303c436a", + "kind": "execute_success" + }, + { + "hash": "2e7854b1df1f1e972423019fe5e8f2b70b401e0d1282950cfa78417c80affeba", + "kind": "execute_success" + }, + { + "hash": "8200938770bb99ddd23710942e9e6298ca30a1a0db02587434f8a6937cf5297a", + "kind": "execute_success" + }, + { + "hash": "65c917f8b6ee4b4430c9009d326fe0f3561b4607ccbd104cc79e20328060bf18", + "kind": "execute_success" + }, + { + "hash": "be16803ba89cdb4ab372078e6b9892a5d942bf84a006a12108d7e210baa5df3d", + "kind": "execute_success" + }, + { + "hash": "122a1eee22c2930ba6a176869dfb29ca09c17bac6569580f75b0c6f0035840ac", + "kind": "execute_success" + }, + { + "hash": "d8c6934579d3ebc0ab6521a8e6b23cf25d22a3fa86298d23f060c47eb44dcaaa", + "kind": "execute_success" + }, + { + "hash": "06a3232385608d1ca2217c617edc25ad98ed8da029e08a2bde74b9ab2e013a05", + "kind": "execute_success" + }, + { + "hash": "57968f93a5669fae3546792110927ce057653f669e3a333dcab86082199d0bf5", + "kind": "execute_success" + }, + { + "hash": "d64a3c31beaffa5cc94a8d0eca83caead8b36dd5deb869525d5c04e89992ccd5", + "kind": "execute_success" + }, + { + "hash": "20bfd6dd51cdd509b4c978a38eb985f436852f26a8948f34872fa652b4cb78b9", + "kind": "execute_success" + }, + { + "hash": "3e7dbc0f9430094cdda31b399106a681b8c5a70211228320bcee7b82b29af61e", + "kind": "execute_success" + }, + { + "hash": "3f5d52eaaea8e98cb664dc6a1b523de2bb7334ff46ee8a63e20ba437219f4b6d", + "kind": "execute_success" + }, + { + "hash": "5375ed93e914ae544084f9306bbf2dd33dee6d6162fc45e77258312240c0b232", + "kind": "execute_success" + }, + { + "hash": "1374fcbe819a22f4d187e791adc03449cd6bfe9468c15275ca8d16e3aae231e7", + "kind": "execute_success" + }, + { + "hash": "7817759ff3a311ec0ed176b6f2d83c8d49b06fd6e4f90d5fe8a702bcf5b06376", + "kind": "execute_success" + }, + { + "hash": "150abbcb2f06cb0f61fc36e588f5b24dc7e73d4b90f2dc51c9671176f92a3105", + "kind": "execute_success" + }, + { + "hash": "6acab56e0e887b80282ae49517d505e8c55c1b8f8bfcbd1d788873544f8758a6", + "kind": "execute_success" + }, + { + "hash": "17199a9e41eadab8f755625641e854dc1d52baf58507df7f9e02d56d647d9cff", + "kind": "execute_success" + }, + { + "hash": "707a31e2ce8a6a492e75997a2a092f5a86afef55213790c5db1df07dde97ef7f", + "kind": "execute_success" + }, + { + "hash": "88beb29a24c1268a56e493374e1a75c6f3efac8ed9e32835c79ca3cc42c6cf05", + "kind": "execute_success" + }, + { + "hash": "311136c571c630e7691e3fb5cebbd66f420e21964c57d9bc0b051f4f19708056", + "kind": "execute_success" + }, + { + "hash": "178ec642fe4418e1ffe49d9f4898dcf997429ccdcf958cc9ecdb4809f653fd75", + "kind": "execute_success" + }, + { + "hash": "72af75f8b94304e2af9f133f652c7c76a21a3b08393c2ee685a184a79ea2b9ec", + "kind": "execute_success" + }, + { + "hash": "e80a1554016db879646d90a2166d5232741457429826395733d985a8592e0476", + "kind": "execute_success" + }, + { + "hash": "86008d7f91d825cfa8defda7a26f0b750b82f206efe09cdf71a254c3dd9fb301", + "kind": "execute_success" + }, + { + "hash": "028adeb8010324c5d773c0cf085682ad8f352f292693fd42c8e72b44bbb68bf7", + "kind": "execute_success" + }, + { + "hash": "79f380621bcf36c312a387bea5a7c02b3e5ee094bf1faded8f0546401b9da886", + "kind": "execute_success" + }, + { + "hash": "2067de3889f967b2d72a102badbc1cb90ef782a833d7cc4890c90d1798239f4c", + "kind": "execute_success" + }, + { + "hash": "7c62752513bb037292be4afb99fbd445a3498ee98d568df1b3cf70b1c359f0b0", + "kind": "execute_success" + }, + { + "hash": "5f1947e35371d294d564e1d6b8ddb37583dbdc6365c2758969f936274869ada1", + "kind": "execute_success" + }, + { + "hash": "8119539adf588533324bf05104d31198589d2a7571a790d5d99834fcfd427886", + "kind": "execute_success" + }, + { + "hash": "48fece32c2ad9b42cdab4badd9b987ada56b04d445123bdb35af7394bc620cd8", + "kind": "execute_success" + }, + { + "hash": "5a05d641134878bcbb64c7733e487951d2d6cc1a122ed544b12514aa46256e93", + "kind": "execute_success" + }, + { + "hash": "acb4fe768721b45afae597d3567ba672136579932045e055f292b7538d273ebc", + "kind": "execute_success" + }, + { + "hash": "0181847db8e15cea97c95ca64299846fe69d8a93a45228dd9365a072adaad07a", + "kind": "execute_success" + }, + { + "hash": "298c46fc834a91005db5409b6a503507aca5704f05cee44fa4eb6f83efd721ec", + "kind": "execute_success" + }, + { + "hash": "3658c5d3e92f10fbf21689ec8bf000802b21f198d5e4a08b55f9a0a2b2d4f10f", + "kind": "execute_success" + }, + { + "hash": "027fe7415281aba9ccdbd04ef11402a919f0880e9c261464ced226432b807719", + "kind": "execute_success" + }, + { + "hash": "04660402ad6fb8ae0fef8da63955783534ffba85c0d5dc3797d4da54b43e0254", + "kind": "execute_success" + }, + { + "hash": "6158fc2a139db736872154e9233c15cca01a5eef1479ab2e8b2b8e6c7e46f79d", + "kind": "execute_success" + }, + { + "hash": "1bf938aa71cd76d61daa96ae107001f84e7dd9fe549f1198bf5bee19ba70e36f", + "kind": "execute_success" + }, + { + "hash": "340ab210d02d3f720886831de915b5298a1322adc53baf64220cdbd2501055c9", + "kind": "execute_success" + }, + { + "hash": "e7d92d548433f054e5de65acc4ca5c3b8874066da918c9d4a15156dcbb9e50bd", + "kind": "execute_success" + }, + { + "hash": "1d3d2a22cc50f1b75ad3826ed57383bfbf8b847ef4f976cdfcac097379a30fa1", + "kind": "execute_success" + }, + { + "hash": "b86db53f4e02a2922846d332162dc7512b4012b845a00c4b1eceb7091bd111a3", + "kind": "execute_success" + }, + { + "hash": "02824bf7722a32ff5a7cd611d599a11522cd6bff6d4f0ed500b1f304d6d12124", + "kind": "execute_success" + }, + { + "hash": "74d6a8d554f431ad0978b0703fc19949d4d128798e7b6e62525bbb58f0fecd28", + "kind": "execute_success" + }, + { + "hash": "4a8e3854bded5a120af22a366996f926e7ab54e9f0779c6e6c007da7571c857b", + "kind": "execute_success" + }, + { + "hash": "204fa454d9792bbf6490cb24fdc34d1c7c1dcedaf8bfd9924d75c686cb1ee7e4", + "kind": "execute_success" + }, + { + "hash": "699de01db2874f09cba061b68153851f506814bfc8d1e5c641e2af79da89e9b4", + "kind": "execute_success" + }, + { + "hash": "4964d52e4e78305411744e836aa54fb3a2e117e20cb1229ba8b23dbacde67404", + "kind": "execute_success" + }, + { + "hash": "6073714712df3e528abedc76ccdfc4d60b6b2d50ab47e7b782338dd59816b439", + "kind": "execute_success" + }, + { + "hash": "68c97bc446ac9e52e078cdfe9164abfbb83a3ce66a8a02dbb998dee6bfa3e8b3", + "kind": "execute_success" + }, + { + "hash": "c5c11f18a6f59375d20b588edc480bafb60cc20de983c877268cf00e49e22541", + "kind": "execute_success" + }, + { + "hash": "618958bf107a4900b7d284f90c218650236ed69cbc4366e96c96a665639be36f", + "kind": "execute_success" + }, + { + "hash": "8864eee44b8b0c1e025f785a5451a9a9161987b38c0efd05ebd7082f42b812cf", + "kind": "execute_success" + }, + { + "hash": "0efe7a00fe85df7da66d14ffef1875b483bb0acf60843c808f3e670fe6adcc68", + "kind": "execute_success" + }, + { + "hash": "5c99bceaa089038e88dd94a4d71306f2aec60570bd2131cea7cba85d1a67de05", + "kind": "execute_success" + }, + { + "hash": "675f4f931f73a116123d1df0d6dc7f913efaea33127a7bb270feaa7b390e218d", + "kind": "execute_success" + }, + { + "hash": "674921d892dde7ce4980f64a8fa0acd9a1cc7b5d7243228c8604b3810017e6b7", + "kind": "execute_success" + }, + { + "hash": "0790b5461ccd479a5291f876feb7e1be66309f9505bfdb7a2b286bd4142ef0bb", + "kind": "execute_success" + }, + { + "hash": "24638a0b371b71c64ac81023ed37b55eed5e5e4dfff06aa09e7c8541c4704c7c", + "kind": "execute_success" + }, + { + "hash": "11d3584e02ddf0c16cf5bf0730779d09759cae3eca4ec2646e5de3699d7d8247", + "kind": "execute_success" + }, + { + "hash": "3f2f5f77aadc625fe093ce6cebb8e0e4e7656fbea098a27809105bb10ccadfa2", + "kind": "execute_success" + }, + { + "hash": "2252e810d77eceb04997c2637d1b2701fb189cd7509efceab3a5ae003616f159", + "kind": "execute_success" + }, + { + "hash": "166dce54fb312b6ff03ec1e4f46c3d86aad44df029b0c1d425fb5ed0e879e88a", + "kind": "execute_success" + }, + { + "hash": "1013420107316c6977e3a19a21cf3a3bc4c1e37b53edc716ba373273bfc2301c", + "kind": "execute_success" + }, + { + "hash": "2528a22633376342624910b7541932dd52882215467dd30047f8ea05523c4abd", + "kind": "execute_success" + }, + { + "hash": "6eadd6fb6f9ba84646ec6791d1b384f4e45913d459bdbe5129836ac62f67fa1f", + "kind": "execute_success" + }, + { + "hash": "3cfc1402997663039a018880ed7041a34a81e68bf200ae34c9a7acc0f16fb229", + "kind": "execute_success" + }, + { + "hash": "f74a200dd10a475935c8010a2af82903f65100bf5c7085e664d4d948cb1d0f08", + "kind": "execute_success" + }, + { + "hash": "2b9ec9aab5bb97c08d03db36e68778d3be9b93edb19d1ec317ee7fa48d85d12d", + "kind": "execute_success" + }, + { + "hash": "010e1c091eeb2e92be596c2c5e26895855881677256d825cd61212841eb22f64", + "kind": "execute_success" + }, + { + "hash": "d0ca86cfe077be2abb8807dc2437d3b2e45a5219489609faa12fec3e7d676eb1", + "kind": "execute_success" + }, + { + "hash": "a62891995c290168d01da63d75ba023d2c158c5bd4dbc945dd9982c68dda2ac5", + "kind": "execute_success" + }, + { + "hash": "6e83a22cd4183a9c6d6c96c54509dd64314c372413feb8e57dbe0a7353b2b079", + "kind": "execute_success" + }, + { + "hash": "b3cdc3bd4ab8b77739177dbd217aeba2c57acfbb204a436b5aca645069304641", + "kind": "execute_success" + }, + { + "hash": "3a24d82b914fcdd4c99f97a3edf37c804fb7ce3d3b1901108b872e7f4fb594b8", + "kind": "execute_success" + }, + { + "hash": "41e4a8116d00ce65ce2d08192ff73c6f80caa4d44dbb26ba55fa679d60c51b45", + "kind": "execute_success" + }, + { + "hash": "0cfede7b9655e7588be8e0515d1f9b890c58ecb35537c78961c15520983f2ad9", + "kind": "execute_success" + }, + { + "hash": "540eaf12ab2e2738a6b83f44dabe5903e4a1cca546a6038b748e506d976d62b9", + "kind": "execute_success" + }, + { + "hash": "255f5e3a5cb82f25d5e39db02b0396d678b6f0add0dd460da12e2e49f9f24cdb", + "kind": "execute_success" + }, + { + "hash": "7ae83c16941362543846f6c5bcc738fc5030af88dad9833f5b204faf0932737a", + "kind": "execute_success" + }, + { + "hash": "457f1b8c4a575ff884a38de7d11c03279ed37fee70952a009c73934b8fc4232e", + "kind": "execute_success" + }, + { + "hash": "e1cd93a32a0f8814e320d6c8d60c50114716b9d7629af96f6f52a51d41af3f40", + "kind": "execute_success" + }, + { + "hash": "1f85271d44ac6395db92ef94970b636d4f412e11dc62525f3b302659bdd40a70", + "kind": "execute_success" + }, + { + "hash": "1fb0110eb854ea6a718dfcce3c2c74a82fd7078c3c9fb46ad8882ceb8bdab702", + "kind": "execute_success" + }, + { + "hash": "5bdc9adddb4709ea9cbad03e895e43ad2909b9ee0a56e9109d4745f435e2e7c8", + "kind": "execute_success" + }, + { + "hash": "6bc4166318467463195c33a8a996eb9c9d1452f2b585decb46c2e5d2c31e384a", + "kind": "execute_success" + }, + { + "hash": "e527d0241a008bb0c9f33584a49793303692b8a495a5af3ee4958629577ad9a4", + "kind": "execute_success" + }, + { + "hash": "c5777dd92d8de2fb834d00ebe39d45a164f38db6f203a88fd4a64d276abc41cc", + "kind": "execute_success" + }, + { + "hash": "681ee8547e5ea3ec5935982e23d75c31c36e60c0d25315aca8984d67d0406c07", + "kind": "execute_success" + }, + { + "hash": "165b4f5166718c87925b323d3f812dd8c7fc6277e5121ee29d3b8f99a8457c10", + "kind": "execute_success" + }, + { + "hash": "11ee3d11357f74fdb7609473bb32fcb21a5bab188e258b746bc7689e95f6d28b", + "kind": "execute_success" + }, + { + "hash": "969add538e5ce720f19b03dfc02117c34644a4c8801147fceb93329b7bf15274", + "kind": "execute_success" + }, + { + "hash": "456cd106dbc08ca27280f0de438efb4e9996f7220fe7533d2f7212af67f26383", + "kind": "execute_success" + }, + { + "hash": "73ed525888f134fb953229bdfc560510420c4b71ff18e00c72d07878810b46dc", + "kind": "execute_success" + }, + { + "hash": "a2cc80bed90d6dce461820ebcd934de7589837861910eb360aa7c96d2901d81d", + "kind": "execute_success" + }, + { + "hash": "fcb553b64b0c73c3f5b22dd831fde94f20496ab219da0fae2be3a72069b15980", + "kind": "execute_success" + }, + { + "hash": "37c6a426621b95be18e1e894f659bbd10a15e2dba32471a884e67a3f3edb33ed", + "kind": "execute_success" + }, + { + "hash": "bcf180c6400006ae1c71c46c1ff3344d9221480c811c5fd06765a7e2d58403bb", + "kind": "execute_success" + }, + { + "hash": "845aca234915e60dfcb3a089b7408c0961e19ceb17547e7b0d8a96a8696ad8b1", + "kind": "execute_success" + }, + { + "hash": "1394bd571c0843bc7d472696eaa76f093046cd7b5a6a876afadb15d10f97bec6", + "kind": "execute_success" + }, + { + "hash": "c14cff5371f95a893edc7c318c0e78811485960714730284545c32aa826bc317", + "kind": "execute_success" + }, + { + "hash": "f4b1f6fa145b3975e93c90ada85128400c21c16aa5be462a7b5b7f29b63e199e", + "kind": "execute_success" + }, + { + "hash": "373ebe64588bc0c1ec641986a206222d40edfc385902ee9181627b6b3ce1e89a", + "kind": "execute_success" + }, + { + "hash": "12e3b1af35d0ae533ce39c898a31f4b01c0ef3e52356aa5c05ee9371df21975a", + "kind": "execute_success" + }, + { + "hash": "099e46ee694a6410caed34a8b4a1a2f0bc5a3696c08d354f1c48a27d8c81ea23", + "kind": "execute_success" + }, + { + "hash": "a3e8e0c8c3a0a29f660ec65106dd63831db8e117fdbb5164daad7969a5606e3d", + "kind": "execute_success" + }, + { + "hash": "0bbfcd354a4ac1145ab77e6e3b42651852fea4b50bd6134697faf33be4eee08b", + "kind": "execute_success" + }, + { + "hash": "fc6bffbe05b92d760293cdffa9f920788fbdd4266753c1cf35859421a50512fd", + "kind": "execute_success" + }, + { + "hash": "41845acd2d829a5006c09fda1547e1544ef8a200a595e6646c58b747772a0fc3", + "kind": "relayed_error" + }, + { + "hash": "d0bc9eac018f0b04982a1531949c7c76dfb469bc546185e28f2d5bea217fff5f", + "kind": "relayed_error" + }, + { + "hash": "2f9a1a3dc200f0f3a58e16a304c5ab42a87c17f471b40c6f323ed55bcd30d377", + "kind": "relayed_error" + }, + { + "hash": "5d89bc3c5c009c060b5d1b58ad51323eb7d67f7d8e3072267d9d07f284baf7fa", + "kind": "relayed_error" + }, + { + "hash": "447e8a2b733ad1879038dbbf0099215e0e7c7a53c793700a43d5236ef14440f8", + "kind": "relayed_error" + }, + { + "hash": "2b593cbc897f05c24d016adccf38e9ea28611f38a6bc3e2d56f560cfa4163ce3", + "kind": "relayed_error" + }, + { + "hash": "4c1b4982c1f0da08f9a6dcf21a4b2008554cb550f343ee8961084247f2b1a3bf", + "kind": "relayed_error" + }, + { + "hash": "2c7a0afeba8476f4353a37ab1bb943c04019b8a3908727d19d9d124f16db57fc", + "kind": "relayed_error" + }, + { + "hash": "d1d93b0ae1e03aef5e0e0dc54a626e5e7a2126c54ff2ead5cbdd8a0de991c1e4", + "kind": "relayed_error" + }, + { + "hash": "1a6fdb15a626d41d9fbb8ab233c8a713867460e38b09f9f8502cd9eb4e6968ab", + "kind": "relayed_error" + }, + { + "hash": "b0103928c3787f9e8f68fa5d2f450f2d2f557c5f4e7ae6f435d8d2a14171fd81", + "kind": "relayed_error" + }, + { + "hash": "6948b41f72524b5a53ed0364c438307ca9911d362d8c5cb92a0c1fd47f14279a", + "kind": "relayed_error" + }, + { + "hash": "1010e5f6c2bb0f58e547c22b7e95a13b15214d9937536b95011759c255677062", + "kind": "relayed_error" + }, + { + "hash": "0a497462e74b94e1cd7e584561c7bad6c65fade8cd299fc346289c4a56f9ac9e", + "kind": "relayed_error" + }, + { + "hash": "684eeac92a0dafc8811da0409efe3c5956c8c9e9d16d10ce7699ac4ee43ee2b6", + "kind": "relayed_error" + }, + { + "hash": "d6d6e4c14303113749db9bb34595612249858f793410fbb5c6b73bb063e5c599", + "kind": "relayed_error" + }, + { + "hash": "1b682f8d6e8e854a9da1f74f48b97f1fdae36e763a72837e7a21f6e37791e5f0", + "kind": "relayed_error" + }, + { + "hash": "226b5643cf9e0860679a425c0ae61a098718ce85afde7a4d2ab30945da4d6202", + "kind": "relayed_error" + }, + { + "hash": "147507ae23dbd8610b48b4a27bf63e7761255f5611f1aaf35e0cda07e998ba89", + "kind": "relayed_error" + }, + { + "hash": "959d63d9698bf836dbdf7824ad3053ff284b5956230142ee26793aaf533f71bd", + "kind": "relayed_error" + }, + { + "hash": "6598b8e0dfbea3862c5098c50e4b89200d416eb70d4cabdec59394d54a2c31da", + "kind": "relayed_error" + }, + { + "hash": "dccc737552cd986eb881f7bcbfc557fcb88e72b6739ab1172ca235acf2c8ef98", + "kind": "relayed_error" + }, + { + "hash": "b709e543126d1cd60e29f7ba9b3d922e3550bbe2086a7c98b85ffb1b9e6a44da", + "kind": "relayed_error" + }, + { + "hash": "b9239bf5ebc3e28735b23ec7305c90d3283369803a75bd7fb80d0621f8cf04f6", + "kind": "relayed_error" + }, + { + "hash": "083bc32e6dd4664e3cebdd1224011632a7c24fc51e823e8b82eaef1005402009", + "kind": "relayed_error" + }, + { + "hash": "3dcb992781b6ae7323de9581165aadc4d3f5c63d55ea3560d2f02c86cb818df5", + "kind": "relayed_error" + }, + { + "hash": "a7c20ed14474fad25b3a2c089fae2a45a5c5d11b1ea7574de32542571b46440a", + "kind": "relayed_error" + }, + { + "hash": "6e0414891686baf7a21c27c24b09e16fe9c3bce040b1bb504a40f4ddf506f402", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "3206004a1366581669210845baa1eca90336534e391f81bd01dfe998da4cec40", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "c8c164f1597410abc8eae16b660e8d446423b2566d5a8b7617430e0bced0257d", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "bb9fb4ca0494ab060aa9ccaf4f24438d0ba2d09127178b97725df3dfa470c264", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "f7df0d7180c70b74706ec54a77c56bef02f86dffe5ac2367816b5537559a1aff", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "251c7805dd1004ce6f33a2932e237cc2cc41c945683100cd1c23f5de9bccd058", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "104187750797f102e3cd223f5a7e3f05bf31ce22606eef9c75318178eb8c6713", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "c4511ee6580b3460b0a80dad8514c0998fb006c7e5896831f307211360654c31", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "4c4327edcc77e4d8f3de27ecb37cdd898620a6aa46077d7c75b3b637c2d07a60", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "f3873ef6f68eab202b775a3b1bec603ceea138031819f290249ad4fbfbb24871", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "0209629e347c84714eeb50cb6561b5053e55cc504062eaf70cbfcac5e14f27b5", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "9f381f611328b20cce90d18eff81a7532451b858711892ef0e3c29f80d6dceff", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "22edc571dd43166a30c0af4182d69c2a628b2543c09724042b6680c0042e0a9e", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "8b3b99a33b1b47377fe2c699244c8c137716a1ca8e8cca7f1c48b32a77f0751e", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "53dfadaea88e58da21f698f10a1949cc51c4a2cc88a061474ff1f43c2190c752", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "080d3a888c140a1664da1f0df59e716da84e377d91e50af45cfd65695c28fcca", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "72736705d7cc350ba9ad9c6bd811e744a7c09ce948e2a3982475bc4adcc609a5", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "dc534504eb937a0aaac4189ad774dcb1cad32f72b35f31f77370997dc2e1c17c", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "122b1bfe8cd22e853708c130be8b8226dfd53380a4e3bd0a56faa8eb66bbe0f6", + "kind": "multi_transfer_too_much_gas" + }, + { + "hash": "a794915071d0924922546fabc67202a06e9d56fb64cda21fa8a235826ae2e3cd", + "kind": "multi_transfer_too_much_gas" + } +] diff --git a/src/testutils/dummyQuery.ts b/src/testutils/dummyQuery.ts new file mode 100644 index 000000000..076369df3 --- /dev/null +++ b/src/testutils/dummyQuery.ts @@ -0,0 +1,19 @@ +import { Address } from "../address"; +import { IAddress } from "../interface"; +import { IContractQuery } from "../networkProviders/interface"; + +export class MockQuery implements IContractQuery { + caller: IAddress = Address.empty(); + address: IAddress = Address.empty(); + func: string = ""; + args: string[] = []; + value: string = ""; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + getEncodedArguments(): string[] { + return this.args; + } +} diff --git a/src/testutils/files.ts b/src/testutils/files.ts new file mode 100644 index 000000000..51863430e --- /dev/null +++ b/src/testutils/files.ts @@ -0,0 +1,27 @@ +import * as fs from "fs"; + +export async function readTestFile(filePath: string): Promise { + if (isOnBrowserTests()) { + return await downloadTextFile(filePath); + } + + return await fs.promises.readFile(filePath, { encoding: "utf8" }); +} + +export function isOnBrowserTests() { + const BROWSER_TESTS_URL = "browser-tests"; + + let noWindow = typeof window === "undefined"; + if (noWindow) { + return false; + } + + let isOnTests = window.location.href.includes(BROWSER_TESTS_URL); + return isOnTests; +} + +export async function downloadTextFile(url: string) { + const response = await fetch(url); + const text = await response.text(); + return text; +} diff --git a/src/testutils/message.ts b/src/testutils/message.ts new file mode 100644 index 000000000..c115d20dc --- /dev/null +++ b/src/testutils/message.ts @@ -0,0 +1,21 @@ +/** + * A dummy message used in tests. + */ +export class TestMessage { + foo: string = ""; + bar: string = ""; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + serializeForSigning(): Buffer { + let plainObject = { + foo: this.foo, + bar: this.bar + }; + + let serialized = JSON.stringify(plainObject); + return Buffer.from(serialized); + } +} diff --git a/src/testutils/mockNetworkProvider.ts b/src/testutils/mockNetworkProvider.ts index a8e0a1817..988d693f5 100644 --- a/src/testutils/mockNetworkProvider.ts +++ b/src/testutils/mockNetworkProvider.ts @@ -1,9 +1,4 @@ -import { - ContractResultItem, - ContractResults, - TransactionOnNetwork, - TransactionStatus, -} from "@multiversx/sdk-network-providers"; +import { ContractResultItem, ContractResults, TransactionOnNetwork, TransactionStatus } from "../networkProviders"; import { Address } from "../address"; import { AsyncTimer } from "../asyncTimer"; import * as errors from "../errors"; diff --git a/src/testutils/networkProviders.ts b/src/testutils/networkProviders.ts index 736a9bedb..67ed2a4d1 100644 --- a/src/testutils/networkProviders.ts +++ b/src/testutils/networkProviders.ts @@ -1,4 +1,3 @@ -import { ApiNetworkProvider, ProxyNetworkProvider } from "@multiversx/sdk-network-providers"; import { IAddress } from "../interface"; import { IAccountOnNetwork, @@ -7,6 +6,7 @@ import { ITransactionOnNetwork, ITransactionStatus, } from "../interfaceOfNetwork"; +import { ApiNetworkProvider, ProxyNetworkProvider } from "../networkProviders"; import { Query } from "../smartcontracts/query"; import { Transaction } from "../transaction"; @@ -15,7 +15,24 @@ export function createLocalnetProvider(): INetworkProvider { } export function createTestnetProvider(): INetworkProvider { - return new ApiNetworkProvider("https://testnet-api.multiversx.com", { timeout: 5000 }); + return new ApiNetworkProvider("https://testnet-api.multiversx.com", { + timeout: 5000, + clientName: "mx-sdk-js-core/tests", + }); +} + +export function createDevnetProvider(): INetworkProvider { + return new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { + timeout: 5000, + clientName: "mx-sdk-js-core/tests", + }); +} + +export function createMainnetProvider(): INetworkProvider { + return new ProxyNetworkProvider("https://gateway.multiversx.com", { + timeout: 10000, + clientName: "mx-sdk-js-core/tests", + }); } export interface INetworkProvider { diff --git a/src/testutils/transaction.ts b/src/testutils/transaction.ts new file mode 100644 index 000000000..318b9a8b6 --- /dev/null +++ b/src/testutils/transaction.ts @@ -0,0 +1,43 @@ +/** + * A dummy transaction used in tests. + */ +export class TestTransaction { + nonce: number = 0; + value: string = ""; + receiver: string = ""; + sender: string = ""; + guardian: string = ""; + gasPrice: number = 0; + gasLimit: number = 0; + data: string = ""; + chainID: string = ""; + version: number = 1; + options: number = 0; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + serializeForSigning(): Buffer { + const dataEncoded = this.data ? Buffer.from(this.data).toString("base64") : undefined; + const guardian = this.guardian ? this.guardian : undefined; + const options = this.options ? this.options : undefined; + + const plainObject = { + nonce: this.nonce, + value: this.value, + receiver: this.receiver, + sender: this.sender, + guardian: guardian, + gasPrice: this.gasPrice, + gasLimit: this.gasLimit, + data: dataEncoded, + chainID: this.chainID, + options: options, + version: this.version + }; + + const serialized = JSON.stringify(plainObject); + return Buffer.from(serialized); + } +} diff --git a/src/testutils/utils.ts b/src/testutils/utils.ts index 76ef1b9f8..349e82f3b 100644 --- a/src/testutils/utils.ts +++ b/src/testutils/utils.ts @@ -1,14 +1,14 @@ -import { PathLike } from "fs"; +import BigNumber from "bignumber.js"; import * as fs from "fs"; -import { SmartContract } from "../smartcontracts/smartContract"; +import { PathLike } from "fs"; +import { IChainID, IGasLimit } from "../interface"; import { Code } from "../smartcontracts/code"; +import { SmartContract } from "../smartcontracts/smartContract"; import { AbiRegistry, TypedValue } from "../smartcontracts/typesystem"; import { Transaction } from "../transaction"; import { TransactionWatcher } from "../transactionWatcher"; -import { IChainID, IGasLimit } from "../interface"; +import { getAxios } from "../utils"; import { TestWallet } from "./wallets"; -import axios, { AxiosResponse } from "axios"; -import BigNumber from "bignumber.js"; export async function prepareDeployment(obj: { deployer: TestWallet; @@ -41,7 +41,8 @@ export async function prepareDeployment(obj: { export async function loadContractCode(path: PathLike): Promise { if (isOnBrowserTests()) { - let response: AxiosResponse = await axios.get(path.toString(), { + const axios = await getAxios(); + let response: any = await axios.default.get(path.toString(), { responseType: "arraybuffer", transformResponse: [], headers: { @@ -60,7 +61,8 @@ export async function loadContractCode(path: PathLike): Promise { export async function loadAbiRegistry(path: PathLike): Promise { if (isOnBrowserTests()) { - let response: AxiosResponse = await axios.get(path.toString()); + const axios = await getAxios(); + let response: any = await axios.default.get(path.toString()); return AbiRegistry.create(response.data); } diff --git a/src/testutils/wallets.ts b/src/testutils/wallets.ts index 1e67da63d..e332cec0c 100644 --- a/src/testutils/wallets.ts +++ b/src/testutils/wallets.ts @@ -1,13 +1,16 @@ -import { UserSecretKey, UserSigner } from "@multiversx/sdk-wallet"; -import axios from "axios"; import * as fs from "fs"; import * as path from "path"; import { Account } from "../account"; import { Address } from "../address"; import { IAddress } from "../interface"; import { IAccountOnNetwork } from "../interfaceOfNetwork"; +import { getAxios } from "../utils"; +import { UserSecretKey, UserSigner } from "./../wallet"; +import { readTestFile } from "./files"; import { isOnBrowserTests } from "./utils"; +export const DummyMnemonicOf12Words = "matter trumpet twenty parade fame north lift sail valve salon foster cinnamon"; + interface IAccountFetcher { getAccount(address: IAddress): Promise; } @@ -45,6 +48,13 @@ export async function loadTestWallets(): Promise> { return walletMap; } +export async function loadTestKeystore(file: string): Promise { + const testdataPath = path.resolve(__dirname, "..", "testdata/testwallets"); + const keystorePath = path.resolve(testdataPath, file); + const json = await readTestFile(keystorePath); + return JSON.parse(json); +} + export async function loadMnemonic(): Promise { return await readTestWalletFileContents("mnemonic.txt"); } @@ -62,7 +72,7 @@ export async function loadTestWallet(name: string): Promise { } async function readTestWalletFileContents(name: string): Promise { - let filePath = path.join("src", "testutils", "testwallets", name); + let filePath = path.join("src", "testdata", "testwallets", name); if (isOnBrowserTests()) { return await downloadTextFile(filePath); @@ -72,7 +82,8 @@ async function readTestWalletFileContents(name: string): Promise { } async function downloadTextFile(url: string) { - let response = await axios.get(url, { responseType: "text", transformResponse: [] }); + const axios = await getAxios(); + let response = await axios.default.get(url, { responseType: "text", transformResponse: [] }); let text = response.data.toString(); return text; } diff --git a/src/tokenOperations/tokenOperationsFactory.testnet.spec.ts b/src/tokenOperations/tokenOperationsFactory.test.net.spec.ts similarity index 100% rename from src/tokenOperations/tokenOperationsFactory.testnet.spec.ts rename to src/tokenOperations/tokenOperationsFactory.test.net.spec.ts diff --git a/src/tokenTransferBuilders.ts b/src/tokenTransferBuilders.ts index 7760ca7d9..a557ca363 100644 --- a/src/tokenTransferBuilders.ts +++ b/src/tokenTransferBuilders.ts @@ -35,7 +35,7 @@ export class ESDTTransferPayloadBuilder { */ export class ESDTNFTTransferPayloadBuilder { payment: ITokenTransfer = TokenTransfer.nonFungible("", 0); - destination: IAddress = new Address(""); + destination: IAddress = Address.empty(); setPayment(payment: ITokenTransfer): ESDTNFTTransferPayloadBuilder { this.payment = payment; @@ -70,7 +70,7 @@ export class ESDTNFTTransferPayloadBuilder { */ export class MultiESDTNFTTransferPayloadBuilder { payments: ITokenTransfer[] = []; - destination: IAddress = new Address(""); + destination: IAddress = Address.empty(); setPayments(payments: ITokenTransfer[]): MultiESDTNFTTransferPayloadBuilder { this.payments = payments; diff --git a/src/tokens.spec.ts b/src/tokens.spec.ts index 9a415815b..e9a29ef54 100644 --- a/src/tokens.spec.ts +++ b/src/tokens.spec.ts @@ -17,9 +17,17 @@ describe("test tokens and token computer", async () => { let nonce = tokenComputer.extractNonceFromExtendedIdentifier(extendedIdentifier); assert.equal(nonce, 10); + const extendedIdentifierWithPrefix = "test-TEST-123456-0a"; + nonce = tokenComputer.extractNonceFromExtendedIdentifier(extendedIdentifierWithPrefix); + assert.equal(nonce, 10); + const fungibleTokenIdentifier = "FNG-123456"; nonce = tokenComputer.extractNonceFromExtendedIdentifier(fungibleTokenIdentifier); assert.equal(nonce, 0); + + const fungibleTokenIdentifierWithPrefix = "fun-FNG-123456"; + nonce = tokenComputer.extractNonceFromExtendedIdentifier(fungibleTokenIdentifierWithPrefix); + assert.equal(nonce, 0); }); it("should extract identifier from extended identifier", async () => { @@ -27,10 +35,26 @@ describe("test tokens and token computer", async () => { let identifier = tokenComputer.extractIdentifierFromExtendedIdentifier(extendedIdentifier); assert.equal(identifier, "TEST-123456"); + const extendedIdentifierWithPrefix = "t0-TEST-123456-0a"; + identifier = tokenComputer.extractIdentifierFromExtendedIdentifier(extendedIdentifierWithPrefix); + assert.equal(identifier, "t0-TEST-123456"); + + const extendedIdentifierWithPrefixWithoutNonce = "t0-TEST-123456"; + identifier = tokenComputer.extractIdentifierFromExtendedIdentifier(extendedIdentifierWithPrefixWithoutNonce); + assert.equal(identifier, "t0-TEST-123456"); + const fungibleTokenIdentifier = "FNG-123456"; identifier = tokenComputer.extractIdentifierFromExtendedIdentifier(fungibleTokenIdentifier); assert.equal(identifier, "FNG-123456"); }); + + it("should fail if prefix longer than expected", async () => { + const nftIdentifier = "prefix-TEST-123456"; + assert.throw( + () => tokenComputer.extractIdentifierFromExtendedIdentifier(nftIdentifier), + "The identifier is not valid. The prefix does not have the right length", + ); + }); }); describe("test token transfer (legacy)", () => { diff --git a/src/tokens.ts b/src/tokens.ts index 62b22a04e..b01c5edfc 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -1,6 +1,6 @@ import BigNumber from "bignumber.js"; -import { ErrInvalidArgument, ErrInvalidTokenIdentifier } from "./errors"; import { EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER } from "./constants"; +import { ErrInvalidArgument, ErrInvalidTokenIdentifier } from "./errors"; // Legacy constants: const EGLDTokenIdentifier = "EGLD"; @@ -226,6 +226,7 @@ export class TokenTransfer { } export class TokenComputer { + TOKEN_RANDOM_SEQUENCE_LENGTH = 6; constructor() {} isFungible(token: Token): boolean { @@ -235,33 +236,55 @@ export class TokenComputer { extractNonceFromExtendedIdentifier(identifier: string): number { const parts = identifier.split("-"); - this.checkIfExtendedIdentifierWasProvided(parts); - this.checkLengthOfRandomSequence(parts[1]); + const { prefix, ticker, randomSequence } = this.splitIdentifierIntoComponents(parts); + this.validateExtendedIdentifier(prefix, ticker, randomSequence, parts); - // in case the identifier of a fungible token is provided - if (parts.length == 2) { + // If identifier is for a fungible token (2 parts or 3 with prefix), return 0 + if (parts.length === 2 || (prefix && parts.length === 3)) { return 0; } - const hexNonce = Buffer.from(parts[2], "hex"); - return decodeUnsignedNumber(hexNonce); + // Otherwise, decode the last part as an unsigned number + const hexNonce = parts[parts.length - 1]; + return decodeUnsignedNumber(Buffer.from(hexNonce, "hex")); } extractIdentifierFromExtendedIdentifier(identifier: string): string { const parts = identifier.split("-"); + const { prefix, ticker, randomSequence } = this.splitIdentifierIntoComponents(parts); + + this.validateExtendedIdentifier(prefix, ticker, randomSequence, parts); + if (prefix) { + this.checkLengthOfPrefix(prefix); + return prefix + "-" + ticker + "-" + randomSequence; + } + return ticker + "-" + randomSequence; + } + + private validateExtendedIdentifier( + prefix: string | null, + ticker: string, + randomSequence: string, + parts: string[], + ): void { + this.checkIfExtendedIdentifierWasProvided(prefix, parts); + this.ensureTokenTickerValidity(ticker); + this.checkLengthOfRandomSequence(randomSequence); + } - this.checkIfExtendedIdentifierWasProvided(parts); - this.ensureTokenTickerValidity(parts[0]); - this.checkLengthOfRandomSequence(parts[1]); + private splitIdentifierIntoComponents(parts: string[]): { prefix: any; ticker: any; randomSequence: any } { + if (this.isLowercaseAlphanumeric(parts[0])) { + return { prefix: parts[0], ticker: parts[1], randomSequence: parts[2] }; + } - return parts[0] + "-" + parts[1]; + return { prefix: null, ticker: parts[0], randomSequence: parts[1] }; } - private checkIfExtendedIdentifierWasProvided(tokenParts: string[]): void { + private checkIfExtendedIdentifierWasProvided(prefix: string | null, tokenParts: string[]): void { // this is for the identifiers of fungible tokens const MIN_EXTENDED_IDENTIFIER_LENGTH_IF_SPLITTED = 2; // this is for the identifiers of nft, sft and meta-esdt - const MAX_EXTENDED_IDENTIFIER_LENGTH_IF_SPLITTED = 3; + const MAX_EXTENDED_IDENTIFIER_LENGTH_IF_SPLITTED = prefix ? 4 : 3; if ( tokenParts.length < MIN_EXTENDED_IDENTIFIER_LENGTH_IF_SPLITTED || @@ -271,16 +294,28 @@ export class TokenComputer { } } - private checkLengthOfRandomSequence(randomSequence: string): void { - const TOKEN_RANDOM_SEQUENCE_LENGTH = 6; + private isLowercaseAlphanumeric(str: string): boolean { + return /^[a-z0-9]+$/.test(str); + } - if (randomSequence.length !== TOKEN_RANDOM_SEQUENCE_LENGTH) { + private checkLengthOfRandomSequence(randomSequence: string): void { + if (randomSequence.length !== this.TOKEN_RANDOM_SEQUENCE_LENGTH) { throw new ErrInvalidTokenIdentifier( "The identifier is not valid. The random sequence does not have the right length", ); } } + private checkLengthOfPrefix(prefix: string): void { + const MAX_TOKEN_PREFIX_LENGTH = 4; + const MIN_TOKEN_PREFIX_LENGTH = 1; + if (prefix.length < MIN_TOKEN_PREFIX_LENGTH || prefix.length > MAX_TOKEN_PREFIX_LENGTH) { + throw new ErrInvalidTokenIdentifier( + "The identifier is not valid. The prefix does not have the right length", + ); + } + } + private ensureTokenTickerValidity(ticker: string) { const MIN_TICKER_LENGTH = 3; const MAX_TICKER_LENGTH = 10; diff --git a/src/transaction.local.net.spec.ts b/src/transaction.local.net.spec.ts index 844091230..15082da7d 100644 --- a/src/transaction.local.net.spec.ts +++ b/src/transaction.local.net.spec.ts @@ -5,11 +5,11 @@ import { loadTestWallets, TestWallet } from "./testutils"; import { createLocalnetProvider, INetworkProvider } from "./testutils/networkProviders"; import { TokenTransfer } from "./tokens"; import { Transaction } from "./transaction"; +import { TransactionComputer } from "./transactionComputer"; import { TransactionPayload } from "./transactionPayload"; import { TransactionWatcher } from "./transactionWatcher"; import { TransactionsFactoryConfig } from "./transactionsFactories/transactionsFactoryConfig"; import { TransferTransactionsFactory } from "./transactionsFactories/transferTransactionsFactory"; -import { TransactionComputer } from "./transactionComputer"; describe("test transaction", function () { let alice: TestWallet, bob: TestWallet; @@ -30,7 +30,7 @@ describe("test transaction", function () { } it("should send transactions and wait for completion", async function () { - this.timeout(70000); + this.timeout(80000); let provider = createLocalnetProvider(); let watcher = createTransactionWatcher(provider); @@ -76,7 +76,7 @@ describe("test transaction", function () { }); it("should send transaction and wait for completion using the new proxy provider", async function () { - this.timeout(70000); + this.timeout(80000); let provider = createLocalnetProvider(); let watcher = createTransactionWatcher(provider); @@ -142,7 +142,7 @@ describe("test transaction", function () { }); it("should create transaction using the TokenTransferFactory", async function () { - this.timeout(70000); + this.timeout(80000); const provider = createLocalnetProvider(); const watcher = createTransactionWatcher(provider); diff --git a/src/transaction.spec.ts b/src/transaction.spec.ts index 6775fbb91..ecf98d5c0 100644 --- a/src/transaction.spec.ts +++ b/src/transaction.spec.ts @@ -1,4 +1,4 @@ -import { UserPublicKey, UserVerifier } from "@multiversx/sdk-wallet"; +import { UserPublicKey, UserVerifier } from "./wallet"; import BigNumber from "bignumber.js"; import { assert } from "chai"; import { Address } from "./address"; diff --git a/src/transaction.ts b/src/transaction.ts index a602cca17..a8fad0a9d 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -102,16 +102,6 @@ export class Transaction { */ public guardianSignature: Uint8Array; - /** - * The relayer in case it is a relayedV3 Transaction. - */ - public relayer: string; - - /** - * The inner transactions in case it is a relayedV3 Transaction. - */ - public innerTransactions: ITransaction[]; - /** * Creates a new Transaction object. */ @@ -131,8 +121,6 @@ export class Transaction { guardian?: IAddress | string; signature?: Uint8Array; guardianSignature?: Uint8Array; - relayer?: string; - innerTransactions?: ITransaction[]; }) { this.nonce = BigInt(options.nonce?.valueOf() || 0n); // We still rely on "bigNumber" for value, because client code might be passing a BigNumber object as a legacy "ITransactionValue", @@ -152,9 +140,6 @@ export class Transaction { this.signature = options.signature || Buffer.from([]); this.guardianSignature = options.guardianSignature || Buffer.from([]); - - this.relayer = options.relayer || ""; - this.innerTransactions = options.innerTransactions || []; } private addressAsBech32(address: IAddress | string): string { diff --git a/src/transactionComputer.ts b/src/transactionComputer.ts index 1a835b04a..da365e7b2 100644 --- a/src/transactionComputer.ts +++ b/src/transactionComputer.ts @@ -122,10 +122,6 @@ export class TransactionComputer { obj.version = transaction.version; obj.options = transaction.options ? transaction.options : undefined; obj.guardian = transaction.guardian ? transaction.guardian : undefined; - obj.relayer = transaction.relayer ? transaction.relayer : undefined; - obj.innerTransactions = transaction.innerTransactions.length - ? transaction.innerTransactions.map((tx) => this.toPlainObject(tx, true)) - : undefined; return obj; } diff --git a/src/transactionWatcher.spec.ts b/src/transactionWatcher.spec.ts index fbcfae2ec..dd223af6d 100644 --- a/src/transactionWatcher.spec.ts +++ b/src/transactionWatcher.spec.ts @@ -1,4 +1,4 @@ -import { TransactionOnNetwork, TransactionStatus } from "@multiversx/sdk-network-providers"; +import { TransactionOnNetwork, TransactionStatus } from "./networkProviders"; import { assert } from "chai"; import { MarkCompleted, MockNetworkProvider, Wait } from "./testutils"; import { TransactionHash } from "./transaction"; diff --git a/src/transactionsFactories/delegationTransactionsFactory.spec.ts b/src/transactionsFactories/delegationTransactionsFactory.spec.ts index 7d5591cc6..c7d72902f 100644 --- a/src/transactionsFactories/delegationTransactionsFactory.spec.ts +++ b/src/transactionsFactories/delegationTransactionsFactory.spec.ts @@ -1,4 +1,4 @@ -import { ValidatorPublicKey } from "@multiversx/sdk-wallet"; +import { ValidatorPublicKey } from "./../wallet"; import { assert } from "chai"; import { Address } from "../address"; import { DELEGATION_MANAGER_SC_ADDRESS } from "../constants"; diff --git a/src/transactionsFactories/relayedTransactionsFactory.spec.ts b/src/transactionsFactories/relayedTransactionsFactory.spec.ts index f45fac443..6c61d331a 100644 --- a/src/transactionsFactories/relayedTransactionsFactory.spec.ts +++ b/src/transactionsFactories/relayedTransactionsFactory.spec.ts @@ -275,69 +275,4 @@ describe("test relayed transactions factory", function () { "relayedTxV2@000000000000000000010000000000000000000000000000000000000002ffff@0f@676574436f6e7472616374436f6e666967@fc3ed87a51ee659f937c1a1ed11c1ae677e99629fae9cc289461f033e6514d1a8cfad1144ae9c1b70f28554d196bd6ba1604240c1c1dc19c959e96c1c3b62d0c", ); }); - - it("should create relayed v3 transaction", async function () { - let innerTransaction = new Transaction({ - sender: bob.address.toBech32(), - receiver: bob.address.toBech32(), - gasLimit: 50000n, - chainID: config.chainID, - nonce: 0n, - version: 2, - relayer: alice.address.toBech32(), - }); - - const serializedInnerTransaction = transactionComputer.computeBytesForSigning(innerTransaction); - innerTransaction.signature = await bob.signer.sign(serializedInnerTransaction); - - const relayedTransaction = factory.createRelayedV3Transaction({ - relayerAddress: alice.address, - innerTransactions: [innerTransaction], - }); - - const serializedRelayedTransaction = transactionComputer.computeBytesForSigning(relayedTransaction); - relayedTransaction.signature = await alice.signer.sign(serializedRelayedTransaction); - - assert.equal( - Buffer.from(relayedTransaction.signature).toString("hex"), - "88b9bce6fe62a641fca593f95c12ad09032a44b34c9e5cf16d070f0563b1695bf9d452a9df52bce3373fd5e10ed96c3d65cd189f5873e3a3184a89f4980c9e0c", - ); - assert.equal(relayedTransaction.gasLimit, 100000n); - }); - - it("should fail to create relayed v3 transaction", async function () { - assert.throws(() => { - factory.createRelayedV3Transaction({ - relayerAddress: alice.address, - innerTransactions: [], - }); - }, "No inner transctions provided"); - - const innerTransaction = new Transaction({ - sender: bob.address.toBech32(), - receiver: bob.address.toBech32(), - gasLimit: 50000n, - chainID: config.chainID, - nonce: 0n, - version: 2, - relayer: carol.address.toBech32(), - }); - - assert.throws(() => { - factory.createRelayedV3Transaction({ - relayerAddress: alice.address, - innerTransactions: [innerTransaction], - }); - }, "Inner transaction is not signed"); - - const serializedInnerTransaction = transactionComputer.computeBytesForSigning(innerTransaction); - innerTransaction.signature = await bob.signer.sign(serializedInnerTransaction); - - assert.throws(() => { - factory.createRelayedV3Transaction({ - relayerAddress: alice.address, - innerTransactions: [innerTransaction], - }); - }, "The inner transaction has an incorrect relayer address"); - }); }); diff --git a/src/transactionsFactories/relayedTransactionsFactory.ts b/src/transactionsFactories/relayedTransactionsFactory.ts index 7464fc259..b69741025 100644 --- a/src/transactionsFactories/relayedTransactionsFactory.ts +++ b/src/transactionsFactories/relayedTransactionsFactory.ts @@ -84,36 +84,6 @@ export class RelayedTransactionsFactory { }); } - createRelayedV3Transaction(options: { relayerAddress: IAddress; innerTransactions: ITransaction[] }): Transaction { - if (!options.innerTransactions.length) { - throw new ErrInvalidInnerTransaction("No inner transctions provided"); - } - - let innerTransactionsGasLimit = 0n; - for (const innerTx of options.innerTransactions) { - if (!innerTx.signature.length) { - throw new ErrInvalidInnerTransaction("Inner transaction is not signed"); - } - - if (innerTx.relayer !== options.relayerAddress.bech32()) { - throw new ErrInvalidInnerTransaction("The inner transaction has an incorrect relayer address"); - } - - innerTransactionsGasLimit += innerTx.gasLimit; - } - - const moveBalanceGas = this.config.minGasLimit * BigInt(options.innerTransactions.length); - const gasLimit = moveBalanceGas + innerTransactionsGasLimit; - - return new Transaction({ - sender: options.relayerAddress.bech32(), - receiver: options.relayerAddress.bech32(), - chainID: this.config.chainID, - gasLimit: gasLimit, - innerTransactions: options.innerTransactions, - }); - } - private prepareInnerTransactionForRelayedV1(innerTransaction: ITransaction): string { const txObject = { nonce: innerTransaction.nonce, diff --git a/src/transactionsFactories/tokenManagementTransactionIntentsFactory.spec.ts b/src/transactionsFactories/tokenManagementTransactionIntentsFactory.spec.ts index 9d7ada3e8..f5c489903 100644 --- a/src/transactionsFactories/tokenManagementTransactionIntentsFactory.spec.ts +++ b/src/transactionsFactories/tokenManagementTransactionIntentsFactory.spec.ts @@ -1,9 +1,9 @@ import { assert } from "chai"; +import { Address } from "../address"; import { ESDT_CONTRACT_ADDRESS_HEX } from "../constants"; import { loadTestWallets, TestWallet } from "../testutils"; import { TokenManagementTransactionsFactory } from "./tokenManagementTransactionsFactory"; import { TransactionsFactoryConfig } from "./transactionsFactoryConfig"; -import { Address } from "../address"; describe("test token management transactions factory", () => { let frank: TestWallet, grace: TestWallet; @@ -354,7 +354,7 @@ describe("test token management transactions factory", () => { assert.deepEqual(transaction.data, Buffer.from("registerDynamic@54657374@544553542d313233343536@464e47")); assert.equal(transaction.sender, grace.address.toString()); assert.equal(transaction.receiver, Address.newFromHex(ESDT_CONTRACT_ADDRESS_HEX, config.addressHrp).toBech32()); - assert.equal(transaction.value, 0n); + assert.equal(transaction.value, 50000000000000000n); assert.equal(transaction.gasLimit, 60131000n); }); @@ -372,7 +372,7 @@ describe("test token management transactions factory", () => { ); assert.equal(transaction.sender, grace.address.toString()); assert.equal(transaction.receiver, Address.newFromHex(ESDT_CONTRACT_ADDRESS_HEX, config.addressHrp).toBech32()); - assert.equal(transaction.value, 0n); + assert.equal(transaction.value, 50000000000000000n); assert.equal(transaction.gasLimit, 60152000n); }); }); diff --git a/src/transactionsFactories/tokenManagementTransactionsFactory.ts b/src/transactionsFactories/tokenManagementTransactionsFactory.ts index eef02df80..b674313a5 100644 --- a/src/transactionsFactories/tokenManagementTransactionsFactory.ts +++ b/src/transactionsFactories/tokenManagementTransactionsFactory.ts @@ -856,6 +856,7 @@ export class TokenManagementTransactionsFactory { dataParts: dataParts, gasLimit: this.config.gasLimitRegisterDynamic, addDataMovementGas: true, + amount: this.config.issueCost, }).build(); } @@ -881,6 +882,7 @@ export class TokenManagementTransactionsFactory { dataParts: dataParts, gasLimit: this.config.gasLimitRegisterDynamic, addDataMovementGas: true, + amount: this.config.issueCost, }).build(); } diff --git a/src/transactionsFactories/transferTransactionsFactory.spec.ts b/src/transactionsFactories/transferTransactionsFactory.spec.ts index 1296be14f..6a7581c3e 100644 --- a/src/transactionsFactories/transferTransactionsFactory.spec.ts +++ b/src/transactionsFactories/transferTransactionsFactory.spec.ts @@ -1,5 +1,6 @@ import { assert } from "chai"; import { Address } from "../address"; +import { EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER } from "../constants"; import { ErrBadUsage } from "../errors"; import { Token, TokenTransfer } from "../tokens"; import { TransactionsFactoryConfig } from "./transactionsFactoryConfig"; @@ -96,6 +97,26 @@ describe("test transfer transactions factory", function () { ); }); + it("should create 'Transaction' for nft transfer with prefix", async () => { + const nft = new Token({ identifier: "t0-NFT-123456", nonce: 10n }); + const transfer = new TokenTransfer({ token: nft, amount: 1n }); + + const transaction = transferFactory.createTransactionForESDTTokenTransfer({ + sender: alice, + receiver: bob, + tokenTransfers: [transfer], + }); + + assert.equal(transaction.sender, alice.toBech32()); + assert.equal(transaction.receiver, alice.toBech32()); + assert.equal(transaction.value.valueOf(), 0n); + assert.equal(transaction.gasLimit.valueOf(), 1219500n); + assert.deepEqual( + transaction.data.toString(), + "ESDTNFTTransfer@74302d4e46542d313233343536@0a@01@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", + ); + }); + it("should create 'Transaction' for multiple nft transfers", async () => { const firstNft = new Token({ identifier: "NFT-123456", nonce: 10n }); const firstTransfer = new TokenTransfer({ token: firstNft, amount: 1n }); @@ -127,6 +148,37 @@ describe("test transfer transactions factory", function () { assert.deepEqual(transaction, secondTransaction); }); + it("should create 'Transaction' for multiple nft transfers with prefix", async () => { + const firstNft = new Token({ identifier: "t0-NFT-123456", nonce: 10n }); + const firstTransfer = new TokenTransfer({ token: firstNft, amount: 1n }); + + const secondNft = new Token({ identifier: "t0-TEST-987654", nonce: 1n }); + const secondTransfer = new TokenTransfer({ token: secondNft, amount: 1n }); + + const transaction = transferFactory.createTransactionForESDTTokenTransfer({ + sender: alice, + receiver: bob, + tokenTransfers: [firstTransfer, secondTransfer], + }); + + assert.equal(transaction.sender, alice.toBech32()); + assert.equal(transaction.receiver, alice.toBech32()); + assert.equal(transaction.value.valueOf(), 0n); + assert.equal(transaction.gasLimit.valueOf(), 1484000n); + assert.deepEqual( + transaction.data.toString(), + "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@02@74302d4e46542d313233343536@0a@01@74302d544553542d393837363534@01@01", + ); + + const secondTransaction = transferFactory.createTransactionForTransfer({ + sender: alice, + receiver: bob, + tokenTransfers: [firstTransfer, secondTransfer], + }); + + assert.deepEqual(transaction, secondTransaction); + }); + it("should fail to create transaction for token transfers", async () => { assert.throws(() => { const nft = new Token({ identifier: "NFT-123456", nonce: 10n }); @@ -205,4 +257,48 @@ describe("test transfer transactions factory", function () { "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@03@4e46542d313233343536@0a@01@544553542d393837363534@01@01@45474c442d303030303030@@0de0b6b3a7640000", ); }); + + it("should create transaction for token transfers with prefix", async () => { + const firstNft = new Token({ identifier: "t0-NFT-123456", nonce: 10n }); + const firstTransfer = new TokenTransfer({ token: firstNft, amount: 1n }); + + const secondNft = new Token({ identifier: "t0-TEST-987654", nonce: 1n }); + const secondTransfer = new TokenTransfer({ token: secondNft, amount: 1n }); + + const transaction = transferFactory.createTransactionForTransfer({ + sender: alice, + receiver: bob, + nativeAmount: 1000000000000000000n, + tokenTransfers: [firstTransfer, secondTransfer], + }); + + assert.equal(transaction.sender, alice.toBech32()); + assert.equal(transaction.receiver, alice.toBech32()); + assert.equal(transaction.value.valueOf(), 0n); + assert.equal(transaction.gasLimit.valueOf(), 1745500n); + assert.deepEqual( + transaction.data.toString(), + "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@03@74302d4e46542d313233343536@0a@01@74302d544553542d393837363534@01@01@45474c442d303030303030@@0de0b6b3a7640000", + ); + }); + + it("should create multi transfer for egld", async () => { + const firstNft = new Token({ identifier: EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER }); + const firstTransfer = new TokenTransfer({ token: firstNft, amount: 1000000000000000000n }); + + const transaction = transferFactory.createTransactionForESDTTokenTransfer({ + sender: alice, + receiver: bob, + tokenTransfers: [firstTransfer], + }); + + assert.equal(transaction.sender, alice.toBech32()); + assert.equal(transaction.receiver, alice.toBech32()); + assert.equal(transaction.value.valueOf(), 0n); + assert.equal(transaction.gasLimit.valueOf(), 1_243_500n); + assert.deepEqual( + transaction.data.toString(), + "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@01@45474c442d303030303030@@0de0b6b3a7640000", + ); + }); }); diff --git a/src/transactionsFactories/transferTransactionsFactory.ts b/src/transactionsFactories/transferTransactionsFactory.ts index 834fa6dd8..84dcf2a63 100644 --- a/src/transactionsFactories/transferTransactionsFactory.ts +++ b/src/transactionsFactories/transferTransactionsFactory.ts @@ -1,3 +1,4 @@ +import { EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER } from "../constants"; import { Err, ErrBadUsage } from "../errors"; import { IAddress, @@ -125,15 +126,11 @@ export class TransferTransactionsFactory { return this.createSingleESDTTransferTransaction(options); } - const dataParts = this.tokenTransfersDataBuilder!.buildDataPartsForMultiESDTNFTTransfer( - options.receiver, + const { dataParts, extraGasForTransfer } = this.buildMultiESDTNFTTransferData( options.tokenTransfers, + options.receiver, ); - const extraGasForTransfer = - this.config!.gasLimitMultiESDTNFTTransfer * BigInt(numberOfTransfers) + - BigInt(ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER); - return new TransactionBuilder({ config: this.config!, sender: options.sender, @@ -366,19 +363,9 @@ export class TransferTransactionsFactory { }): Transaction { this.ensureConfigIsDefined(); - let dataParts: string[] = []; const transfer = options.tokenTransfers[0]; - let extraGasForTransfer = 0n; - let receiver = options.receiver; - if (this.tokenComputer!.isFungible(transfer.token)) { - dataParts = this.tokenTransfersDataBuilder!.buildDataPartsForESDTTransfer(transfer); - extraGasForTransfer = this.config!.gasLimitESDTTransfer + BigInt(ADDITIONAL_GAS_FOR_ESDT_TRANSFER); - } else { - dataParts = this.tokenTransfersDataBuilder!.buildDataPartsForSingleESDTNFTTransfer(transfer, receiver); - extraGasForTransfer = this.config!.gasLimitESDTNFTTransfer + BigInt(ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER); - receiver = options.sender; - } + const { dataParts, extraGasForTransfer, receiver } = this.buildTransferData(transfer, options); return new TransactionBuilder({ config: this.config!, @@ -390,6 +377,48 @@ export class TransferTransactionsFactory { }).build(); } + private buildTransferData(transfer: TokenTransfer, options: { sender: IAddress; receiver: IAddress }) { + let dataParts: string[] = []; + let extraGasForTransfer: bigint; + let receiver = options.receiver; + + if (this.tokenComputer!.isFungible(transfer.token)) { + if (transfer.token.identifier === EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER) { + ({ dataParts, extraGasForTransfer } = this.buildMultiESDTNFTTransferData([transfer], receiver)); + receiver = options.sender; + } else { + ({ dataParts, extraGasForTransfer } = this.buildESDTTransferData(transfer)); + } + } else { + ({ dataParts, extraGasForTransfer } = this.buildSingleESDTNFTTransferData(transfer, receiver)); + receiver = options.sender; // Override receiver for non-fungible tokens + } + return { dataParts, extraGasForTransfer, receiver }; + } + + private buildMultiESDTNFTTransferData(transfer: TokenTransfer[], receiver: IAddress) { + return { + dataParts: this.tokenTransfersDataBuilder!.buildDataPartsForMultiESDTNFTTransfer(receiver, transfer), + extraGasForTransfer: + this.config!.gasLimitMultiESDTNFTTransfer * BigInt(transfer.length) + + BigInt(ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER), + }; + } + + private buildESDTTransferData(transfer: TokenTransfer) { + return { + dataParts: this.tokenTransfersDataBuilder!.buildDataPartsForESDTTransfer(transfer), + extraGasForTransfer: this.config!.gasLimitESDTTransfer + BigInt(ADDITIONAL_GAS_FOR_ESDT_TRANSFER), + }; + } + + private buildSingleESDTNFTTransferData(transfer: TokenTransfer, receiver: IAddress) { + return { + dataParts: this.tokenTransfersDataBuilder!.buildDataPartsForSingleESDTNFTTransfer(transfer, receiver), + extraGasForTransfer: this.config!.gasLimitESDTNFTTransfer + BigInt(ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER), + }; + } + private computeGasForMoveBalance(config: IConfig, data: Uint8Array): bigint { return config.minGasLimit + config.gasLimitPerByte * BigInt(data.length); } diff --git a/src/transactionsOutcomeParsers/delegationTransactionsOutcomeParser.ts b/src/transactionsOutcomeParsers/delegationTransactionsOutcomeParser.ts index 305949058..b7e9a0a03 100644 --- a/src/transactionsOutcomeParsers/delegationTransactionsOutcomeParser.ts +++ b/src/transactionsOutcomeParsers/delegationTransactionsOutcomeParser.ts @@ -1,18 +1,35 @@ import { Address } from "../address"; +import { TransactionsConverter } from "../converters/transactionsConverter"; import { ErrParseTransactionOutcome } from "../errors"; +import { ITransactionOnNetwork } from "../interfaceOfNetwork"; import { TransactionEvent, TransactionOutcome, findEventsByIdentifier } from "./resources"; export class DelegationTransactionsOutcomeParser { constructor() {} - parseCreateNewDelegationContract(transactionOutcome: TransactionOutcome): { contractAddress: string }[] { - this.ensureNoError(transactionOutcome.logs.events); + parseCreateNewDelegationContract( + transaction: TransactionOutcome | ITransactionOnNetwork, + ): { contractAddress: string }[] { + transaction = this.ensureTransactionOutcome(transaction); - const events = findEventsByIdentifier(transactionOutcome, "SCDeploy"); + this.ensureNoError(transaction.logs.events); + + const events = findEventsByIdentifier(transaction, "SCDeploy"); return events.map((event) => ({ contractAddress: this.extractContractAddress(event) })); } + /** + * Temporary workaround, until "TransactionOnNetwork" completely replaces "TransactionOutcome". + */ + private ensureTransactionOutcome(transaction: TransactionOutcome | ITransactionOnNetwork): TransactionOutcome { + if ("hash" in transaction) { + return new TransactionsConverter().transactionOnNetworkToOutcome(transaction); + } + + return transaction; + } + private ensureNoError(transactionEvents: TransactionEvent[]) { for (const event of transactionEvents) { if (event.identifier == "signalError") { diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.dev.net.spec.ts b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.dev.net.spec.ts new file mode 100644 index 000000000..6eb10aa4f --- /dev/null +++ b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.dev.net.spec.ts @@ -0,0 +1,40 @@ +import { assert } from "chai"; +import { TransactionsConverter } from "../converters/transactionsConverter"; +import { createDevnetProvider } from "../testutils/networkProviders"; +import { SmartContractTransactionsOutcomeParser } from "./smartContractTransactionsOutcomeParser"; + +describe("test smart contract transactions outcome parser on devnet", () => { + const networkProvider = createDevnetProvider(); + const parser = new SmartContractTransactionsOutcomeParser(); + const transactionsConverter = new TransactionsConverter(); + + it("should parse outcome of deploy transactions (1)", async () => { + const transactionHash = "5d2ff2af8eb3fe7f2acb7e29c0436854b4c6c44de02878b6afff582888024a55"; + const transactionOnNetwork = await networkProvider.getTransaction(transactionHash); + const transactionOutcome = transactionsConverter.transactionOnNetworkToOutcome(transactionOnNetwork); + const parsedGivenTransactionOnNetwork = parser.parseDeploy({ transactionOnNetwork }); + const parsedGivenTransactionOutcome = parser.parseDeploy({ transactionOutcome }); + + assert.deepEqual(parsedGivenTransactionOnNetwork, parsedGivenTransactionOutcome); + assert.equal(parsedGivenTransactionOnNetwork.returnCode, "ok"); + assert.deepEqual(parsedGivenTransactionOnNetwork.contracts, [ + { + address: "erd1qqqqqqqqqqqqqpgqpayq2es08gq8798xhnpr0kzgn7495qt5q6uqd7lpwf", + ownerAddress: "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6", + codeHash: Buffer.from("c876625ec34a04445cfd99067777ebe488afdbc6899cd958f4c1d36107ca02d9", "hex"), + }, + ]); + }); + + it("should parse outcome of deploy transactions (2)", async () => { + const transactionHash = "76683e926dad142fc9651afca208487f2a80d327fc87e5c876eec9d028196352"; + const transactionOnNetwork = await networkProvider.getTransaction(transactionHash); + const transactionOutcome = transactionsConverter.transactionOnNetworkToOutcome(transactionOnNetwork); + const parsedGivenTransactionOnNetwork = parser.parseDeploy({ transactionOnNetwork }); + const parsedGivenTransactionOutcome = parser.parseDeploy({ transactionOutcome }); + + assert.deepEqual(parsedGivenTransactionOnNetwork, parsedGivenTransactionOutcome); + assert.equal(parsedGivenTransactionOnNetwork.returnCode, "execution failed"); + assert.lengthOf(parsedGivenTransactionOnNetwork.contracts, 0); + }); +}); diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.main.net.spec.ts b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.main.net.spec.ts new file mode 100644 index 000000000..00ee27737 --- /dev/null +++ b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.main.net.spec.ts @@ -0,0 +1,157 @@ +import { assert } from "chai"; +import { promises } from "fs"; +import { TransactionsConverter } from "../converters/transactionsConverter"; +import { createMainnetProvider } from "../testutils/networkProviders"; +import { SmartContractTransactionsOutcomeParser } from "./smartContractTransactionsOutcomeParser"; + +describe("test smart contract transactions outcome parser on mainnet", () => { + const networkProvider = createMainnetProvider(); + const parser = new SmartContractTransactionsOutcomeParser(); + const converter = new TransactionsConverter(); + + it("should parse (execute_success)", async function () { + this.timeout(3600000); + + const records = await loadRecords("execute_success"); + + for (let i = 0; i < records.length; i++) { + const { hash } = records[i]; + console.log(i, hash); + + const transactionOnNetwork = await networkProvider.getTransaction(hash); + const transactionOutcome = converter.transactionOnNetworkToOutcome(transactionOnNetwork); + const parsedOutcomeGivenTransactionOutcome = parser.parseExecute({ transactionOutcome }); + const parsedOutcomeGivenTransactionOnNetwork = parser.parseExecute({ transactionOnNetwork }); + + assert.deepEqual(parsedOutcomeGivenTransactionOutcome, parsedOutcomeGivenTransactionOnNetwork); + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnCode, "ok"); + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnMessage, "ok"); + } + }); + + it("should parse (execute_error)", async function () { + this.timeout(3600000); + + const records = await loadRecords("execute_error"); + + for (let i = 0; i < records.length; i++) { + const { hash } = records[i]; + console.log(i, hash); + + const transactionOnNetwork = await networkProvider.getTransaction(hash); + const transactionOutcome = converter.transactionOnNetworkToOutcome(transactionOnNetwork); + const parsedOutcomeGivenTransactionOutcome = parser.parseExecute({ transactionOutcome }); + const parsedOutcomeGivenTransactionOnNetwork = parser.parseExecute({ transactionOnNetwork }); + + assert.deepEqual(parsedOutcomeGivenTransactionOutcome, parsedOutcomeGivenTransactionOnNetwork); + assert.isTrue(parsedOutcomeGivenTransactionOnNetwork.returnCode.length > 0); + assert.isTrue(parsedOutcomeGivenTransactionOnNetwork.returnMessage.length > 0); + assert.lengthOf(parsedOutcomeGivenTransactionOnNetwork.values, 0); + } + }); + + it("should parse (transfer_execute_success)", async function () { + this.timeout(3600000); + + const records = await loadRecords("transfer_execute_success"); + + for (let i = 0; i < records.length; i++) { + const { hash } = records[i]; + console.log(i, hash); + + const transactionOnNetwork = await networkProvider.getTransaction(hash); + const transactionOutcome = converter.transactionOnNetworkToOutcome(transactionOnNetwork); + const parsedOutcomeGivenTransactionOutcome = parser.parseExecute({ transactionOutcome }); + const parsedOutcomeGivenTransactionOnNetwork = parser.parseExecute({ transactionOnNetwork }); + + assert.deepEqual(parsedOutcomeGivenTransactionOutcome, parsedOutcomeGivenTransactionOnNetwork); + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnCode, "ok"); + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnMessage, "ok"); + } + }); + + it("should parse (transfer_execute_error)", async function () { + this.timeout(3600000); + + const records = await loadRecords("transfer_execute_error"); + + for (let i = 0; i < records.length; i++) { + const { hash } = records[i]; + console.log(i, hash); + + const transactionOnNetwork = await networkProvider.getTransaction(hash); + const transactionOutcome = converter.transactionOnNetworkToOutcome(transactionOnNetwork); + const parsedOutcomeGivenTransactionOutcome = parser.parseExecute({ transactionOutcome }); + const parsedOutcomeGivenTransactionOnNetwork = parser.parseExecute({ transactionOnNetwork }); + + assert.deepEqual(parsedOutcomeGivenTransactionOutcome, parsedOutcomeGivenTransactionOnNetwork); + assert.isTrue(parsedOutcomeGivenTransactionOnNetwork.returnCode.length > 0); + assert.isTrue(parsedOutcomeGivenTransactionOnNetwork.returnMessage.length > 0); + assert.lengthOf(parsedOutcomeGivenTransactionOnNetwork.values, 0); + } + }); + + it("should parse (relayed_success)", async function () { + this.timeout(3600000); + + const records = await loadRecords("relayed_success"); + + for (let i = 0; i < records.length; i++) { + const { hash } = records[i]; + console.log(i, hash); + + const transactionOnNetwork = await networkProvider.getTransaction(hash); + const parsedOutcomeGivenTransactionOnNetwork = parser.parseExecute({ transactionOnNetwork }); + + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnCode, "ok"); + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnMessage, "ok"); + } + }); + + it("should parse (relayed_error)", async function () { + this.timeout(3600000); + + const records = await loadRecords("relayed_error"); + + for (let i = 0; i < records.length; i++) { + const { hash } = records[i]; + console.log(i, hash); + + const transactionOnNetwork = await networkProvider.getTransaction(hash); + const parsedOutcomeGivenTransactionOnNetwork = parser.parseExecute({ transactionOnNetwork }); + + assert.isTrue(parsedOutcomeGivenTransactionOnNetwork.returnCode.length > 0); + assert.isTrue(parsedOutcomeGivenTransactionOnNetwork.returnMessage.length > 0); + assert.lengthOf(parsedOutcomeGivenTransactionOnNetwork.values, 0); + } + }); + + it("should parse (multi_transfer_too_much_gas)", async function () { + this.timeout(3600000); + + const records = await loadRecords("multi_transfer_too_much_gas"); + + for (let i = 0; i < records.length; i++) { + const { hash } = records[i]; + console.log(i, hash); + + const transactionOnNetwork = await networkProvider.getTransaction(hash); + const transactionOutcome = converter.transactionOnNetworkToOutcome(transactionOnNetwork); + const parsedOutcomeGivenTransactionOutcome = parser.parseExecute({ transactionOutcome }); + const parsedOutcomeGivenTransactionOnNetwork = parser.parseExecute({ transactionOnNetwork }); + + assert.deepEqual(parsedOutcomeGivenTransactionOutcome, parsedOutcomeGivenTransactionOnNetwork); + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnCode, "ok"); + assert.equal(parsedOutcomeGivenTransactionOnNetwork.returnMessage, "ok"); + assert.lengthOf(parsedOutcomeGivenTransactionOnNetwork.values, 0); + } + }); + + async function loadRecords(kind: string): Promise { + const path = "src/testdata/transactions.mainnet.json"; + const content: string = await promises.readFile(path, { encoding: "utf8" }); + const records = JSON.parse(content); + const recordsFiltered = records.filter((record: any) => record.kind == kind); + return recordsFiltered; + } +}); diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.spec.ts b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.spec.ts index 5bbcbdd52..e005f1b39 100644 --- a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.spec.ts +++ b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.spec.ts @@ -3,9 +3,9 @@ import { ContractResults, TransactionEventTopic, TransactionOnNetwork, - TransactionEvent as TransactionOnNetworkEvent, - TransactionLogs as TransactionOnNetworkLogs, -} from "@multiversx/sdk-network-providers"; + TransactionEventOnNetwork, + TransactionLogsOnNetwork, +} from "../networkProviders"; import BigNumber from "bignumber.js"; import { assert } from "chai"; import { Address } from "../address"; @@ -60,9 +60,9 @@ describe("test smart contract transactions outcome parser", () => { const transactionOnNetwork = new TransactionOnNetwork({ nonce: 7, - logs: new TransactionOnNetworkLogs({ + logs: new TransactionLogsOnNetwork({ events: [ - new TransactionOnNetworkEvent({ + new TransactionEventOnNetwork({ identifier: "SCDeploy", topics: [ new TransactionEventTopic(contract.getPublicKey().toString("base64")), @@ -102,9 +102,9 @@ describe("test smart contract transactions outcome parser", () => { const transactionOnNetwork = new TransactionOnNetwork({ nonce: 7, - logs: new TransactionOnNetworkLogs({ + logs: new TransactionLogsOnNetwork({ events: [ - new TransactionOnNetworkEvent({ + new TransactionEventOnNetwork({ identifier: "signalError", topics: [ new TransactionEventTopic(deployer.getPublicKey().toString("base64")), diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts index 7c240504c..9f57b4782 100644 --- a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts +++ b/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts @@ -1,7 +1,22 @@ import { Address } from "../address"; +import { ARGUMENTS_SEPARATOR } from "../constants"; import { Err } from "../errors"; -import { EndpointDefinition, ResultsParser, ReturnCode, Type, UntypedOutcomeBundle } from "../smartcontracts"; -import { TransactionEvent, TransactionOutcome, findEventsByIdentifier } from "./resources"; +import { IContractResultItem, ITransactionEvent, ITransactionOnNetwork } from "../interfaceOfNetwork"; +import { + ArgSerializer, + EndpointDefinition, + ResultsParser, + ReturnCode, + Type, + UntypedOutcomeBundle, +} from "../smartcontracts"; +import { SmartContractCallOutcome, TransactionOutcome, findEventsByIdentifier } from "./resources"; + +enum Events { + SCDeploy = "SCDeploy", + SignalError = "signalError", + WriteLog = "writeLog", +} interface IAbi { getEndpoint(name: string): EndpointDefinition; @@ -28,15 +43,31 @@ export class SmartContractTransactionsOutcomeParser { constructor(options?: { abi?: IAbi; legacyResultsParser?: ILegacyResultsParser }) { this.abi = options?.abi; - - // Prior v13, we've advertised that people can override the "ResultsParser" to alter it's behavior in case of exotic flows. - // Now, since the new "SmartContractTransactionsOutcomeParser" (still) depends on the legacy "ResultsParser", - // at least until "return data parts of direct outcome of contract call" are included on API & Proxy responses (on GET transaction), - // we have to allow the same level of customization (for exotic flows). this.legacyResultsParser = options?.legacyResultsParser || new ResultsParser(); } - parseDeploy(options: { transactionOutcome: TransactionOutcome }): { + parseDeploy( + options: { transactionOutcome: TransactionOutcome } | { transactionOnNetwork: ITransactionOnNetwork }, + ): { + returnCode: string; + returnMessage: string; + contracts: { + address: string; + ownerAddress: string; + codeHash: Uint8Array; + }[]; + } { + if ("transactionOutcome" in options) { + return this.parseDeployGivenTransactionOutcome(options.transactionOutcome); + } + + return this.parseDeployGivenTransactionOnNetwork(options.transactionOnNetwork); + } + + /** + * Legacy approach. + */ + protected parseDeployGivenTransactionOutcome(transactionOutcome: TransactionOutcome): { returnCode: string; returnMessage: string; contracts: { @@ -45,8 +76,8 @@ export class SmartContractTransactionsOutcomeParser { codeHash: Uint8Array; }[]; } { - const directCallOutcome = options.transactionOutcome.directSmartContractCallOutcome; - const events = findEventsByIdentifier(options.transactionOutcome, "SCDeploy"); + const directCallOutcome = transactionOutcome.directSmartContractCallOutcome; + const events = findEventsByIdentifier(transactionOutcome, Events.SCDeploy); const contracts = events.map((event) => this.parseScDeployEvent(event)); return { @@ -56,7 +87,35 @@ export class SmartContractTransactionsOutcomeParser { }; } - private parseScDeployEvent(event: TransactionEvent): { + protected parseDeployGivenTransactionOnNetwork(transactionOnNetwork: ITransactionOnNetwork): { + returnCode: string; + returnMessage: string; + contracts: { + address: string; + ownerAddress: string; + codeHash: Uint8Array; + }[]; + } { + const directCallOutcome = this.findDirectSmartContractCallOutcome(transactionOnNetwork); + + const events = transactionOnNetwork.logs.events + .concat(transactionOnNetwork.contractResults.items.flatMap((result) => result.logs.events)) + .filter((event) => event.identifier === Events.SCDeploy); + + const contracts = events.map((event) => + this.parseScDeployEvent({ + topics: event.topics.map((topic) => Buffer.from(topic.hex(), "hex")), + }), + ); + + return { + returnCode: directCallOutcome.returnCode, + returnMessage: directCallOutcome.returnMessage, + contracts: contracts, + }; + } + + private parseScDeployEvent(event: { topics: Uint8Array[] }): { address: string; ownerAddress: string; codeHash: Uint8Array; @@ -76,12 +135,34 @@ export class SmartContractTransactionsOutcomeParser { }; } - parseExecute(options: { transactionOutcome: TransactionOutcome; function?: string }): { + parseExecute( + options: + | { transactionOutcome: TransactionOutcome; function?: string } + | { transactionOnNetwork: ITransactionOnNetwork; function?: string }, + ): { values: any[]; returnCode: string; returnMessage: string; } { - const directCallOutcome = options.transactionOutcome.directSmartContractCallOutcome; + if ("transactionOutcome" in options) { + return this.parseExecuteGivenTransactionOutcome(options.transactionOutcome, options.function); + } + + return this.parseExecuteGivenTransactionOnNetwork(options.transactionOnNetwork, options.function); + } + + /** + * Legacy approach. + */ + protected parseExecuteGivenTransactionOutcome( + transactionOutcome: TransactionOutcome, + functionName?: string, + ): { + values: any[]; + returnCode: string; + returnMessage: string; + } { + const directCallOutcome = transactionOutcome.directSmartContractCallOutcome; if (!this.abi) { return { @@ -91,7 +172,7 @@ export class SmartContractTransactionsOutcomeParser { }; } - const functionName = options.function || directCallOutcome.function; + functionName = functionName || directCallOutcome.function; if (!functionName) { throw new Err( @@ -115,4 +196,195 @@ export class SmartContractTransactionsOutcomeParser { returnMessage: legacyTypedBundle.returnMessage, }; } + + protected parseExecuteGivenTransactionOnNetwork( + transactionOnNetwork: ITransactionOnNetwork, + functionName?: string, + ): { + values: any[]; + returnCode: string; + returnMessage: string; + } { + const directCallOutcome = this.findDirectSmartContractCallOutcome(transactionOnNetwork); + + if (!this.abi) { + return { + values: directCallOutcome.returnDataParts, + returnCode: directCallOutcome.returnCode, + returnMessage: directCallOutcome.returnMessage, + }; + } + + functionName = functionName || directCallOutcome.function; + + if (!functionName) { + throw new Err( + `Function name is not available in the transaction, thus endpoint definition (ABI) cannot be picked (for parsing). Maybe provide the "function" parameter explicitly?`, + ); + } + + const argsSerializer = new ArgSerializer(); + const endpoint = this.abi.getEndpoint(functionName); + const buffers = directCallOutcome.returnDataParts.map((part) => Buffer.from(part)); + const values = argsSerializer.buffersToValues(buffers, endpoint.output); + + return { + returnCode: directCallOutcome.returnCode, + returnMessage: directCallOutcome.returnMessage, + values: values, + }; + } + + protected findDirectSmartContractCallOutcome( + transactionOnNetwork: ITransactionOnNetwork, + ): SmartContractCallOutcome { + let outcome = this.findDirectSmartContractCallOutcomeWithinSmartContractResults(transactionOnNetwork); + if (outcome) { + return outcome; + } + + outcome = this.findDirectSmartContractCallOutcomeIfError(transactionOnNetwork); + if (outcome) { + return outcome; + } + + outcome = this.findDirectSmartContractCallOutcomeWithinWriteLogEvents(transactionOnNetwork); + if (outcome) { + return outcome; + } + + return new SmartContractCallOutcome({ + function: transactionOnNetwork.function, + returnCode: "", + returnMessage: "", + returnDataParts: [], + }); + } + + protected findDirectSmartContractCallOutcomeWithinSmartContractResults( + transactionOnNetwork: ITransactionOnNetwork, + ): SmartContractCallOutcome | null { + const argSerializer = new ArgSerializer(); + const eligibleResults: IContractResultItem[] = []; + + for (const result of transactionOnNetwork.contractResults.items) { + const matchesCriteriaOnData = result.data.startsWith(ARGUMENTS_SEPARATOR); + const matchesCriteriaOnReceiver = result.receiver.bech32() === transactionOnNetwork.sender.bech32(); + const matchesCriteriaOnPreviousHash = result.previousHash === transactionOnNetwork.hash; + + const matchesCriteria = matchesCriteriaOnData && matchesCriteriaOnReceiver && matchesCriteriaOnPreviousHash; + if (matchesCriteria) { + eligibleResults.push(result); + } + } + + if (eligibleResults.length === 0) { + return null; + } + + if (eligibleResults.length > 1) { + throw new Error( + `More than one smart contract result (holding the return data) found for transaction: ${transactionOnNetwork.hash}`, + ); + } + + const [result] = eligibleResults; + const [_ignored, returnCode, ...returnDataParts] = argSerializer.stringToBuffers(result.data); + + return new SmartContractCallOutcome({ + function: transactionOnNetwork.function, + returnCode: returnCode?.toString(), + returnMessage: result.returnMessage || returnCode?.toString(), + returnDataParts: returnDataParts, + }); + } + + protected findDirectSmartContractCallOutcomeIfError( + transactionOnNetwork: ITransactionOnNetwork, + ): SmartContractCallOutcome | null { + const argSerializer = new ArgSerializer(); + const eventIdentifier = Events.SignalError; + const eligibleEvents: ITransactionEvent[] = []; + + // First, look in "logs": + eligibleEvents.push( + ...transactionOnNetwork.logs.events.filter((event) => event.identifier === eventIdentifier), + ); + + // Then, look in "logs" of "contractResults": + for (const result of transactionOnNetwork.contractResults.items) { + if (result.previousHash != transactionOnNetwork.hash) { + continue; + } + + eligibleEvents.push(...result.logs.events.filter((event) => event.identifier === eventIdentifier)); + } + + if (eligibleEvents.length === 0) { + return null; + } + + if (eligibleEvents.length > 1) { + throw new Error( + `More than one "${eventIdentifier}" event found for transaction: ${transactionOnNetwork.hash}`, + ); + } + + const [event] = eligibleEvents; + const data = event.dataPayload?.valueOf().toString() || ""; + const lastTopic = event.getLastTopic()?.toString(); + const parts = argSerializer.stringToBuffers(data); + // Assumption: the last part is the return code. + const returnCode = parts[parts.length - 1]; + + return new SmartContractCallOutcome({ + function: transactionOnNetwork.function, + returnCode: returnCode?.toString() || eventIdentifier, + returnMessage: lastTopic || returnCode?.toString() || eventIdentifier, + returnDataParts: [], + }); + } + + protected findDirectSmartContractCallOutcomeWithinWriteLogEvents( + transactionOnNetwork: ITransactionOnNetwork, + ): SmartContractCallOutcome | null { + const argSerializer = new ArgSerializer(); + const eventIdentifier = Events.WriteLog; + const eligibleEvents: ITransactionEvent[] = []; + + // First, look in "logs": + eligibleEvents.push( + ...transactionOnNetwork.logs.events.filter((event) => event.identifier === eventIdentifier), + ); + + // Then, look in "logs" of "contractResults": + for (const result of transactionOnNetwork.contractResults.items) { + if (result.previousHash != transactionOnNetwork.hash) { + continue; + } + + eligibleEvents.push(...result.logs.events.filter((event) => event.identifier === eventIdentifier)); + } + + if (eligibleEvents.length === 0) { + return null; + } + + if (eligibleEvents.length > 1) { + throw new Error( + `More than one "${eventIdentifier}" event found for transaction: ${transactionOnNetwork.hash}`, + ); + } + + const [event] = eligibleEvents; + const data = event.dataPayload?.valueOf().toString() || ""; + const [_ignored, returnCode, ...returnDataParts] = argSerializer.stringToBuffers(data); + + return new SmartContractCallOutcome({ + function: transactionOnNetwork.function, + returnCode: returnCode?.toString(), + returnMessage: returnCode?.toString(), + returnDataParts: returnDataParts, + }); + } } diff --git a/src/transactionsOutcomeParsers/tokenManagementTransactionsOutcomeParser.ts b/src/transactionsOutcomeParsers/tokenManagementTransactionsOutcomeParser.ts index 0702cba6c..fcf78d585 100644 --- a/src/transactionsOutcomeParsers/tokenManagementTransactionsOutcomeParser.ts +++ b/src/transactionsOutcomeParsers/tokenManagementTransactionsOutcomeParser.ts @@ -1,45 +1,57 @@ import { Address } from "../address"; +import { TransactionsConverter } from "../converters/transactionsConverter"; import { ErrParseTransactionOutcome } from "../errors"; +import { ITransactionOnNetwork } from "../interfaceOfNetwork"; import { bufferToBigInt } from "../smartcontracts/codec/utils"; import { TransactionEvent, TransactionOutcome, findEventsByIdentifier } from "./resources"; export class TokenManagementTransactionsOutcomeParser { constructor() {} - parseIssueFungible(transactionOutcome: TransactionOutcome): { tokenIdentifier: string }[] { - this.ensureNoError(transactionOutcome.logs.events); + parseIssueFungible(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string }[] { + transaction = this.ensureTransactionOutcome(transaction); - const events = findEventsByIdentifier(transactionOutcome, "issue"); + this.ensureNoError(transaction.logs.events); + + const events = findEventsByIdentifier(transaction, "issue"); return events.map((event) => ({ tokenIdentifier: this.extractTokenIdentifier(event) })); } - parseIssueNonFungible(transactionOutcome: TransactionOutcome): { tokenIdentifier: string }[] { - this.ensureNoError(transactionOutcome.logs.events); + parseIssueNonFungible(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string }[] { + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "issueNonFungible"); + const events = findEventsByIdentifier(transaction, "issueNonFungible"); return events.map((event) => ({ tokenIdentifier: this.extractTokenIdentifier(event) })); } - parseIssueSemiFungible(transactionOutcome: TransactionOutcome): { tokenIdentifier: string }[] { - this.ensureNoError(transactionOutcome.logs.events); + parseIssueSemiFungible(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string }[] { + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "issueSemiFungible"); + const events = findEventsByIdentifier(transaction, "issueSemiFungible"); return events.map((event) => ({ tokenIdentifier: this.extractTokenIdentifier(event) })); } - parseRegisterMetaEsdt(transactionOutcome: TransactionOutcome): { tokenIdentifier: string }[] { - this.ensureNoError(transactionOutcome.logs.events); + parseRegisterMetaEsdt(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string }[] { + transaction = this.ensureTransactionOutcome(transaction); - const events = findEventsByIdentifier(transactionOutcome, "registerMetaESDT"); + this.ensureNoError(transaction.logs.events); + + const events = findEventsByIdentifier(transaction, "registerMetaESDT"); return events.map((event) => ({ tokenIdentifier: this.extractTokenIdentifier(event) })); } parseRegisterAndSetAllRoles( - transactionOutcome: TransactionOutcome, + transaction: TransactionOutcome | ITransactionOnNetwork, ): { tokenIdentifier: string; roles: string[] }[] { - this.ensureNoError(transactionOutcome.logs.events); - const registerEvents = findEventsByIdentifier(transactionOutcome, "registerAndSetAllRoles"); - const setRoleEvents = findEventsByIdentifier(transactionOutcome, "ESDTSetRole"); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); + const registerEvents = findEventsByIdentifier(transaction, "registerAndSetAllRoles"); + const setRoleEvents = findEventsByIdentifier(transaction, "ESDTSetRole"); if (registerEvents.length !== setRoleEvents.length) { throw new ErrParseTransactionOutcome( @@ -55,22 +67,28 @@ export class TokenManagementTransactionsOutcomeParser { }); } - parseSetBurnRoleGlobally(transactionOutcome: TransactionOutcome) { - this.ensureNoError(transactionOutcome.logs.events); + parseSetBurnRoleGlobally(transaction: TransactionOutcome | ITransactionOnNetwork) { + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); } - parseUnsetBurnRoleGlobally(transactionOutcome: TransactionOutcome) { - this.ensureNoError(transactionOutcome.logs.events); + parseUnsetBurnRoleGlobally(transaction: TransactionOutcome | ITransactionOnNetwork) { + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); } - parseSetSpecialRole(transactionOutcome: TransactionOutcome): { + parseSetSpecialRole(transaction: TransactionOutcome | ITransactionOnNetwork): { userAddress: string; tokenIdentifier: string; roles: string[]; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTSetRole"); + const events = findEventsByIdentifier(transaction, "ESDTSetRole"); return events.map((event) => this.getOutputForSetSpecialRoleEvent(event)); } @@ -87,14 +105,16 @@ export class TokenManagementTransactionsOutcomeParser { return { userAddress: userAddress, tokenIdentifier: tokenIdentifier, roles: roles }; } - parseNftCreate(transactionOutcome: TransactionOutcome): { + parseNftCreate(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string; nonce: bigint; initialQuantity: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTNFTCreate"); + const events = findEventsByIdentifier(transaction, "ESDTNFTCreate"); return events.map((event) => this.getOutputForNftCreateEvent(event)); } @@ -110,15 +130,17 @@ export class TokenManagementTransactionsOutcomeParser { return { tokenIdentifier: tokenIdentifier, nonce: nonce, initialQuantity: amount }; } - parseLocalMint(transactionOutcome: TransactionOutcome): { + parseLocalMint(transaction: TransactionOutcome | ITransactionOnNetwork): { userAddress: string; tokenIdentifier: string; nonce: bigint; mintedSupply: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); - const events = findEventsByIdentifier(transactionOutcome, "ESDTLocalMint"); + this.ensureNoError(transaction.logs.events); + + const events = findEventsByIdentifier(transaction, "ESDTLocalMint"); return events.map((event) => this.getOutputForLocalMintEvent(event)); } @@ -141,15 +163,17 @@ export class TokenManagementTransactionsOutcomeParser { }; } - parseLocalBurn(transactionOutcome: TransactionOutcome): { + parseLocalBurn(transaction: TransactionOutcome | ITransactionOnNetwork): { userAddress: string; tokenIdentifier: string; nonce: bigint; burntSupply: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTLocalBurn"); + const events = findEventsByIdentifier(transaction, "ESDTLocalBurn"); return events.map((event) => this.getOutputForLocalBurnEvent(event)); } @@ -172,29 +196,35 @@ export class TokenManagementTransactionsOutcomeParser { }; } - parsePause(transactionOutcome: TransactionOutcome): { tokenIdentifier: string }[] { - this.ensureNoError(transactionOutcome.logs.events); + parsePause(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string }[] { + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTPause"); + const events = findEventsByIdentifier(transaction, "ESDTPause"); return events.map((event) => ({ tokenIdentifier: this.extractTokenIdentifier(event) })); } - parseUnpause(transactionOutcome: TransactionOutcome): { tokenIdentifier: string }[] { - this.ensureNoError(transactionOutcome.logs.events); + parseUnpause(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string }[] { + transaction = this.ensureTransactionOutcome(transaction); - const events = findEventsByIdentifier(transactionOutcome, "ESDTUnPause"); + this.ensureNoError(transaction.logs.events); + + const events = findEventsByIdentifier(transaction, "ESDTUnPause"); return events.map((event) => ({ tokenIdentifier: this.extractTokenIdentifier(event) })); } - parseFreeze(transactionOutcome: TransactionOutcome): { + parseFreeze(transaction: TransactionOutcome | ITransactionOnNetwork): { userAddress: string; tokenIdentifier: string; nonce: bigint; balance: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTFreeze"); + const events = findEventsByIdentifier(transaction, "ESDTFreeze"); return events.map((event) => this.getOutputForFreezeEvent(event)); } @@ -217,15 +247,17 @@ export class TokenManagementTransactionsOutcomeParser { }; } - parseUnfreeze(transactionOutcome: TransactionOutcome): { + parseUnfreeze(transaction: TransactionOutcome | ITransactionOnNetwork): { userAddress: string; tokenIdentifier: string; nonce: bigint; balance: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTUnFreeze"); + const events = findEventsByIdentifier(transaction, "ESDTUnFreeze"); return events.map((event) => this.getOutputForUnfreezeEvent(event)); } @@ -248,15 +280,17 @@ export class TokenManagementTransactionsOutcomeParser { }; } - parseWipe(transactionOutcome: TransactionOutcome): { + parseWipe(transaction: TransactionOutcome | ITransactionOnNetwork): { userAddress: string; tokenIdentifier: string; nonce: bigint; balance: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); - const events = findEventsByIdentifier(transactionOutcome, "ESDTWipe"); + this.ensureNoError(transaction.logs.events); + + const events = findEventsByIdentifier(transaction, "ESDTWipe"); return events.map((event) => this.getOutputForWipeEvent(event)); } @@ -279,14 +313,16 @@ export class TokenManagementTransactionsOutcomeParser { }; } - parseUpdateAttributes(transactionOutcome: TransactionOutcome): { + parseUpdateAttributes(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string; nonce: bigint; attributes: Uint8Array; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTNFTUpdateAttributes"); + const events = findEventsByIdentifier(transaction, "ESDTNFTUpdateAttributes"); return events.map((event) => this.getOutputForUpdateAttributesEvent(event)); } @@ -306,14 +342,16 @@ export class TokenManagementTransactionsOutcomeParser { }; } - parseAddQuantity(transactionOutcome: TransactionOutcome): { + parseAddQuantity(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string; nonce: bigint; addedQuantity: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); + + this.ensureNoError(transaction.logs.events); - const events = findEventsByIdentifier(transactionOutcome, "ESDTNFTAddQuantity"); + const events = findEventsByIdentifier(transaction, "ESDTNFTAddQuantity"); return events.map((event) => this.getOutputForAddQuantityEvent(event)); } @@ -333,14 +371,16 @@ export class TokenManagementTransactionsOutcomeParser { }; } - parseBurnQuantity(transactionOutcome: TransactionOutcome): { + parseBurnQuantity(transaction: TransactionOutcome | ITransactionOnNetwork): { tokenIdentifier: string; nonce: bigint; burntQuantity: bigint; }[] { - this.ensureNoError(transactionOutcome.logs.events); + transaction = this.ensureTransactionOutcome(transaction); - const events = findEventsByIdentifier(transactionOutcome, "ESDTNFTBurn"); + this.ensureNoError(transaction.logs.events); + + const events = findEventsByIdentifier(transaction, "ESDTNFTBurn"); return events.map((event) => this.getOutputForBurnQuantityEvent(event)); } @@ -360,6 +400,17 @@ export class TokenManagementTransactionsOutcomeParser { }; } + /** + * Temporary workaround, until "TransactionOnNetwork" completely replaces "TransactionOutcome". + */ + private ensureTransactionOutcome(transaction: TransactionOutcome | ITransactionOnNetwork): TransactionOutcome { + if ("hash" in transaction) { + return new TransactionsConverter().transactionOnNetworkToOutcome(transaction); + } + + return transaction; + } + private ensureNoError(transactionEvents: TransactionEvent[]) { for (const event of transactionEvents) { if (event.identifier == "signalError") { diff --git a/src/transactionsOutcomeParsers/transactionEventsParser.spec.ts b/src/transactionsOutcomeParsers/transactionEventsParser.spec.ts index 9ed01c91c..cddc8ea3d 100644 --- a/src/transactionsOutcomeParsers/transactionEventsParser.spec.ts +++ b/src/transactionsOutcomeParsers/transactionEventsParser.spec.ts @@ -2,11 +2,11 @@ import { ContractResultItem, ContractResults, TransactionEventData, - TransactionEvent as TransactionEventOnNetwork, + TransactionEventOnNetwork, TransactionEventTopic, - TransactionLogs as TransactionLogsOnNetwork, + TransactionLogsOnNetwork, TransactionOnNetwork, -} from "@multiversx/sdk-network-providers"; +} from "../networkProviders"; import BigNumber from "bignumber.js"; import { assert } from "chai"; import { Address } from "../address"; diff --git a/src/utils.ts b/src/utils.ts index dd72af659..c80c7c6df 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -56,3 +56,11 @@ export function isEmpty(value: { isEmpty?: () => boolean; length?: number }): bo return value.length === 0; } + +export function getAxios() { + try { + return require("axios"); + } catch (error) { + throw new Error("axios is required but not installed. Please install axios to make network requests."); + } +} diff --git a/src/wallet/assertions.ts b/src/wallet/assertions.ts new file mode 100644 index 000000000..09ac481d2 --- /dev/null +++ b/src/wallet/assertions.ts @@ -0,0 +1,9 @@ +import { ErrInvariantFailed } from "../errors"; + +export function guardLength(withLength: { length?: number }, expectedLength: number) { + let actualLength = withLength.length || 0; + + if (actualLength != expectedLength) { + throw new ErrInvariantFailed(`wrong length, expected: ${expectedLength}, actual: ${actualLength}`); + } +} diff --git a/src/wallet/crypto/constants.ts b/src/wallet/crypto/constants.ts new file mode 100644 index 000000000..9d29781d0 --- /dev/null +++ b/src/wallet/crypto/constants.ts @@ -0,0 +1,8 @@ +export const CipherAlgorithm = "aes-128-ctr"; +export const DigestAlgorithm = "sha256"; +export const KeyDerivationFunction = "scrypt"; + +// X25519 public key encryption +export const PubKeyEncVersion = 1; +export const PubKeyEncNonceLength = 24; +export const PubKeyEncCipher = "x25519-xsalsa20-poly1305"; diff --git a/src/wallet/crypto/decryptor.ts b/src/wallet/crypto/decryptor.ts new file mode 100644 index 000000000..388b9fd63 --- /dev/null +++ b/src/wallet/crypto/decryptor.ts @@ -0,0 +1,27 @@ +import crypto from "crypto"; +import { Err } from "../../errors"; +import { DigestAlgorithm } from "./constants"; +import { EncryptedData } from "./encryptedData"; + +export class Decryptor { + static decrypt(data: EncryptedData, password: string): Buffer { + const kdfparams = data.kdfparams; + const salt = Buffer.from(data.salt, "hex"); + const iv = Buffer.from(data.iv, "hex"); + const ciphertext = Buffer.from(data.ciphertext, "hex"); + const derivedKey = kdfparams.generateDerivedKey(Buffer.from(password), salt); + const derivedKeyFirstHalf = derivedKey.slice(0, 16); + const derivedKeySecondHalf = derivedKey.slice(16, 32); + + const computedMAC = crypto.createHmac(DigestAlgorithm, derivedKeySecondHalf).update(ciphertext).digest(); + const actualMAC = data.mac; + + if (computedMAC.toString("hex") !== actualMAC) { + throw new Err("MAC mismatch, possibly wrong password"); + } + + const decipher = crypto.createDecipheriv(data.cipher, derivedKeyFirstHalf, iv); + + return Buffer.concat([decipher.update(ciphertext), decipher.final()]); + } +} diff --git a/src/wallet/crypto/derivationParams.ts b/src/wallet/crypto/derivationParams.ts new file mode 100644 index 000000000..134a95343 --- /dev/null +++ b/src/wallet/crypto/derivationParams.ts @@ -0,0 +1,36 @@ +import scryptsy from "scryptsy"; + +export class ScryptKeyDerivationParams { + /** + * numIterations + */ + n = 4096; + + /** + * memFactor + */ + r = 8; + + /** + * pFactor + */ + p = 1; + + dklen = 32; + + constructor(n = 4096, r = 8, p = 1, dklen = 32) { + this.n = n; + this. r = r; + this.p = p; + this.dklen = dklen; + } + + /** + * Will take about: + * - 80-90 ms in Node.js, on a i3-8100 CPU @ 3.60GHz + * - 350-360 ms in browser (Firefox), on a i3-8100 CPU @ 3.60GHz + */ + public generateDerivedKey(password: Buffer, salt: Buffer): Buffer { + return scryptsy(password, salt, this.n, this.r, this.p, this.dklen); + } +} diff --git a/src/wallet/crypto/encrypt.spec.ts b/src/wallet/crypto/encrypt.spec.ts new file mode 100644 index 000000000..1f785968d --- /dev/null +++ b/src/wallet/crypto/encrypt.spec.ts @@ -0,0 +1,22 @@ +import { assert } from "chai"; +import { Decryptor } from "./decryptor"; +import { EncryptedData } from "./encryptedData"; +import { Encryptor } from "./encryptor"; + +describe("test address", () => { + it("encrypts/decrypts", () => { + const sensitiveData = Buffer.from("my mnemonic"); + const encryptedData = Encryptor.encrypt(sensitiveData, "password123"); + const decryptedBuffer = Decryptor.decrypt(encryptedData, "password123"); + + assert.equal(sensitiveData.toString('hex'), decryptedBuffer.toString('hex')); + }); + + it("encodes/decodes kdfparams", () => { + const sensitiveData = Buffer.from("my mnemonic"); + const encryptedData = Encryptor.encrypt(sensitiveData, "password123"); + const decodedData = EncryptedData.fromJSON(encryptedData.toJSON()); + + assert.deepEqual(decodedData, encryptedData, "invalid decoded data"); + }); +}); diff --git a/src/wallet/crypto/encryptedData.ts b/src/wallet/crypto/encryptedData.ts new file mode 100644 index 000000000..b882a5707 --- /dev/null +++ b/src/wallet/crypto/encryptedData.ts @@ -0,0 +1,65 @@ +import { ScryptKeyDerivationParams } from "./derivationParams"; + +export class EncryptedData { + id: string; + version: number; + cipher: string; + ciphertext: string; + iv: string; + kdf: string; + kdfparams: ScryptKeyDerivationParams; + salt: string; + mac: string; + + constructor(data: Omit) { + this.id = data.id; + this.version = data.version; + this.ciphertext = data.ciphertext; + this.iv = data.iv; + this.cipher = data.cipher; + this.kdf = data.kdf; + this.kdfparams = data.kdfparams; + this.mac = data.mac; + this.salt = data.salt; + } + + toJSON(): any { + return { + version: this.version, + id: this.id, + crypto: { + ciphertext: this.ciphertext, + cipherparams: { iv: this.iv }, + cipher: this.cipher, + kdf: this.kdf, + kdfparams: { + dklen: this.kdfparams.dklen, + salt: this.salt, + n: this.kdfparams.n, + r: this.kdfparams.r, + p: this.kdfparams.p + }, + mac: this.mac, + } + }; + } + + static fromJSON(data: any): EncryptedData { + return new EncryptedData({ + version: data.version, + id: data.id, + ciphertext: data.crypto.ciphertext, + iv: data.crypto.cipherparams.iv, + cipher: data.crypto.cipher, + kdf: data.crypto.kdf, + kdfparams: new ScryptKeyDerivationParams( + data.crypto.kdfparams.n, + data.crypto.kdfparams.r, + data.crypto.kdfparams.p, + data.crypto.kdfparams.dklen, + ), + salt: data.crypto.kdfparams.salt, + mac: data.crypto.mac, + }); + } +} diff --git a/src/wallet/crypto/encryptor.ts b/src/wallet/crypto/encryptor.ts new file mode 100644 index 000000000..9d6e33c1b --- /dev/null +++ b/src/wallet/crypto/encryptor.ts @@ -0,0 +1,40 @@ +import crypto from "crypto"; +import { CipherAlgorithm, DigestAlgorithm, KeyDerivationFunction } from "./constants"; +import { ScryptKeyDerivationParams } from "./derivationParams"; +import { EncryptedData } from "./encryptedData"; +import { Randomness } from "./randomness"; + +interface IRandomness { + id: string; + iv: Buffer; + salt: Buffer; +} + +export enum EncryptorVersion { + V4 = 4, +} + +export class Encryptor { + static encrypt(data: Buffer, password: string, randomness: IRandomness = new Randomness()): EncryptedData { + const kdParams = new ScryptKeyDerivationParams(); + const derivedKey = kdParams.generateDerivedKey(Buffer.from(password), randomness.salt); + const derivedKeyFirstHalf = derivedKey.slice(0, 16); + const derivedKeySecondHalf = derivedKey.slice(16, 32); + const cipher = crypto.createCipheriv(CipherAlgorithm, derivedKeyFirstHalf, randomness.iv); + + const ciphertext = Buffer.concat([cipher.update(data), cipher.final()]); + const mac = crypto.createHmac(DigestAlgorithm, derivedKeySecondHalf).update(ciphertext).digest(); + + return new EncryptedData({ + version: EncryptorVersion.V4, + id: randomness.id, + ciphertext: ciphertext.toString('hex'), + iv: randomness.iv.toString('hex'), + cipher: CipherAlgorithm, + kdf: KeyDerivationFunction, + kdfparams: kdParams, + mac: mac.toString('hex'), + salt: randomness.salt.toString('hex') + }); + } +} diff --git a/src/wallet/crypto/index.ts b/src/wallet/crypto/index.ts new file mode 100644 index 000000000..183a29c0f --- /dev/null +++ b/src/wallet/crypto/index.ts @@ -0,0 +1,7 @@ +export * from "./constants"; +export * from "./encryptor"; +export * from "./decryptor"; +export * from "./pubkeyEncryptor"; +export * from "./pubkeyDecryptor"; +export * from "./encryptedData"; +export * from "./randomness"; diff --git a/src/wallet/crypto/pubkeyDecryptor.ts b/src/wallet/crypto/pubkeyDecryptor.ts new file mode 100644 index 000000000..e9b6d7a00 --- /dev/null +++ b/src/wallet/crypto/pubkeyDecryptor.ts @@ -0,0 +1,36 @@ +import crypto from "crypto"; +import nacl from "tweetnacl"; +import ed2curve from "ed2curve"; +import { X25519EncryptedData } from "./x25519EncryptedData"; +import { UserPublicKey, UserSecretKey } from "../userKeys"; + +export class PubkeyDecryptor { + static decrypt(data: X25519EncryptedData, decryptorSecretKey: UserSecretKey): Buffer { + const ciphertext = Buffer.from(data.ciphertext, 'hex'); + const edhPubKey = Buffer.from(data.identities.ephemeralPubKey, 'hex'); + const originatorPubKeyBuffer = Buffer.from(data.identities.originatorPubKey, 'hex'); + const originatorPubKey = new UserPublicKey(originatorPubKeyBuffer); + + const authMessage = crypto.createHash('sha256').update( + Buffer.concat([ciphertext, edhPubKey]) + ).digest(); + + if (!originatorPubKey.verify(authMessage, Buffer.from(data.mac, 'hex'))) { + throw new Error("Invalid authentication for encrypted message originator"); + } + + const nonce = Buffer.from(data.nonce, 'hex'); + const x25519Secret = ed2curve.convertSecretKey(decryptorSecretKey.valueOf()); + const x25519EdhPubKey = ed2curve.convertPublicKey(edhPubKey); + if (x25519EdhPubKey === null) { + throw new Error("Could not convert ed25519 public key to x25519"); + } + + const decryptedMessage = nacl.box.open(ciphertext, nonce, x25519EdhPubKey, x25519Secret); + if (decryptedMessage === null) { + throw new Error("Failed authentication for given ciphertext"); + } + + return Buffer.from(decryptedMessage); + } +} diff --git a/src/wallet/crypto/pubkeyEncrypt.spec.ts b/src/wallet/crypto/pubkeyEncrypt.spec.ts new file mode 100644 index 000000000..804a35f5b --- /dev/null +++ b/src/wallet/crypto/pubkeyEncrypt.spec.ts @@ -0,0 +1,45 @@ +import { assert } from "chai"; +import { loadTestWallet, TestWallet } from "../../testutils/wallets"; +import { UserPublicKey, UserSecretKey } from "../userKeys"; +import { PubkeyDecryptor } from "./pubkeyDecryptor"; +import { PubkeyEncryptor } from "./pubkeyEncryptor"; +import { X25519EncryptedData } from "./x25519EncryptedData"; + +describe("test address", () => { + let alice: TestWallet, bob: TestWallet, carol: TestWallet; + const sensitiveData = Buffer.from("alice's secret text for bob"); + let encryptedDataOfAliceForBob: X25519EncryptedData; + + before(async () => { + alice = await loadTestWallet("alice"); + bob = await loadTestWallet("bob"); + carol = await loadTestWallet("carol"); + + encryptedDataOfAliceForBob = PubkeyEncryptor.encrypt( + sensitiveData, + new UserPublicKey(bob.address.pubkey()), + new UserSecretKey(alice.secretKey), + ); + }); + + it("encrypts/decrypts", () => { + const decryptedData = PubkeyDecryptor.decrypt(encryptedDataOfAliceForBob, new UserSecretKey(bob.secretKey)); + assert.equal(sensitiveData.toString("hex"), decryptedData.toString("hex")); + }); + + it("fails for different originator", () => { + encryptedDataOfAliceForBob.identities.originatorPubKey = carol.address.hex(); + assert.throws( + () => PubkeyDecryptor.decrypt(encryptedDataOfAliceForBob, new UserSecretKey(bob.secretKey)), + "Invalid authentication for encrypted message originator", + ); + }); + + it("fails for different DH public key", () => { + encryptedDataOfAliceForBob.identities.ephemeralPubKey = carol.address.hex(); + assert.throws( + () => PubkeyDecryptor.decrypt(encryptedDataOfAliceForBob, new UserSecretKey(bob.secretKey)), + "Invalid authentication for encrypted message originator", + ); + }); +}); diff --git a/src/wallet/crypto/pubkeyEncryptor.ts b/src/wallet/crypto/pubkeyEncryptor.ts new file mode 100644 index 000000000..0c89bf16c --- /dev/null +++ b/src/wallet/crypto/pubkeyEncryptor.ts @@ -0,0 +1,47 @@ +import crypto from "crypto"; +import ed2curve from "ed2curve"; +import nacl from "tweetnacl"; +import { UserPublicKey, UserSecretKey } from "../userKeys"; +import { PubKeyEncCipher, PubKeyEncNonceLength, PubKeyEncVersion } from "./constants"; +import { X25519EncryptedData } from "./x25519EncryptedData"; + +export class PubkeyEncryptor { + static encrypt(data: Buffer, recipientPubKey: UserPublicKey, authSecretKey: UserSecretKey): X25519EncryptedData { + // create a new x25519 keypair that will be used for EDH + const edhPair = nacl.sign.keyPair(); + const recipientDHPubKey = ed2curve.convertPublicKey(recipientPubKey.valueOf()); + if (recipientDHPubKey === null) { + throw new Error("Could not convert ed25519 public key to x25519"); + } + const edhConvertedSecretKey = ed2curve.convertSecretKey(edhPair.secretKey); + + // For the nonce we use a random component and a deterministic one based on the message + // - this is so we won't completely rely on the random number generator + const nonceDeterministic = crypto.createHash('sha256').update(data).digest().slice(0, PubKeyEncNonceLength / 2); + const nonceRandom = nacl.randomBytes(PubKeyEncNonceLength / 2); + const nonce = Buffer.concat([nonceDeterministic, nonceRandom]); + const encryptedMessage = nacl.box(data, nonce, recipientDHPubKey, edhConvertedSecretKey); + + // Note that the ciphertext is already authenticated for the ephemeral key - but we want it authenticated by + // the ed25519 key which the user interacts with. A signature over H(ciphertext | edhPubKey) + // would be enough + const authMessage = crypto.createHash('sha256').update( + Buffer.concat([encryptedMessage, edhPair.publicKey]) + ).digest(); + + const signature = authSecretKey.sign(authMessage); + + return new X25519EncryptedData({ + version: PubKeyEncVersion, + nonce: Buffer.from(nonce).toString('hex'), + cipher: PubKeyEncCipher, + ciphertext: Buffer.from(encryptedMessage).toString('hex'), + mac: signature.toString('hex'), + identities: { + recipient: recipientPubKey.hex(), + ephemeralPubKey: Buffer.from(edhPair.publicKey).toString('hex'), + originatorPubKey: authSecretKey.generatePublicKey().hex(), + } + }); + } +} diff --git a/src/wallet/crypto/randomness.ts b/src/wallet/crypto/randomness.ts new file mode 100644 index 000000000..c6355ff87 --- /dev/null +++ b/src/wallet/crypto/randomness.ts @@ -0,0 +1,15 @@ +import { utils } from "@noble/ed25519"; +import { v4 as uuidv4 } from "uuid"; +const crypto = require("crypto"); + +export class Randomness { + salt: Buffer; + iv: Buffer; + id: string; + + constructor(init?: Partial) { + this.salt = init?.salt || Buffer.from(utils.randomBytes(32)); + this.iv = init?.iv || Buffer.from(utils.randomBytes(16)); + this.id = init?.id || uuidv4({ random: crypto.randomBytes(16) }); + } +} diff --git a/src/wallet/crypto/x25519EncryptedData.ts b/src/wallet/crypto/x25519EncryptedData.ts new file mode 100644 index 000000000..4bc3ffbc8 --- /dev/null +++ b/src/wallet/crypto/x25519EncryptedData.ts @@ -0,0 +1,45 @@ +export class X25519EncryptedData { + nonce: string; + version: number; + cipher: string; + ciphertext: string; + mac: string; + identities: { + recipient: string, + ephemeralPubKey: string, + originatorPubKey: string, + }; + + constructor(data: Omit) { + this.nonce = data.nonce; + this.version = data.version; + this.cipher = data.cipher; + this.ciphertext = data.ciphertext; + this.mac = data.mac; + this.identities = data.identities; + } + + toJSON(): any { + return { + version: this.version, + nonce: this.nonce, + identities: this.identities, + crypto: { + ciphertext: this.ciphertext, + cipher: this.cipher, + mac: this.mac, + } + }; + } + + static fromJSON(data: any): X25519EncryptedData { + return new X25519EncryptedData({ + nonce: data.nonce, + version: data.version, + ciphertext: data.crypto.ciphertext, + cipher: data.crypto.cipher, + mac: data.crypto.mac, + identities: data.identities, + }); + } +} diff --git a/src/wallet/index.ts b/src/wallet/index.ts new file mode 100644 index 000000000..7207e0c14 --- /dev/null +++ b/src/wallet/index.ts @@ -0,0 +1,9 @@ +export * from "./crypto"; +export * from "./mnemonic"; +export * from "./pem"; +export * from "./userKeys"; +export * from "./userSigner"; +export * from "./userVerifier"; +export * from "./userWallet"; +export * from "./validatorKeys"; +export * from "./validatorSigner"; diff --git a/src/wallet/mnemonic.ts b/src/wallet/mnemonic.ts new file mode 100644 index 000000000..77c397b4c --- /dev/null +++ b/src/wallet/mnemonic.ts @@ -0,0 +1,83 @@ +import { derivePath } from "ed25519-hd-key"; +import { ErrBadMnemonicEntropy, ErrWrongMnemonic } from "../errors"; +import { UserSecretKey } from "./userKeys"; + +const MNEMONIC_STRENGTH = 256; +const BIP44_DERIVATION_PREFIX = "m/44'/508'/0'/0'"; + +let bip39: any; + +// Load bip39 when needed +function loadBip39() { + if (!bip39) { + try { + bip39 = require("bip39"); + } catch (error) { + throw new Error("bip39 is required but not installed. Please install 'bip39' to use mnemonic features."); + } + } +} + +export class Mnemonic { + private readonly text: string; + + private constructor(text: string) { + this.text = text; + } + + static generate(): Mnemonic { + loadBip39(); + const text = bip39.generateMnemonic(MNEMONIC_STRENGTH); + return new Mnemonic(text); + } + + static fromString(text: string) { + loadBip39(); + text = text.trim(); + + Mnemonic.assertTextIsValid(text); + return new Mnemonic(text); + } + + static fromEntropy(entropy: Uint8Array): Mnemonic { + loadBip39(); + try { + const text = bip39.entropyToMnemonic(Buffer.from(entropy)); + return new Mnemonic(text); + } catch (err: any) { + throw new ErrBadMnemonicEntropy(err); + } + } + + public static assertTextIsValid(text: string) { + loadBip39(); + let isValid = bip39.validateMnemonic(text); + + if (!isValid) { + throw new ErrWrongMnemonic(); + } + } + + deriveKey(addressIndex: number = 0, password: string = ""): UserSecretKey { + loadBip39(); + let seed = bip39.mnemonicToSeedSync(this.text, password); + let derivationPath = `${BIP44_DERIVATION_PREFIX}/${addressIndex}'`; + let derivationResult = derivePath(derivationPath, seed.toString("hex")); + let key = derivationResult.key; + return new UserSecretKey(key); + } + + getWords(): string[] { + return this.text.split(" "); + } + + getEntropy(): Uint8Array { + loadBip39(); + const entropy = bip39.mnemonicToEntropy(this.text); + return Buffer.from(entropy, "hex"); + } + + toString(): string { + return this.text; + } +} diff --git a/src/wallet/pem.spec.ts b/src/wallet/pem.spec.ts new file mode 100644 index 000000000..73eda6b96 --- /dev/null +++ b/src/wallet/pem.spec.ts @@ -0,0 +1,99 @@ +import { Buffer } from "buffer"; +import { assert } from "chai"; +import { ErrBadPEM } from "../errors"; +import { loadTestWallet, TestWallet } from "./../testutils/wallets"; +import { parse, parseUserKey, parseValidatorKey } from "./pem"; +import { BLS } from "./validatorKeys"; + +describe("test PEMs", () => { + let alice: TestWallet, bob: TestWallet, carol: TestWallet; + + before(async function () { + alice = await loadTestWallet("alice"); + bob = await loadTestWallet("bob"); + carol = await loadTestWallet("carol"); + }); + + it("should parseUserKey", () => { + let aliceKey = parseUserKey(alice.pemFileText); + + assert.equal(aliceKey.hex(), alice.secretKeyHex); + assert.equal(aliceKey.generatePublicKey().toAddress().bech32(), alice.address.bech32()); + }); + + it("should parseValidatorKey", async () => { + await BLS.initIfNecessary(); + + let pem = `-----BEGIN PRIVATE KEY for e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208----- +N2NmZjk5YmQ2NzE1MDJkYjdkMTViYzhhYmMwYzlhODA0ZmI5MjU0MDZmYmRkNTBm +MWU0YzE3YTRjZDc3NDI0Nw== +-----END PRIVATE KEY for e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208-----`; + + let validatorKey = parseValidatorKey(pem); + + assert.equal(validatorKey.hex(), "7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247"); + assert.equal( + validatorKey.generatePublicKey().hex(), + "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208", + ); + }); + + it("should parse multi-key PEM files", () => { + // The user PEM files encode both the seed and the pubkey in their payloads. + let payloadAlice = Buffer.from(alice.secretKeyHex + alice.address.hex()).toString("base64"); + let payloadBob = Buffer.from(bob.secretKeyHex + bob.address.hex()).toString("base64"); + let payloadCarol = Buffer.from(carol.secretKeyHex + carol.address.hex()).toString("base64"); + + let expected = [ + Buffer.concat([alice.secretKey, alice.address.pubkey()]), + Buffer.concat([bob.secretKey, bob.address.pubkey()]), + Buffer.concat([carol.secretKey, carol.address.pubkey()]), + ]; + + let trivialContent = `-----BEGIN PRIVATE KEY for alice +${payloadAlice} +-----END PRIVATE KEY for alice +-----BEGIN PRIVATE KEY for bob +${payloadBob} +-----END PRIVATE KEY for bob +-----BEGIN PRIVATE KEY for carol +${payloadCarol} +-----END PRIVATE KEY for carol +`; + + assert.deepEqual(parse(trivialContent, 64), expected); + + let contentWithWhitespaces = ` +-----BEGIN PRIVATE KEY for alice + ${payloadAlice} + -----END PRIVATE KEY for alice + + -----BEGIN PRIVATE KEY for bob + ${payloadBob} + -----END PRIVATE KEY for bob + -----BEGIN PRIVATE KEY for carol + + + ${payloadCarol} + -----END PRIVATE KEY for carol + `; + + assert.deepEqual(parse(contentWithWhitespaces, 64), expected); + }); + + it("should report parsing errors", () => { + let contentWithoutEnd = `-----BEGIN PRIVATE KEY for alice + NDEzZjQyNTc1ZjdmMjZmYWQzMzE3YTc3ODc3MTIxMmZkYjgwMjQ1ODUwOTgxZTQ4 + YjU4YTRmMjVlMzQ0ZThmOTAxMzk0NzJlZmY2ODg2NzcxYTk4MmYzMDgzZGE1ZDQy + MWYyNGMyOTE4MWU2Mzg4ODIyOGRjODFjYTYwZDY5ZTE=`; + + assert.throw(() => parseUserKey(contentWithoutEnd), ErrBadPEM); + + let contentWithBadData = `-----BEGIN PRIVATE KEY for alice + NDEzZjQyNTc1ZjdmMjZmYWQzMzE3YTc3ODc3MTIxMmZkYjgwMjQ1ODUwOTgxZTQ4 + YjU4YTRmMjVlMzQ0ZThmOTAxMzk0NzJlZmY2ODg2NzcxYTk4MmYzMDgzZGE1Zfoo + -----END PRIVATE KEY for alice`; + + assert.throw(() => parseUserKey(contentWithBadData), ErrBadPEM); + }); +}); diff --git a/src/wallet/pem.ts b/src/wallet/pem.ts new file mode 100644 index 000000000..b60119699 --- /dev/null +++ b/src/wallet/pem.ts @@ -0,0 +1,59 @@ +import { ErrBadPEM } from "../errors"; +import { USER_PUBKEY_LENGTH, USER_SEED_LENGTH, UserSecretKey } from "./userKeys"; +import { VALIDATOR_SECRETKEY_LENGTH, ValidatorSecretKey } from "./validatorKeys"; + +export function parseUserKey(text: string, index: number = 0): UserSecretKey { + const keys = parseUserKeys(text); + return keys[index]; +} + +export function parseUserKeys(text: string): UserSecretKey[] { + // The user PEM files encode both the seed and the pubkey in their payloads. + const buffers = parse(text, USER_SEED_LENGTH + USER_PUBKEY_LENGTH); + return buffers.map((buffer) => new UserSecretKey(buffer.slice(0, USER_SEED_LENGTH))); +} + +export function parseValidatorKey(text: string, index: number = 0): ValidatorSecretKey { + const keys = parseValidatorKeys(text); + return keys[index]; +} + +export function parseValidatorKeys(text: string): ValidatorSecretKey[] { + const buffers = parse(text, VALIDATOR_SECRETKEY_LENGTH); + return buffers.map((buffer) => new ValidatorSecretKey(buffer)); +} + +export function parse(text: string, expectedLength: number): Buffer[] { + // Split by newlines, trim whitespace, then discard remaining empty lines. + const lines = text + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line.length > 0); + const buffers: Buffer[] = []; + let linesAccumulator: string[] = []; + + for (const line of lines) { + if (line.startsWith("-----BEGIN")) { + linesAccumulator = []; + } else if (line.startsWith("-----END")) { + const asBase64 = linesAccumulator.join(""); + const asHex = Buffer.from(asBase64, "base64").toString(); + const asBytes = Buffer.from(asHex, "hex"); + + if (asBytes.length != expectedLength) { + throw new ErrBadPEM(`incorrect key length: expected ${expectedLength}, found ${asBytes.length}`); + } + + buffers.push(asBytes); + linesAccumulator = []; + } else { + linesAccumulator.push(line); + } + } + + if (linesAccumulator.length != 0) { + throw new ErrBadPEM("incorrect file structure"); + } + + return buffers; +} diff --git a/src/wallet/userKeys.ts b/src/wallet/userKeys.ts new file mode 100644 index 000000000..eaee0e10a --- /dev/null +++ b/src/wallet/userKeys.ts @@ -0,0 +1,83 @@ +import * as ed from "@noble/ed25519"; +import { sha512 } from "@noble/hashes/sha512"; +import { Address } from "../address"; +import { guardLength } from "./assertions"; +import { parseUserKey } from "./pem"; + +export const USER_SEED_LENGTH = 32; +export const USER_PUBKEY_LENGTH = 32; + +// See: https://github.com/paulmillr/noble-ed25519 +// In a future version of sdk-wallet, we'll switch to using the async functions of noble-ed25519. +ed.utils.sha512Sync = (...m) => sha512(ed.utils.concatBytes(...m)); + +export class UserSecretKey { + private readonly buffer: Buffer; + + constructor(buffer: Uint8Array) { + guardLength(buffer, USER_SEED_LENGTH); + + this.buffer = Buffer.from(buffer); + } + + static fromString(value: string): UserSecretKey { + guardLength(value, USER_SEED_LENGTH * 2); + + const buffer = Buffer.from(value, "hex"); + return new UserSecretKey(buffer); + } + + static fromPem(text: string, index: number = 0): UserSecretKey { + return parseUserKey(text, index); + } + + generatePublicKey(): UserPublicKey { + const buffer = ed.sync.getPublicKey(new Uint8Array(this.buffer)); + return new UserPublicKey(buffer); + } + + sign(message: Buffer | Uint8Array): Buffer { + const signature = ed.sync.sign(new Uint8Array(message), new Uint8Array(this.buffer)); + return Buffer.from(signature); + } + + hex(): string { + return this.buffer.toString("hex"); + } + + valueOf(): Buffer { + return this.buffer; + } +} + +export class UserPublicKey { + private readonly buffer: Buffer; + + constructor(buffer: Uint8Array) { + guardLength(buffer, USER_PUBKEY_LENGTH); + + this.buffer = Buffer.from(buffer); + } + + verify(data: Buffer | Uint8Array, signature: Buffer | Uint8Array): boolean { + try { + const ok = ed.sync.verify(new Uint8Array(signature), new Uint8Array(data), new Uint8Array(this.buffer)); + return ok; + } catch (err: any) { + console.error(err); + return false; + } + } + + hex(): string { + return this.buffer.toString("hex"); + } + + toAddress(hrp?: string): Address { + return new Address(this.buffer, hrp); + } + + valueOf(): Buffer { + return this.buffer; + } +} diff --git a/src/wallet/userSigner.ts b/src/wallet/userSigner.ts new file mode 100644 index 000000000..acc8f6f09 --- /dev/null +++ b/src/wallet/userSigner.ts @@ -0,0 +1,51 @@ +import { Address } from "../address"; +import { ErrSignerCannotSign } from "../errors"; +import { UserSecretKey } from "./userKeys"; +import { UserWallet } from "./userWallet"; + +interface IUserSecretKey { + sign(message: Buffer | Uint8Array): Buffer; + generatePublicKey(): IUserPublicKey; +} + +interface IUserPublicKey { + toAddress(hrp?: string): { bech32(): string }; +} + +/** + * ed25519 signer + */ +export class UserSigner { + protected readonly secretKey: IUserSecretKey; + + constructor(secretKey: IUserSecretKey) { + this.secretKey = secretKey; + } + + static fromWallet(keyFileObject: any, password: string, addressIndex?: number): UserSigner { + const secretKey = UserWallet.decrypt(keyFileObject, password, addressIndex); + return new UserSigner(secretKey); + } + + static fromPem(text: string, index: number = 0) { + let secretKey = UserSecretKey.fromPem(text, index); + return new UserSigner(secretKey); + } + + async sign(data: Buffer | Uint8Array): Promise { + try { + const signature = this.secretKey.sign(data); + return signature; + } catch (err: any) { + throw new ErrSignerCannotSign(err); + } + } + + /** + * Gets the address of the signer. + */ + getAddress(hrp?: string): Address { + const bech32 = this.secretKey.generatePublicKey().toAddress(hrp).bech32(); + return Address.newFromBech32(bech32); + } +} diff --git a/src/wallet/userVerifier.ts b/src/wallet/userVerifier.ts new file mode 100644 index 000000000..ca56585a0 --- /dev/null +++ b/src/wallet/userVerifier.ts @@ -0,0 +1,31 @@ +import { UserPublicKey } from "./userKeys"; + +interface IAddress { + pubkey(): Buffer; +} + +/** + * ed25519 signature verification + */ +export class UserVerifier { + publicKey: UserPublicKey; + + constructor(publicKey: UserPublicKey) { + this.publicKey = publicKey; + } + + static fromAddress(address: IAddress): UserVerifier { + let publicKey = new UserPublicKey(address.pubkey()); + return new UserVerifier(publicKey); + } + + /** + * + * @param data the raw data to be verified (e.g. an already-serialized enveloped message) + * @param signature the signature to be verified + * @returns true if the signature is valid, false otherwise + */ + verify(data: Buffer | Uint8Array, signature: Buffer | Uint8Array): boolean { + return this.publicKey.verify(data, signature); + } +} diff --git a/src/wallet/userWallet.ts b/src/wallet/userWallet.ts new file mode 100644 index 000000000..743f4ac69 --- /dev/null +++ b/src/wallet/userWallet.ts @@ -0,0 +1,217 @@ +import { Err } from "../errors"; +import { CipherAlgorithm, Decryptor, EncryptedData, Encryptor, KeyDerivationFunction, Randomness } from "./crypto"; +import { ScryptKeyDerivationParams } from "./crypto/derivationParams"; +import { Mnemonic } from "./mnemonic"; +import { UserPublicKey, UserSecretKey } from "./userKeys"; + +interface IRandomness { + id: string; + iv: Buffer; + salt: Buffer; +} + +export enum UserWalletKind { + SecretKey = "secretKey", + Mnemonic = "mnemonic", +} + +export class UserWallet { + private readonly kind: UserWalletKind; + private readonly encryptedData: EncryptedData; + private readonly publicKeyWhenKindIsSecretKey?: UserPublicKey; + + private constructor({ + kind, + encryptedData, + publicKeyWhenKindIsSecretKey, + }: { + kind: UserWalletKind; + encryptedData: EncryptedData; + publicKeyWhenKindIsSecretKey?: UserPublicKey; + }) { + this.kind = kind; + this.encryptedData = encryptedData; + this.publicKeyWhenKindIsSecretKey = publicKeyWhenKindIsSecretKey; + } + + static fromSecretKey({ + secretKey, + password, + randomness, + }: { + secretKey: UserSecretKey; + password: string; + randomness?: IRandomness; + }): UserWallet { + randomness = randomness || new Randomness(); + + const publicKey = secretKey.generatePublicKey(); + const data = Buffer.concat([secretKey.valueOf(), publicKey.valueOf()]); + const encryptedData = Encryptor.encrypt(data, password, randomness); + + return new UserWallet({ + kind: UserWalletKind.SecretKey, + encryptedData, + publicKeyWhenKindIsSecretKey: publicKey, + }); + } + + static fromMnemonic({ + mnemonic, + password, + randomness, + }: { + mnemonic: string; + password: string; + randomness?: IRandomness; + }): UserWallet { + randomness = randomness || new Randomness(); + + Mnemonic.assertTextIsValid(mnemonic); + const data = Buffer.from(mnemonic); + const encryptedData = Encryptor.encrypt(data, password, randomness); + + return new UserWallet({ + kind: UserWalletKind.Mnemonic, + encryptedData, + }); + } + + static decrypt(keyFileObject: any, password: string, addressIndex?: number): UserSecretKey { + const kind = keyFileObject.kind || UserWalletKind.SecretKey; + + if (kind == UserWalletKind.SecretKey) { + if (addressIndex !== undefined) { + throw new Err("addressIndex must not be provided when kind == 'secretKey'"); + } + + return UserWallet.decryptSecretKey(keyFileObject, password); + } + + if (kind == UserWalletKind.Mnemonic) { + const mnemonic = this.decryptMnemonic(keyFileObject, password); + return mnemonic.deriveKey(addressIndex || 0); + } + + throw new Err(`Unknown kind: ${kind}`); + } + + /** + * Copied from: https://github.com/multiversx/mx-deprecated-core-js/blob/v1.28.0/src/account.js#L42 + * Notes: adjustements (code refactoring, no change in logic), in terms of: + * - typing (since this is the TypeScript version) + * - error handling (in line with sdk-core's error system) + * - references to crypto functions + * - references to object members + * + * From an encrypted keyfile, given the password, loads the secret key and the public key. + */ + static decryptSecretKey(keyFileObject: any, password: string): UserSecretKey { + // Here, we check the "kind" field only for files that have it. Older keystore files (holding only secret keys) do not have this field. + const kind = keyFileObject.kind; + if (kind && kind !== UserWalletKind.SecretKey) { + throw new Err(`Expected keystore kind to be ${UserWalletKind.SecretKey}, but it was ${kind}.`); + } + + const encryptedData = UserWallet.edFromJSON(keyFileObject); + + let text = Decryptor.decrypt(encryptedData, password); + while (text.length < 32) { + let zeroPadding = Buffer.from([0x00]); + text = Buffer.concat([zeroPadding, text]); + } + + const seed = text.slice(0, 32); + return new UserSecretKey(seed); + } + + static decryptMnemonic(keyFileObject: any, password: string): Mnemonic { + if (keyFileObject.kind != UserWalletKind.Mnemonic) { + throw new Err(`Expected keystore kind to be ${UserWalletKind.Mnemonic}, but it was ${keyFileObject.kind}.`); + } + + const encryptedData = UserWallet.edFromJSON(keyFileObject); + const data = Decryptor.decrypt(encryptedData, password); + const mnemonic = Mnemonic.fromString(data.toString()); + return mnemonic; + } + + static edFromJSON(keyfileObject: any): EncryptedData { + return new EncryptedData({ + version: keyfileObject.version, + id: keyfileObject.id, + cipher: keyfileObject.crypto.cipher, + ciphertext: keyfileObject.crypto.ciphertext, + iv: keyfileObject.crypto.cipherparams.iv, + kdf: keyfileObject.crypto.kdf, + kdfparams: new ScryptKeyDerivationParams( + keyfileObject.crypto.kdfparams.n, + keyfileObject.crypto.kdfparams.r, + keyfileObject.crypto.kdfparams.p, + keyfileObject.crypto.kdfparams.dklen, + ), + salt: keyfileObject.crypto.kdfparams.salt, + mac: keyfileObject.crypto.mac, + }); + } + + /** + * Converts the encrypted keyfile to plain JavaScript object. + */ + toJSON(addressHrp?: string): any { + if (this.kind == UserWalletKind.SecretKey) { + return this.toJSONWhenKindIsSecretKey(addressHrp); + } + + return this.toJSONWhenKindIsMnemonic(); + } + + private toJSONWhenKindIsSecretKey(addressHrp?: string): any { + if (!this.publicKeyWhenKindIsSecretKey) { + throw new Err("Public key isn't available"); + } + + const cryptoSection = this.getCryptoSectionAsJSON(); + + const envelope: any = { + version: this.encryptedData.version, + kind: this.kind, + id: this.encryptedData.id, + address: this.publicKeyWhenKindIsSecretKey.hex(), + bech32: this.publicKeyWhenKindIsSecretKey.toAddress(addressHrp).toString(), + crypto: cryptoSection, + }; + + return envelope; + } + + getCryptoSectionAsJSON(): any { + const cryptoSection: any = { + ciphertext: this.encryptedData.ciphertext, + cipherparams: { iv: this.encryptedData.iv }, + cipher: CipherAlgorithm, + kdf: KeyDerivationFunction, + kdfparams: { + dklen: this.encryptedData.kdfparams.dklen, + salt: this.encryptedData.salt, + n: this.encryptedData.kdfparams.n, + r: this.encryptedData.kdfparams.r, + p: this.encryptedData.kdfparams.p, + }, + mac: this.encryptedData.mac, + }; + + return cryptoSection; + } + + toJSONWhenKindIsMnemonic(): any { + const cryptoSection = this.getCryptoSectionAsJSON(); + + return { + version: this.encryptedData.version, + id: this.encryptedData.id, + kind: this.kind, + crypto: cryptoSection, + }; + } +} diff --git a/src/wallet/users.spec.ts b/src/wallet/users.spec.ts new file mode 100644 index 000000000..976f4ef85 --- /dev/null +++ b/src/wallet/users.spec.ts @@ -0,0 +1,517 @@ +import { assert } from "chai"; +import { ErrBadMnemonicEntropy, ErrInvariantFailed } from "../errors"; +import { TestMessage } from "./../testutils/message"; +import { TestTransaction } from "./../testutils/transaction"; +import { + DummyMnemonicOf12Words, + loadMnemonic, + loadPassword, + loadTestKeystore, + loadTestWallet, + TestWallet, +} from "./../testutils/wallets"; +import { Randomness } from "./crypto"; +import { Mnemonic } from "./mnemonic"; +import { UserSecretKey } from "./userKeys"; +import { UserSigner } from "./userSigner"; +import { UserVerifier } from "./userVerifier"; +import { UserWallet } from "./userWallet"; + +describe("test user wallets", async () => { + let alice: TestWallet, bob: TestWallet, carol: TestWallet; + let password: string = await loadPassword(); + const dummyMnemonic = await loadMnemonic(); + + before(async function () { + alice = await loadTestWallet("alice"); + bob = await loadTestWallet("bob"); + carol = await loadTestWallet("carol"); + }); + + it("should generate mnemonic", () => { + let mnemonic = Mnemonic.generate(); + let words = mnemonic.getWords(); + assert.lengthOf(words, 24); + }); + + it("should convert entropy to mnemonic and back", () => { + function testConversion(text: string, entropyHex: string) { + const entropyFromMnemonic = Mnemonic.fromString(text).getEntropy(); + const mnemonicFromEntropy = Mnemonic.fromEntropy(Buffer.from(entropyHex, "hex")); + + assert.equal(Buffer.from(entropyFromMnemonic).toString("hex"), entropyHex); + assert.equal(mnemonicFromEntropy.toString(), text); + } + + testConversion( + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "00000000000000000000000000000000", + ); + + testConversion( + "moral volcano peasant pass circle pen over picture flat shop clap goat never lyrics gather prepare woman film husband gravity behind test tiger improve", + "8fbeb688d0529344e77d225898d4a73209510ad81d4ffceac9bfb30149bf387b", + ); + + assert.throws( + () => { + Mnemonic.fromEntropy(Buffer.from("abba", "hex")); + }, + ErrBadMnemonicEntropy, + `Bad mnemonic entropy`, + ); + }); + + it("should derive keys", async () => { + let mnemonic = Mnemonic.fromString(dummyMnemonic); + + assert.equal(mnemonic.deriveKey(0).hex(), alice.secretKeyHex); + assert.equal(mnemonic.deriveKey(1).hex(), bob.secretKeyHex); + assert.equal(mnemonic.deriveKey(2).hex(), carol.secretKeyHex); + }); + + it("should derive keys (12 words)", async () => { + const mnemonic = Mnemonic.fromString(DummyMnemonicOf12Words); + + assert.equal( + mnemonic.deriveKey(0).generatePublicKey().toAddress().bech32(), + "erd1l8g9dk3gz035gkjhwegsjkqzdu3augrwhcfxrnucnyyrpc2220pqg4g7na", + ); + assert.equal( + mnemonic.deriveKey(1).generatePublicKey().toAddress().bech32(), + "erd1fmhwg84rldg0xzngf53m0y607wvefvamh07n2mkypedx27lcqnts4zs09p", + ); + assert.equal( + mnemonic.deriveKey(2).generatePublicKey().toAddress().bech32(), + "erd1tyuyemt4xz2yjvc7rxxp8kyfmk2n3h8gv3aavzd9ru4v2vhrkcksptewtj", + ); + + assert.equal( + mnemonic.deriveKey(0).generatePublicKey().toAddress("test").bech32(), + "test1l8g9dk3gz035gkjhwegsjkqzdu3augrwhcfxrnucnyyrpc2220pqc6tnnf", + ); + assert.equal( + mnemonic.deriveKey(1).generatePublicKey().toAddress("xerd").bech32(), + "xerd1fmhwg84rldg0xzngf53m0y607wvefvamh07n2mkypedx27lcqntsj4adj4", + ); + assert.equal( + mnemonic.deriveKey(2).generatePublicKey().toAddress("yerd").bech32(), + "yerd1tyuyemt4xz2yjvc7rxxp8kyfmk2n3h8gv3aavzd9ru4v2vhrkcksn8p0n5", + ); + }); + + it("should create secret key", () => { + const keyHex = alice.secretKeyHex; + const fromBuffer = new UserSecretKey(Buffer.from(keyHex, "hex")); + const fromArray = new UserSecretKey(Uint8Array.from(Buffer.from(keyHex, "hex"))); + const fromHex = UserSecretKey.fromString(keyHex); + + assert.equal(fromBuffer.hex(), keyHex); + assert.equal(fromArray.hex(), keyHex); + assert.equal(fromHex.hex(), keyHex); + }); + + it("should compute public key (and address)", () => { + let secretKey: UserSecretKey; + + secretKey = new UserSecretKey(Buffer.from(alice.secretKeyHex, "hex")); + assert.equal(secretKey.generatePublicKey().hex(), alice.address.hex()); + assert.deepEqual(secretKey.generatePublicKey().toAddress(), alice.address); + + secretKey = new UserSecretKey(Buffer.from(bob.secretKeyHex, "hex")); + assert.equal(secretKey.generatePublicKey().hex(), bob.address.hex()); + assert.deepEqual(secretKey.generatePublicKey().toAddress(), bob.address); + + secretKey = new UserSecretKey(Buffer.from(carol.secretKeyHex, "hex")); + assert.equal(secretKey.generatePublicKey().hex(), carol.address.hex()); + assert.deepEqual(secretKey.generatePublicKey().toAddress(), carol.address); + }); + + it("should throw error when invalid input", () => { + assert.throw(() => new UserSecretKey(Buffer.alloc(42)), ErrInvariantFailed); + assert.throw(() => UserSecretKey.fromString("foobar"), ErrInvariantFailed); + }); + + it("should handle PEM files", () => { + assert.equal(UserSecretKey.fromPem(alice.pemFileText).hex(), alice.secretKeyHex); + assert.equal(UserSecretKey.fromPem(bob.pemFileText).hex(), bob.secretKeyHex); + assert.equal(UserSecretKey.fromPem(carol.pemFileText).hex(), carol.secretKeyHex); + }); + + it("should create and load keystore files (with secret keys)", function () { + this.timeout(10000); + + let aliceSecretKey = UserSecretKey.fromString(alice.secretKeyHex); + let bobSecretKey = UserSecretKey.fromString(bob.secretKeyHex); + let carolSecretKey = UserSecretKey.fromString(carol.secretKeyHex); + + console.time("encrypt"); + let aliceKeyFile = UserWallet.fromSecretKey({ secretKey: aliceSecretKey, password: password }); + let bobKeyFile = UserWallet.fromSecretKey({ secretKey: bobSecretKey, password: password }); + let carolKeyFile = UserWallet.fromSecretKey({ secretKey: carolSecretKey, password: password }); + console.timeEnd("encrypt"); + + assert.equal(aliceKeyFile.toJSON().bech32, alice.address.bech32()); + assert.equal(bobKeyFile.toJSON().bech32, bob.address.bech32()); + assert.equal(carolKeyFile.toJSON().bech32, carol.address.bech32()); + + console.time("decrypt"); + assert.deepEqual(UserWallet.decryptSecretKey(aliceKeyFile.toJSON(), password), aliceSecretKey); + assert.deepEqual(UserWallet.decryptSecretKey(bobKeyFile.toJSON(), password), bobSecretKey); + assert.deepEqual(UserWallet.decryptSecretKey(carolKeyFile.toJSON(), password), carolSecretKey); + console.timeEnd("decrypt"); + + // With provided randomness, in order to reproduce our development wallets + + aliceKeyFile = UserWallet.fromSecretKey({ + secretKey: aliceSecretKey, + password: password, + randomness: new Randomness({ + id: alice.keyFileObject.id, + iv: Buffer.from(alice.keyFileObject.crypto.cipherparams.iv, "hex"), + salt: Buffer.from(alice.keyFileObject.crypto.kdfparams.salt, "hex"), + }), + }); + + bobKeyFile = UserWallet.fromSecretKey({ + secretKey: bobSecretKey, + password: password, + randomness: new Randomness({ + id: bob.keyFileObject.id, + iv: Buffer.from(bob.keyFileObject.crypto.cipherparams.iv, "hex"), + salt: Buffer.from(bob.keyFileObject.crypto.kdfparams.salt, "hex"), + }), + }); + + carolKeyFile = UserWallet.fromSecretKey({ + secretKey: carolSecretKey, + password: password, + randomness: new Randomness({ + id: carol.keyFileObject.id, + iv: Buffer.from(carol.keyFileObject.crypto.cipherparams.iv, "hex"), + salt: Buffer.from(carol.keyFileObject.crypto.kdfparams.salt, "hex"), + }), + }); + + assert.deepEqual(aliceKeyFile.toJSON(), alice.keyFileObject); + assert.deepEqual(bobKeyFile.toJSON(), bob.keyFileObject); + assert.deepEqual(carolKeyFile.toJSON(), carol.keyFileObject); + }); + + it("should load keystore files (with secret keys, but without 'kind' field)", async function () { + const keyFileObject = await loadTestKeystore("withoutKind.json"); + const secretKey = UserWallet.decryptSecretKey(keyFileObject, password); + + assert.equal( + secretKey.generatePublicKey().toAddress().bech32(), + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + ); + }); + + it("should create and load keystore files (with mnemonics)", async function () { + this.timeout(10000); + + const wallet = UserWallet.fromMnemonic({ mnemonic: dummyMnemonic, password: password }); + const json = wallet.toJSON(); + + assert.equal(json.version, 4); + assert.equal(json.kind, "mnemonic"); + assert.isUndefined(json.bech32); + + const mnemonic = UserWallet.decryptMnemonic(json, password); + const mnemonicText = mnemonic.toString(); + + assert.equal(mnemonicText, dummyMnemonic); + assert.equal(mnemonic.deriveKey(0).generatePublicKey().toAddress().bech32(), alice.address.bech32()); + assert.equal(mnemonic.deriveKey(1).generatePublicKey().toAddress().bech32(), bob.address.bech32()); + assert.equal(mnemonic.deriveKey(2).generatePublicKey().toAddress().bech32(), carol.address.bech32()); + + // With provided randomness, in order to reproduce our test wallets + const expectedDummyWallet = await loadTestKeystore("withDummyMnemonic.json"); + const dummyWallet = UserWallet.fromMnemonic({ + mnemonic: dummyMnemonic, + password: password, + randomness: new Randomness({ + id: "5b448dbc-5c72-4d83-8038-938b1f8dff19", + iv: Buffer.from("2da5620906634972d9a623bc249d63d4", "hex"), + salt: Buffer.from("aa9e0ba6b188703071a582c10e5331f2756279feb0e2768f1ba0fd38ec77f035", "hex"), + }), + }); + + assert.deepEqual(dummyWallet.toJSON(), expectedDummyWallet); + }); + + it("should loadSecretKey, but without 'kind' field", async function () { + const keyFileObject = await loadTestKeystore("withoutKind.json"); + const secretKey = UserWallet.decrypt(keyFileObject, password); + + assert.equal( + secretKey.generatePublicKey().toAddress().bech32(), + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + ); + }); + + it("should throw when calling loadSecretKey with unecessary address index", async function () { + const keyFileObject = await loadTestKeystore("alice.json"); + + assert.throws( + () => UserWallet.decrypt(keyFileObject, password, 42), + "addressIndex must not be provided when kind == 'secretKey'", + ); + }); + + it("should loadSecretKey with mnemonic", async function () { + const keyFileObject = await loadTestKeystore("withDummyMnemonic.json"); + + assert.equal( + UserWallet.decrypt(keyFileObject, password, 0).generatePublicKey().toAddress().bech32(), + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + ); + assert.equal( + UserWallet.decrypt(keyFileObject, password, 1).generatePublicKey().toAddress().bech32(), + "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + ); + assert.equal( + UserWallet.decrypt(keyFileObject, password, 2).generatePublicKey().toAddress().bech32(), + "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", + ); + }); + + it("should sign transactions", async () => { + let signer = new UserSigner( + UserSecretKey.fromString("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"), + ); + let verifier = new UserVerifier( + UserSecretKey.fromString( + "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf", + ).generatePublicKey(), + ); + + // With data field + let transaction = new TestTransaction({ + nonce: 0, + value: "0", + receiver: "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r", + gasPrice: 1000000000, + gasLimit: 50000, + data: "foo", + chainID: "1", + }); + + let serialized = transaction.serializeForSigning(); + let signature = await signer.sign(serialized); + + assert.deepEqual(await signer.sign(serialized), await signer.sign(Uint8Array.from(serialized))); + assert.equal( + serialized.toString(), + `{"nonce":0,"value":"0","receiver":"erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r","sender":"","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","version":1}`, + ); + assert.equal( + signature.toString("hex"), + "a3b61a2fe461f3393c42e6cb0477a6b52ffd92168f10c111f6aa8d0a310ee0c314fae0670f8313f1ad992933ac637c61a8ff20cc20b6a8b2260a4af1a120a70d", + ); + assert.isTrue(verifier.verify(serialized, signature)); + + // Without data field + transaction = new TestTransaction({ + nonce: 8, + value: "10000000000000000000", + receiver: "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r", + gasPrice: 1000000000, + gasLimit: 50000, + chainID: "1", + }); + + serialized = transaction.serializeForSigning(); + signature = await signer.sign(serialized); + + assert.deepEqual(await signer.sign(serialized), await signer.sign(Uint8Array.from(serialized))); + assert.equal( + serialized.toString(), + `{"nonce":8,"value":"10000000000000000000","receiver":"erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r","sender":"","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","version":1}`, + ); + assert.equal( + signature.toString("hex"), + "f136c901d37349a7da8cfe3ab5ec8ef333b0bc351517c0e9bef9eb9704aed3077bf222769cade5ff29dffe5f42e4f0c5e0b068bdba90cd2cb41da51fd45d5a03", + ); + }); + + it("guardian should sign transactions from PEM", async () => { + // bob is the guardian + let signer = new UserSigner( + UserSecretKey.fromString("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"), + ); + let verifier = new UserVerifier( + UserSecretKey.fromString( + "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf", + ).generatePublicKey(), + ); + let guardianSigner = new UserSigner(UserSecretKey.fromPem(bob.pemFileText)); + + // With data field + let transaction = new TestTransaction({ + nonce: 0, + value: "0", + receiver: "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r", + sender: "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", + gasPrice: 1000000000, + gasLimit: 50000, + data: "foo", + chainID: "1", + guardian: "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + options: 2, + version: 2, + }); + + let serialized = transaction.serializeForSigning(); + let signature = await signer.sign(serialized); + let guardianSignature = await guardianSigner.sign(serialized); + + assert.equal( + serialized.toString(), + `{"nonce":0,"value":"0","receiver":"erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","guardian":"erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","options":2,"version":2}`, + ); + assert.equal( + signature.toString("hex"), + "00b867ae749616954711ef227c0a3f5c6556246f26dbde12ad929a099094065341a0fae7c5ced98e6bdd100ce922c975667444ea859dce9597b46e63cade2a03", + ); + assert.equal( + guardianSignature.toString("hex"), + "1326e44941ef7bfbad3edf346e72abe23704ee32b4b6a6a6a9b793bd7c62b6d4a69d3c6ea2dddf7eabc8df8fe291cd24822409ab9194b6a0f3bbbf1c59b0a10f", + ); + assert.isTrue(verifier.verify(serialized, signature)); + + // Without data field + transaction = new TestTransaction({ + nonce: 8, + value: "10000000000000000000", + receiver: "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r", + sender: "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", + gasPrice: 1000000000, + gasLimit: 50000, + chainID: "1", + guardian: "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + options: 2, + version: 2, + }); + + serialized = transaction.serializeForSigning(); + signature = await signer.sign(serialized); + guardianSignature = await guardianSigner.sign(serialized); + + assert.equal( + serialized.toString(), + `{"nonce":8,"value":"10000000000000000000","receiver":"erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","guardian":"erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","options":2,"version":2}`, + ); + assert.equal( + signature.toString("hex"), + "49a63fa0e3cfb81a2b6d926c741328fb270ea4f58fa32585fe8aa3cde191245e5a13c5c059d5576f4c05fc24d2534a2124ff79c98d067ce8412c806779066b03", + ); + assert.equal( + guardianSignature.toString("hex"), + "4c25a54381bf66576d05f32659d30672b5b0bfbfb6b6aee52290d28cfbc87860637f095f83663a1893d12d0d5a27b2ab3325829ff1f1215b81a7ced8ee5d7203", + ); + assert.isTrue(verifier.verify(serialized, signature)); + }); + + it("should sign transactions using PEM files", async () => { + const signer = UserSigner.fromPem(alice.pemFileText); + + const transaction = new TestTransaction({ + nonce: 0, + value: "0", + receiver: "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r", + gasPrice: 1000000000, + gasLimit: 50000, + data: "foo", + chainID: "1", + }); + + const serialized = transaction.serializeForSigning(); + const signature = await signer.sign(serialized); + + assert.deepEqual(await signer.sign(serialized), await signer.sign(Uint8Array.from(serialized))); + assert.equal( + signature.toString("hex"), + "ba4fa95fea1402e4876abf1d5a510615aab374ee48bb76f5230798a7d3f2fcae6ba91ba56c6d62e6e7003ce531ff02f219cb7218dd00dd2ca650ba747f19640a", + ); + }); + + it("signs a general message", async function () { + let signer = new UserSigner( + UserSecretKey.fromString("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"), + ); + let verifier = new UserVerifier( + UserSecretKey.fromString( + "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf", + ).generatePublicKey(), + ); + + const message = new TestMessage({ + foo: "hello", + bar: "world", + }); + + const data = message.serializeForSigning(); + const signature = await signer.sign(data); + + assert.deepEqual(await signer.sign(data), await signer.sign(Uint8Array.from(data))); + assert.isTrue(verifier.verify(data, signature)); + assert.isTrue(verifier.verify(Uint8Array.from(data), Uint8Array.from(signature))); + assert.isFalse(verifier.verify(Buffer.from("hello"), signature)); + assert.isFalse(verifier.verify(new TextEncoder().encode("hello"), signature)); + }); + + it("should create UserSigner from wallet", async function () { + const keyFileObjectWithoutKind = await loadTestKeystore("withoutKind.json"); + const keyFileObjectWithMnemonic = await loadTestKeystore("withDummyMnemonic.json"); + const keyFileObjectWithSecretKey = await loadTestKeystore("withDummySecretKey.json"); + + assert.equal( + UserSigner.fromWallet(keyFileObjectWithoutKind, password).getAddress().bech32(), + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + ); + assert.equal( + UserSigner.fromWallet(keyFileObjectWithMnemonic, password).getAddress().bech32(), + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + ); + assert.equal( + UserSigner.fromWallet(keyFileObjectWithSecretKey, password).getAddress().bech32(), + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + ); + assert.equal( + UserSigner.fromWallet(keyFileObjectWithMnemonic, password, 0).getAddress().bech32(), + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + ); + assert.equal( + UserSigner.fromWallet(keyFileObjectWithMnemonic, password, 1).getAddress().bech32(), + "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + ); + assert.equal( + UserSigner.fromWallet(keyFileObjectWithMnemonic, password, 2).getAddress().bech32(), + "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", + ); + + assert.equal( + UserSigner.fromWallet(keyFileObjectWithMnemonic, password, 0).getAddress("test").bech32(), + "test1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ss5hqhtr", + ); + assert.equal( + UserSigner.fromWallet(keyFileObjectWithMnemonic, password, 1).getAddress("xerd").bech32(), + "xerd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruq9thc9j", + ); + assert.equal( + UserSigner.fromWallet(keyFileObjectWithMnemonic, password, 2).getAddress("yerd").bech32(), + "yerd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaqgh23pp", + ); + }); + + it("should throw error when decrypting secret key with keystore-mnemonic file", async function () { + const userWallet = UserWallet.fromMnemonic({ mnemonic: dummyMnemonic, password: `` }); + const keystoreMnemonic = userWallet.toJSON(); + + assert.throws(() => { + UserWallet.decryptSecretKey(keystoreMnemonic, ``); + }, `Expected keystore kind to be secretKey, but it was mnemonic.`); + }); +}); diff --git a/src/wallet/usersBenchmark.spec.ts b/src/wallet/usersBenchmark.spec.ts new file mode 100644 index 000000000..eeb318e0a --- /dev/null +++ b/src/wallet/usersBenchmark.spec.ts @@ -0,0 +1,54 @@ +import { utils } from "@noble/ed25519"; +import { assert } from "chai"; +import { UserPublicKey, UserSecretKey } from "./userKeys"; + +describe("behchmark sign and verify", () => { + it("should sign and verify", async function () { + this.timeout(60000); + + const n = 1000; + const secretKeys: UserSecretKey[] = []; + const publicKeys: UserPublicKey[] = []; + const messages: Buffer[] = []; + const goodSignatures: Buffer[] = []; + + for (let i = 0; i < n; i++) { + const secretKey = new UserSecretKey(Buffer.from(utils.randomBytes(32))); + const publicKey = secretKey.generatePublicKey(); + const message = Buffer.from(utils.randomBytes(256)); + + secretKeys.push(secretKey); + publicKeys.push(publicKey); + messages.push(message); + } + + console.info(`N = ${n}`); + + console.time("sign"); + + for (let i = 0; i < n; i++) { + const signature = secretKeys[i].sign(messages[i]); + goodSignatures.push(signature); + } + + console.timeEnd("sign"); + + console.time("verify (good)"); + + for (let i = 0; i < n; i++) { + const ok = publicKeys[i].verify(messages[i], goodSignatures[i]); + assert.isTrue(ok); + } + + console.timeEnd("verify (good)"); + + console.time("verify (bad)"); + + for (let i = 0; i < n; i++) { + const ok = publicKeys[i].verify(messages[messages.length - i - 1], goodSignatures[i]); + assert.isFalse(ok); + } + + console.timeEnd("verify (bad)"); + }); +}); diff --git a/src/wallet/validatorKeys.ts b/src/wallet/validatorKeys.ts new file mode 100644 index 000000000..4b2b856f7 --- /dev/null +++ b/src/wallet/validatorKeys.ts @@ -0,0 +1,94 @@ +import { ErrInvariantFailed } from "../errors"; +import { guardLength } from "./assertions"; +import { parseValidatorKey } from "./pem"; + +export const VALIDATOR_SECRETKEY_LENGTH = 32; +export const VALIDATOR_PUBKEY_LENGTH = 96; + +export class BLS { + private static isInitialized: boolean = false; + public static bls: any; + + private static loadBLSModule() { + if (!BLS.bls) { + try { + BLS.bls = require("@multiversx/sdk-bls-wasm"); + } catch (error) { + throw new Error("BLS module is required but not installed. Please install '@multiversx/sdk-bls-wasm'."); + } + } + } + + static async initIfNecessary() { + if (BLS.isInitialized) { + return; + } + BLS.loadBLSModule(); + await BLS.bls.init(BLS.bls.BLS12_381); + + BLS.isInitialized = true; + } + + static guardInitialized() { + if (!BLS.isInitialized) { + throw new ErrInvariantFailed( + "BLS modules are not initalized. Make sure that 'await BLS.initIfNecessary()' is called correctly.", + ); + } + } +} + +export class ValidatorSecretKey { + private readonly secretKey: any; + private readonly publicKey: any; + + constructor(buffer: Buffer | Uint8Array) { + BLS.guardInitialized(); + guardLength(buffer, VALIDATOR_SECRETKEY_LENGTH); + + this.secretKey = new BLS.bls.SecretKey(); + this.secretKey.setLittleEndian(Uint8Array.from(buffer)); + this.publicKey = this.secretKey.getPublicKey(); + } + + static fromPem(text: string, index: number = 0) { + return parseValidatorKey(text, index); + } + + generatePublicKey(): ValidatorPublicKey { + let buffer = Buffer.from(this.publicKey.serialize()); + return new ValidatorPublicKey(buffer); + } + + sign(message: Buffer | Uint8Array): Buffer { + let signatureObject = this.secretKey.sign(message); + let signature = Buffer.from(signatureObject.serialize()); + return signature; + } + + hex(): string { + return this.valueOf().toString("hex"); + } + + valueOf(): Buffer { + return Buffer.from(this.secretKey.serialize()); + } +} + +export class ValidatorPublicKey { + private readonly buffer: Buffer; + + constructor(buffer: Buffer | Uint8Array) { + guardLength(buffer, VALIDATOR_PUBKEY_LENGTH); + + this.buffer = Buffer.from(buffer); + } + + hex(): string { + return this.buffer.toString("hex"); + } + + valueOf(): Buffer { + return this.buffer; + } +} diff --git a/src/wallet/validatorSigner.ts b/src/wallet/validatorSigner.ts new file mode 100644 index 000000000..161c2dad1 --- /dev/null +++ b/src/wallet/validatorSigner.ts @@ -0,0 +1,21 @@ +import { ErrSignerCannotSign } from "../errors"; +import { BLS, ValidatorSecretKey } from "./validatorKeys"; + +/** + * Validator signer (BLS signer) + */ +export class ValidatorSigner { + /** + * Signs a message. + */ + async signUsingPem(pemText: string, pemIndex: number = 0, signable: Buffer | Uint8Array): Promise { + await BLS.initIfNecessary(); + + try { + let secretKey = ValidatorSecretKey.fromPem(pemText, pemIndex); + secretKey.sign(signable); + } catch (err: any) { + throw new ErrSignerCannotSign(err); + } + } +} diff --git a/src/wallet/validators.spec.ts b/src/wallet/validators.spec.ts new file mode 100644 index 000000000..5a01b7a45 --- /dev/null +++ b/src/wallet/validators.spec.ts @@ -0,0 +1,41 @@ +import { assert } from "chai"; +import { BLS, ValidatorSecretKey } from "./validatorKeys"; + +describe("test validator keys", () => { + + it("should create secret key and sign a message", async () => { + await BLS.initIfNecessary(); + + let secretKey = Buffer.from(Buffer.from("N2NmZjk5YmQ2NzE1MDJkYjdkMTViYzhhYmMwYzlhODA0ZmI5MjU0MDZmYmRkNTBmMWU0YzE3YTRjZDc3NDI0Nw==", "base64").toString(), "hex"); + let key = new ValidatorSecretKey(secretKey); + + assert.deepEqual(new ValidatorSecretKey(secretKey), new ValidatorSecretKey(Uint8Array.from(secretKey))); + assert.equal(key.generatePublicKey().hex(), "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208"); + + const data = Buffer.from("hello"); + + let signature = key.sign(data); + + assert.deepEqual(key.sign(data), key.sign(Uint8Array.from(data))); + assert.equal(signature.toString("hex"), "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86"); + + secretKey = Buffer.from(Buffer.from("ODA4NWJhMWQ3ZjdjM2RiOTM4YWQ3MDU5NWEyYmRhYjA5NjQ0ZjFlYzM4MDNiZTE3MWMzM2YxNGJjODBkNGUzYg==", "base64").toString(), "hex"); + key = new ValidatorSecretKey(secretKey); + assert.equal(key.generatePublicKey().hex(), "78689fd4b1e2e434d567fe01e61598a42717d83124308266bd09ccc15d2339dd318c019914b86ac29adbae5dd8a02d0307425e9bd85a296e94943708c72f8c670f0b7c50a890a5719088dbd9f1d062cad9acffa06df834106eebe1a4257ef00d"); + + signature = key.sign(data); + + assert.deepEqual(key.sign(data), key.sign(Uint8Array.from(data))); + assert.equal(signature.toString("hex"), "be2e593ff10899a2ee8e1d5c8094e36c9f48e04b87e129991ff09475808743e07bb41bf6e7bc1463fa554c4b46594b98"); + }); + + it("should handle PEM files", async () => { + await BLS.initIfNecessary(); + + let text = `-----BEGIN foobar +N2NmZjk5YmQ2NzE1MDJkYjdkMTViYzhhYmMwYzlhODA0ZmI5MjU0MDZmYmRkNTBmMWU0YzE3YTRjZDc3NDI0Nw== +-----END foobar`; + assert.equal(ValidatorSecretKey.fromPem(text).hex(), "7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247"); + assert.equal(ValidatorSecretKey.fromPem(text).generatePublicKey().hex(), "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208"); + }); +});