diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 7cc88f06..00000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.sol linguist-language=Solidity \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7bdcf273..c42df1d6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,10 +14,10 @@ jobs: - run: yarn install --frozen-lockfile --non-interactive - name: Run linter - run: yarn run lint:solidity + run: yarn run lint-solidity - lint-js: - name: Lint JS + lint-ts: + name: Lint TS runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -27,4 +27,4 @@ jobs: - run: yarn install --frozen-lockfile --non-interactive - name: Run linter - run: yarn run lint:js + run: yarn run lint-ts diff --git a/.github/workflows/publish-contracts.yml b/.github/workflows/publish-contracts.yml index 544a55bd..98d8a3d0 100644 --- a/.github/workflows/publish-contracts.yml +++ b/.github/workflows/publish-contracts.yml @@ -27,7 +27,7 @@ jobs: run: yarn run compile - name: Deploy local 1 - run: yarn run deploy:local:1 + run: yarn run deploy-local-1 - name: Login to ghcr uses: docker/login-action@v2 @@ -47,7 +47,7 @@ jobs: run: rm -r data/ - name: Deploy local 2 - run: yarn run deploy:local:2 + run: yarn run deploy-local-2 - name: Push docker image to GitHub Packages uses: docker/build-push-action@v3 @@ -56,15 +56,6 @@ jobs: tags: ghcr.io/${{ github.repository }}:evm2-${{ github.ref_name }} push: true - - name: Remove data - run: rm -r data/ - - - name: Generate types - run: yarn run generate-types - - - name: Build packages - run: yarn run build - - name: Publish to npm registry run: npm publish --access public env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a93b7458..b057fc8c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,23 +25,24 @@ jobs: with: node-version: ${{ matrix.node-version }} - name: Install dependencies - run: make install-deps + run: yarn install - name: Compile contracts - run: make compile + run: yarn run compile - name: Store contract artifacts uses: actions/upload-artifact@v3 with: - name: contracts-artifacts - path: build - - name: Ganache Tests + name: cotracts-artifacts + path: artifacts + - name: Run Tests run: | SILENT=true make start-ganache - make test + npx hardhat node + yarn run test - name: Forked Mainnet Tests run: | fuser -k 8545/tcp - make start-forkedMainnet FORKED_TESTS_PROVIDER=${{ secrets.FORKED_TESTS_PROVIDER }} - make test-forked + yarn run node-fork FORKED_TESTS_PROVIDER=${{ secrets.FORKED_TESTS_PROVIDER }} + yarn run test-fork coverage: needs: test @@ -61,6 +62,6 @@ jobs: uses: actions/download-artifact@v3 with: name: contracts-artifacts - path: build + path: artifacts - name: Yarn install run: yarn install --frozen-lockfile diff --git a/.gitignore b/.gitignore index 3427f008..664e288c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,9 @@ gethdata/ gethdata2/ coverage/ coverage.json -src/ethers src/web3 -ganache/ dist/ data/ .vscode/ .env +artifacts/ diff --git a/.solhint.json b/.solhint.json deleted file mode 100644 index d7d81191..00000000 --- a/.solhint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "solhint:default", - "rules": { - "max-line-length": ["off", 120] - } -} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d705af8f..00000000 --- a/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM trufflesuite/ganache - -WORKDIR /app -COPY data/ /app/data - -CMD ["ganache", "--db", "data/", "-h", "0.0.0.0", "-p", "8545"] diff --git a/Makefile b/Makefile deleted file mode 100644 index 0c6358fb..00000000 --- a/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -URL?=http://localhost:8545 - -install-deps: - @echo " > \033[32mInstalling dependencies... \033[0m " - ./scripts/install_deps.sh - -.PHONY: test -test: - @echo " > \033[32mTesting contracts... \033[0m " - truffle test --stacktrace - -compile: - @echo " > \033[32mCompiling contracts... \033[0m " - truffle compile - -start-ganache: - @echo " > \033[32mStarting ganache... \033[0m " - ./scripts/start_ganache.sh - -start-forkedMainnet: - @echo " > \033[32mStarting forked environment... \033[0m " - ganache -f $(FORKED_TESTS_PROVIDER) & sleep 3 - -test-forked: - @echo " > \033[32mTesting contracts... \033[0m " - truffle test --stacktrace testUnderForked/* - -start-geth: - @echo " > \033[32mStarting geth... \033[0m " - ./scripts/geth/start_geth.sh - -bindings: compile - @echo " > \033[32mCreating go bindings for ethereum contracts... \033[0m " - ./scripts/create_bindings.sh - -func-signatures: - @echo " > \033[32mGenerating signature hashes... \033[0m " - node -e "require('./scripts/generateFuncSignatures.js').generateAccessControlFuncSignatures()" - -## license: Adds license header to missing files. -license: - @echo " > \033[32mAdding license headers...\033[0m " - GO111MODULE=off go get -u github.com/google/addlicense - addlicense -c "Sygma" -f ./scripts/header.txt -y 2021 . - -## license-check: Checks for missing license headers -license-check: - @echo " > \033[Checking for license headers...\033[0m " - GO111MODULE=off go get -u github.com/google/addlicense - addlicense -check -c "SYgma" -f ./scripts/header.txt -y 2021 . diff --git a/cache/solidity-files-cache.json b/cache/solidity-files-cache.json new file mode 100644 index 00000000..1aa08ceb --- /dev/null +++ b/cache/solidity-files-cache.json @@ -0,0 +1,3619 @@ +{ + "_format": "hh-sol-cache-2", + "files": { + "/home/nikola/git/sygma-solidity/contracts/Bridge.sol": { + "lastModificationDate": 1730380778175, + "contentHash": "6d4309ff2a39b88cc40f613008c2f1b0", + "sourceName": "contracts/Bridge.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol", + "@openzeppelin/contracts/utils/Context.sol", + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol", + "./utils/Pausable.sol", + "./interfaces/IERCHandler.sol", + "./interfaces/IHandler.sol", + "./interfaces/IFeeHandler.sol", + "./interfaces/IAccessControlSegregator.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "Bridge" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/utils/Pausable.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "146a6a025472164c67223b7d81ad401b", + "sourceName": "contracts/utils/Pausable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "Pausable" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/IERCHandler.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "3c49e339b550696b1102c25044461cf4", + "sourceName": "contracts/interfaces/IERCHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "IERCHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/IHandler.sol": { + "lastModificationDate": 1715183348960, + "contentHash": "d8191ddfae220340ed5801ba53cc236a", + "sourceName": "contracts/interfaces/IHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "IHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/IFeeHandler.sol": { + "lastModificationDate": 1727172990069, + "contentHash": "b3527424348382c3a45ae9e7ed0520a9", + "sourceName": "contracts/interfaces/IFeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "IFeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/IAccessControlSegregator.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "26d5447095d5a0df9268999b5f137e9f", + "sourceName": "contracts/interfaces/IAccessControlSegregator.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "IAccessControlSegregator" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/Context.sol": { + "lastModificationDate": 1733739714081, + "contentHash": "5f2c5c4b6af2dd4551027144797bc8be", + "sourceName": "@openzeppelin/contracts/utils/Context.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "Context" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": { + "lastModificationDate": 1733739714935, + "contentHash": "161aae4dc1450371d0f324488f66a9cf", + "sourceName": "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./ECDSA.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "EIP712" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "482bcc512029ecf51ca4ae85cf4667c7", + "sourceName": "@openzeppelin/contracts/utils/cryptography/ECDSA.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../Strings.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ECDSA" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/Strings.sol": { + "lastModificationDate": 1733739714081, + "contentHash": "9c54c6c065d9e590fdcdd72c451425b9", + "sourceName": "@openzeppelin/contracts/utils/Strings.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "Strings" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "4e2473d86be8e737a3ba1c38f36a2aab", + "sourceName": "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./draft-IERC20Permit.sol", + "../ERC20.sol", + "../../../utils/cryptography/draft-EIP712.sol", + "../../../utils/cryptography/ECDSA.sol", + "../../../utils/Counters.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC20Permit" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "bab063ddd80e9cc9e313361fef7ef07f", + "sourceName": "@openzeppelin/contracts/token/ERC20/ERC20.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IERC20.sol", + "./extensions/IERC20Metadata.sol", + "../../utils/Context.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC20" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/Counters.sol": { + "lastModificationDate": 1733739714081, + "contentHash": "74654e3ae5d7f39555055dfe244dab7a", + "sourceName": "@openzeppelin/contracts/utils/Counters.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "Counters" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "fb77f144244b9ab12533aa6ce85ef8c5", + "sourceName": "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC20Permit" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "a44d1a099633876550ad2476b21bafbe", + "sourceName": "@openzeppelin/contracts/token/ERC20/IERC20.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC20" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "909ab67fc5c25033fe6cd364f8c056f9", + "sourceName": "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../IERC20.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC20Metadata" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/ERC721MinterBurnerPauser.sol": { + "lastModificationDate": 1706188773394, + "contentHash": "9018e0e73592a2ca5830706708ed7a46", + "sourceName": "contracts/ERC721MinterBurnerPauser.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./utils/AccessControl.sol", + "@openzeppelin/contracts/utils/Context.sol", + "@openzeppelin/contracts/utils/Counters.sol", + "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol", + "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol", + "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC721MinterBurnerPauser" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/utils/AccessControl.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "e1fffd9c57dc478d6d0e5850e3d44654", + "sourceName": "contracts/utils/AccessControl.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol", + "@openzeppelin/contracts/utils/Address.sol", + "@openzeppelin/contracts/utils/Context.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "AccessControl" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol": { + "lastModificationDate": 1733739715586, + "contentHash": "7bbd5ca6e396f0ad628cfbf0031d9e32", + "sourceName": "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC721.sol", + "../../../utils/Context.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC721Burnable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol": { + "lastModificationDate": 1733739715586, + "contentHash": "2bc2d361b7e7bda979021da66e1696af", + "sourceName": "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC721.sol", + "../../../security/Pausable.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC721Pausable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol": { + "lastModificationDate": 1733739715586, + "contentHash": "580a443491d9d70eb064b0130fc3cd01", + "sourceName": "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC721.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC721URIStorage" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/Address.sol": { + "lastModificationDate": 1733739714081, + "contentHash": "ad714a6368ee7d43cded6bbe8af0b155", + "sourceName": "@openzeppelin/contracts/utils/Address.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.1" + ], + "artifacts": [ + "Address" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "lastModificationDate": 1733739714935, + "contentHash": "b8070bbbb327a49a4d37f5c590b38238", + "sourceName": "@openzeppelin/contracts/utils/structs/EnumerableSet.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "EnumerableSet" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "49295810dc45f300e5f84b4b50d88a59", + "sourceName": "@openzeppelin/contracts/token/ERC721/ERC721.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IERC721.sol", + "./IERC721Receiver.sol", + "./extensions/IERC721Metadata.sol", + "../../utils/Address.sol", + "../../utils/Context.sol", + "../../utils/Strings.sol", + "../../utils/introspection/ERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC721" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "lastModificationDate": 1733739714935, + "contentHash": "0e7db055ce108f9da7bb6686a00287c0", + "sourceName": "@openzeppelin/contracts/utils/introspection/ERC165.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC165" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "27d219ec6f69478d065fdbfa7931da68", + "sourceName": "@openzeppelin/contracts/token/ERC721/IERC721.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../../utils/introspection/IERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC721" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "592df588492d45fdcf46b3cb608c0fbf", + "sourceName": "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC721Receiver" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "lastModificationDate": 1733739715586, + "contentHash": "efbc0d15b80a74e34dbe8da0f3e879bb", + "sourceName": "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../IERC721.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC721Metadata" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "lastModificationDate": 1733739714935, + "contentHash": "03e6768535ac4da0e9756f1d8a4a018a", + "sourceName": "@openzeppelin/contracts/utils/introspection/IERC165.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC165" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/security/Pausable.sol": { + "lastModificationDate": 1733739714081, + "contentHash": "9c2dccab8e3a43a18c41e358763fe4d8", + "sourceName": "@openzeppelin/contracts/security/Pausable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../utils/Context.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "Pausable" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/ERC721Safe.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "02778abcce76a2ebdf20de4874fb4257", + "sourceName": "contracts/ERC721Safe.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/token/ERC721/IERC721.sol", + "./ERC721MinterBurnerPauser.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC721Safe" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/ERC721Handler.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "3ac2d27f16b084a8a70c81d19975c1e9", + "sourceName": "contracts/handlers/ERC721Handler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IHandler.sol", + "./ERCHandlerHelpers.sol", + "../ERC721Safe.sol", + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol", + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC721Handler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/ERCHandlerHelpers.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "49e3484320a3c1d8436ea3ad71fa3235", + "sourceName": "contracts/handlers/ERCHandlerHelpers.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IERCHandler.sol", + "../utils/AccessControl.sol", + "../utils/SanityChecks.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERCHandlerHelpers" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": { + "lastModificationDate": 1733739714935, + "contentHash": "1abe3767b27223b96a265645cb2a56e3", + "sourceName": "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC165Checker" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/utils/SanityChecks.sol": { + "lastModificationDate": 1729003333302, + "contentHash": "9d19240df5b134a2a377ad98facf6f29", + "sourceName": "contracts/utils/SanityChecks.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "SanityChecks" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol": { + "lastModificationDate": 1733739715586, + "contentHash": "54062ff887823a306b33ea6494a220bc", + "sourceName": "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../IERC721Receiver.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC721Holder" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/DefaultMessageReceiver.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "7224a6e2715a5c46a3a5783f8b0e2f00", + "sourceName": "contracts/handlers/DefaultMessageReceiver.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/token/ERC20/IERC20.sol", + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol", + "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol", + "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol", + "../utils/AccessControl.sol", + "../interfaces/ISygmaMessageReceiver.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "DefaultMessageReceiver" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/ISygmaMessageReceiver.sol": { + "lastModificationDate": 1729003333302, + "contentHash": "0353086f59f9eebf55720e7e02462941", + "sourceName": "contracts/interfaces/ISygmaMessageReceiver.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ISygmaMessageReceiver" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "76814c83c32552ed2b521c816b4d801a", + "sourceName": "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../IERC20.sol", + "../../../utils/Address.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "SafeERC20" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol": { + "lastModificationDate": 1733739715586, + "contentHash": "88079762e28b246888129028f757e047", + "sourceName": "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./ERC1155Receiver.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC1155Holder" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol": { + "lastModificationDate": 1733739715586, + "contentHash": "55b180cf664783e9a2baac20e82683fb", + "sourceName": "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../IERC1155Receiver.sol", + "../../../utils/introspection/ERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC1155Receiver" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "9f8822b72fe2702979e40160cb6d9636", + "sourceName": "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../../utils/introspection/IERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC1155Receiver" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/ERC1155.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "1d68a32647e54f6acd6ff471d940ef4c", + "sourceName": "@openzeppelin/contracts/token/ERC1155/ERC1155.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IERC1155.sol", + "./IERC1155Receiver.sol", + "./extensions/IERC1155MetadataURI.sol", + "../../utils/Address.sol", + "../../utils/Context.sol", + "../../utils/introspection/ERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC1155" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/IERC1155.sol": { + "lastModificationDate": 1733739714933, + "contentHash": "59e1bc5713fdebc7f821dc52f4d3e0ef", + "sourceName": "@openzeppelin/contracts/token/ERC1155/IERC1155.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../../utils/introspection/IERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC1155" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "9148c2e10c4efb12c71a7f080da5559b", + "sourceName": "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../IERC1155.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IERC1155MetadataURI" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "8c76f015a31a093020b83ba53a33c84d", + "sourceName": "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC1155.sol", + "../../../security/Pausable.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC1155Pausable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol": { + "lastModificationDate": 1733739715584, + "contentHash": "ab4babe7912604097ae769a62fa08506", + "sourceName": "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC20.sol", + "../../../security/Pausable.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC20Pausable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol": { + "lastModificationDate": 1733739715584, + "contentHash": "a1c7f80ae26f5b2d7d563475627fbf25", + "sourceName": "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC20.sol", + "../../../utils/Context.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC20Burnable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "ca6cd8d752c4e75efa2a15734be0cb94", + "sourceName": "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC20.sol", + "../extensions/ERC20Burnable.sol", + "../extensions/ERC20Pausable.sol", + "../../../access/AccessControlEnumerable.sol", + "../../../utils/Context.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC20PresetMinterPauser" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "lastModificationDate": 1733739714079, + "contentHash": "b6d9b165dc57e9ad8153bdca05c783a4", + "sourceName": "@openzeppelin/contracts/access/AccessControlEnumerable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IAccessControlEnumerable.sol", + "./AccessControl.sol", + "../utils/structs/EnumerableSet.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "AccessControlEnumerable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/access/AccessControl.sol": { + "lastModificationDate": 1733739714077, + "contentHash": "76cae8e1eb9c27e818b0b08e1527f731", + "sourceName": "@openzeppelin/contracts/access/AccessControl.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IAccessControl.sol", + "../utils/Context.sol", + "../utils/Strings.sol", + "../utils/introspection/ERC165.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "AccessControl" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "lastModificationDate": 1733739714079, + "contentHash": "4e71cc90682e109e999ce2bd329f6572", + "sourceName": "@openzeppelin/contracts/access/IAccessControlEnumerable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./IAccessControl.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IAccessControlEnumerable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/access/IAccessControl.sol": { + "lastModificationDate": 1733739714079, + "contentHash": "57c84298234411cea19c7c284d86be8b", + "sourceName": "@openzeppelin/contracts/access/IAccessControl.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "IAccessControl" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/IBridge.sol": { + "lastModificationDate": 1727172990069, + "contentHash": "4eb770e68c05638278e26c4d7be2dce6", + "sourceName": "contracts/interfaces/IBridge.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "IBridge" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/ERC1155Handler.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "347757521b4649df0d81389df1440fb8", + "sourceName": "contracts/handlers/ERC1155Handler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IHandler.sol", + "./ERCHandlerHelpers.sol", + "../ERC1155Safe.sol", + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol", + "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol", + "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC1155Handler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/ERC1155Safe.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "08fd92b3a8a779e3155d8ddce9adbdc4", + "sourceName": "contracts/ERC1155Safe.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/token/ERC1155/IERC1155.sol", + "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol", + "@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC1155Safe" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "b9f23167c71a0ebb43ef5915b463a264", + "sourceName": "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC1155.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC1155Burnable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol": { + "lastModificationDate": 1733739715585, + "contentHash": "ce9333438d295d2c4bebc7951ad33d93", + "sourceName": "@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../ERC1155.sol", + "../extensions/ERC1155Burnable.sol", + "../extensions/ERC1155Pausable.sol", + "../../../access/AccessControlEnumerable.sol", + "../../../utils/Context.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "ERC1155PresetMinterPauser" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/XC20Handler.sol": { + "lastModificationDate": 1729003333302, + "contentHash": "a41553a624304bc0f42f934866446f33", + "sourceName": "contracts/handlers/XC20Handler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IHandler.sol", + "./ERCHandlerHelpers.sol", + "../XC20Safe.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "XC20Handler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/XC20Safe.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "bd5ec2b0bcb1dfca3cc74ffc28479f7a", + "sourceName": "contracts/XC20Safe.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./ERC20Safe.sol", + "./interfaces/IERC20Plus.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "XC20Safe" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/ERC20Safe.sol": { + "lastModificationDate": 1726588178067, + "contentHash": "df27df558b320a3b1646eb1e168d0a13", + "sourceName": "contracts/ERC20Safe.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/token/ERC20/IERC20.sol", + "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol", + "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC20Safe" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/IERC20Plus.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "b8eb25c84463a95ee4720775b092d54c", + "sourceName": "contracts/interfaces/IERC20Plus.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/token/ERC20/IERC20.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "IERC20Plus" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/fee/dynamic/TwapFeeHandler.sol": { + "lastModificationDate": 1729498507554, + "contentHash": "3fe3a705425b707cd01b477847c1fa7a", + "sourceName": "contracts/handlers/fee/dynamic/TwapFeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol", + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol", + "../../../interfaces/IFeeHandler.sol", + "../../../interfaces/IERCHandler.sol", + "../../../interfaces/IBridge.sol", + "../../../utils/SanityChecks.sol", + "./TwapOracle.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "TwapFeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/fee/dynamic/TwapOracle.sol": { + "lastModificationDate": 1727172990068, + "contentHash": "cb3a55c3e4553b1843f781c6311a8820", + "sourceName": "contracts/handlers/fee/dynamic/TwapOracle.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol", + "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol", + "../../../utils/TickMath.sol", + "../../../utils/FullMath.sol", + "../../../utils/AccessControl.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "TwapOracle" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/utils/TickMath.sol": { + "lastModificationDate": 1727172990069, + "contentHash": "bb9c21008aef589c6fb567344fb08942", + "sourceName": "contracts/utils/TickMath.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "TickMath" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/utils/FullMath.sol": { + "lastModificationDate": 1727172990069, + "contentHash": "2ca3e14806bc8bf648267136cffef969", + "sourceName": "contracts/utils/FullMath.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "FullMath" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol": { + "lastModificationDate": 1733739715056, + "contentHash": "e6badd8268772b99e7ca397aff11a965", + "sourceName": "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./pool/IUniswapV3PoolImmutables.sol", + "./pool/IUniswapV3PoolState.sol", + "./pool/IUniswapV3PoolDerivedState.sol", + "./pool/IUniswapV3PoolActions.sol", + "./pool/IUniswapV3PoolOwnerActions.sol", + "./pool/IUniswapV3PoolEvents.sol" + ], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3Pool" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol": { + "lastModificationDate": 1733739715056, + "contentHash": "f0eeb76e5ae42bcbacc8efc10e091716", + "sourceName": "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3Factory" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol": { + "lastModificationDate": 1733739715640, + "contentHash": "0488495ef9087b4513d3b43634035ef9", + "sourceName": "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3PoolState" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol": { + "lastModificationDate": 1733739715639, + "contentHash": "e236e09a9d654fb2f20a6da5dba2bd2f", + "sourceName": "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3PoolImmutables" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol": { + "lastModificationDate": 1733739715639, + "contentHash": "1b06ecc79e75f836c446ccf286e671e4", + "sourceName": "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3PoolOwnerActions" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolDerivedState.sol": { + "lastModificationDate": 1733739715639, + "contentHash": "25b71180ec9f5132a158334971ee2ace", + "sourceName": "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolDerivedState.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3PoolDerivedState" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol": { + "lastModificationDate": 1733739715639, + "contentHash": "83d338eb1394008c808a20ac7c5bab0c", + "sourceName": "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3PoolActions" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolEvents.sol": { + "lastModificationDate": 1733739715639, + "contentHash": "05abb59ec113db1046f7dadc78bb297b", + "sourceName": "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolEvents.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.5.0" + ], + "artifacts": [ + "IUniswapV3PoolEvents" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/fee/dynamic/TwapNativeTokenFeeHandler.sol": { + "lastModificationDate": 1729498507554, + "contentHash": "73cb0be2771b608cc8448a57dcaff3aa", + "sourceName": "contracts/handlers/fee/dynamic/TwapNativeTokenFeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./TwapFeeHandler.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "TwapNativeTokenFeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/fee/dynamic/TwapERC20NativeFeeHandler.sol": { + "lastModificationDate": 1729498507554, + "contentHash": "997bb63775bddff01ef397bd77103e09", + "sourceName": "contracts/handlers/fee/dynamic/TwapERC20NativeFeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./TwapNativeTokenFeeHandler.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "TwapERC20NativeFeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/fee/dynamic/TwapGenericFeeHandler.sol": { + "lastModificationDate": 1733739702695, + "contentHash": "4b4ea647d3fbc04b784ec5e9e4cae561", + "sourceName": "contracts/handlers/fee/dynamic/TwapGenericFeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./TwapFeeHandler.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "TwapGenericFeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/solmate/src/utils/CREATE3.sol": { + "lastModificationDate": 1733739715423, + "contentHash": "cb740b456e2814e69904f7b22b835435", + "sourceName": "solmate/src/utils/CREATE3.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./Bytes32AddressLib.sol" + ], + "versionPragmas": [ + ">=0.8.0" + ], + "artifacts": [ + "CREATE3" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/access/Ownable.sol": { + "lastModificationDate": 1733739714079, + "contentHash": "8398972af73b4e9e5ff3b31cad86234f", + "sourceName": "@openzeppelin/contracts/access/Ownable.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../utils/Context.sol" + ], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "Ownable" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol": { + "lastModificationDate": 1733739714935, + "contentHash": "cd91252bfcbee6eaba8f5144f504583c", + "sourceName": "@openzeppelin/contracts/utils/math/SafeCast.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "^0.8.0" + ], + "artifacts": [ + "SafeCast" + ] + }, + "/home/nikola/git/sygma-solidity/node_modules/solmate/src/utils/Bytes32AddressLib.sol": { + "lastModificationDate": 1733739715423, + "contentHash": "8a05c8576a41e44d3e96a6e169162327", + "sourceName": "solmate/src/utils/Bytes32AddressLib.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + ">=0.8.0" + ], + "artifacts": [ + "Bytes32AddressLib" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/Retry.sol": { + "lastModificationDate": 1727172990065, + "contentHash": "a16ff2bf05d2e496b177ba3ba072eac8", + "sourceName": "contracts/Retry.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/access/Ownable.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "Retry" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/FROSTKeygen.sol": { + "lastModificationDate": 1727172990065, + "contentHash": "bde288e2f6f38a62408c127431970fee", + "sourceName": "contracts/FROSTKeygen.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/access/Ownable.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "FROSTKeygen" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/fee/BasicFeeHandler.sol": { + "lastModificationDate": 1729003333302, + "contentHash": "a12d44ab36587c3e31d3ccd52e1be2fa", + "sourceName": "contracts/handlers/fee/BasicFeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../../interfaces/IFeeHandler.sol", + "../../utils/AccessControl.sol", + "../../utils/SanityChecks.sol", + "../FeeHandlerRouter.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "BasicFeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/FeeHandlerRouter.sol": { + "lastModificationDate": 1727172990067, + "contentHash": "cc036e3228c62d20bd81fa76c713ba5a", + "sourceName": "contracts/handlers/FeeHandlerRouter.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IFeeHandler.sol", + "../utils/AccessControl.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "FeeHandlerRouter" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/fee/PercentageERC20FeeHandler.sol": { + "lastModificationDate": 1729003333302, + "contentHash": "5b370293fdfdd385998a1096a1fdc183", + "sourceName": "contracts/handlers/fee/PercentageERC20FeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../../interfaces/IBridge.sol", + "../../interfaces/IERCHandler.sol", + "../../ERC20Safe.sol", + "../../utils/SanityChecks.sol", + "./BasicFeeHandler.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "PercentageERC20FeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/GmpHandler.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "ca495c8d9527268687fb0357176604d0", + "sourceName": "contracts/handlers/GmpHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IHandler.sol", + "../utils/SanityChecks.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "GmpHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/NativeTokenHandler.sol": { + "lastModificationDate": 1729003333302, + "contentHash": "932f247a800cb1e3d41a373684b2d9a8", + "sourceName": "contracts/handlers/NativeTokenHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IHandler.sol", + "../interfaces/ISygmaMessageReceiver.sol", + "./ERCHandlerHelpers.sol", + "./DepositDataHelper.sol", + "../utils/ExcessivelySafeCall.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "NativeTokenHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/utils/ExcessivelySafeCall.sol": { + "lastModificationDate": 1729003333302, + "contentHash": "8e7d996ce7dcb02aae1e45d638e1d4bb", + "sourceName": "contracts/utils/ExcessivelySafeCall.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ExcessivelySafeCall" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/DepositDataHelper.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "76a7930dec9d9eeb39e4267da18e6530", + "sourceName": "contracts/handlers/DepositDataHelper.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./ERCHandlerHelpers.sol", + "../interfaces/ISygmaMessageReceiver.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "DepositDataHelper" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/handlers/ERC20Handler.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "030026d0534091cf4dc718c6ad1e31f4", + "sourceName": "contracts/handlers/ERC20Handler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "../interfaces/IHandler.sol", + "./ERCHandlerHelpers.sol", + "../ERC20Safe.sol", + "./DepositDataHelper.sol", + "../utils/ExcessivelySafeCall.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC20Handler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/TestContracts.sol": { + "lastModificationDate": 1729003333301, + "contentHash": "a407409ce2f4e633e1ee1d52a8b5cad1", + "sourceName": "contracts/TestContracts.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol", + "./handlers/ERCHandlerHelpers.sol", + "./interfaces/IERC20Plus.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "ERC20PresetMinterPauserDecimals", + "ERC20PresetMinterPauserMock", + "HandlerRevert", + "NoArgument", + "OneArgument", + "ReturnData", + "TestDeposit", + "TestForwarder", + "TestStore", + "TestTarget", + "ThreeArguments", + "TwoArguments", + "WithDepositor", + "XC20Test", + "XC20TestMock" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/Forwarder.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "095e1fd5afe43393a1ac41146037cdd7", + "sourceName": "contracts/Forwarder.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol", + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol" + ], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "Forwarder" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/interfaces/IBasicFeeHandler.sol": { + "lastModificationDate": 1727172990069, + "contentHash": "0ece64175e993fc03ffd66f50b38301c", + "sourceName": "contracts/interfaces/IBasicFeeHandler.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "IBasicFeeHandler" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/utils/AccessControlSegregator.sol": { + "lastModificationDate": 1695814116551, + "contentHash": "16db87fcf475af23a703d1e936ef6b79", + "sourceName": "contracts/utils/AccessControlSegregator.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [], + "versionPragmas": [ + "0.8.11" + ], + "artifacts": [ + "AccessControlSegregator" + ] + }, + "/home/nikola/git/sygma-solidity/contracts/NativeTokenTransferGateway.sol": { + "lastModificationDate": 1734356537617, + "contentHash": "42a7087c24cb31223b505c3dad0e0ada", + "sourceName": "contracts/NativeTokenTransferGateway.sol", + "solcConfig": { + "version": "0.8.11", + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } + }, + "imports": [ + "./interfaces/IBridge.sol", + "./interfaces/IFeeHandler.sol" + ], + "versionPragmas": [ + "^0.8.11" + ], + "artifacts": [ + "NativeTokenAdapter" + ] + } + } +} diff --git a/codechecks.yml b/codechecks.yml deleted file mode 100644 index 78a95b3f..00000000 --- a/codechecks.yml +++ /dev/null @@ -1,2 +0,0 @@ -checks: - - name: eth-gas-reporter/codechecks diff --git a/contracts/Migrations.sol b/contracts/Migrations.sol deleted file mode 100644 index 718b8071..00000000 --- a/contracts/Migrations.sol +++ /dev/null @@ -1,25 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity 0.8.11; - -contract Migrations { - address public immutable owner; - uint public last_completed_migration; - - constructor() { - owner = msg.sender; - } - - modifier restricted() { - if (msg.sender == owner) _; - } - - function setCompleted(uint completed) public restricted { - last_completed_migration = completed; - } - - function upgrade(address new_address) public restricted { - Migrations upgraded = Migrations(new_address); - upgraded.setCompleted(last_completed_migration); - } -} diff --git a/contracts/adapters/nativeTokens/NativeTokenAdapter.sol b/contracts/NativeTokenTransferGateway.sol similarity index 97% rename from contracts/adapters/nativeTokens/NativeTokenAdapter.sol rename to contracts/NativeTokenTransferGateway.sol index ed6a7b2b..bc317a97 100644 --- a/contracts/adapters/nativeTokens/NativeTokenAdapter.sol +++ b/contracts/NativeTokenTransferGateway.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.11; -import "../../interfaces/IBridge.sol"; -import "../../interfaces/IFeeHandler.sol"; +import "./interfaces/IBridge.sol"; +import "./interfaces/IFeeHandler.sol"; -contract NativeTokenAdapter { +contract NativeTokenTransferGateway { IBridge public immutable _bridge; bytes32 public immutable _resourceID; diff --git a/contracts/XERC20/XERC20.sol b/contracts/XERC20/XERC20.sol deleted file mode 100644 index c8deb99b..00000000 --- a/contracts/XERC20/XERC20.sol +++ /dev/null @@ -1,286 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.4 <0.9.0; - -import { IXERC20 } from "./interfaces/IXERC20.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; - -/** - * @custom:attribution https://github.com/defi-wonderland/xERC20/blob/dev/solidity/contracts/XERC20.sol - */ -contract XERC20 is ERC20, Ownable, IXERC20, ERC20Permit { - /** - * @notice The duration it takes for the limits to fully replenish - */ - uint256 private constant _DURATION = 1 days; - - /** - * @notice The address of the factory which deployed this contract - */ - address public immutable FACTORY; - - /** - * @notice The address of the lockbox contract - */ - address public lockbox; - - /** - * @notice Maps bridge address to bridge configurations - */ - mapping(address => Bridge) public bridges; - - /** - * @notice Constructs the initial config of the XERC20 - * - * @param _name The name of the token - * @param _symbol The symbol of the token - * @param _factory The factory which deployed this contract - */ - constructor(string memory _name, string memory _symbol, address _factory) ERC20(_name, _symbol) ERC20Permit(_name) { - _transferOwnership(_factory); - FACTORY = _factory; - } - - /** - * @notice Mints tokens for a user - * @dev Can only be called by a bridge - * @param _user The address of the user who needs tokens minted - * @param _amount The amount of tokens being minted - */ - function mint(address _user, uint256 _amount) public { - _mintWithCaller(msg.sender, _user, _amount); - } - - /** - * @notice Burns tokens for a user - * @dev Can only be called by a bridge - * @param _user The address of the user who needs tokens burned - * @param _amount The amount of tokens being burned - */ - function burn(address _user, uint256 _amount) public { - if (msg.sender != _user) { - _spendAllowance(_user, msg.sender, _amount); - } - - _burnWithCaller(msg.sender, _user, _amount); - } - - /** - * @notice Sets the lockbox address - * - * @param _lockbox The address of the lockbox - */ - function setLockbox(address _lockbox) public { - if (msg.sender != FACTORY) revert IXERC20_NotFactory(); - lockbox = _lockbox; - - emit LockboxSet(_lockbox); - } - - /** - * @notice Updates the limits of any bridge - * @dev Can only be called by the owner - * @param _mintingLimit The updated minting limit we are setting to the bridge - * @param _burningLimit The updated burning limit we are setting to the bridge - * @param _bridge The address of the bridge we are setting the limits too - */ - function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external onlyOwner { - if (_mintingLimit > (type(uint256).max / 2) || _burningLimit > (type(uint256).max / 2)) { - revert IXERC20_LimitsTooHigh(); - } - - _changeMinterLimit(_bridge, _mintingLimit); - _changeBurnerLimit(_bridge, _burningLimit); - emit BridgeLimitsSet(_mintingLimit, _burningLimit, _bridge); - } - - /** - * @notice Returns the max limit of a bridge - * - * @param _bridge the bridge we are viewing the limits of - * @return _limit The limit the bridge has - */ - function mintingMaxLimitOf(address _bridge) public view returns (uint256 _limit) { - _limit = bridges[_bridge].minterParams.maxLimit; - } - - /** - * @notice Returns the max limit of a bridge - * - * @param _bridge the bridge we are viewing the limits of - * @return _limit The limit the bridge has - */ - function burningMaxLimitOf(address _bridge) public view returns (uint256 _limit) { - _limit = bridges[_bridge].burnerParams.maxLimit; - } - - /** - * @notice Returns the current limit of a bridge - * - * @param _bridge the bridge we are viewing the limits of - * @return _limit The limit the bridge has - */ - function mintingCurrentLimitOf(address _bridge) public view returns (uint256 _limit) { - _limit = _getCurrentLimit( - bridges[_bridge].minterParams.currentLimit, - bridges[_bridge].minterParams.maxLimit, - bridges[_bridge].minterParams.timestamp, - bridges[_bridge].minterParams.ratePerSecond - ); - } - - /** - * @notice Returns the current limit of a bridge - * - * @param _bridge the bridge we are viewing the limits of - * @return _limit The limit the bridge has - */ - function burningCurrentLimitOf(address _bridge) public view returns (uint256 _limit) { - _limit = _getCurrentLimit( - bridges[_bridge].burnerParams.currentLimit, - bridges[_bridge].burnerParams.maxLimit, - bridges[_bridge].burnerParams.timestamp, - bridges[_bridge].burnerParams.ratePerSecond - ); - } - - /** - * @notice Uses the limit of any bridge - * @param _bridge The address of the bridge who is being changed - * @param _change The change in the limit - */ - function _useMinterLimits(address _bridge, uint256 _change) internal { - uint256 _currentLimit = mintingCurrentLimitOf(_bridge); - bridges[_bridge].minterParams.timestamp = block.timestamp; - bridges[_bridge].minterParams.currentLimit = _currentLimit - _change; - } - - /** - * @notice Uses the limit of any bridge - * @param _bridge The address of the bridge who is being changed - * @param _change The change in the limit - */ - function _useBurnerLimits(address _bridge, uint256 _change) internal { - uint256 _currentLimit = burningCurrentLimitOf(_bridge); - bridges[_bridge].burnerParams.timestamp = block.timestamp; - bridges[_bridge].burnerParams.currentLimit = _currentLimit - _change; - } - - /** - * @notice Updates the limit of any bridge - * @dev Can only be called by the owner - * @param _bridge The address of the bridge we are setting the limit too - * @param _limit The updated limit we are setting to the bridge - */ - function _changeMinterLimit(address _bridge, uint256 _limit) internal { - uint256 _oldLimit = bridges[_bridge].minterParams.maxLimit; - uint256 _currentLimit = mintingCurrentLimitOf(_bridge); - bridges[_bridge].minterParams.maxLimit = _limit; - - bridges[_bridge].minterParams.currentLimit = _calculateNewCurrentLimit(_limit, _oldLimit, _currentLimit); - - bridges[_bridge].minterParams.ratePerSecond = _limit / _DURATION; - bridges[_bridge].minterParams.timestamp = block.timestamp; - } - - /** - * @notice Updates the limit of any bridge - * @dev Can only be called by the owner - * @param _bridge The address of the bridge we are setting the limit too - * @param _limit The updated limit we are setting to the bridge - */ - function _changeBurnerLimit(address _bridge, uint256 _limit) internal { - uint256 _oldLimit = bridges[_bridge].burnerParams.maxLimit; - uint256 _currentLimit = burningCurrentLimitOf(_bridge); - bridges[_bridge].burnerParams.maxLimit = _limit; - - bridges[_bridge].burnerParams.currentLimit = _calculateNewCurrentLimit(_limit, _oldLimit, _currentLimit); - - bridges[_bridge].burnerParams.ratePerSecond = _limit / _DURATION; - bridges[_bridge].burnerParams.timestamp = block.timestamp; - } - - /** - * @notice Updates the current limit - * - * @param _limit The new limit - * @param _oldLimit The old limit - * @param _currentLimit The current limit - * @return _newCurrentLimit The new current limit - */ - function _calculateNewCurrentLimit( - uint256 _limit, - uint256 _oldLimit, - uint256 _currentLimit - ) internal pure returns (uint256 _newCurrentLimit) { - uint256 _difference; - - if (_oldLimit > _limit) { - _difference = _oldLimit - _limit; - _newCurrentLimit = _currentLimit > _difference ? _currentLimit - _difference : 0; - } else { - _difference = _limit - _oldLimit; - _newCurrentLimit = _currentLimit + _difference; - } - } - - /** - * @notice Gets the current limit - * - * @param _currentLimit The current limit - * @param _maxLimit The max limit - * @param _timestamp The timestamp of the last update - * @param _ratePerSecond The rate per second - * @return _limit The current limit - */ - function _getCurrentLimit( - uint256 _currentLimit, - uint256 _maxLimit, - uint256 _timestamp, - uint256 _ratePerSecond - ) internal view returns (uint256 _limit) { - _limit = _currentLimit; - if (_limit == _maxLimit) { - return _limit; - } else if (_timestamp + _DURATION <= block.timestamp) { - _limit = _maxLimit; - } else if (_timestamp + _DURATION > block.timestamp) { - uint256 _timePassed = block.timestamp - _timestamp; - uint256 _calculatedLimit = _limit + (_timePassed * _ratePerSecond); - _limit = _calculatedLimit > _maxLimit ? _maxLimit : _calculatedLimit; - } - } - - /** - * @notice Internal function for burning tokens - * - * @param _caller The caller address - * @param _user The user address - * @param _amount The amount to burn - */ - function _burnWithCaller(address _caller, address _user, uint256 _amount) internal { - if (_caller != lockbox) { - uint256 _currentLimit = burningCurrentLimitOf(_caller); - if (_currentLimit < _amount) revert IXERC20_NotHighEnoughLimits(); - _useBurnerLimits(_caller, _amount); - } - _burn(_user, _amount); - } - - /** - * @notice Internal function for minting tokens - * - * @param _caller The caller address - * @param _user The user address - * @param _amount The amount to mint - */ - function _mintWithCaller(address _caller, address _user, uint256 _amount) internal { - if (_caller != lockbox) { - uint256 _currentLimit = mintingCurrentLimitOf(_caller); - if (_currentLimit < _amount) revert IXERC20_NotHighEnoughLimits(); - _useMinterLimits(_caller, _amount); - } - _mint(_user, _amount); - } -} diff --git a/contracts/XERC20/XERC20Factory.sol b/contracts/XERC20/XERC20Factory.sol deleted file mode 100644 index 60bb1323..00000000 --- a/contracts/XERC20/XERC20Factory.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.4 <0.9.0; - -import { XERC20 } from "./XERC20.sol"; -import { IXERC20Factory } from "./interfaces/IXERC20Factory.sol"; -import { XERC20Lockbox } from "./XERC20Lockbox.sol"; -import { CREATE3 } from "solmate/src/utils/CREATE3.sol"; -import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; - -/** - * @custom:attribution https://github.com/defi-wonderland/xERC20/blob/dev/solidity/contracts/XERC20Factory.sol - */ -contract XERC20Factory is IXERC20Factory { - using EnumerableSet for EnumerableSet.AddressSet; - - /** - * @notice Address of the xerc20 maps to the address of its lockbox if it has one - */ - mapping(address => address) internal _lockboxRegistry; - - /** - * @notice The set of registered lockboxes - */ - EnumerableSet.AddressSet internal _lockboxRegistryArray; - - /** - * @notice The set of registered XERC20 tokens - */ - EnumerableSet.AddressSet internal _xerc20RegistryArray; - - /** - * @notice Deploys an XERC20 contract using CREATE3 - * @dev _limits and _minters must be the same length - * @param _name The name of the token - * @param _symbol The symbol of the token - * @param _minterLimits The array of limits that you are adding (optional, can be an empty array) - * @param _burnerLimits The array of limits that you are adding (optional, can be an empty array) - * @param _bridges The array of bridges that you are adding (optional, can be an empty array) - * @return _xerc20 The address of the xerc20 - */ - - function deployXERC20( - string memory _name, - string memory _symbol, - uint256[] memory _minterLimits, - uint256[] memory _burnerLimits, - address[] memory _bridges - ) external returns (address _xerc20) { - _xerc20 = _deployXERC20(_name, _symbol, _minterLimits, _burnerLimits, _bridges); - - emit XERC20Deployed(_xerc20); - } - - /** - * @notice Deploys an XERC20Lockbox contract using CREATE3 - * - * @dev When deploying a lockbox for the gas token of the chain, then, the base token needs to be address(0) - * @param _xerc20 The address of the xerc20 that you want to deploy a lockbox for - * @param _baseToken The address of the base token that you want to lock - * @param _isNative Whether or not the base token is the native (gas) token of the chain. Eg: MATIC for polygon chain - * @return _lockbox The address of the lockbox - */ - - function deployLockbox( - address _xerc20, - address _baseToken, - bool _isNative - ) external returns (address payable _lockbox) { - if ((_baseToken == address(0) && !_isNative) || (_isNative && _baseToken != address(0))) { - revert IXERC20Factory_BadTokenAddress(); - } - - if (XERC20(_xerc20).owner() != msg.sender) revert IXERC20Factory_NotOwner(); - if (_lockboxRegistry[_xerc20] != address(0)) revert IXERC20Factory_LockboxAlreadyDeployed(); - - _lockbox = _deployLockbox(_xerc20, _baseToken, _isNative); - - emit LockboxDeployed(_lockbox); - } - - /** - * @notice Deploys an XERC20 contract using CREATE3 - * @dev _limits and _minters must be the same length - * @param _name The name of the token - * @param _symbol The symbol of the token - * @param _minterLimits The array of limits that you are adding (optional, can be an empty array) - * @param _burnerLimits The array of limits that you are adding (optional, can be an empty array) - * @param _bridges The array of burners that you are adding (optional, can be an empty array) - * @return _xerc20 The address of the xerc20 - */ - - function _deployXERC20( - string memory _name, - string memory _symbol, - uint256[] memory _minterLimits, - uint256[] memory _burnerLimits, - address[] memory _bridges - ) internal returns (address _xerc20) { - uint256 _bridgesLength = _bridges.length; - if (_minterLimits.length != _bridgesLength || _burnerLimits.length != _bridgesLength) { - revert IXERC20Factory_InvalidLength(); - } - bytes32 _salt = keccak256(abi.encodePacked(_name, _symbol, msg.sender)); - bytes memory _creation = type(XERC20).creationCode; - bytes memory _bytecode = abi.encodePacked(_creation, abi.encode(_name, _symbol, address(this))); - - _xerc20 = CREATE3.deploy(_salt, _bytecode, 0); - - EnumerableSet.add(_xerc20RegistryArray, _xerc20); - - for (uint256 _i; _i < _bridgesLength; ++_i) { - XERC20(_xerc20).setLimits(_bridges[_i], _minterLimits[_i], _burnerLimits[_i]); - } - - XERC20(_xerc20).transferOwnership(msg.sender); - } - - /** - * @notice Deploys an XERC20Lockbox contract using CREATE3 - * - * @dev When deploying a lockbox for the gas token of the chain, then, the base token needs to be address(0) - * @param _xerc20 The address of the xerc20 that you want to deploy a lockbox for - * @param _baseToken The address of the base token that you want to lock - * @param _isNative Whether or not the base token is the native (gas) token of the chain. Eg: MATIC for polygon chain - * @return _lockbox The address of the lockbox - */ - function _deployLockbox( - address _xerc20, - address _baseToken, - bool _isNative - ) internal returns (address payable _lockbox) { - bytes32 _salt = keccak256(abi.encodePacked(_xerc20, _baseToken, msg.sender)); - bytes memory _creation = type(XERC20Lockbox).creationCode; - bytes memory _bytecode = abi.encodePacked(_creation, abi.encode(_xerc20, _baseToken, _isNative)); - - _lockbox = payable(CREATE3.deploy(_salt, _bytecode, 0)); - - XERC20(_xerc20).setLockbox(address(_lockbox)); - EnumerableSet.add(_lockboxRegistryArray, _lockbox); - _lockboxRegistry[_xerc20] = _lockbox; - } -} diff --git a/contracts/XERC20/XERC20Lockbox.sol b/contracts/XERC20/XERC20Lockbox.sol deleted file mode 100644 index b2053883..00000000 --- a/contracts/XERC20/XERC20Lockbox.sol +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.4 <0.9.0; - -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { IXERC20 } from "./interfaces/IXERC20.sol"; -import { IXERC20Lockbox } from "./interfaces/IXERC20Lockbox.sol"; - -/** - * @custom:attribution https://github.com/defi-wonderland/xERC20/blob/dev/solidity/contracts/XERC20Lockbox.sol - */ -contract XERC20Lockbox is IXERC20Lockbox { - using SafeERC20 for IERC20; - using SafeCast for uint256; - - /** - * @notice The XERC20 token of this contract - */ - IXERC20 public immutable XERC20; - - /** - * @notice The ERC20 token of this contract - */ - IERC20 public immutable ERC20; - - /** - * @notice Whether the ERC20 token is the native gas token of this chain - */ - - bool public immutable IS_NATIVE; - - /** - * @notice Constructor - * - * @param _xerc20 The address of the XERC20 contract - * @param _erc20 The address of the ERC20 contract - * @param _isNative Whether the ERC20 token is the native gas token of this chain or not - */ - - constructor(address _xerc20, address _erc20, bool _isNative) { - XERC20 = IXERC20(_xerc20); - ERC20 = IERC20(_erc20); - IS_NATIVE = _isNative; - } - - /** - * @notice Deposit native tokens into the lockbox - */ - - function depositNative() public payable { - if (!IS_NATIVE) revert IXERC20Lockbox_NotNative(); - - _deposit(msg.sender, msg.value); - } - - /** - * @notice Deposit ERC20 tokens into the lockbox - * - * @param _amount The amount of tokens to deposit - */ - - function deposit(uint256 _amount) external { - if (IS_NATIVE) revert IXERC20Lockbox_Native(); - - _deposit(msg.sender, _amount); - } - - /** - * @notice Deposit ERC20 tokens into the lockbox, and send the XERC20 to a user - * - * @param _to The user to send the XERC20 to - * @param _amount The amount of tokens to deposit - */ - - function depositTo(address _to, uint256 _amount) external { - if (IS_NATIVE) revert IXERC20Lockbox_Native(); - - _deposit(_to, _amount); - } - - /** - * @notice Deposit the native asset into the lockbox, and send the XERC20 to a user - * - * @param _to The user to send the XERC20 to - */ - - function depositNativeTo(address _to) public payable { - if (!IS_NATIVE) revert IXERC20Lockbox_NotNative(); - - _deposit(_to, msg.value); - } - - /** - * @notice Withdraw ERC20 tokens from the lockbox - * - * @param _amount The amount of tokens to withdraw - */ - - function withdraw(uint256 _amount) external { - _withdraw(msg.sender, _amount); - } - - /** - * @notice Withdraw tokens from the lockbox - * - * @param _to The user to withdraw to - * @param _amount The amount of tokens to withdraw - */ - - function withdrawTo(address _to, uint256 _amount) external { - _withdraw(_to, _amount); - } - - /** - * @notice Withdraw tokens from the lockbox - * - * @param _to The user to withdraw to - * @param _amount The amount of tokens to withdraw - */ - - function _withdraw(address _to, uint256 _amount) internal { - emit Withdraw(_to, _amount); - - XERC20.burn(msg.sender, _amount); - - if (IS_NATIVE) { - (bool _success,) = payable(_to).call{value: _amount}(''); - if (!_success) revert IXERC20Lockbox_WithdrawFailed(); - } else { - ERC20.safeTransfer(_to, _amount); - } - } - - /** - * @notice Deposit tokens into the lockbox - * - * @param _to The address to send the XERC20 to - * @param _amount The amount of tokens to deposit - */ - - function _deposit(address _to, uint256 _amount) internal { - if (!IS_NATIVE) { - emit ABC(address(ERC20)); - ERC20.safeTransferFrom(msg.sender, address(this), _amount); - } - - XERC20.mint(_to, _amount); - emit Deposit(_to, _amount); - } - - event ABC(address abc); - - /** - * @notice Fallback function to deposit native tokens - */ - receive() external payable { - depositNative(); - } -} diff --git a/contracts/XERC20/interfaces/IXERC20.sol b/contracts/XERC20/interfaces/IXERC20.sol deleted file mode 100644 index 621eb2c1..00000000 --- a/contracts/XERC20/interfaces/IXERC20.sol +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.4 <0.9.0; - -/** - * @custom:attribution https://github.com/defi-wonderland/xERC20/blob/dev/solidity/interfaces/IXERC20.sol - */ -interface IXERC20 { - /** - * @notice Emits when a lockbox is set - * - * @param _lockbox The address of the lockbox - */ - event LockboxSet(address _lockbox); - - /** - * @notice Emits when a limit is set - * - * @param _mintingLimit The updated minting limit we are setting to the bridge - * @param _burningLimit The updated burning limit we are setting to the bridge - * @param _bridge The address of the bridge we are setting the limit too - */ - event BridgeLimitsSet(uint256 _mintingLimit, uint256 _burningLimit, address indexed _bridge); - - /** - * @notice Reverts when a user with too low of a limit tries to call mint/burn - */ - error IXERC20_NotHighEnoughLimits(); - - /** - * @notice Reverts when caller is not the factory - */ - error IXERC20_NotFactory(); - - /** - * @notice Reverts when limits are too high - */ - error IXERC20_LimitsTooHigh(); - - /** - * @notice Contains the full minting and burning data for a particular bridge - * - * @param minterParams The minting parameters for the bridge - * @param burnerParams The burning parameters for the bridge - */ - struct Bridge { - BridgeParameters minterParams; - BridgeParameters burnerParams; - } - - /** - * @notice Contains the mint or burn parameters for a bridge - * - * @param timestamp The timestamp of the last mint/burn - * @param ratePerSecond The rate per second of the bridge - * @param maxLimit The max limit of the bridge - * @param currentLimit The current limit of the bridge - */ - struct BridgeParameters { - uint256 timestamp; - uint256 ratePerSecond; - uint256 maxLimit; - uint256 currentLimit; - } - - /** - * @notice Sets the lockbox address - * - * @param _lockbox The address of the lockbox - */ - function setLockbox(address _lockbox) external; - - /** - * @notice Updates the limits of any bridge - * @dev Can only be called by the owner - * @param _mintingLimit The updated minting limit we are setting to the bridge - * @param _burningLimit The updated burning limit we are setting to the bridge - * @param _bridge The address of the bridge we are setting the limits too - */ - function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external; - - /** - * @notice Returns the max limit of a minter - * - * @param _minter The minter we are viewing the limits of - * @return _limit The limit the minter has - */ - function mintingMaxLimitOf(address _minter) external view returns (uint256 _limit); - - /** - * @notice Returns the max limit of a bridge - * - * @param _bridge the bridge we are viewing the limits of - * @return _limit The limit the bridge has - */ - function burningMaxLimitOf(address _bridge) external view returns (uint256 _limit); - - /** - * @notice Returns the current limit of a minter - * - * @param _minter The minter we are viewing the limits of - * @return _limit The limit the minter has - */ - function mintingCurrentLimitOf(address _minter) external view returns (uint256 _limit); - - /** - * @notice Returns the current limit of a bridge - * - * @param _bridge the bridge we are viewing the limits of - * @return _limit The limit the bridge has - */ - function burningCurrentLimitOf(address _bridge) external view returns (uint256 _limit); - - /** - * @notice Mints tokens for a user - * @dev Can only be called by a minter - * @param _user The address of the user who needs tokens minted - * @param _amount The amount of tokens being minted - */ - function mint(address _user, uint256 _amount) external; - - /** - * @notice Burns tokens for a user - * @dev Can only be called by a minter - * @param _user The address of the user who needs tokens burned - * @param _amount The amount of tokens being burned - */ - function burn(address _user, uint256 _amount) external; -} diff --git a/contracts/XERC20/interfaces/IXERC20Factory.sol b/contracts/XERC20/interfaces/IXERC20Factory.sol deleted file mode 100644 index 99f41588..00000000 --- a/contracts/XERC20/interfaces/IXERC20Factory.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.4 <0.9.0; - -interface IXERC20Factory { - /** - * @notice Emitted when a new XERC20 is deployed - * - * @param _xerc20 The address of the xerc20 - */ - - event XERC20Deployed(address _xerc20); - - /** - * @notice Emitted when a new XERC20Lockbox is deployed - * - * @param _lockbox The address of the lockbox - */ - - event LockboxDeployed(address _lockbox); - - /** - * @notice Reverts when a non-owner attempts to call - */ - - error IXERC20Factory_NotOwner(); - - /** - * @notice Reverts when a lockbox is trying to be deployed from a malicious address - */ - - error IXERC20Factory_BadTokenAddress(); - - /** - * @notice Reverts when a lockbox is already deployed - */ - - error IXERC20Factory_LockboxAlreadyDeployed(); - - /** - * @notice Reverts when a the length of arrays sent is incorrect - */ - error IXERC20Factory_InvalidLength(); - - /** - * @notice Deploys an XERC20 contract using CREATE3 - * @dev _limits and _minters must be the same length - * @param _name The name of the token - * @param _symbol The symbol of the token - * @param _minterLimits The array of minter limits that you are adding (optional, can be an empty array) - * @param _burnerLimits The array of burning limits that you are adding (optional, can be an empty array) - * @param _bridges The array of burners that you are adding (optional, can be an empty array) - * @return _xerc20 The address of the xerc20 - */ - - function deployXERC20( - string memory _name, - string memory _symbol, - uint256[] memory _minterLimits, - uint256[] memory _burnerLimits, - address[] memory _bridges - ) external returns (address _xerc20); - - /** - * @notice Deploys an XERC20Lockbox contract using CREATE3 - * - * @param _xerc20 The address of the xerc20 that you want to deploy a lockbox for - * @param _baseToken The address of the base token that you want to lock - * @param _isNative Whether or not the base token is native - * @return _lockbox The address of the lockbox - */ - - function deployLockbox( - address _xerc20, - address _baseToken, - bool _isNative - ) external returns (address payable _lockbox); -} diff --git a/contracts/XERC20/interfaces/IXERC20Lockbox.sol b/contracts/XERC20/interfaces/IXERC20Lockbox.sol deleted file mode 100644 index dd98ac04..00000000 --- a/contracts/XERC20/interfaces/IXERC20Lockbox.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.4 <0.9.0; - -/** - * @custom:attribution https://github.com/defi-wonderland/xERC20/blob/dev/solidity/interfaces/IXERC20Lockbox.sol - */ -interface IXERC20Lockbox { - /** - * @notice Emitted when tokens are deposited into the lockbox - * - * @param _sender The address of the user who deposited - * @param _amount The amount of tokens deposited - */ - - event Deposit(address _sender, uint256 _amount); - - /** - * @notice Emitted when tokens are withdrawn from the lockbox - * - * @param _sender The address of the user who withdrew - * @param _amount The amount of tokens withdrawn - */ - - event Withdraw(address _sender, uint256 _amount); - - /** - * @notice Reverts when a user tries to deposit native tokens on a non-native lockbox - */ - - error IXERC20Lockbox_NotNative(); - - /** - * @notice Reverts when a user tries to deposit non-native tokens on a native lockbox - */ - - error IXERC20Lockbox_Native(); - - /** - * @notice Reverts when a user tries to withdraw and the call fails - */ - - error IXERC20Lockbox_WithdrawFailed(); - - /** - * @notice Deposit ERC20 tokens into the lockbox - * - * @param _amount The amount of tokens to deposit - */ - - function deposit(uint256 _amount) external; - - /** - * @notice Deposit ERC20 tokens into the lockbox, and send the XERC20 to a user - * - * @param _user The user to send the XERC20 to - * @param _amount The amount of tokens to deposit - */ - - function depositTo(address _user, uint256 _amount) external; - - /** - * @notice Deposit the native asset into the lockbox, and send the XERC20 to a user - * - * @param _user The user to send the XERC20 to - */ - - function depositNativeTo(address _user) external payable; - - /** - * @notice Withdraw ERC20 tokens from the lockbox - * - * @param _amount The amount of tokens to withdraw - */ - - function withdraw(uint256 _amount) external; - - /** - * @notice Withdraw ERC20 tokens from the lockbox - * - * @param _user The user to withdraw to - * @param _amount The amount of tokens to withdraw - */ - - function withdrawTo(address _user, uint256 _amount) external; -} diff --git a/contracts/adapters/GmpTransferAdapter.sol b/contracts/adapters/GmpTransferAdapter.sol deleted file mode 100644 index 6dfbc228..00000000 --- a/contracts/adapters/GmpTransferAdapter.sol +++ /dev/null @@ -1,130 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity 0.8.11; - -import "@openzeppelin/contracts/access/AccessControl.sol"; -import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; -import "../../contracts/interfaces/IBridge.sol"; -import "../../contracts/interfaces/IFeeHandler.sol"; -import "../XERC20/interfaces/IXERC20.sol"; -import "./interfaces/IGmpTransferAdapter.sol"; - -/** - .__ __. ______ .___________. __ ______ _______ - | \ | | / __ \ | || | / || ____| - | \| | | | | | `---| |----`| | | ,----'| |__ - | . ` | | | | | | | | | | | | __| - | |\ | | `--' | | | | | | `----.| |____ - |__| \__| \______/ |__| |__| \______||_______| - - Be careful when interacting with this contact as it enables - permissionless token addition and transfers via Sygma bridge. - Make sure that a malicious actor cannot deploy arbitrary code - to the same address as your XERC20 token on another chain. - This would allow them to burn fake tokens on chain A then mint - legit tokens on chain B. -*/ -contract GmpTransferAdapter is IGmpTransferAdapter, AccessControl { - using ERC165Checker for address; - - IBridge public immutable _bridge; - bytes32 public immutable _resourceID; - address immutable _gmpAddress; - // source token address => destination domainID => destination token address - mapping(address => mapping(uint256 => address)) public crossChainTokenPairs; - - event Withdrawal(address recipient, uint amount); - - error InsufficientMsgValueAmount(uint256 amount); - error InvalidHandler(address handler); - error InvalidOriginAdapter(address adapter); - error FailedRefund(); - error CallerNotAdmin(); - error FailedFundsTransfer(); - - /** - @notice This contract requires for transfer that the origin adapter address is the same across all networks. - Because of that it should be deployed using multichain deployer or create2. - */ - constructor(IBridge bridge, address newGmpAddress, bytes32 resourceID) { - _bridge = bridge; - _gmpAddress = newGmpAddress; - _resourceID = resourceID; - _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); - } - - modifier onlyAdmin() { - if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert CallerNotAdmin(); - _; - } - - function deposit(uint8 destinationDomainID, address recipientAddress, address XERC20Address, uint256 tokenAmount) external payable { - address feeHandlerRouter = _bridge._feeHandler(); - (uint256 fee, ) = IFeeHandler(feeHandlerRouter).calculateFee( - address(this), - _bridge._domainID(), - destinationDomainID, - _resourceID, - "", // depositData - not parsed - "" // feeData - not parsed - ); - - if (msg.value < fee) { - revert InsufficientMsgValueAmount(msg.value); - // refund excess msg.value - } else if (msg.value > fee) { - (bool success, ) = msg.sender.call{value: msg.value - fee}(""); - if (!success) revert FailedRefund(); - } - - address destinationToken; - address assignedDestinationToken = crossChainTokenPairs[XERC20Address][destinationDomainID]; - if (assignedDestinationToken != address(0)) { - destinationToken = assignedDestinationToken; - } else { - destinationToken = XERC20Address; - } - - bytes memory depositData = abi.encodePacked( - // uint256 maxFee - uint256(950000), - // uint16 len(executeFuncSignature) - uint16(4), - // bytes executeFuncSignature - IGmpTransferAdapter(address(this)).executeProposal.selector, - // uint8 len(executeContractAddress) - uint8(20), - // bytes executeContractAddress - address(this), - // uint8 len(executionDataDepositor) - uint8(20), - // bytes executionDataDepositor - address(this), - // bytes executionDataDepositor + executionData - prepareDepositData(recipientAddress, destinationToken, tokenAmount) - ); - - IXERC20(XERC20Address).burn(msg.sender, tokenAmount); - - _bridge.deposit{value: fee}(destinationDomainID, _resourceID, depositData, ""); - } - - function executeProposal(address gmpAdapter, address recipient, address XERC20Address, uint256 amount) external { - if (gmpAdapter != address(this)) revert InvalidOriginAdapter(gmpAdapter); - if (msg.sender != _gmpAddress) revert InvalidHandler(msg.sender); - - IXERC20(XERC20Address).mint(recipient, amount); - } - - function setTokenPairAddress(address sourceTokenAddress, uint8 destinationDomainID, address destinationTokenAddress) external onlyAdmin { - crossChainTokenPairs[sourceTokenAddress][destinationDomainID] = destinationTokenAddress; - } - - function prepareDepositData( - address recipientAddress, - address XERC20Address, - uint256 bridgingAmount - ) public view returns (bytes memory) { - return abi.encode(recipientAddress, XERC20Address, bridgingAmount); - } -} diff --git a/contracts/adapters/interfaces/IGmpTransferAdapter.sol b/contracts/adapters/interfaces/IGmpTransferAdapter.sol deleted file mode 100644 index 1014feab..00000000 --- a/contracts/adapters/interfaces/IGmpTransferAdapter.sol +++ /dev/null @@ -1,37 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity 0.8.11; - -/** - @title Interface for Bridge contract. - @author ChainSafe Systems. - */ -interface IGmpTransferAdapter { - /** - @notice Initiates a transfer using Gmp handler. - @param destinationDomainID ID of chain deposit will be bridged to. - @param recipientAddress Address that will receive tokens on destination chain. - @param XERC20Address Address of the tokens that shoul be transferred and burned on source chain. - @param tokenAmount Amount of tokens that should be transferred. - */ - function deposit( - uint8 destinationDomainID, - address recipientAddress, - address XERC20Address, - uint256 tokenAmount - ) external payable; - - /** - @notice Executes a GMP deposit proposal on GMP transfer adapter contract. - @param gmpAdapter Address of the adapter on soruce chain (should be the same address across all chains). - @param recipient Address that will receive tokens. - @param XERC20Address Address of XERC20 contract that will mint tokens on destination chain. - @param amount Amount of tones that should be minted to the recipinet. - */ - function executeProposal( - address gmpAdapter, - address recipient, - address XERC20Address, - uint256 amount - ) external; -} diff --git a/contracts/handlers/NativeTokenHandler.sol b/contracts/handlers/NativeTokenHandler.sol index c3ef03c4..56d3b605 100644 --- a/contracts/handlers/NativeTokenHandler.sol +++ b/contracts/handlers/NativeTokenHandler.sol @@ -18,19 +18,19 @@ contract NativeTokenHandler is IHandler, ERCHandlerHelpers, DepositDataHelper { using ExcessivelySafeCall for address; uint256 internal constant defaultGas = 50000; - address public immutable _nativeTokenAdapterAddress; + address public immutable _NativeTokenTransferGatewayAddress; /** @param bridgeAddress Contract address of previously deployed Bridge. - @param nativeTokenAdapterAddress Contract address of previously deployed NativeTokenAdapter. + @param NativeTokenTransferGatewayAddress Contract address of previously deployed NativeTokenTransferGateway. @param defaultMessageReceiver Contract address of previously deployed DefaultMessageReceiver. */ constructor( address bridgeAddress, - address nativeTokenAdapterAddress, + address NativeTokenTransferGatewayAddress, address defaultMessageReceiver ) DepositDataHelper(bridgeAddress, defaultMessageReceiver) { - _nativeTokenAdapterAddress = nativeTokenAdapterAddress; + _NativeTokenTransferGatewayAddress = NativeTokenTransferGatewayAddress; } event Withdrawal(address recipient, uint256 amount); @@ -41,7 +41,7 @@ contract NativeTokenHandler is IHandler, ERCHandlerHelpers, DepositDataHelper { error InvalidSender(address sender); /** - @notice A deposit is initiated by making a deposit to the NativeTokenAdapter which constructs the required + @notice A deposit is initiated by making a deposit to the NativeTokenTransferGateway which constructs the required deposit data and propagates it to the Bridge contract. @param resourceID ResourceID used to find address of token to be used for deposit. @param depositor Address of account making the deposit in the Bridge contract. @@ -63,7 +63,7 @@ contract NativeTokenHandler is IHandler, ERCHandlerHelpers, DepositDataHelper { uint256 amount; (amount) = abi.decode(data, (uint256)); - if(depositor != _nativeTokenAdapterAddress) revert InvalidSender(depositor); + if(depositor != _NativeTokenTransferGatewayAddress) revert InvalidSender(depositor); address tokenAddress = _resourceIDToTokenContractAddress[resourceID]; diff --git a/contracts/handlers/fee/dynamic/DynamicGenericFeeHandler.sol b/contracts/handlers/fee/dynamic/TwapGenericFeeHandler.sol similarity index 100% rename from contracts/handlers/fee/dynamic/DynamicGenericFeeHandler.sol rename to contracts/handlers/fee/dynamic/TwapGenericFeeHandler.sol diff --git a/contracts/handlers/fee/dynamic/TwapOracle.sol b/contracts/handlers/fee/dynamic/TwapOracle.sol index 56daf9c5..e7c7b31c 100644 --- a/contracts/handlers/fee/dynamic/TwapOracle.sol +++ b/contracts/handlers/fee/dynamic/TwapOracle.sol @@ -1,3 +1,4 @@ + // The Licensed Work is (c) 2022 Sygma // SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; @@ -57,7 +58,7 @@ contract TwapOracle is AccessControl { int24 arithmeticMeanTick = int24(tickCumulativesDelta / int56(uint56(secondsAgo))); // Always round to negative infinity if (tickCumulativesDelta < 0 && (tickCumulativesDelta % int56(uint56(secondsAgo)) != 0)) arithmeticMeanTick--; - + uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(arithmeticMeanTick); // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself diff --git a/hardhat.config.ts b/hardhat.config.ts new file mode 100644 index 00000000..d9c6b4f3 --- /dev/null +++ b/hardhat.config.ts @@ -0,0 +1,17 @@ +import type { HardhatUserConfig } from "hardhat/config"; +import "@nomicfoundation/hardhat-toolbox-viem"; +import "@nomiclabs/hardhat-solhint"; +import "hardhat-chai-matchers-viem"; +import "hardhat-gas-reporter" + +const config: HardhatUserConfig = { + networks: { + hardhat: {}, + }, + solidity: "0.8.11", + gasReporter: { + L1: "ethereum" + } +}; + +export default config; diff --git a/ignition/modules/Lock.ts b/ignition/modules/Lock.ts new file mode 100644 index 00000000..b2547410 --- /dev/null +++ b/ignition/modules/Lock.ts @@ -0,0 +1,18 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; +import { parseEther } from "viem"; + +const JAN_1ST_2030 = 1893456000; +const ONE_GWEI: bigint = parseEther("0.001"); + +const LockModule = buildModule("LockModule", (m) => { + const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030); + const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI); + + const lock = m.describe("Lock", [unlockTime], { + value: lockedAmount, + }); + + return { lock }; +}); + +export default LockModule; diff --git a/migrations/utils.js b/migrations/utils.ts similarity index 93% rename from migrations/utils.js rename to migrations/utils.ts index 74864113..ee018817 100644 --- a/migrations/utils.js +++ b/migrations/utils.ts @@ -2,24 +2,25 @@ // The Licensed Work is (c) 2022 Sygma // SPDX-License-Identifier: LGPL-3.0-only +import { toHex, parseEther } from "viem"; + const parseArgs = require("minimist"); const fs = require("fs"); -const Ethers = require("ethers"); const Helpers = require("../test/helpers"); -const TestStoreContract = artifacts.require("TestStore"); -const ERC20PresetMinterPauser = artifacts.require("ERC20PresetMinterPauserDecimals"); -const ERC721MinterBurnerPauserContract = artifacts.require( - "ERC721MinterBurnerPauser" -); -const ERC1155MinterBurnerPauserContract = artifacts.require( - "ERC1155PresetMinterPauser" -); +//1 const TestStoreContract = artifacts.require("TestStore"); +//1 const ERC20PresetMinterPauser = artifacts.require("ERC20PresetMinterPauserDecimals"); +//1 const ERC721MinterBurnerPauserContract = artifacts.require( +//1 "ERC721MinterBurnerPauser" +//1 ); +//1 const ERC1155MinterBurnerPauserContract = artifacts.require( +//1 "ERC1155PresetMinterPauser" +//1 ); const DEFAULT_CONFIG_PATH = "./migrations/local.json"; const emptySetResourceData = "0x"; -const erc20TokenAmount = Ethers.utils.parseUnits("1000", 18); +const erc20TokenAmount = parseEther("1000"); function getNetworksConfig() { let path = parseArgs(process.argv.slice(2))["file"]; @@ -54,7 +55,7 @@ async function setupErc20( erc20HandlerInstance.address, erc20.resourceID, erc20Instance.address, - Ethers.utils.hexlify(Number(erc20.decimals)) + toHex(erc20.decimals) ); // strategy can be either mb (mint/burn) or lr (lock/release) diff --git a/package.json b/package.json index 08e3fba4..439f8711 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "@buildwithsygma/sygma-contracts", "version": "2.10.1", "description": "", - "main": "dist/index.js", "repository": "https://github.com/sygmaprotocol/sygma-solidity.git", "files": [ "dist", @@ -21,36 +20,33 @@ "build/contracts/DefaultMessageReceiver.json", "contracts/interfaces" ], - "directories": { - "test": "test" - }, "scripts": { "prepare": "env-prompt -d .env.sample", - "compile": "truffle compile", - "build": "rollup -c", + "compile": "npx hardhat compile", + "node": "npx hardhat node", + "node-fork": "npx hardhat node --fork", + "test": "npx hardhat test ./test/forwarder/forwarder.test.ts", + "test-fork": "npx hardhat test ./forkedMainnet/**/*.test.ts", "publish-package": "npm run compile && npm run generate-types && npm run build && npm publish", - "generate-types": "npm run generate-types:ethers", - "generate-types:ethers": "npx typechain \"build/contracts/*\" --target=ethers-v5 --out-dir src/ethers", - "test": "echo \\\\\\\"Error: no test specified\\\\\\\" && exit 1", - "deploy:local:1": "concurrently --raw --kill-others --success first \"ganache --chain.chainId 1337 --database.dbPath data/ --m 'black toward wish jar twin produce remember fluid always confirm bacon slush' \" \"truffle migrate --network test\"", - "deploy:local:2": "concurrently --raw --kill-others --success first \"ganache -p 8547 --chain.chainId 1338 --database.dbPath data/ --m 'black toward wish jar twin produce remember fluid always confirm bacon slush' \" \"truffle migrate --network test2\"", - "lint": "npm run lint:solidity && npm run lint:js", - "lint:solidity": "solhint contracts/**/*.sol", - "lint:js": "eslint --ext .js ." + "lint": "npm run lint-solidity && npm run lint-js", + "lint-solidity": "npx hardhat check", + "lint-ts": "eslint --ext .js ." }, "author": "Sygma", "license": "BUSL-1.1", "devDependencies": { - "@babel/core": "^7.17.4", - "@codechecks/client": "^0.1.12", - "@rollup/plugin-babel": "^5.3.0", - "@rollup/plugin-commonjs": "^21.0.1", - "@rollup/plugin-node-resolve": "^13.1.3", - "@truffle/hdwallet-provider": "2.0.14", - "@typechain/ethers-v5": "^9.0.0", - "commander": "^9.0.0", - "concurrently": "^7.4.0", - "coveralls": "^3.1.1", + "@nomicfoundation/hardhat-ignition": "^0.15.0", + "@nomicfoundation/hardhat-ignition-viem": "^0.15.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomicfoundation/hardhat-toolbox-viem": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.0", + "@nomicfoundation/hardhat-viem": "^2.0.5", + "@nomiclabs/hardhat-solhint": "^4.0.1", + "@types/chai": "^4.2.0", + "@types/chai-as-promised": "^7.1.6", + "@types/mocha": "^10.0.8", + "@types/node": ">=18.0.0", + "chai": "^4.x.x", "dotenv": "^16.0.2", "env-prompt": "^2.0.3", "eslint": "^8.0.1", @@ -58,32 +54,24 @@ "eslint-plugin-import": "^2.25.2", "eslint-plugin-n": "^15.0.0", "eslint-plugin-promise": "^6.0.0", - "eth-sig-util": "^3.0.1", - "ethereumjs-wallet": "^1.0.2", - "ethers": "^5.5.4", - "ganache": "^7.9.2", - "lodash.template": "^4.5.0", - "minimist": "^1.2.7", + "hardhat": "^2.22.15", + "hardhat-chai-matchers-viem": "^2.0.8", + "hardhat-gas-reporter": "^2.2.2", "prettier": "2.8.1", - "rimraf": "^3.0.2", - "rollup": "^2.67.2", - "rollup-plugin-node-polyfills": "^0.2.1", - "rollup-plugin-peer-deps-external": "^2.2.4", - "rollup-plugin-typescript2": "^0.31.2", "solhint": "^3.3.7", - "solidity-coverage": "^0.7.20", - "truffle": "^5.4.32", - "truffle-assertions": "^0.9.2", - "truffle-plugin-verify": "0.6.0", - "typechain": "^7.0.0", - "typescript": "^4.5.5" + "solidity-coverage": "^0.8.0", + "ts-node": ">=8.0.0", + "typescript": "5.0.3", + "viem": "^2.21.37" }, - "peerDependencies": { - "ethers": ">= 5.0.0" + "overrides": { + "ethers": "6.13.x" }, "dependencies": { + "@metamask/eth-sig-util": "^8.1.1", "@openzeppelin/contracts": "4.5.0", "@uniswap/v3-periphery": "^1.4.4", + "ethers": "^6.13.4", "solmate": "^6.2.0" } } diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index 8da5216c..00000000 --- a/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -import commonjs from "@rollup/plugin-commonjs"; -import resolve from "@rollup/plugin-node-resolve"; -import peerDepsExternal from "rollup-plugin-peer-deps-external"; -import typescript from "rollup-plugin-typescript2"; -import babel from "@rollup/plugin-babel"; - -export default { - input: "./src/index.ts", - output: { - format: "cjs", - dir: "dist/", - exports: "named", - sourcemap: true, - strict: true, - }, - plugins: [ - peerDepsExternal(), - resolve({ - preferBuiltins: true, - }), - commonjs(), - typescript(), - babel({ - exclude: "node_modules/**", - }), - ], - external: ["ethers", "web3"], -}; diff --git a/scripts/.solcover.js b/scripts/.solcover.js deleted file mode 100644 index 80701930..00000000 --- a/scripts/.solcover.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - providerOptions: { - "port" : 8545 - } -}; \ No newline at end of file diff --git a/scripts/compileAbiBin.js b/scripts/compileAbiBin.js deleted file mode 100755 index 845462e3..00000000 --- a/scripts/compileAbiBin.js +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env node -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const fs = require("fs"); -const rimraf = require("rimraf"); - -const BUILD_PATH = "./build/bindings/"; -const ABI_PATH = BUILD_PATH + "abi/" -const BIN_PATH = BUILD_PATH + "bin/" -const RUNTIME_PATH = BUILD_PATH + "runtime/" - -// Loop through all the files in the temp directory -fs.readdir("./build/contracts", function (err, files) { - if (err) { - console.error("Could not list the directory.", err); - process.exit(1); - } - - // Remove old build - rimraf.sync(BUILD_PATH); - - // Create empty dirs - fs.mkdirSync(BUILD_PATH) - if (!fs.existsSync(ABI_PATH)) { - fs.mkdirSync(ABI_PATH); - } - if (!fs.existsSync(BIN_PATH)) { - fs.mkdirSync(BIN_PATH); - } - if (!fs.existsSync(RUNTIME_PATH)) { - fs.mkdirSync(RUNTIME_PATH); - } - - files.forEach(function (file) { - const basename = file.split(".")[0]; - const path = "./build/contracts/" + file - const rawdata = fs.readFileSync(path); - const contract = JSON.parse(rawdata); - // eslint-disable-next-line prefer-const - let {abi, bytecode} = contract; - bytecode = bytecode.substring(2); - - if (abi.length === 0) return; - fs.writeFileSync(ABI_PATH + basename + ".abi" , JSON.stringify(abi)); - fs.writeFileSync(BIN_PATH + basename + ".bin", bytecode); - }); -}); diff --git a/scripts/create_bindings.sh b/scripts/create_bindings.sh deleted file mode 100755 index 5ad6072f..00000000 --- a/scripts/create_bindings.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# The Licensed Work is (c) 2022 Sygma -# SPDX-License-Identifier: LGPL-3.0-only - - -set -e - -base_path="./build/bindings" -BIN_DIR="$base_path/bin" -ABI_DIR="$base_path/abi" -RUNTIME_DIR="$base_path/runtime" -GO_DIR="$base_path/go" - -echo "Generating json ABI and associated files..." -./scripts/compileAbiBin.js - -# Remove old bin and abi -echo "Removing old builds..." -mkdir $GO_DIR - -for file in "$BIN_DIR"/*.bin -do - base=`basename $file` - value="${base%.*}" - echo Compiling file $value from path $file - - # Create the go package directory - mkdir $GO_DIR/$value - - # Build the go package - abigen --abi $ABI_DIR/${value}.abi --pkg $value --type $value --bin $BIN_DIR/${value}.bin --out $GO_DIR/$value/$value.go -done \ No newline at end of file diff --git a/scripts/generateFuncSignatures.js b/scripts/generateFuncSignatures.js deleted file mode 100755 index bad48b93..00000000 --- a/scripts/generateFuncSignatures.js +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env node -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const fs = require("fs"); -const {utils} = require("ethers"); -const {resolve} = require("path"); - - -const BRIDGE_CONTRACT_PATH = resolve(__dirname, "../contracts/Bridge.sol"); -const ARTIFACTS_PATH = resolve(__dirname, "../build/contracts/Bridge.json"); - -function generateAccessControlFuncSignatures() { - const bridgeAbiJson = JSON.parse(fs.readFileSync(ARTIFACTS_PATH)); - const bridgeContractMethods = bridgeAbiJson.userdoc.methods - const bridgeContract = fs.readFileSync(BRIDGE_CONTRACT_PATH); - - // regex that will match all functions that have "onlyAllowed" modifier - const regex = RegExp("function\\s+(?:(?!_onlyAllowed|function).)+onlyAllowed", "gs"); - - let a; - const b = []; - // fetch all functions that have "onlyAllowed" modifier from "Bridge.sol" - while ((a = regex.exec(bridgeContract)) !== null) { - // filter out only function name from matching (onlyAllowed) functions - b.push(a[0].split(/[\s()]+/)[1]); - } - - let accessControlFuncSignatures = [] - // filter out from Bridge ABI functions signatures with "onlyAllowed" modifier - accessControlFuncSignatures = Object.keys(bridgeContractMethods).filter( - el1 => b.some( - el2 => el1.includes(el2))).map( - func => ({ - function: func, - hash: utils.keccak256(Buffer.from(func)).substring(0,10) - }) - ); - - console.table(accessControlFuncSignatures); - - return accessControlFuncSignatures; -} - -module.exports = { - generateAccessControlFuncSignatures -}; diff --git a/scripts/generateFuncSignatures.ts b/scripts/generateFuncSignatures.ts new file mode 100644 index 00000000..5c87974c --- /dev/null +++ b/scripts/generateFuncSignatures.ts @@ -0,0 +1,52 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +const fs = require("fs"); +const {resolve} = require("path"); +import {Hex, toFunctionSelector} from "viem"; + +type AbiFunction = { + inputs: Array, + name: string, + outputs: Array, + stateMutability: string, + type: string, +} + +const BRIDGE_CONTRACT_PATH = resolve(__dirname, "../contracts/Bridge.sol"); +const ARTIFACTS_PATH = resolve(__dirname, "../artifacts/contracts/Bridge.sol/Bridge.json"); + +export function generateAccessControlFuncSignatures() { + const bridgeJson = JSON.parse(fs.readFileSync(ARTIFACTS_PATH)); + const bridgeAbi = bridgeJson.abi + const bridgeContract = fs.readFileSync(BRIDGE_CONTRACT_PATH); + + // regex that will match all functions that have "onlyAllowed" modifier + const regex = RegExp("function\\s+(?:(?!_onlyAllowed|function).)+onlyAllowed", "gs"); + + let item; + const functionNames:Array = []; + const functionSignatures:Array = []; + + // fetch all functions that have "onlyAllowed" modifier from "Bridge.sol" + while ((item = regex.exec(bridgeContract)) !== null) { + // filter out only function name from matching (onlyAllowed) functions + const funcName = item[0].split(/[\s()]+/)[1]; + functionNames.push(funcName); + } + + bridgeAbi.forEach((item: AbiFunction) => { + if (item.name && functionNames.includes(item.name)) { + functionSignatures.push(toFunctionSelector(item)); + } + }); + + // generate table with function names and sinatures + const functionSignaturesTable = functionNames.map((functionNames, index) => ({ + Values: functionNames, + Hex: functionSignatures[index] + })); + + console.table(functionSignaturesTable); + return functionSignatures; +} diff --git a/scripts/geth/genesis.json b/scripts/geth/genesis.json deleted file mode 100644 index 2314f3a9..00000000 --- a/scripts/geth/genesis.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "config": { - "chainId": 5, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "clique": { - "period": 1, - "epoch": 30000 - } - }, - "difficulty": "1", - "gasLimit": "8000000", - "extradata": "0x0000000000000000000000000000000000000000000000000000000000000000ff93B45308FD417dF303D6515aB04D9e89a750Ca0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "alloc": { - "0xff93B45308FD417dF303D6515aB04D9e89a750Ca": { "balance": "20000000000000000000"}, - "0x8e0a907331554AF72563Bd8D43051C2E64Be5d35": { "balance": "20000000000000000000"}, - "0x24962717f8fA5BA3b931bACaF9ac03924EB475a0": { "balance": "20000000000000000000"}, - "0x148FfB2074A9e59eD58142822b3eB3fcBffb0cd7": { "balance": "20000000000000000000"}, - "0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485": { "balance": "20000000000000000000"} - } -} \ No newline at end of file diff --git a/scripts/geth/keystore/UTC--2020-04-07T13-50-35.447Z--ff93b45308fd417df303d6515ab04d9e89a750ca b/scripts/geth/keystore/UTC--2020-04-07T13-50-35.447Z--ff93b45308fd417df303d6515ab04d9e89a750ca deleted file mode 100644 index 8f413f91..00000000 --- a/scripts/geth/keystore/UTC--2020-04-07T13-50-35.447Z--ff93b45308fd417df303d6515ab04d9e89a750ca +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"id":"369ea1d8-73ac-440b-932c-0722491eb9a2","address":"ff93b45308fd417df303d6515ab04d9e89a750ca","crypto":{"ciphertext":"095e1ad5c02249880243cfba01c79297b3a58315d5819d79c5349db7e65fcb13","cipherparams":{"iv":"589cfe4b3f5c935ea4847dd233980f0a"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"f01da06f89421cdc88d7b896844ca3b0295f01208cff36f89fa2a6706d248107","n":8192,"r":8,"p":1},"mac":"60267143aa71c8124156ac2dafb5e771cb1d0a9862634c78606549418573b907"}} \ No newline at end of file diff --git a/scripts/geth/keystore/UTC--2020-04-07T13-52-12.564Z--8e0a907331554af72563bd8d43051c2e64be5d35 b/scripts/geth/keystore/UTC--2020-04-07T13-52-12.564Z--8e0a907331554af72563bd8d43051c2e64be5d35 deleted file mode 100644 index 8f729108..00000000 --- a/scripts/geth/keystore/UTC--2020-04-07T13-52-12.564Z--8e0a907331554af72563bd8d43051c2e64be5d35 +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"id":"1bdffff9-241c-4cda-b9b1-a2afffa73a3a","address":"8e0a907331554af72563bd8d43051c2e64be5d35","crypto":{"ciphertext":"d1af2dc6976cabe7b390799c908940150315285515622c3e5332412564c57d6d","cipherparams":{"iv":"87c6ffc252c435c3b612fcca5e9a10a0"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"e85eebb3570913942908be7201003435f9541beb26668ed275a1f2a6d4bcd932","n":8192,"r":8,"p":1},"mac":"dc8e177a84ac62c8395ecda5b7680f7ad7b0278499beddaa2e8c71965477b07b"}} \ No newline at end of file diff --git a/scripts/geth/keystore/UTC--2020-04-07T13-53-49.003Z--24962717f8fa5ba3b931bacaf9ac03924eb475a0 b/scripts/geth/keystore/UTC--2020-04-07T13-53-49.003Z--24962717f8fa5ba3b931bacaf9ac03924eb475a0 deleted file mode 100644 index afa43592..00000000 --- a/scripts/geth/keystore/UTC--2020-04-07T13-53-49.003Z--24962717f8fa5ba3b931bacaf9ac03924eb475a0 +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"id":"fca758b1-8782-4e54-9ede-96ca22931b72","address":"24962717f8fa5ba3b931bacaf9ac03924eb475a0","crypto":{"ciphertext":"5120712ba214043947befd835e3d86a38fce60c8d830f878ca1a053120d37056","cipherparams":{"iv":"71168d1cbf61b9e65ea02b5db38de7e7"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"2010ca09bebf3988fb95997279ad7d761ab0d4b8323c647470dd680bdfc2f202","n":8192,"r":8,"p":1},"mac":"920f27b77fcdaaa3c322a33e91e088a7c30f82b0e3a9bfd1072058198b367f07"}} \ No newline at end of file diff --git a/scripts/geth/keystore/UTC--2020-04-07T13-55-20.258Z--148ffb2074a9e59ed58142822b3eb3fcbffb0cd7 b/scripts/geth/keystore/UTC--2020-04-07T13-55-20.258Z--148ffb2074a9e59ed58142822b3eb3fcbffb0cd7 deleted file mode 100644 index 810d54c7..00000000 --- a/scripts/geth/keystore/UTC--2020-04-07T13-55-20.258Z--148ffb2074a9e59ed58142822b3eb3fcbffb0cd7 +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"id":"2995e9ab-3ac6-4814-bc40-03165cf23f1b","address":"148ffb2074a9e59ed58142822b3eb3fcbffb0cd7","crypto":{"ciphertext":"c986b6930bd7814092d613c607e7f4df0758d895f6216294fc0452bb18348d91","cipherparams":{"iv":"527bb46169ca968a6821d75c845bfd3f"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"71f9c2041a9a6b5476393331ef6924335f5485cf4c175cbc33c83c685c3f4394","n":8192,"r":8,"p":1},"mac":"c10a5aaf7a34a9d08377a02a517339b3afaa4ed7e6ec9a6a70dd1bcf3b4e1fba"}} \ No newline at end of file diff --git a/scripts/geth/keystore/UTC--2020-04-07T13-56-44.768Z--4ceef6139f00f9f4535ad19640ff7a0137708485 b/scripts/geth/keystore/UTC--2020-04-07T13-56-44.768Z--4ceef6139f00f9f4535ad19640ff7a0137708485 deleted file mode 100644 index 3daa9f09..00000000 --- a/scripts/geth/keystore/UTC--2020-04-07T13-56-44.768Z--4ceef6139f00f9f4535ad19640ff7a0137708485 +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"id":"a163ef8f-b883-4474-a79f-9ecddf079683","address":"4ceef6139f00f9f4535ad19640ff7a0137708485","crypto":{"ciphertext":"fa612d9881ab9863b830daea365acaac6643469d0f02189b82fb84948f59d643","cipherparams":{"iv":"b91f79de31d0a9bdc8a0670a129efea8"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"ddb540564be1bf1546245fafafd1b952431213b4d742a9af3d4fbedc54846ae3","n":8192,"r":8,"p":1},"mac":"ffbc5fab063f361c8dfa52f91be661d08a1e9119c9a81aac83fa81af4a2f5909"}} \ No newline at end of file diff --git a/scripts/geth/password.txt b/scripts/geth/password.txt deleted file mode 100644 index d0e7eacf..00000000 --- a/scripts/geth/password.txt +++ /dev/null @@ -1,5 +0,0 @@ -passwordpassword -passwordpassword -passwordpassword -passwordpassword -passwordpassword \ No newline at end of file diff --git a/scripts/geth/run_geth.sh b/scripts/geth/run_geth.sh deleted file mode 100644 index daab6fdb..00000000 --- a/scripts/geth/run_geth.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 ChainSafe Systems -# SPDX-License-Identifier: LGPL-3.0-only - -# Exit on failure -set -e - -# Delete old chain data -rm -rf $DATADIR -# Init genesis -geth init ./scripts/geth/genesis.json --datadir $DATADIR -# Copy keystore -rm -rf $DATADIR/keystore -cp -r ./scripts/geth/keystore $DATADIR -# Start geth with rpc, mining and unlocked accounts - -if [[ $QUIET ]]; then - geth --verbosity 2 \ - --datadir $DATADIR \ - --port P2P_PORT \ - --nodiscover \ - --unlock "0xff93B45308FD417dF303D6515aB04D9e89a750Ca","0x8e0a907331554AF72563Bd8D43051C2E64Be5d35","0x24962717f8fA5BA3b931bACaF9ac03924EB475a0","0x148FfB2074A9e59eD58142822b3eB3fcBffb0cd7","0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485" \ - --password ./scripts/geth/password.txt \ - --ws \ - --wsport RPC_PORT \ - --wsorigins="*" \ - --rpc \ - --rpcport RPC_PORT \ - --rpccorsdomain="*" \ - --networkid 5 \ - --targetgaslimit 8000000 \ - --allow-insecure-unlock \ - --mine & -else - geth --datadir $DATADIR \ - --port P2P_PORT \ - --nodiscover \ - --unlock "0xff93B45308FD417dF303D6515aB04D9e89a750Ca","0x8e0a907331554AF72563Bd8D43051C2E64Be5d35","0x24962717f8fA5BA3b931bACaF9ac03924EB475a0","0x148FfB2074A9e59eD58142822b3eB3fcBffb0cd7","0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485" \ - --password ./scripts/geth/password.txt \ - --ws \ - --wsport RPC_PORT \ - --wsorigins="*" \ - --rpc \ - --rpcport RPC_PORT \ - --rpccorsdomain="*" \ - --networkid 5 \ - --targetgaslimit 8000000 \ - --allow-insecure-unlock \ - --mine -fi diff --git a/scripts/geth/start_geth.sh b/scripts/geth/start_geth.sh deleted file mode 100755 index 5b1d5dbb..00000000 --- a/scripts/geth/start_geth.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 ChainSafe Systems -# SPDX-License-Identifier: LGPL-3.0-only -DATADIR=./gethdata - -# Exit on failure -set -e - -# Delete old chain data -rm -rf $DATADIR -# Init genesis -geth init ./scripts/geth/genesis.json --datadir $DATADIR -# Copy keystore -rm -rf $DATADIR/keystore -cp -r ./scripts/geth/keystore $DATADIR -# Start geth with rpc, mining and unlocked accounts - -if [[ $QUIET ]]; then - geth --verbosity 2 \ - --datadir $DATADIR \ - --nodiscover \ - --unlock "0xff93B45308FD417dF303D6515aB04D9e89a750Ca","0x8e0a907331554AF72563Bd8D43051C2E64Be5d35","0x24962717f8fA5BA3b931bACaF9ac03924EB475a0","0x148FfB2074A9e59eD58142822b3eB3fcBffb0cd7","0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485" \ - --password ./scripts/geth/password.txt \ - --ws \ - --ws.port 8545 \ - --networkid 5 \ - --ws.origins="*" \ - --port 8545 \ - --http.corsdomain="*" \ - --miner.gaslimit 8000000 \ - --allow-insecure-unlock \ - --mine -else - geth --datadir $DATADIR \ - --nodiscover \ - --unlock "0xff93B45308FD417dF303D6515aB04D9e89a750Ca","0x8e0a907331554AF72563Bd8D43051C2E64Be5d35","0x24962717f8fA5BA3b931bACaF9ac03924EB475a0","0x148FfB2074A9e59eD58142822b3eB3fcBffb0cd7","0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485" \ - --password ./scripts/geth/password.txt \ - --ws \ - --ws.port 8545 \ - --networkid 5 \ - --ws.origins="*" \ - --port 8545 \ - --http.corsdomain="*" \ - --miner.gaslimit 8000000 \ - --allow-insecure-unlock \ - --mine -fi diff --git a/scripts/geth/start_geth2.sh b/scripts/geth/start_geth2.sh deleted file mode 100755 index 8705101f..00000000 --- a/scripts/geth/start_geth2.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 ChainSafe Systems -# SPDX-License-Identifier: LGPL-3.0-only -DATADIR=./gethdata2 - -# Exit on failure -set -e - -# Delete old chain data -rm -rf $DATADIR -# Init genesis -geth init ./scripts/geth/genesis.json --datadir $DATADIR -# Copy keystore -rm -rf $DATADIR/keystore -cp -r ./scripts/geth/keystore $DATADIR -# Start geth with rpc, mining and unlocked accounts - -if [[ $QUIET ]]; then - geth --verbosity 2 \ - --datadir $DATADIR \ - --port 30304 \ - --nodiscover \ - --unlock "0xff93B45308FD417dF303D6515aB04D9e89a750Ca","0x8e0a907331554AF72563Bd8D43051C2E64Be5d35","0x24962717f8fA5BA3b931bACaF9ac03924EB475a0","0x148FfB2074A9e59eD58142822b3eB3fcBffb0cd7","0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485" \ - --password ./scripts/geth/password.txt \ - --ws \ - --wsport 8546 \ - --networkid 5 \ - --wsorigins="*" \ - --targetgaslimit 8000000 \ - --allow-insecure-unlock \ - --mine -else - geth --datadir $DATADIR \ - --nodiscover \ - --port 30304 \ - --unlock "0xff93B45308FD417dF303D6515aB04D9e89a750Ca","0x8e0a907331554AF72563Bd8D43051C2E64Be5d35","0x24962717f8fA5BA3b931bACaF9ac03924EB475a0","0x148FfB2074A9e59eD58142822b3eB3fcBffb0cd7","0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485" \ - --password ./scripts/geth/password.txt \ - --ws \ - --wsport 8546 \ - --networkid 5 \ - --wsorigins="*" \ - --targetgaslimit 8000000 \ - --allow-insecure-unlock \ - --mine -fi \ No newline at end of file diff --git a/scripts/header.txt b/scripts/header.txt deleted file mode 100644 index a98598c4..00000000 --- a/scripts/header.txt +++ /dev/null @@ -1,2 +0,0 @@ -The Licensed Work is (c) 2022 Sygma -SPDX-License-Identifier: LGPL-3.0-only \ No newline at end of file diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh deleted file mode 100755 index 4ae7a012..00000000 --- a/scripts/install_deps.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# The Licensed Work is (c) 2022 Sygma -# SPDX-License-Identifier: LGPL-3.0-only - - -set -e - -(set -x; yarn install --frozen-lockfil) - -if [ -x "$(command -v truffle)" ] -then - echo "truffle found, skipping install" -else - (set -x; npm install --global truffle) -fi - -if [ -x "$(command -v ganache)" ] -then - echo "ganache found, skipping install" -else - (set -x; npm install --global ganache) -fi - -if [ -x "$(command -v abigen)" ] -then - echo "abigen found, skipping install" -else - unameOut="$(uname -s)" - case "${unameOut}" in - Linux*) - echo "Found linux machine, will try using apt to install" - ( set -x; sudo add-apt-repository -y ppa:ethereum/ethereum && - sudo apt-get update && - sudo apt-get install ethereum ) - ;; - Darwin*) - echo "Found macOS machine, will try using brew to install" - ( set -x; brew tap ethereum/ethereum && - brew install ethereum ) - ;; - *) - echo "Operating system not supported, please manually install: https://geth.ethereum.org/docs/install-and-build/installing-geth" - esac -fi diff --git a/scripts/start_ganache.sh b/scripts/start_ganache.sh deleted file mode 100755 index 9fff5da1..00000000 --- a/scripts/start_ganache.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -# The Licensed Work is (c) 2022 Sygma -# SPDX-License-Identifier: LGPL-3.0-only - - -# Exit on failure -set -e - -PORT=${PORT:-8545} - -echo "Running ganache..." -if [[ $SILENT ]]; then - ganache -k london --chain.asyncRequestProcessing false --chain.chainId 1 -q -p $PORT --account "0x000000000000000000000000000000000000000000000000000000616c696365,100000000000000000000" --account "0x0000000000000000000000000000000000000000000000000000000000626f62,100000000000000000000" --account "0x00000000000000000000000000000000000000000000000000636861726c6965,100000000000000000000" --account "0x0000000000000000000000000000000000000000000000000000000064617665,100000000000000000000" --account "0x0000000000000000000000000000000000000000000000000000000000657665,100000000000000000000" & - # Otherwise CI will run tests before ganache has started - sleep 3 -else - ganache -k london --chain.asyncRequestProcessing false --chain.chainId 1 -p $PORT --account "0x000000000000000000000000000000000000000000000000000000616c696365,100000000000000000000" --account "0x0000000000000000000000000000000000000000000000000000000000626f62,100000000000000000000" --account "0x00000000000000000000000000000000000000000000000000636861726c6965,100000000000000000000" --account "0x0000000000000000000000000000000000000000000000000000000064617665,100000000000000000000" --account "0x0000000000000000000000000000000000000000000000000000000000657665,100000000000000000000" -fi diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 152748c8..00000000 --- a/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./ethers"; diff --git a/test/adapters/native/collectFee.js b/test/adapters/native/collectFee.js deleted file mode 100644 index 035f302f..00000000 --- a/test/adapters/native/collectFee.js +++ /dev/null @@ -1,117 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("Bridge - [collect fee - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const btcRecipientAddress = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("Native token fee should be successfully deducted", async () => { - const depositorBalanceBefore = await web3.eth.getBalance(depositorAddress); - const adapterBalanceBefore = await web3.eth.getBalance(NativeTokenAdapterInstance.address); - const handlerBalanceBefore = await web3.eth.getBalance(NativeTokenHandlerInstance.address); - - await TruffleAssert.passes( - NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - )); - - // check that correct ETH amount is successfully transferred to the adapter - const adapterBalanceAfter = await web3.eth.getBalance(NativeTokenAdapterInstance.address); - const handlerBalanceAfter = await web3.eth.getBalance(NativeTokenHandlerInstance.address); - assert.strictEqual( - new Ethers.BigNumber.from(transferredAmount).add(handlerBalanceBefore).toString(), handlerBalanceAfter - ); - - // check that adapter funds are transferred to the native handler contracts - assert.strictEqual( - adapterBalanceBefore, - adapterBalanceAfter - ); - - // check that depositor before and after balances align - const depositorBalanceAfter = await web3.eth.getBalance(depositorAddress); - expect( - Number(Ethers.utils.formatEther(new Ethers.BigNumber.from(depositorBalanceBefore).sub(depositAmount))) - ).to.be.within( - Number(Ethers.utils.formatEther(depositorBalanceAfter))*0.99, - Number(Ethers.utils.formatEther(depositorBalanceAfter))*1.01 - ) - }); -}); diff --git a/test/adapters/native/collectFee.test.ts b/test/adapters/native/collectFee.test.ts new file mode 100644 index 00000000..f70e38aa --- /dev/null +++ b/test/adapters/native/collectFee.test.ts @@ -0,0 +1,102 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {parseEther, formatEther, WalletClient, toHex} from "viem"; +import {deploySourceChainContracts, getBalance, mpcAddress} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; + + +describe("Bridge - [collect fee - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const btcrecipient = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + + let depositor: WalletClient; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + NativeTokenHandlerInstance, + BasicFeeHandlerInstance, + FeeHandlerRouterInstance, + NativeTokenTransferGatewayInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("Native token fee should be successfully deducted", async () => { + const depositorBalanceBefore = await getBalance(depositor); + const adapterBalanceBefore = await getBalance(NativeTokenTransferGatewayInstance.address); + const handlerBalanceBefore = await getBalance(NativeTokenHandlerInstance.address); + + await expect( + NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor.account, + value: depositAmount, + } + )).not.to.be.reverted; + + // check that correct ETH amount is successfully transferred to the adapter + const adapterBalanceAfter = await getBalance(NativeTokenTransferGatewayInstance.address); + const handlerBalanceAfter = await getBalance(NativeTokenHandlerInstance.address); + assert.strictEqual( + transferredAmount + handlerBalanceBefore, handlerBalanceAfter + ); + + // check that adapter funds are transferred to the native handler contracts + assert.strictEqual( + adapterBalanceBefore, + adapterBalanceAfter + ); + + // check that depositor before and after balances align + const depositorBalanceAfter = await getBalance(depositor); + expect( + depositorBalanceBefore - depositAmount + ).to.be.within( + depositorBalanceAfter*0.99, + depositorBalanceAfter*1.01 + ) + }); +}); diff --git a/test/adapters/native/decimalConversion.js b/test/adapters/native/decimalConversion.js deleted file mode 100644 index 3eeeb058..00000000 --- a/test/adapters/native/decimalConversion.js +++ /dev/null @@ -1,213 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("Bridge - [decimal conversion - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const btcRecipientAddress = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; - const originDecimalPlaces = 8; - const depositAmount = Ethers.utils.parseUnits("1", originDecimalPlaces); - const fee = Ethers.utils.parseUnits("0.1", originDecimalPlaces); - const transferredAmount = depositAmount.sub(fee); - const convertedTransferAmount = Ethers.utils.parseEther("0.9"); - - const AbiCoder = new Ethers.utils.AbiCoder(); - const expectedDepositData = Helpers.createBtcDepositData(transferredAmount, btcRecipientAddress); - const expectedHandlerResponse = AbiCoder.encode( - ["uint256"], - [convertedTransferAmount] - ); - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - let depositProposalData; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - originDecimalPlaces - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - - depositProposalData = Helpers.createERCDepositData( - transferredAmount, - 20, - btcRecipientAddress - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData, - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - // send ETH to destination adapter for transfers - await web3.eth.sendTransaction({ - from: depositorAddress, - to: NativeTokenHandlerInstance.address, - value: "1000000000000000000" - }) - }); - - - it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { - const NativeTokenDecimals = (await NativeTokenHandlerInstance._tokenContractAddressToTokenProperties.call( - NativeTokenHandlerInstance.address - )).decimals; - - assert.strictEqual(NativeTokenDecimals.isSet, true); - assert.strictEqual(NativeTokenDecimals["externalDecimals"], "8"); - }); - - it("Deposit converts sent token amount with 8 decimals to 18 decimal places", async () => { - const depositTx = await NativeTokenAdapterInstance.deposit(destinationDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - - await TruffleAssert.passes(depositTx); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === NativeTokenAdapterInstance.address && - event.data === expectedDepositData && - event.handlerResponse === expectedHandlerResponse - ); - }); - }); - - it("Proposal execution converts sent token amount with 18 decimals to 8 decimal places", async () => { - const expectedRecipientTransferAmount = Ethers.utils.parseUnits("0.9", originDecimalPlaces); - const proposalData = Helpers.createERCDepositData( - convertedTransferAmount, // 18 decimals - 20, - evmRecipientAddress - ); - - const dataHash = Ethers.utils.keccak256( - NativeTokenHandlerInstance.address + proposalData.substr(2) - ); - - const proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: proposalData, - }; - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - const recipientBalanceBefore = await web3.eth.getBalance(evmRecipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - const internalHandlerTx = await TruffleAssert.createTransactionResult( - NativeTokenHandlerInstance, - proposalTx.tx - ); - TruffleAssert.eventEmitted(internalHandlerTx, "FundsTransferred", (event) => { - return ( - event.amount.toNumber() === expectedRecipientTransferAmount.toNumber() - ); - }); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [NativeTokenHandlerInstance.address, evmRecipientAddress, convertedTransferAmount] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalanceAfter = await web3.eth.getBalance(evmRecipientAddress); - assert.strictEqual(transferredAmount.add(recipientBalanceBefore).toString(), recipientBalanceAfter); - }); -}); diff --git a/test/adapters/native/decimalConversion.test.ts b/test/adapters/native/decimalConversion.test.ts new file mode 100644 index 00000000..b04e7160 --- /dev/null +++ b/test/adapters/native/decimalConversion.test.ts @@ -0,0 +1,195 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createERCDepositData, deploySourceChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; + + +describe("Bridge - [decimal conversion - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const resourceID = toHex(650, {size:32}); + const btcrecipient = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; + const originDecimalPlaces = 8; + const originHexDecimalPlaces = toHex(originDecimalPlaces); + const depositAmount = parseUnits("1", originDecimalPlaces); + const fee = parseUnits("0.1", originDecimalPlaces); + const transferredAmount = depositAmount - fee; + const convertedTransferAmount = parseEther("0.9"); + + const expectedDepositData = createBtcDepositData(transferredAmount, btcrecipient); + const expectedHandlerResponse = encodeAbiParameters( + parseAbiParameters("uint256"), + [convertedTransferAmount] + ); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + + let admin: WalletClient; + let depositor: WalletClient; + let evmRecipient: WalletClient; + let relayer1: WalletClient; + + let depositProposalData: Hex; + let proposal: Proposal; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + NativeTokenHandlerInstance, + BasicFeeHandlerInstance, + FeeHandlerRouterInstance, + NativeTokenTransferGatewayInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + evmRecipient, + relayer1 + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + originHexDecimalPlaces + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + depositProposalData = createBtcDepositData( + transferredAmount, + btcrecipient + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData, + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + + // send ETH to destination adapter for transfers + + await depositor.sendTransaction({ + account: depositor!.account, + to: NativeTokenHandlerInstance.address, + value: BigInt(1000000000000000000), + chain: null + }) + }); + + + it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { + const NativeTokenDecimals = (await NativeTokenHandlerInstance.read._tokenContractAddressToTokenProperties([ + NativeTokenHandlerInstance.address + ]))[3]; + + assert.strictEqual(NativeTokenDecimals.isSet, true); + assert.strictEqual(NativeTokenDecimals["externalDecimals"], 8); + }); + + it("Deposit converts sent token amount with 8 decimals to 18 decimal places", async () => { + const depositTx = await NativeTokenTransferGatewayInstance.write.deposit([destinationDomainID, btcrecipient], { + account: depositor.account?.address, + value: depositAmount + }) + + await expect(depositTx).not.to.be.reverted; + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + NativeTokenTransferGatewayInstance.address, + expectedDepositData, + expectedHandlerResponse + ) + }); + + it("Proposal execution converts sent token amount with 18 decimals to 8 decimal places", async () => { + const expectedRecipientTransferAmount = parseUnits("0.9", originDecimalPlaces); + const proposalData = createERCDepositData( + convertedTransferAmount, // 18 decimals + 20, + evmRecipient.account!.address + ); + + const dataHash = keccak256( + concat([ + NativeTokenHandlerInstance.address, + trimPrefix(proposalData) + ]) + ); + + const proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: proposalData, + }; + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + const recipientBalanceBefore = await getBalance(evmRecipient); + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData, + ], + { + account: relayer1.account + } + ); + + await expect(proposalTx).to.emit(BridgeInstance, "FundsTransferred").withArgs( + expectedRecipientTransferAmount + ) + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [NativeTokenHandlerInstance.address, evmRecipient.account!.address, expectedRecipientTransferAmount] + ) + ) + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalanceAfter = await getBalance(evmRecipient); + assert.strictEqual(transferredAmount + recipientBalanceBefore, recipientBalanceAfter); + }); +}); diff --git a/test/adapters/native/deposit.js b/test/adapters/native/deposit.js deleted file mode 100644 index 96c5da31..00000000 --- a/test/adapters/native/deposit.js +++ /dev/null @@ -1,170 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("Bridge - [deposit - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const btcRecipientAddress = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("Native token deposit can be made", async () => { - await TruffleAssert.passes( - await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - ) - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("Deposit event is fired with expected value", async () => { - const depositTx = await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - ); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - const depositData = Helpers.createBtcDepositData(transferredAmount, btcRecipientAddress); - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === NativeTokenAdapterInstance.address && - event.data === depositData && - event.handlerResponse === null - ); - }); - }); - - it("Should revert if destination domain is current bridge domain", async () => { - await Helpers.reverts( - NativeTokenAdapterInstance.deposit(originDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - }); - - it("Should revert if sender is not native token adapter", async () => { - const invalidAdapterAddress = accounts[2]; - const NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - invalidAdapterAddress, - DefaultMessageReceiverInstance.address, - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - - await Helpers.reverts( - NativeTokenAdapterInstance.deposit(destinationDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - }); -}); diff --git a/test/adapters/native/deposit.test.ts b/test/adapters/native/deposit.test.ts new file mode 100644 index 00000000..c43427bb --- /dev/null +++ b/test/adapters/native/deposit.test.ts @@ -0,0 +1,156 @@ +import hre from 'hardhat'; +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {assert, expect} from "chai"; +import {parseEther, WalletClient} from "viem"; +import {createBtcDepositData, deploySourceChainContracts, mpcAddress} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; + + + + +describe("Bridge - [deposit - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; + const btcrecipient = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + + let depositor: WalletClient; + let invalidAdapterMock: WalletClient; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + NativeTokenHandlerInstance, + BasicFeeHandlerInstance, + FeeHandlerRouterInstance, + NativeTokenTransferGatewayInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + invalidAdapterMock + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]), + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("Native token deposit can be made", async () => { + await expect( + await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor.account, + value: depositAmount, + } + ) + ).not.to.be.reverted; + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor.account, + value: depositAmount, + } + ); + + const depositCount = await BridgeInstance.read._depositCounts( + [destinationDomainID] + ); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("Deposit event is fired with expected value", async () => { + const depositTx = await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor.account, + value: depositAmount, + } + ); + + const depositData = createBtcDepositData(transferredAmount, btcrecipient); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + NativeTokenTransferGatewayInstance.address, + depositData, + null + ) + }); + + it("Should revert if destination domain is current bridge domain", async () => { + await expect( + NativeTokenTransferGatewayInstance.write.deposit([originDomainID, btcrecipient], + { + account: depositor.account, + value: depositAmount + }) + ).to.be.reverted; + }); + + it("Should revert if sender is not native token adapter", async () => { + const NativeTokenHandlerInstance = await hre.viem.deployContract("NativeTokenHandler", + [ + BridgeInstance.address, + invalidAdapterMock.address, + DefaultMessageReceiverInstance.address + ]); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + + await expect( + NativeTokenTransferGatewayInstance.write.deposit([destinationDomainID, btcrecipient], + { + account: depositor.account, + value: depositAmount + }) + ).to.be.reverted; + }); +}); diff --git a/test/adapters/native/distributeFee.js b/test/adapters/native/distributeFee.js deleted file mode 100644 index 15bba3c5..00000000 --- a/test/adapters/native/distributeFee.js +++ /dev/null @@ -1,249 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers.js"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("Native token adapter - [distributeFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const btcRecipientAddress = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - - - - const assertOnlyAdmin = (method, ...params) => { - return TruffleAssert.fails( - method(...params, {from: accounts[1]}), - "sender doesn't have admin role" - ); - }; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let NativeTokenAdapterInstance; - let FeeHandlerRouterInstance; - let BasicFeeHandlerInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )) - ]); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should distribute fees", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - assert.equal( - web3.utils.fromWei(await BasicFeeHandlerInstance._domainResourceIDToFee( - destinationDomainID, - resourceID - ), "ether"), - Ethers.utils.formatUnits(fee) - ); - - // check the balance is 0 - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BridgeInstance.address), - "ether" - ), - "0" - ); - await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount - } - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BridgeInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenAdapterInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenHandlerInstance.address), - "ether" - ), - Ethers.utils.formatUnits(transferredAmount) - ); - - const b1Before = await web3.eth.getBalance(accounts[1]); - const b2Before = await web3.eth.getBalance(accounts[2]); - - const payout = Ethers.utils.parseEther("0.01"); - // Transfer the funds - const tx = await BasicFeeHandlerInstance.transferFee( - [accounts[1], accounts[2]], - [payout, payout] - ); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === "0x0000000000000000000000000000000000000000" && - event.recipient === accounts[1] && - event.amount.toString() === payout.toString() - ); - }); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === "0x0000000000000000000000000000000000000000" && - event.recipient === accounts[2] && - event.amount.toString() === payout.toString() - ); - }); - b1 = await web3.eth.getBalance(accounts[1]); - b2 = await web3.eth.getBalance(accounts[2]); - assert.equal(b1, Ethers.BigNumber.from(b1Before).add(payout)); - assert.equal(b2, Ethers.BigNumber.from(b2Before).add(payout)); - }); - - it("should require admin role to distribute fee", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - - await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount - } - ); - - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenAdapterInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenHandlerInstance.address), - "ether" - ), - Ethers.utils.formatUnits(transferredAmount) - ); - - const payout = Ethers.utils.parseEther("0.01"); - await assertOnlyAdmin( - BasicFeeHandlerInstance.transferFee, - [accounts[3], accounts[4]], - [payout, payout] - ); - }); - - it("should revert if addrs and amounts arrays have different length", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - - await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount - } - ); - - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenAdapterInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenHandlerInstance.address), - "ether" - ), - Ethers.utils.formatUnits(transferredAmount) - ); - - const payout = Ethers.utils.parseEther("0.01"); - await TruffleAssert.fails( - BasicFeeHandlerInstance.transferFee( - [accounts[3], accounts[4]], - [payout, payout, payout] - ), - "addrs[], amounts[]: diff length" - ); - }); -}); diff --git a/test/adapters/native/distributeFee.test.ts b/test/adapters/native/distributeFee.test.ts new file mode 100644 index 00000000..783b8bf7 --- /dev/null +++ b/test/adapters/native/distributeFee.test.ts @@ -0,0 +1,198 @@ +import hre from 'hardhat'; +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {createPublicClient, formatEther, formatUnits, Hex, http, parseEther, toHex, WalletClient, zeroAddress} from "viem"; +import {createERCDepositData, deploySourceChainContracts, getBalance, mpcAddress} from "../../helpers"; +import {assert, expect} from "chai"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {hardhat, localhost, mainnet} from 'viem/chains'; + + +describe("Native token adapter - [distributeFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const tokenDecimals = 18; + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const btcrecipient = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + + let nonAdmin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let firstEOA: WalletClient; + let secondEOA: WalletClient; + + let depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + NativeTokenHandlerInstance, + BasicFeeHandlerInstance, + FeeHandlerRouterInstance, + NativeTokenTransferGatewayInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + nonAdmin, + depositor, + recipient, + firstEOA, + secondEOA + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should distribute fees", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + const configuredFee = (await BasicFeeHandlerInstance.read._domainResourceIDToFee([ + destinationDomainID, + resourceID + ])) + assert.equal( + parseEther(configuredFee.toString()), + parseEther(fee.toString()) + ); + + // check the balance is 0 + assert.equal( + await getBalance(BridgeInstance), + BigInt(0) + ); + await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor!.account, + value: depositAmount + } + ); + + assert.equal( + await getBalance(BridgeInstance), + BigInt(0) + ); + assert.equal( + await getBalance(NativeTokenTransferGatewayInstance), + BigInt(0) + ); + assert.equal( + await getBalance(NativeTokenHandlerInstance), + transferredAmount + ); + + const firstEOABefore = await getBalance(firstEOA); + const secondEOABefore = await getBalance(secondEOA); + + const payout = parseEther("0.01"); + // Transfer the funds + const tx = await BasicFeeHandlerInstance.write.transferFee([ + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ]); + + await expect(tx).to.emit(BasicFeeHandlerInstance, "FeeDistributed").withArgs( + zeroAddress, + recipient, + payout + ); + + const firstEOABalanceAfter = await getBalance(firstEOA); + const secondEOABalanceAfter = await getBalance(secondEOA); + assert.equal(firstEOABalanceAfter, firstEOABefore + payout); + assert.equal(secondEOABalanceAfter, secondEOABefore + payout); + }); + + it("should require admin role to distribute fee", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor.account, + value: depositAmount + } + ); + + assert.equal( + await getBalance(NativeTokenTransferGatewayInstance), + BigInt(0) + ); + assert.equal( + await getBalance(NativeTokenHandlerInstance), + BigInt(formatUnits(transferredAmount, tokenDecimals)) + ); + + const payout = parseEther("0.01"); + await expect( + BasicFeeHandlerInstance.write.transferFee([ + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ], {account: nonAdmin.account}), + ).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should revert if addrs and amounts arrays have different length", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor.account, + value: depositAmount + } + ); + + assert.equal( + await getBalance(NativeTokenTransferGatewayInstance), + BigInt(0) + ); + assert.equal( + await getBalance(NativeTokenHandlerInstance), + BigInt(formatUnits(transferredAmount, tokenDecimals)) + ); + + const payout = parseEther("0.01"); + await expect( + BasicFeeHandlerInstance.write.transferFee([ + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout, payout] + ]) + ).to.be.revertedWith("addrs[], amounts[]: diff length"); + }); +}); diff --git a/test/adapters/native/executeProposal.js b/test/adapters/native/executeProposal.js deleted file mode 100644 index d40d1632..00000000 --- a/test/adapters/native/executeProposal.js +++ /dev/null @@ -1,262 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("Bridge - [execute proposal - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const btcRecipientAddress = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - let proposal; - let depositProposalData; - let dataHash; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - - depositProposalData = Helpers.createERCDepositData( - transferredAmount, - 20, - recipientAddress - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData, - }; - - dataHash = Ethers.utils.keccak256( - NativeTokenHandlerInstance.address + depositProposalData.substr(2) - ); - - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - // send ETH to destination adapter for transfers - await web3.eth.sendTransaction({ - from: depositorAddress, - to: NativeTokenHandlerInstance.address, - value: "1000000000000000000" - }) - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.deposit(originDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - - const recipientBalanceBefore = await web3.eth.getBalance(recipientAddress); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(transferredAmount.add(recipientBalanceBefore).toString(), recipientBalanceAfter); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.deposit(originDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.deposit(originDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - - const recipientBalanceBefore = await web3.eth.getBalance(recipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [NativeTokenHandlerInstance.address, recipientAddress, transferredAmount] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - - // check that tokens are transferred to recipient address - const recipientBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(transferredAmount.add(recipientBalanceBefore).toString(), recipientBalanceAfter); - }); - - it(`should fail to executeProposal if signed Proposal has different - chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.deposit(originDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); -}); diff --git a/test/adapters/native/executeProposal.test.ts b/test/adapters/native/executeProposal.test.ts new file mode 100644 index 00000000..89b8422d --- /dev/null +++ b/test/adapters/native/executeProposal.test.ts @@ -0,0 +1,260 @@ +import hre from 'hardhat'; +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {assert, expect} from "chai"; +import {concat, encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, toHex, WalletClient} from "viem"; +import {createERCDepositData, deploySourceChainContracts, getBalance, mockSignTypedProposalWithInvalidChainID, mpcAddress, trimPrefix} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {Proposal} from '../../../types'; + +describe("Bridge - [execute proposal - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const btcrecipient = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let proposal: Proposal; + let depositProposalData; + let dataHash: Hex; + + before(async () => { + ({ + BridgeInstance, + NativeTokenHandlerInstance, + BasicFeeHandlerInstance, + FeeHandlerRouterInstance, + NativeTokenTransferGatewayInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + relayer1 + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]), + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + originDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + depositProposalData = createERCDepositData( + transferredAmount, + 20, + recipient + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData, + }; + + dataHash = keccak256( + concat([ + NativeTokenHandlerInstance.address, + trimPrefix(depositProposalData) + ]) + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + + // send ETH to destination adapter for transfers + await web3.eth.sendTransaction({ + account: depositor.account, + to: NativeTokenHandlerInstance.address, + value: "1000000000000000000" + }) + }); + + it("isProposalExecuted returns false if depositNonce is not used", async () => { + const destinationDomainID = await BridgeInstance.read._domainID(); + + assert.isFalse( + await BridgeInstance.read.isProposalExecuted([ + destinationDomainID, + expectedDepositNonce + ]) + ); + }); + + it("should create and execute executeProposal successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.deposit([originDomainID, btcrecipient], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + const recipientBalanceBefore = await getBalance(recipient); + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], + { + account: relayer1.account, + }) + ).not.to.be.reverted; + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalanceAfter = await getBalance(recipient); + assert.strictEqual(transferredAmount + recipientBalanceBefore, recipientBalanceAfter); + }); + + it("should skip executing proposal if deposit nonce is already used", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.deposit([originDomainID, btcrecipient], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], + { + account: relayer1.account, + }) + ).not.to.be.reverted; + + const skipExecuteTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + // check that no ProposalExecution events are emitted + await expect(skipExecuteTx).not.to.emit(BridgeInstance, "ProposalExecution"); + }); + + it("executeProposal event should be emitted with expected values", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.deposit([originDomainID, btcrecipient], + { + account: depositor.account, + value: depositAmount + }) + ); + + const recipientBalanceBefore = await getBalance(recipient); + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [NativeTokenHandlerInstance.address, recipient.account!.address, transferredAmount] + ) + ) + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + + // check that tokens are transferred to recipient address + const recipientBalanceAfter = await getBalance(recipient); + assert.strictEqual(transferredAmount + recipientBalanceBefore, recipientBalanceAfter); + }); + + it(`should fail to executeProposal if signed Proposal has different + chainID than the one on which it should be executed`, async () => { + const proposalSignedData = + await mockSignTypedProposalWithInvalidChainID( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.deposit([originDomainID, btcrecipient], + { + account: depositor.account, + value: depositAmount + }) + ); + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], + { + account: relayer1.account, + } + ), + ).to.be.revertedWithCustomError(BridgeInstance, "InvalidProposalSigner()"); + }); +}); diff --git a/test/adapters/native/optionalContractCall/collectFee.js b/test/adapters/native/optionalContractCall/collectFee.js deleted file mode 100644 index 9300a717..00000000 --- a/test/adapters/native/optionalContractCall/collectFee.js +++ /dev/null @@ -1,162 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("Bridge - [collect fee - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - const executionGasAmount = 30000000; - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - let message; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - Ethers.constants.AddressZero, - emptySetResourceData - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("Native token fee should be successfully deducted", async () => { - const depositorBalanceBefore = await web3.eth.getBalance(depositorAddress); - const adapterBalanceBefore = await web3.eth.getBalance(NativeTokenAdapterInstance.address); - const handlerBalanceBefore = await web3.eth.getBalance(NativeTokenHandlerInstance.address); - - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - destinationDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount, - } - )); - - // check that correct ETH amount is successfully transferred to the adapter - const adapterBalanceAfter = await web3.eth.getBalance(NativeTokenAdapterInstance.address); - const handlerBalanceAfter = await web3.eth.getBalance(NativeTokenHandlerInstance.address); - assert.strictEqual( - new Ethers.BigNumber.from(transferredAmount).add(handlerBalanceBefore).toString(), handlerBalanceAfter - ); - - // check that adapter funds are transferred to the native handler contracts - assert.strictEqual( - adapterBalanceBefore, - adapterBalanceAfter - ); - - // check that depositor before and after balances align - const depositorBalanceAfter = await web3.eth.getBalance(depositorAddress); - expect( - Number(Ethers.utils.formatEther(new Ethers.BigNumber.from(depositorBalanceBefore).sub(depositAmount))) - ).to.be.within( - Number(Ethers.utils.formatEther(depositorBalanceAfter))*0.99, - Number(Ethers.utils.formatEther(depositorBalanceAfter))*1.01 - ) - }); -}); diff --git a/test/adapters/native/optionalContractCall/collectFee.test.ts b/test/adapters/native/optionalContractCall/collectFee.test.ts new file mode 100644 index 00000000..7bedfd98 --- /dev/null +++ b/test/adapters/native/optionalContractCall/collectFee.test.ts @@ -0,0 +1,138 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; + +describe("Bridge - [collect fee - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = 1; + const emptySetResourceData = "0x"; + const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + const executionGasAmount = BigInt(30000000); + const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + + let depositor: WalletClient; + let evmRecipient: WalletClient; + + let message: Hex; + let depositProposalData: Hex + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + BasicFeeHandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + evmRecipient + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + zeroAddress, + emptySetResourceData + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 tokenId, string memory _data)"], + functionName: "mint", + args: [evmRecipient, "5", ""] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC20MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + evmRecipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + transferredAmount, + zeroAddress, + executionGasAmount, + message + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("Native token fee should be successfully deducted", async () => { + const depositorBalanceBefore = await getBalance(depositor); + const adapterBalanceBefore = await getBalance(NativeTokenTransferGatewayInstance.address); + const handlerBalanceBefore = await getBalance(NativeTokenHandlerInstance.address); + + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount, + } + )).not.to.be.reverted; + + // check that correct ETH amount is successfully transferred to the adapter + const adapterBalanceAfter = await getBalance(NativeTokenTransferGatewayInstance.address); + const handlerBalanceAfter = await getBalance(NativeTokenHandlerInstance.address); + assert.strictEqual( + transferredAmount + handlerBalanceBefore, handlerBalanceAfter + ); + + // check that adapter funds are transferred to the native handler contracts + assert.strictEqual( + adapterBalanceBefore, + adapterBalanceAfter + ); + + // check that depositor before and after balances align + const depositorBalanceAfter = await getBalance(depositor); + expect(depositorBalanceBefore - depositAmount).to.be.within( + Number(formatEther(depositorBalanceAfter))*0.99, + Number(formatEther(depositorBalanceAfter))*1.01 + ) + }); +}); diff --git a/test/adapters/native/optionalContractCall/decimalConversion.js b/test/adapters/native/optionalContractCall/decimalConversion.js deleted file mode 100644 index f86d27bc..00000000 --- a/test/adapters/native/optionalContractCall/decimalConversion.js +++ /dev/null @@ -1,255 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("Bridge - [decimal conversion - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const originDecimalPlaces = 8; - const depositAmount = Ethers.utils.parseUnits("1", originDecimalPlaces); - const fee = Ethers.utils.parseUnits("0.1", originDecimalPlaces); - const transferredAmount = depositAmount.sub(fee); - const convertedTransferAmount = Ethers.utils.parseEther("0.9"); - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - - - const AbiCoder = new Ethers.utils.AbiCoder(); - const expectedHandlerResponse = AbiCoder.encode( - ["uint256"], - [convertedTransferAmount] - ); - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - let depositProposalData; - let ERC20MintableInstance; - - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - Ethers.constants.AddressZero, - originDecimalPlaces - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - - await DefaultMessageReceiverInstance.grantRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - NativeTokenHandlerInstance.address - ); - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // send ETH to destination adapter for transfers - await web3.eth.sendTransaction({ - from: depositorAddress, - to: NativeTokenHandlerInstance.address, - value: "1000000000000000000" - }) - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { - const NativeTokenDecimals = (await NativeTokenHandlerInstance._tokenContractAddressToTokenProperties.call( - Ethers.constants.AddressZero - )).decimals; - - assert.strictEqual(NativeTokenDecimals.isSet, true); - assert.strictEqual(NativeTokenDecimals["externalDecimals"], "8"); - }); - - it("Deposit converts sent token amount with 8 decimals to 18 decimal places", async () => { - const depositTx = await NativeTokenAdapterInstance.depositToEVMWithMessage( - destinationDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - } - ); - - await TruffleAssert.passes(depositTx); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === NativeTokenAdapterInstance.address && - event.data === depositProposalData && - event.handlerResponse === expectedHandlerResponse - ); - }); - }); - - it("Proposal execution converts sent token amount with 18 decimals to 8 decimal places", async () => { - const expectedRecipientTransferAmount = Ethers.utils.parseUnits("0.9", originDecimalPlaces); - const proposalData = Helpers.createOptionalContractCallDepositData( - convertedTransferAmount, // 18 decimals - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - const dataHash = Ethers.utils.keccak256( - NativeTokenHandlerInstance.address + proposalData.substr(2) - ); - - const proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: proposalData, - }; - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - const recipientBalanceBefore = await web3.eth.getBalance(evmRecipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - const internalHandlerTx = await TruffleAssert.createTransactionResult( - NativeTokenHandlerInstance, - proposalTx.tx - ); - TruffleAssert.eventEmitted(internalHandlerTx, "FundsTransferred", (event) => { - return ( - event.amount.toNumber() === expectedRecipientTransferAmount.toNumber() - ); - }); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [Ethers.constants.AddressZero, DefaultMessageReceiverInstance.address, convertedTransferAmount] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalanceAfter = await web3.eth.getBalance(evmRecipientAddress); - assert.strictEqual(transferredAmount.add(recipientBalanceBefore).toString(), recipientBalanceAfter); - }); -}); diff --git a/test/adapters/native/optionalContractCall/decimalConversion.test.ts b/test/adapters/native/optionalContractCall/decimalConversion.test.ts new file mode 100644 index 00000000..e820b32a --- /dev/null +++ b/test/adapters/native/optionalContractCall/decimalConversion.test.ts @@ -0,0 +1,246 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, mpcAddress, trimPrefix} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Wallet} from 'ethers'; +import {Proposal} from '../../../../types'; + + +describe("Bridge - [decimal conversion - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const resourceID = toHex(650, {size:32}); + const originDecimalPlaces = 8; + const depositAmount = parseUnits("1", originDecimalPlaces); + const fee = parseUnits("0.1", originDecimalPlaces); + const transferredAmount = depositAmount - fee ; + const convertedTransferAmount = parseEther("0.9"); + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + + const expectedHandlerResponse = + encodeAbiParameters( + parseAbiParameters( + ["uint256"] + ), + [convertedTransferAmount] + ); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + + let depositor: WalletClient; + let evmRecipient: WalletClient; + let relayer1: WalletClient; + + let depositProposalData: Hex; + let message: Hex; + let proposal: Proposal; + + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + NativeTokenHandlerInstance, + FeeHandlerRouterInstance, + NativeTokenTransferGatewayInstance, + BasicFeeHandlerInstance, + ERC20MintableInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + evmRecipient, + relayer1 + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + zeroAddress, + toHex(originDecimalPlaces) + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + await DefaultMessageReceiverInstance.write.grantRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + NativeTokenHandlerInstance.address + ]); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 amount)"], + functionName: "mint", + args: [evmRecipient, "5"] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC20MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + evmRecipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + transferredAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + // send ETH to destination adapter for transfers + await web3.eth.sendTransaction({ + account: depositor.account, + to: NativeTokenHandlerInstance.address, + value: "1000000000000000000" + }) + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { + const NativeTokenDecimals = (await NativeTokenHandlerInstance.read._tokenContractAddressToTokenProperties([ + zeroAddress + ]))[3]; + + assert.strictEqual(NativeTokenDecimals.isSet, true); + assert.strictEqual(NativeTokenDecimals["externalDecimals"], 8); + }); + + it("Deposit converts sent token amount with 8 decimals to 18 decimal places", async () => { + const depositTx = await NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + executionGasAmount, + message + ], + { + fromaccount: depositor.account, + value: depositAmount + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositProposalData, + expectedHandlerResponse + ); + }); + + it("Proposal execution converts sent token amount with 18 decimals to 8 decimal places", async () => { + const expectedRecipientTransferAmount = parseUnits("0.9", originDecimalPlaces); + const proposalData = createOptionalContractCallDepositData( + convertedTransferAmount, // 18 decimals + zeroAddress, + executionGasAmount, + message + ); + + const dataHash = keccak256( + concat([ + NativeTokenHandlerInstance.address, + trimPrefix(proposalData) + ]) + ); + + const proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: proposalData, + }; + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + const recipientBalanceBefore = await getBalance(evmRecipient); + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + await expect(proposalTx).to.emit(NativeTokenHandlerInstance, "FundsTransferred").withArgs( + expectedRecipientTransferAmount + ); + + const expectedHandlerResponse = encodeAbiParameters( + parseAbiParameters( + ["address", "address", "uint256"] + ), + [ + zeroAddress, + DefaultMessageReceiverInstance.address, + convertedTransferAmount, + ] + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + expectedHandlerResponse + ); + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalanceAfter = await getBalance(evmRecipient); + assert.strictEqual(transferredAmount.add(recipientBalanceBefore).toString(), recipientBalanceAfter); + }); +}); diff --git a/test/adapters/native/optionalContractCall/deposit.js b/test/adapters/native/optionalContractCall/deposit.js deleted file mode 100644 index 3970e293..00000000 --- a/test/adapters/native/optionalContractCall/deposit.js +++ /dev/null @@ -1,272 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - - -contract("Bridge - [deposit - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const btcRecipientAddress = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - let ERC20MintableInstance; - let message; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]), - }]; - message = Helpers.createMessageCallData( - transactionId, - actions, - DefaultMessageReceiverInstance.address - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("Native token deposit can be made", async () => { - await TruffleAssert.passes( - await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - ) - ); - }); - - it("Native token deposit to EVM can be made", async () => { - await TruffleAssert.passes( - await NativeTokenAdapterInstance.depositToEVM( - destinationDomainID, - evmRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - ) - ); - }); - - it("Native token deposit to EVM with message can be made", async () => { - await TruffleAssert.passes( - await NativeTokenAdapterInstance.depositToEVMWithMessage( - destinationDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount, - } - ) - ); - }); - - it("Native token general deposit can be made", async () => { - const addressLength = 20; - const depositData = Helpers.abiEncode(["uint256", "address"], [addressLength, evmRecipientAddress]) - await TruffleAssert.passes( - await NativeTokenAdapterInstance.depositGeneral( - destinationDomainID, - depositData, - { - from: depositorAddress, - value: depositAmount, - } - ) - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("Deposit event is fired with expected value", async () => { - const depositTx = await NativeTokenAdapterInstance.deposit( - destinationDomainID, - btcRecipientAddress, - { - from: depositorAddress, - value: depositAmount, - } - ); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - const depositData = Helpers.createBtcDepositData(transferredAmount, btcRecipientAddress); - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === NativeTokenAdapterInstance.address && - event.data === depositData && - event.handlerResponse === null - ); - }); - }); - - it("Should revert if destination domain is current bridge domain", async () => { - await Helpers.reverts( - NativeTokenAdapterInstance.deposit(originDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - }); - - it("Should revert if sender is not native token adapter", async () => { - const invalidAdapterAddress = accounts[2]; - const NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - invalidAdapterAddress, - DefaultMessageReceiverInstance.address, - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - - await Helpers.reverts( - NativeTokenAdapterInstance.deposit(destinationDomainID, btcRecipientAddress, { - from: depositorAddress, - value: depositAmount - }) - ); - }); - - it("Should revert if execution gas provided is 0", async () => { - const invalidExecutionGasAmount = 0; - await Helpers.expectToRevertWithCustomError( - NativeTokenAdapterInstance.depositToEVMWithMessage.call( - destinationDomainID, - Ethers.constants.AddressZero, - invalidExecutionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount, - } - ), - "ZeroGas()" - ); - }); - - it("Should revert if msg.value is 0", async () => { - await Helpers.expectToRevertWithCustomError( - NativeTokenAdapterInstance.depositToEVMWithMessage.call( - destinationDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - } - ), - "InsufficientMsgValueAmount(uint256)" - ); - }); -}); diff --git a/test/adapters/native/optionalContractCall/deposit.test.ts b/test/adapters/native/optionalContractCall/deposit.test.ts new file mode 100644 index 00000000..726238a0 --- /dev/null +++ b/test/adapters/native/optionalContractCall/deposit.test.ts @@ -0,0 +1,254 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createBtcDepositData, createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, mpcAddress, trimPrefix} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Wallet} from 'ethers'; +import {Proposal} from '../../../../types'; + + +describe("Bridge - [deposit - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const btcrecipient = "bc1qs0fcdq73vgurej48yhtupzcv83un2p5qhsje7n"; + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + + let depositor: WalletClient; + let evmRecipient: WalletClient; + let invalidAdapterMock: WalletClient; + + let message: Hex; + + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + BasicFeeHandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + evmRecipient, + invalidAdapterMock + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 amount)"], + functionName: "mint", + args: [evmRecipient, "5"] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC20MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }]; + message = createMessageCallData( + transactionId, + actions, + DefaultMessageReceiverInstance.address + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("Native token deposit can be made", async () => { + await expect( + await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient + ], + { + account: depositor.account, + value: depositAmount, + } + ) + ).not.to.be.reverted; + }); + + it("Native token deposit to EVM can be made", async () => { + await expect( + await NativeTokenTransferGatewayInstance.write.depositToEVM([ + destinationDomainID, + evmRecipient.account!.address + ], + { + account: depositor.account, + value: depositAmount, + } + ) + ).not.to.be.reverted; + }); + + it("Native token deposit to EVM with message can be made", async () => { + await expect( + await NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount, + } + ) + ).not.to.be.reverted; + }); + + it("Native token general deposit can be made", async () => { + const addressLength = BigInt(20); + const depositData = encodeAbiParameters( + parseAbiParameters(["uint256", "address"]), + [addressLength, evmRecipient.account!.address] + ); + await expect( + await NativeTokenTransferGatewayInstance.write.depositGeneral([ + destinationDomainID, + depositData], + { + account: depositor.account, + value: depositAmount, + } + ) + ).not.to.be.reverted; + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient], + { + account: depositor.account, + value: depositAmount, + } + ); + + const depositCount = await BridgeInstance.read._depositCounts([ + destinationDomainID + ]); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("Deposit event is fired with expected value", async () => { + const depositTx = await NativeTokenTransferGatewayInstance.write.deposit([ + destinationDomainID, + btcrecipient], + { + account: depositor.account, + value: depositAmount, + } + ); + + const depositData = createBtcDepositData(transferredAmount, btcrecipient); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + NativeTokenTransferGatewayInstance.address, + depositData, + null + ); + }); + + it("Should revert if destination domain is current bridge domain", async () => { + await expect( + NativeTokenTransferGatewayInstance.write.deposit([originDomainID, btcrecipient], { + account: depositor.account, + value: depositAmount + }) + ).to.be.reverted; + }); + + it("Should revert if sender is not native token adapter", async () => { + const NativeTokenHandlerInstance = await hre.viem.deployContract("NativeTokenHandler", [ + BridgeInstance.address, + invalidAdapterMock.account!.address, + DefaultMessageReceiverInstance.address + ]); + + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + + await expect( + NativeTokenTransferGatewayInstance.write.deposit([destinationDomainID, btcrecipient], { + account: depositor.account, + value: depositAmount + }) + ).to.be.reverted; + }); + + it("Should revert if execution gas provided is 0", async () => { + const invalidExecutionGasAmount = BigInt(0); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + invalidExecutionGasAmount, + message], + { + account: depositor.account, + value: depositAmount, + } + ), + ).to.be.revertedWithCustomError(NativeTokenHandlerInstance, "ZeroGas()"); + }); + + it("Should revert if msg.value is 0", async () => { + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + } + ), + ).to.be.revertedWithCustomError(NativeTokenHandlerInstance, "InsufficientMsgValueAmount(uint256)"); + }); +}); diff --git a/test/adapters/native/optionalContractCall/distributeFee.js b/test/adapters/native/optionalContractCall/distributeFee.js deleted file mode 100644 index de781915..00000000 --- a/test/adapters/native/optionalContractCall/distributeFee.js +++ /dev/null @@ -1,285 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers.js"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("Native token adapter - [distributeFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - - - const assertOnlyAdmin = (method, ...params) => { - return TruffleAssert.fails( - method(...params, {from: accounts[1]}), - "sender doesn't have admin role" - ); - }; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let NativeTokenAdapterInstance; - let FeeHandlerRouterInstance; - let BasicFeeHandlerInstance; - let ERC20MintableInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )) - ]); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - NativeTokenHandlerInstance.address, - emptySetResourceData - ); - - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [recipientAddress, "20"]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - recipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should distribute fees", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - assert.equal( - web3.utils.fromWei(await BasicFeeHandlerInstance._domainResourceIDToFee( - destinationDomainID, - resourceID - ), "ether"), - Ethers.utils.formatUnits(fee) - ); - - // check the balance is 0 - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BridgeInstance.address), - "ether" - ), - "0" - ); - await NativeTokenAdapterInstance.depositToEVMWithMessage( - destinationDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - } - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BridgeInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenAdapterInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenHandlerInstance.address), - "ether" - ), - Ethers.utils.formatUnits(transferredAmount) - ); - - const b1Before = await web3.eth.getBalance(accounts[1]); - const b2Before = await web3.eth.getBalance(accounts[2]); - - const payout = Ethers.utils.parseEther("0.01"); - // Transfer the funds - const tx = await BasicFeeHandlerInstance.transferFee( - [accounts[1], accounts[2]], - [payout, payout] - ); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === "0x0000000000000000000000000000000000000000" && - event.recipient === accounts[1] && - event.amount.toString() === payout.toString() - ); - }); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === "0x0000000000000000000000000000000000000000" && - event.recipient === accounts[2] && - event.amount.toString() === payout.toString() - ); - }); - b1 = await web3.eth.getBalance(accounts[1]); - b2 = await web3.eth.getBalance(accounts[2]); - assert.equal(b1, Ethers.BigNumber.from(b1Before).add(payout)); - assert.equal(b2, Ethers.BigNumber.from(b2Before).add(payout)); - }); - - it("should require admin role to distribute fee", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - - await NativeTokenAdapterInstance.depositToEVMWithMessage( - destinationDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - } - ); - - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenAdapterInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenHandlerInstance.address), - "ether" - ), - Ethers.utils.formatUnits(transferredAmount) - ); - - const payout = Ethers.utils.parseEther("0.01"); - await assertOnlyAdmin( - BasicFeeHandlerInstance.transferFee, - [accounts[3], accounts[4]], - [payout, payout] - ); - }); - - it("should revert if addrs and amounts arrays have different length", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - - await NativeTokenAdapterInstance.depositToEVMWithMessage( - destinationDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - } - ); - - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenAdapterInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(NativeTokenHandlerInstance.address), - "ether" - ), - Ethers.utils.formatUnits(transferredAmount) - ); - - const payout = Ethers.utils.parseEther("0.01"); - await TruffleAssert.fails( - BasicFeeHandlerInstance.transferFee( - [accounts[3], accounts[4]], - [payout, payout, payout] - ), - "addrs[], amounts[]: diff length" - ); - }); -}); diff --git a/test/adapters/native/optionalContractCall/distributeFee.test.ts b/test/adapters/native/optionalContractCall/distributeFee.test.ts new file mode 100644 index 00000000..84c42318 --- /dev/null +++ b/test/adapters/native/optionalContractCall/distributeFee.test.ts @@ -0,0 +1,256 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createBtcDepositData, createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, mpcAddress, trimPrefix} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Proposal} from '../../../../types'; + + +describe("Native token adapter - [distributeFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + + let depositor: WalletClient; + let recipient: WalletClient; + let firstEOA: WalletClient; + let seconEOA: WalletClient; + + let message: Hex; + let depositProposalData: Hex + let proposal: Proposal; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + BasicFeeHandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + firstEOA, + seconEOA, + ] = await hre.viem.getWalletClients(); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + NativeTokenHandlerInstance.address, + emptySetResourceData + ]); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 amount)"], + functionName: "mint", + args: [recipient, "5"] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC20MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }]; + + message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + transferredAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should distribute fees", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + assert.equal( + await BasicFeeHandlerInstance.read._domainResourceIDToFee([ + destinationDomainID, + resourceID + ]), + fee + ); + + // check the balance is 0 + assert.equal( + web3.utils.fromWei( + await getBalance(BridgeInstance.address), + "ether" + ), + "0" + ); + await NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + } + ); + assert.equal( + web3.utils.fromWei( + await getBalance(BridgeInstance.address), + "ether" + ), + "0" + ); + assert.equal( + web3.utils.fromWei( + await getBalance(NativeTokenTransferGatewayInstance.address), + "ether" + ), + "0" + ); + assert.equal( + web3.utils.fromWei( + await getBalance(NativeTokenHandlerInstance.address), + "ether" + ), + Ethers.utils.formatUnits(transferredAmount) + ); + + const depositorBalanceBefore = await getBalance(depositor); + const recipientBalanceBefore = await getBalance(recipient); + + const payout = parseEther("0.01"); + // Transfer the funds + const transferFeeTx = await BasicFeeHandlerInstance.write.transferFee([ + [depositor.account!.address, recipient.account!.address], + [payout, payout] + ]); + + await expect(transferFeeTx).to.emit(BasicFeeHandlerInstance, "FeeDistributed").withArgs( + zeroAddress, + depositor.account!.address, + payout + ); + + await expect(transferFeeTx).to.emit(BasicFeeHandlerInstance, "FeeDistributed").withArgs( + zeroAddress, + recipient.account!.address, + payout + ); + + const depositorBalanceAfter = await getBalance(depositor.account!.address); + const recipientBalanceAfter = await getBalance(recipient.account!.address); + assert.equal(depositorBalanceAfter, depositorBalanceBefore + payout); + assert.equal(recipientBalanceAfter, recipientBalanceBefore + payout); + }); + + it("should require admin role to distribute fee", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + await NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + } + ); + + assert.equal( + web3.utils.fromWei( + await getBalance(NativeTokenTransferGatewayInstance.address), + "ether" + ), + "0" + ); + assert.equal( + web3.utils.fromWei( + await getBalance(NativeTokenHandlerInstance.address), + "ether" + ), + Ethers.utils.formatUnits(transferredAmount) + ); + + const payout = parseEther("0.01"); + await expect( + BasicFeeHandlerInstance.write.transferFee([ + [firstEOA.account!.address, seconEOA.account!.address], + [payout, payout] + ])).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should revert if addrs and amounts arrays have different length", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + await NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + destinationDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + } + ); + + assert.equal( + web3.utils.fromWei( + await getBalance(NativeTokenTransferGatewayInstance.address), + "ether" + ), + "0" + ); + assert.equal( + web3.utils.fromWei( + await getBalance(NativeTokenHandlerInstance.address), + "ether" + ), + Ethers.utils.formatUnits(transferredAmount) + ); + + const payout = parseEther("0.01"); + await expect( + BasicFeeHandlerInstance.write.transferFee([ + [firstEOA.account!.address, seconEOA.account!.address], + [payout, payout, payout] + ]), + ).to.be.revertedWith("addrs[], amounts[]: diff length"); + }); +}); diff --git a/test/adapters/native/optionalContractCall/executeProposal.js b/test/adapters/native/optionalContractCall/executeProposal.js deleted file mode 100644 index f903b32e..00000000 --- a/test/adapters/native/optionalContractCall/executeProposal.js +++ /dev/null @@ -1,409 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("Bridge - [execute proposal - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - const amountToMint = 20; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - let ERC20MintableInstance; - let proposal; - let depositProposalData; - let dataHash; - let message; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - await DefaultMessageReceiverInstance.grantRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - NativeTokenHandlerInstance.address - ); - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - Ethers.constants.AddressZero, - emptySetResourceData - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - dataHash = Ethers.utils.keccak256( - NativeTokenHandlerInstance.address + depositProposalData.substr(2) - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal with contract call successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - const recipientNativeBalanceBefore = await web3.eth.getBalance(evmRecipientAddress); - const recipientERC20BalanceBefore = await ERC20MintableInstance.balanceOf(evmRecipientAddress); - const defaultReceiverBalanceBefore = await web3.eth.getBalance(DefaultMessageReceiverInstance.address); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - gas: executionGasAmount - }) - ); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientNativeBalanceAfter = await web3.eth.getBalance(evmRecipientAddress); - const recipientERC20BalanceAfter = await ERC20MintableInstance.balanceOf(evmRecipientAddress); - const defaultReceiverBalanceAfter = await web3.eth.getBalance(DefaultMessageReceiverInstance.address); - - assert.strictEqual( - transferredAmount.add(recipientNativeBalanceBefore).toString(), - recipientNativeBalanceAfter - ); - assert.strictEqual(new Ethers.BigNumber.from(amountToMint).add( - recipientERC20BalanceBefore.toString()).toString(), recipientERC20BalanceAfter.toString() - ); - assert.strictEqual(defaultReceiverBalanceBefore.toString(), defaultReceiverBalanceAfter.toString()); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - gas: executionGasAmount - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - const recipientBalanceBefore = await web3.eth.getBalance(evmRecipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [Ethers.constants.AddressZero, DefaultMessageReceiverInstance.address, transferredAmount] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - - // check that tokens are transferred to recipient address - const recipientBalanceAfter = await web3.eth.getBalance(evmRecipientAddress); - assert.strictEqual(transferredAmount.add(recipientBalanceBefore).toString(), recipientBalanceAfter); - }); - - it(`should fail to executeProposal if signed Proposal has different - chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); - - it("should revert if handler does not have SYGMA_HANDLER_ROLE", async () => { - await DefaultMessageReceiverInstance.revokeRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - NativeTokenHandlerInstance.address - ); - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.lowLevelData === "0xdeda9030" // InsufficientPermission() - ); - }); - }); - - it("should revert if insufficient gas limit left for executing action", async () => { - const insufficientExecutionGasAmount = 100000; - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - insufficientExecutionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: insufficientExecutionGasAmount - } - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.lowLevelData === "0x60ee1247" // InsufficientGasLimit() - ); - }); - }); -}); diff --git a/test/adapters/native/optionalContractCall/executeProposal.test.ts b/test/adapters/native/optionalContractCall/executeProposal.test.ts new file mode 100644 index 00000000..82c7dcdb --- /dev/null +++ b/test/adapters/native/optionalContractCall/executeProposal.test.ts @@ -0,0 +1,395 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createBtcDepositData, createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, getBalance, mockSignTypedProposalWithInvalidChainID, mpcAddress, signTypedProposal, trimPrefix} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Proposal} from '../../../../types'; + + +describe("Bridge - [execute proposal - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + const amountToMint = BigInt(20); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + let firstEOA: WalletClient; + let seconEOA: WalletClient; + + let proposal: Proposal; + let depositProposalData: Hex; + let dataHash: Hex; + let message: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + BasicFeeHandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + relayer1, + firstEOA, + seconEOA, + ] = await hre.viem.getWalletClients(); + + await DefaultMessageReceiverInstance.write.grantRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + NativeTokenHandlerInstance.address + ]); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + zeroAddress, + emptySetResourceData + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + originDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 amount)"], + functionName: "mint", + args: [recipient, "5"] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC20MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + transferredAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + dataHash = keccak256( + concat([ + NativeTokenHandlerInstance.address, + trimPrefix(depositProposalData) + ]) + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("isProposalExecuted returns false if depositNonce is not used", async () => { + const destinationDomainID = await BridgeInstance.read._domainID(); + + assert.isFalse( + await BridgeInstance.read.isProposalExecuted([ + destinationDomainID, + expectedDepositNonce + ]) + ); + }); + + it("should create and execute executeProposal with contract call successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + const recipientNativeBalanceBefore = await getBalance(recipient); + const recipientERC20BalanceBefore = await ERC20MintableInstance.read.balanceOf([recipient]); + const defaultReceiverBalanceBefore = await getBalance(DefaultMessageReceiverInstance.address); + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + gas: executionGasAmount + }) + ).not.to.be.reverted; + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientNativeBalanceAfter = await getBalance(recipient); + const recipientERC20BalanceAfter = await ERC20MintableInstance.read.balanceOf([recipient.account!.address]); + const defaultReceiverBalanceAfter = await getBalance(DefaultMessageReceiverInstance.address); + + assert.strictEqual( + recipientNativeBalanceBefore + transferredAmount, + recipientNativeBalanceAfter + ); + assert.strictEqual( + recipientERC20BalanceBefore + amountToMint, + recipientERC20BalanceAfter + ); + assert.strictEqual(defaultReceiverBalanceBefore, defaultReceiverBalanceAfter); + }); + + it("should skip executing proposal if deposit nonce is already used", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + }) + ); + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + gas: executionGasAmount + }) + ).not.to.be.reverted; + + const skipExecuteTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + // check that no ProposalExecution events are emitted + await expect(skipExecuteTx).not.to.emit(BridgeInstance, "ProposalExecution"); + }); + + it("executeProposal event should be emitted with expected values", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + const recipientBalanceBefore = await getBalance(recipient); + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [zeroAddress, DefaultMessageReceiverInstance.address, transferredAmount] + ) + ) + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalanceAfter = await getBalance(recipient); + assert.strictEqual(recipientBalanceBefore + transferredAmount, recipientBalanceAfter); + }); + + it(`should fail to executeProposal if signed Proposal has different + chainID than the one on which it should be executed`, async () => { + const proposalSignedData = + await mockSignTypedProposalWithInvalidChainID( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }), + ).to.be.revertedWithCustomError(BridgeInstance, "InvalidProposalSigner()"); + }); + + it("should revert if handler does not have SYGMA_HANDLER_ROLE", async () => { + await DefaultMessageReceiverInstance.write.revokeRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + NativeTokenHandlerInstance.address + ]); + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonce, + "0xdeda9030" // InsufficientPermission() + ); + }); + + it("should revert if insufficient gas limit left for executing action", async () => { + const insufficientExecutionGasAmount = BigInt(100000); + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + insufficientExecutionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + { + account: relayer1.account, + gas: insufficientExecutionGasAmount + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonce, + "0x60ee1247" // InsufficientGasLimit() + ); + }); +}); diff --git a/test/contractBridge/admin.js b/test/contractBridge/admin.js deleted file mode 100644 index afa68e0f..00000000 --- a/test/contractBridge/admin.js +++ /dev/null @@ -1,528 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const TestStoreContract = artifacts.require("TestStore"); - -// This test does NOT include all getter methods, just -// getters that should work with only the constructor called -contract("Bridge - [admin]", async (accounts) => { - const domainID = 1; - const nonAdminAddress = accounts[1]; - - const expectedBridgeAdmin = accounts[0]; - const authorizedAddress = accounts[2]; - const someAddress = "0xcafecafecafecafecafecafecafecafecafecafe"; - const nullAddress = "0x0000000000000000000000000000000000000000"; - const topologyHash = "549f715f5b06809ada23145c2dc548db"; - const txHash = - "0x59d881e01ca682130e550e3576b6de760951fb45b1d5dd81342132f57920bbfa"; - const depositAmount = 10; - const bytes32 = "0x0"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC1155HandlerInstance; - let ERC1155MintableInstance; - let ERC721MintableInstance; - let genericHandlerSetResourceData; - - let withdrawData = ""; - - const assertOnlyAdmin = (method) => { - return Helpers.expectToRevertWithCustomError( - method(), - "AccessNotAllowed(address,bytes4)" - ); - }; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - domainID, - expectedBridgeAdmin - )), - TestStoreContract.new().then( - (instance) => (TestStoreInstance = instance) - ), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance = instance) - ), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance = instance), - ), - ]); - - ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - genericHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - Helpers.blankFunctionSig, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - }); - - // Testing pauseable methods - - it("Bridge should not be paused after MPC address is set", async () => { - await BridgeInstance.endKeygen(Helpers.mpcAddress); - assert.isFalse(await BridgeInstance.paused()); - }); - - it("Bridge should be paused after being paused by admin", async () => { - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - await TruffleAssert.passes(BridgeInstance.adminPauseTransfers()); - assert.isTrue(await BridgeInstance.paused()); - }); - - it("Bridge should be unpaused after being paused by admin", async () => { - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - await TruffleAssert.passes(BridgeInstance.adminPauseTransfers()); - assert.isTrue(await BridgeInstance.paused()); - await TruffleAssert.passes(BridgeInstance.adminUnpauseTransfers()); - assert.isFalse(await BridgeInstance.paused()); - }); - - // Testing starKeygen, endKeygen and refreshKey methods - - it("Should successfully emit \"StartKeygen\" event if called by admin", async () => { - const startKeygenTx = await BridgeInstance.startKeygen(); - - TruffleAssert.eventEmitted(startKeygenTx, "StartKeygen"); - }); - - it("Should fail if \"StartKeygen\" is called by non admin", async () => { - await assertOnlyAdmin(() => - BridgeInstance.startKeygen({from: nonAdminAddress}) - ); - }); - - it("Should fail if \"StartKeygen\" is called after MPC address is set", async () => { - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.startKeygen(), - "MPCAddressAlreadySet()" - ); - }); - - it("Should successfully set MPC address and emit \"EndKeygen\" event if called by admin", async () => { - const startKeygenTx = await BridgeInstance.endKeygen(Helpers.mpcAddress); - - assert.equal(await BridgeInstance._MPCAddress(), Helpers.mpcAddress); - - TruffleAssert.eventEmitted(startKeygenTx, "EndKeygen"); - }); - - it("Should fail if \"endKeygen\" is called by non admin", async () => { - await assertOnlyAdmin(() => - BridgeInstance.endKeygen( - someAddress, - {from: nonAdminAddress} - ) - ) - }); - - it("Should fail if null address is passed as MPC address", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.endKeygen(nullAddress), - "MPCAddressZeroAddress()" - ); - }); - - it("Should fail if admin tries to update MPC address", async () => { - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.endKeygen(someAddress), - "MPCAddressIsNotUpdatable()" - ); - }); - - it("Should successfully emit \"KeyRefresh\" event with expected hash value if called by admin", async () => { - const startKeygenTx = await BridgeInstance.refreshKey(topologyHash); - - TruffleAssert.eventEmitted(startKeygenTx, "KeyRefresh", (event) => { - return (event.hash = topologyHash); - }); - }); - - it("Should fail if \"refreshKey\" is called by non admin", async () => { - await assertOnlyAdmin(() => - BridgeInstance.refreshKey( - topologyHash, - {from: nonAdminAddress} - ) - ) - }); - - // Set Handler Address - - it("Should set a Resource ID for handler address", async () => { - const ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - const resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - domainID - ); - const DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - assert.equal( - await BridgeInstance._resourceIDToHandlerAddress.call(resourceID), - Ethers.constants.AddressZero - ); - - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - genericHandlerSetResourceData - ) - ); - assert.equal( - await BridgeInstance._resourceIDToHandlerAddress.call(resourceID), - ERC20HandlerInstance.address - ); - }); - - // Set resource ID - - it("Should set a ERC20 Resource ID and contract address", async () => { - const ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - const resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - domainID - ); - const DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - genericHandlerSetResourceData - ) - ); - assert.equal( - await ERC20HandlerInstance._resourceIDToTokenContractAddress.call( - resourceID - ), - ERC20MintableInstance.address - ); - - const retrievedResourceID = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance.address - )).resourceID - - assert.equal( - retrievedResourceID.toLowerCase(), - resourceID.toLowerCase() - ); - }); - - it("Should require admin role to set a ERC20 Resource ID and contract address", async () => { - await assertOnlyAdmin(() => - BridgeInstance.adminSetResource( - someAddress, - bytes32, - someAddress, - genericHandlerSetResourceData, - {from: nonAdminAddress} - ) - ); - }); - - it("should revert when setting resourceID if token doesn't support IERC1155", async () => { - const invalidResourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - domainID - ); - - await Helpers.reverts( - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - invalidResourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - "token does not support IERC1155" - ); - }); - - it("should successfully set resourceID if token supports IERC1155", async () => { - const resourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - domainID - ); - - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - resourceID, - ERC1155MintableInstance.address, - emptySetResourceData - ) - ) - }); - - // Set burnable - - it("Should set ERC20MintableInstance.address as burnable", async () => { - const ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - const resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - domainID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - genericHandlerSetResourceData - ) - ); - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - ERC20MintableInstance.address - ) - ); - const isBurnable = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance.address - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - }); - - it("Should require admin role to set ERC20MintableInstance.address as burnable", async () => { - await assertOnlyAdmin(() => - BridgeInstance.adminSetBurnable( - someAddress, - someAddress, - {from: nonAdminAddress} - ) - ); - }); - - // Withdraw - - it("Should withdraw funds", async () => { - const numTokens = 10; - const tokenOwner = accounts[0]; - - let ownerBalance; - - const ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - const resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - domainID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - genericHandlerSetResourceData - ) - ); - - await ERC20MintableInstance.mint(tokenOwner, numTokens); - ownerBalance = await ERC20MintableInstance.balanceOf(tokenOwner); - assert.equal(ownerBalance, numTokens); - - await ERC20MintableInstance.transfer( - ERC20HandlerInstance.address, - numTokens - ); - - ownerBalance = await ERC20MintableInstance.balanceOf(tokenOwner); - assert.equal(ownerBalance, 0); - const handlerBalance = await ERC20MintableInstance.balanceOf( - ERC20HandlerInstance.address - ); - assert.equal(handlerBalance, numTokens); - - withdrawData = Helpers.createERCWithdrawData( - ERC20MintableInstance.address, - tokenOwner, - numTokens - ); - - await BridgeInstance.adminWithdraw( - ERC20HandlerInstance.address, - withdrawData - ); - ownerBalance = await ERC20MintableInstance.balanceOf(tokenOwner); - assert.equal(ownerBalance, numTokens); - }); - - it("Should require admin role to withdraw funds", async () => { - await assertOnlyAdmin(() => - BridgeInstance.adminWithdraw( - someAddress, - "0x0", - {from: nonAdminAddress} - ) - ) - }); - - it("Should allow to withdraw funds if called by authorized address", async () => { - const tokenOwner = accounts[0]; - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - - ); - const ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - await ERC20MintableInstance.mint(ERC20HandlerInstance.address, depositAmount) - - expect(await ERC20HandlerInstance.hasRole( - await ERC20HandlerInstance.LIQUIDITY_MANAGER_ROLE(), - tokenOwner - )).to.be.equal(false); - - await ERC20HandlerInstance.grantRole( - await ERC20HandlerInstance.LIQUIDITY_MANAGER_ROLE(), - authorizedAddress, - { - from: tokenOwner - } - ); - - const recipientBalanceBefore = await ERC20MintableInstance.balanceOf(tokenOwner); - const withdrawData = Helpers.createERCWithdrawData( - ERC20MintableInstance.address, - tokenOwner, - depositAmount, - ); - - await TruffleAssert.passes(ERC20HandlerInstance.withdraw(withdrawData, {from: authorizedAddress})); - const recipientBalanceAfter = await ERC20MintableInstance.balanceOf(tokenOwner); - - expect( - new Ethers.BigNumber.from(depositAmount).add(recipientBalanceBefore.toString()).toString() - ).to.be.equal(recipientBalanceAfter.toString()); - }); - - // Set nonce - - it("Should set nonce", async () => { - const nonce = 3; - await BridgeInstance.adminSetDepositNonce(domainID, nonce); - const nonceAfterSet = await BridgeInstance._depositCounts.call(domainID); - assert.equal(nonceAfterSet, nonce); - }); - - it("Should require admin role to set nonce", async () => { - await assertOnlyAdmin(() => - BridgeInstance.adminSetDepositNonce( - 1, - 3, - {from: nonAdminAddress} - ) - ) - }); - - it("Should not allow for decrements of the nonce", async () => { - const currentNonce = 3; - await BridgeInstance.adminSetDepositNonce(domainID, currentNonce); - const newNonce = 2; - await Helpers.reverts( - BridgeInstance.adminSetDepositNonce(domainID, newNonce), - "Does not allow decrements of the nonce" - ); - }); - - // Change access control contract - - it("Should require admin role to change access control contract", async () => { - await assertOnlyAdmin(() => - BridgeInstance.adminChangeAccessControl( - someAddress, - {from: nonAdminAddress} - ) - ) - }); - - // Retry - - it("Should require admin role to retry deposit", async () => { - await assertOnlyAdmin(() => - BridgeInstance.retry( - txHash, - {from: nonAdminAddress} - ) - ) - }); - - it("Should successfully emit Retry event", async () => { - const eventTx = await BridgeInstance.retry(txHash); - - TruffleAssert.eventEmitted(eventTx, "Retry", (event) => { - return event.txHash === txHash; - }); - }); -}); diff --git a/test/contractBridge/admin.test.ts b/test/contractBridge/admin.test.ts new file mode 100644 index 00000000..0bd67726 --- /dev/null +++ b/test/contractBridge/admin.test.ts @@ -0,0 +1,441 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only +import hre from "hardhat"; +import { assert, expect } from "chai"; +import { loadFixture } from "@nomicfoundation/hardhat-toolbox-viem/network-helpers"; +import { WalletClient, Address, Hex, toHex, zeroAddress, pad, testActions, walletActions, publicActions } from "viem"; +import { ContractTypesMap } from "hardhat/types"; +import {blankFunctionDepositorOffset, blankFunctionSig, constructGenericHandlerSetResourceData, createERCWithdrawData, createMessageCallData, createResourceID, deployDestinationChainContracts, deploySourceChainContracts, mpcAddress} from '../helpers'; + +// This test does NOT include all getter methods, just +// getters that should work with only the constructor called +describe("Bridge - [admin]", () => { + const domainID = 1; + + const someAddress: Address = "0xcafecafecafecafecafecafecafecafecafecafe"; + const nullAddress: Address = "0x0000000000000000000000000000000000000000"; + const topologyHash = "549f715f5b06809ada23145c2dc548db"; + const txHash = + "0x59d881e01ca682130e550e3576b6de760951fb45b1d5dd81342132f57920bbfa"; + + const bytes32 = "0x0"; + const emptySetResourceData = "0x"; + const depositAmount = BigInt(10); + + let authorizedAddress: WalletClient; + let nonadmin: WalletClient; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + let genericHandlerSetResourceData: Hex; + let withdrawData: Hex; + + const assertOnlyAdmin = async (contract: any, methodCall: unknown) => { + await expect(methodCall).to.be.revertedWithCustomError(contract,"AccessNotAllowed(address,bytes4)") + }; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC1155MintableInstance, + ERC1155HandlerInstance, + ERC721MintableInstance, + ERC721HandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [authorizedAddress, nonadmin] = await hre.viem.getWalletClients(); + + genericHandlerSetResourceData = + constructGenericHandlerSetResourceData( + blankFunctionSig, + blankFunctionDepositorOffset, + blankFunctionSig + ); + }); + + // Testing pauseable methods + + it("Bridge should not be paused after MPC address is set", async () => { + await BridgeInstance.write.endKeygen([mpcAddress]); + assert.isFalse(await BridgeInstance.read.paused()); + }); + + it("Bridge should be paused after being paused by admin", async () => { + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + + await expect(BridgeInstance.write.adminPauseTransfers()).not.to.be.reverted; + assert.isTrue(await BridgeInstance.read.paused()); + }); + + it("Bridge should be unpaused after being paused by admin", async () => { + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + + await expect(BridgeInstance.write.adminPauseTransfers()).not.to.be.reverted; + assert.isTrue(await BridgeInstance.read.paused()); + await expect(BridgeInstance.write.adminUnpauseTransfers()).not.to.be.reverted; + assert.isFalse(await BridgeInstance.read.paused()); + }); + + // Testing starKeygen, endKeygen and refreshKey methods + + it("Should successfully emit \"StartKeygen\" event if called by admin", async () => { + await expect(BridgeInstance.write.startKeygen()).to.emit(BridgeInstance, "StartKeygen"); + }); + + it("Should fail if \"StartKeygen\" is called by non admin", async () => { + await expect(BridgeInstance.write.startKeygen({ + account: nonadmin.account?.address + })).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)"); + }); + + it("Should fail if \"StartKeygen\" is called after MPC address is set", async () => { + await BridgeInstance.write.endKeygen([mpcAddress]); + + await expect(BridgeInstance.write.startKeygen(), + ).to.be.revertedWithCustomError(BridgeInstance, "MPCAddressAlreadySet()"); + }); + + it("Should successfully set MPC address and emit \"EndKeygen\" event if called by admin", async () => { + await expect(BridgeInstance.write.endKeygen([mpcAddress])).to.emit(BridgeInstance, "EndKeygen"); + + assert.equal(await BridgeInstance.read._MPCAddress(), mpcAddress); + + }); + + it("Should fail if \"endKeygen\" is called by non admin", async () => { + await expect(BridgeInstance.write.endKeygen( + [ + someAddress, + ], + {account: nonadmin.account?.address} + )).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)") + }); + + it("Should fail if null address is passed as MPC address", async () => { + await expect( + BridgeInstance.write.endKeygen([nullAddress]) + ).to.be.revertedWithCustomError(BridgeInstance, "MPCAddressZeroAddress()"); + }); + + it("Should fail if admin tries to update MPC address", async () => { + await BridgeInstance.write.endKeygen([mpcAddress]); + + await expect( + BridgeInstance.write.endKeygen([someAddress]) + ).to.be.revertedWithCustomError(BridgeInstance, "MPCAddressIsNotUpdatable()"); + }); + + it("Should successfully emit \"KeyRefresh\" event with expected hash value if called by admin", async () => { + await expect(BridgeInstance.write.refreshKey([topologyHash])).to.emit(BridgeInstance, "KeyRefresh"); + }); + + it("Should fail if \"refreshKey\" is called by non admin", async () => { + await expect(BridgeInstance.write.refreshKey([topologyHash],{ + account: nonadmin.account?.address + })).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)"); + }); + + // Set Handler Address + + it("Should set a Resource ID for handler address", async () => { + const resourceID = createResourceID( + ERC20MintableInstance.address, + domainID + ); + + assert.equal( + await BridgeInstance.read._resourceIDToHandlerAddress([resourceID]), + zeroAddress + ); + + await expect( + BridgeInstance.write.adminSetResource( + [ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + genericHandlerSetResourceData + ] + ) + ).not.to.be.reverted; + assert.equal( + (await BridgeInstance.read._resourceIDToHandlerAddress([resourceID])).toLowerCase(), + ERC20HandlerInstance.address.toLowerCase() + ); + }); + + // Set resource ID + + it("Should set a ERC20 Resource ID and contract address", async () => { + const resourceID = createResourceID( + ERC20MintableInstance.address, + domainID + ); + + await expect( + BridgeInstance.write.adminSetResource( + [ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + genericHandlerSetResourceData + ] + ) + ).not.to.be.reverted; + assert.equal( + (await ERC20HandlerInstance.read._resourceIDToTokenContractAddress( + [resourceID] + )).toLowerCase(), + ERC20MintableInstance.address.toLowerCase() + ); + + const retrievedResourceID = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties( + [ERC20MintableInstance.address] + )) + + assert.equal( + retrievedResourceID[0], + resourceID + ); + }); + + it("Should require admin role to set a ERC20 Resource ID and contract address", async () => { + await expect(BridgeInstance.write.refreshKey([topologyHash],{ + account: nonadmin.account?.address + })).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)"); + + BridgeInstance.write.adminSetResource( + [ + someAddress, + bytes32, + someAddress, + genericHandlerSetResourceData, + ], + {account: nonadmin.account?.address} + ) + }); + + it("should revert when setting resourceID if token doesn't support IERC1155", async () => { + const invalidResourceID = createResourceID( + ERC1155MintableInstance.address, + domainID + ); + + await expect( + BridgeInstance.write.adminSetResource( + [ + ERC1155HandlerInstance.address, + invalidResourceID, + ERC721MintableInstance.address, + emptySetResourceData + ] + ), + ).to.be.revertedWith("token does not support IERC1155"); + }); + + it("should successfully set resourceID if token supports IERC1155", async () => { + const resourceID = createResourceID( + ERC1155MintableInstance.address, + domainID + ); + + await expect( + BridgeInstance.write.adminSetResource( + [ + ERC1155HandlerInstance.address, + resourceID, + ERC1155MintableInstance.address, + emptySetResourceData + ] + ) + ).not.to.be.reverted + }); + + // Set burnable + + it("Should set ERC20MintableInstance as burnable", async () => { + const resourceID = createResourceID( + ERC20MintableInstance.address, + domainID + ); + + await expect( + BridgeInstance.write.adminSetResource( + [ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + genericHandlerSetResourceData + ] + ) + ).not.to.be.reverted; + await expect( + BridgeInstance.write.adminSetBurnable( + [ + ERC20HandlerInstance.address, + ERC20MintableInstance.address + ] + ) + ).not.to.be.reverted; + const isBurnable = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties( + [ERC20MintableInstance.address] + )); + + assert.isTrue(isBurnable[2], "Contract wasn't successfully marked burnable"); + }); + + it("Should require admin role to set ERC20MintableInstance.address as burnable", async () => { + await expect(BridgeInstance.write.adminSetBurnable([someAddress, someAddress],{ + account: nonadmin.account?.address + })).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)"); + }); + + // Withdraw + + it("Should withdraw funds", async () => { + const numTokens = BigInt(10); + const tokenOwner = authorizedAddress.account!.address; + + let ownerBalance; + + const resourceID = createResourceID( + ERC20MintableInstance.address, + domainID + ); + + await expect( + BridgeInstance.write.adminSetResource( + [ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + genericHandlerSetResourceData + ] + ) + ).not.to.be.reverted; + + await ERC20MintableInstance.write.mint([tokenOwner, numTokens]); + ownerBalance = await ERC20MintableInstance.read.balanceOf([tokenOwner]); + assert.equal(ownerBalance, numTokens); + + await ERC20MintableInstance.write.transfer( + [ERC20HandlerInstance.address, + numTokens] + ); + + ownerBalance = await ERC20MintableInstance.read.balanceOf([tokenOwner]); + assert.equal(ownerBalance, BigInt(0)); + const handlerBalance = await ERC20MintableInstance.read.balanceOf( + [ERC20HandlerInstance.address] + ); + assert.equal(handlerBalance, numTokens); + + withdrawData = createERCWithdrawData( + ERC20MintableInstance.address, + tokenOwner, + numTokens + ); + + await BridgeInstance.write.adminWithdraw( + [ + ERC20HandlerInstance.address, + withdrawData + ] + ); + ownerBalance = await ERC20MintableInstance.read.balanceOf([tokenOwner]); + assert.equal(ownerBalance, numTokens); + }); + + it("Should allow to withdraw funds if called by authorized address", async () => { + const tokenOwner = authorizedAddress.account!.address; + await ERC20MintableInstance.write.mint([ERC20HandlerInstance.address, depositAmount]) + + expect(await ERC20HandlerInstance.read.hasRole( + [ + await ERC20HandlerInstance.read.LIQUIDITY_MANAGER_ROLE(), + tokenOwner + ] + )).to.be.equal(false); + + await ERC20HandlerInstance.write.grantRole( + [ + await ERC20HandlerInstance.read.LIQUIDITY_MANAGER_ROLE(), + authorizedAddress.account!.address, + ], + ); + + const recipientBalanceBefore = await ERC20MintableInstance.read.balanceOf([tokenOwner]); + const withdrawData = createERCWithdrawData( + ERC20MintableInstance.address, + tokenOwner, + depositAmount, + ); + + await expect( + ERC20HandlerInstance.write.withdraw([withdrawData], {account: authorizedAddress.account}) + ).not.to.be.reverted; + const recipientBalanceAfter = await ERC20MintableInstance.read.balanceOf([tokenOwner]); + + expect( + depositAmount + recipientBalanceBefore + ).to.be.equal(recipientBalanceAfter); + }); + + // Set nonce + + it("Should set nonce", async () => { + const nonce = BigInt(3); + await BridgeInstance.write.adminSetDepositNonce([domainID, nonce]); + const nonceAfterSet = await BridgeInstance.read._depositCounts([domainID]); + assert.equal(nonceAfterSet, nonce); + }); + + it("Should require admin role to set nonce", async () => { + const nonce = BigInt(3); + await expect(BridgeInstance.write.adminSetDepositNonce([domainID, nonce],{ + account: nonadmin.account?.address + })).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)"); + }); + + it("Should not allow for decrements of the nonce", async () => { + const currentNonce = BigInt(3); + await BridgeInstance.write.adminSetDepositNonce([domainID, currentNonce]); + const newNonce = BigInt(2); + await expect( + BridgeInstance.write.adminSetDepositNonce([domainID, newNonce]), + ).to.be.revertedWith("Does not allow decrements of the nonce"); + }); + + // Change access control contract + + it("Should require admin role to change access control contract", async () => { + await expect( + BridgeInstance.write.adminChangeAccessControl([someAddress],{account: nonadmin.account}), + ).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)"); + }); + + // Retry + + it("Should require admin role to retry deposit", async () => { + await expect( + BridgeInstance.write.retry([txHash],{account: nonadmin.account}), + ).to.be.revertedWithCustomError(BridgeInstance, "AccessNotAllowed(address,bytes4)"); + }); + + it("Should successfully emit Retry event", async () => { + const eventTx = await BridgeInstance.write.retry([txHash]); + + await expect(BridgeInstance.write.retry([txHash], { + account: authorizedAddress.account + })).to.emit(BridgeInstance, "Retry").withArgs(txHash); + }); +}); diff --git a/test/contractBridge/depositERC1155.js b/test/contractBridge/depositERC1155.js deleted file mode 100644 index 5754ca4a..00000000 --- a/test/contractBridge/depositERC1155.js +++ /dev/null @@ -1,204 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../helpers"); - -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); - -contract("Bridge - [deposit - ERC1155]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - - const originChainTokenID = 42; - const originChainInitialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let OriginERC1155MintableInstance; - let OriginERC1155HandlerInstance; - let depositData; - - beforeEach(async () => { - await Promise.all([ - ERC1155MintableContract.new("TOK").then( - (instance) => (OriginERC1155MintableInstance = instance) - ), - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - resourceID = Helpers.createResourceID( - OriginERC1155MintableInstance.address, - originDomainID - ); - - OriginERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - await Promise.all([ - BridgeInstance.adminSetResource( - OriginERC1155HandlerInstance.address, - resourceID, - OriginERC1155MintableInstance.address, - emptySetResourceData - ), - OriginERC1155MintableInstance.mintBatch( - depositorAddress, - [originChainTokenID], - [originChainInitialTokenAmount], - "0x0" - ), - ]); - await OriginERC1155MintableInstance.setApprovalForAll( - OriginERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ); - - depositData = Helpers.createERC1155DepositData( - [originChainTokenID], - [depositAmount] - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] test depositorAddress' balance", async () => { - const originChainDepositorBalance = - await OriginERC1155MintableInstance.balanceOf( - depositorAddress, - originChainTokenID - ); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - ); - }); - - it("[sanity] test OriginERC1155HandlerInstance.address' allowance", async () => { - const originChainHandlerApprovedStatus = - await OriginERC1155MintableInstance.isApprovedForAll( - depositorAddress, - OriginERC1155HandlerInstance.address - ); - assert.strictEqual(originChainHandlerApprovedStatus, true); - }); - - it("ERC1155 deposit can be made", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("ERC1155 can be deposited with correct balances", async () => { - await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - const originChainDepositorBalance = - await OriginERC1155MintableInstance.balanceOf( - depositorAddress, - originChainTokenID - ); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - depositAmount - ); - - const originChainHandlerBalance = - await OriginERC1155MintableInstance.balanceOf( - OriginERC1155HandlerInstance.address, - originChainTokenID - ); - assert.strictEqual(originChainHandlerBalance.toNumber(), depositAmount); - }); - - it("Deposit event is fired with expected value", async () => { - let depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce - ); - }); - - depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce + 1 - ); - }); - }); - - it("deposit requires resourceID that is mapped to a handler", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit(destinationDomainID, "0x0", depositData, feeData, { - from: depositorAddress, - }), - "ResourceIDNotMappedToHandler()" - ); - }); - - it("Deposit destination domain can not be current bridge domain ", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit(originDomainID, "0x0", depositData, feeData, { - from: depositorAddress, - }), - "DepositToCurrentDomain()" - ); - }); -}); diff --git a/test/contractBridge/depositERC1155.test.ts b/test/contractBridge/depositERC1155.test.ts new file mode 100644 index 00000000..0d9f0a1d --- /dev/null +++ b/test/contractBridge/depositERC1155.test.ts @@ -0,0 +1,212 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createERC1155DepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../helpers"; +import {Hex, WalletClient} from "viem"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from "chai"; + +describe("Bridge - [deposit - ERC1155]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const tokenID = BigInt(42); + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + + let depositor: WalletClient; + + let depositData: Hex; + let resourceID: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC1155HandlerInstance, + ERC1155MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC1155MintableInstance.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + resourceID, + ERC1155MintableInstance.address, + emptySetResourceData + ]); + await ERC1155MintableInstance.write.mintBatch([ + depositor.account!.address, + [tokenID], + [initialTokenAmount], + "0x0" + ]); + await ERC1155MintableInstance.write.setApprovalForAll([ + ERC1155HandlerInstance.address, + true + ], + { + account: depositor.account + } + ); + + depositData = createERC1155DepositData( + [tokenID], + [depositAmount] + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] test depositor' balance", async () => { + const originChainDepositorBalance = + await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + + assert.strictEqual( + originChainDepositorBalance, + initialTokenAmount + ); + }); + + it("[sanity] test ERC1155HandlerInstance.address' allowance", async () => { + const originChainHandlerApprovedStatus = + await ERC1155MintableInstance.read.isApprovedForAll([ + depositor.account!.address, + ERC1155HandlerInstance.address + ]); + + assert.strictEqual(originChainHandlerApprovedStatus, true); + }); + + it("ERC1155 deposit can be made", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const depositCount = await BridgeInstance.read._depositCounts([ + destinationDomainID + ]); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("ERC1155 can be deposited with correct balances", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const originChainDepositorBalance = + await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + + assert.strictEqual( + originChainDepositorBalance, + initialTokenAmount - depositAmount + ); + + const originChainHandlerBalance = + await ERC1155MintableInstance.read.balanceOf([ + ERC1155HandlerInstance.address, + tokenID + ]); + assert.strictEqual(originChainHandlerBalance, depositAmount); + }); + + it("Deposit event is fired with expected value", async () => { + let depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce + ); + }); + + it("deposit requires resourceID that is mapped to a handler", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + "0x0", + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).to.be.revertedWithCustomError(BridgeInstance,"ResourceIDNotMappedToHandler()"); + }); + + it("Deposit destination domain can not be current bridge domain ", async () => { + await expect( + BridgeInstance.write.deposit([ + originDomainID, + "0x0", + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "DepositToCurrentDomain()"); + }); +}); diff --git a/test/contractBridge/depositERC20.js b/test/contractBridge/depositERC20.js deleted file mode 100644 index 19953896..00000000 --- a/test/contractBridge/depositERC20.js +++ /dev/null @@ -1,245 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC20MintableContractMock = artifacts.require("ERC20PresetMinterPauserMock"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("Bridge - [deposit - ERC20]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const originChainInitialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let OriginERC20MintableInstance; - let OriginERC20MintableInstanceMock; - let OriginERC20HandlerInstance; - let depositData; - let initialResourceIDs; - - beforeEach(async () => { - await Promise.all([ - ERC20MintableContract.new("token", "TOK").then( - (instance) => (OriginERC20MintableInstance = instance) - ), - ERC20MintableContractMock.new("token", "TOK").then( - (instance) => (OriginERC20MintableInstanceMock = instance) - ), - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - const resourceID1 = Helpers.createResourceID( - OriginERC20MintableInstance.address, - originDomainID - ); - const resourceID2 = Helpers.createResourceID( - OriginERC20MintableInstanceMock.address, - originDomainID - ); - - initialResourceIDs = [resourceID1, resourceID2]; - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - OriginERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await Promise.all([ - BridgeInstance.adminSetResource( - OriginERC20HandlerInstance.address, - initialResourceIDs[0], - OriginERC20MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - OriginERC20HandlerInstance.address, - initialResourceIDs[1], - OriginERC20MintableInstanceMock.address, - emptySetResourceData - ), - OriginERC20MintableInstance.mint( - depositorAddress, - originChainInitialTokenAmount - ), - OriginERC20MintableInstanceMock.mint( - depositorAddress, - originChainInitialTokenAmount - ), - ]); - await OriginERC20MintableInstance.approve( - OriginERC20HandlerInstance.address, - depositAmount * 2, - {from: depositorAddress} - ); - await OriginERC20MintableInstanceMock.approve( - OriginERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] test depositorAddress' balance", async () => { - const originChainDepositorBalance = - await OriginERC20MintableInstance.balanceOf(depositorAddress); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - ); - }); - - it("[sanity] test OriginERC20HandlerInstance.address' allowance", async () => { - const originChainHandlerAllowance = - await OriginERC20MintableInstance.allowance( - depositorAddress, - OriginERC20HandlerInstance.address - ); - assert.strictEqual( - originChainHandlerAllowance.toNumber(), - depositAmount * 2 - ); - }); - - it("ERC20 deposit can be made", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ) - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("ERC20 can be deposited with correct balances", async () => { - await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - const originChainDepositorBalance = - await OriginERC20MintableInstance.balanceOf(depositorAddress); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - depositAmount - ); - - const originChainHandlerBalance = - await OriginERC20MintableInstance.balanceOf( - OriginERC20HandlerInstance.address - ); - assert.strictEqual(originChainHandlerBalance.toNumber(), depositAmount); - }); - - it("Deposit event is fired with expected value", async () => { - let depositTx = await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === initialResourceIDs[0].toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce - ); - }); - - depositTx = await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === initialResourceIDs[0].toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce + 1 - ); - }); - }); - - it("deposit requires resourceID that is mapped to a handler", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit(destinationDomainID, "0x0", depositData, feeData, { - from: depositorAddress, - }), - "ResourceIDNotMappedToHandler()" - ); - }); - - it("Deposit destination domain can not be current bridge domain ", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit(originDomainID, "0x0", depositData, feeData, { - from: depositorAddress, - }), - "DepositToCurrentDomain()" - ); - }); - - it("should revert if ERC20Safe contract call fails", async () => { - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[1], - depositData, - feeData, - {from: depositorAddress} - ), - "ERC20: operation did not succeed" - ); - }); -}); diff --git a/test/contractBridge/depositERC20.test.ts b/test/contractBridge/depositERC20.test.ts new file mode 100644 index 00000000..098a4cfb --- /dev/null +++ b/test/contractBridge/depositERC20.test.ts @@ -0,0 +1,246 @@ +import hre from 'hardhat'; +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {assert, expect} from "chai"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, WalletClient} from "viem"; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; + +const Helpers = require("../helpers"); + +describe("Bridge - [deposit - ERC20]", async () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const originChainInitialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + const ERC20MintableInstanceMock = await hre.viem.deployContract( + "ERC20PresetMinterPauser", + ["Token", "TOK"] + ); + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let depositData: Hex; + let resourceID1: Hex; + let resourceID2: Hex; + + let depositor: WalletClient; + let recipient: WalletClient; + + + before(async () => { + ({ + BridgeInstance, + ERC20HandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + ] = await hre.viem.getWalletClients(); + + const resourceID1 = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + const resourceID2 = createResourceID( + ERC20MintableInstanceMock.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID2, + ERC20MintableInstanceMock.address, + emptySetResourceData + ]); + await ERC20MintableInstance.write.mint([ + depositor.account!.address, + originChainInitialTokenAmount + ]); + await ERC20MintableInstanceMock.write.mint([ + depositor.account!.address, + originChainInitialTokenAmount + ]); + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + await ERC20MintableInstanceMock.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] test depositor' balance", async () => { + const originChainDepositorBalance = + await ERC20MintableInstance.read.balanceOf(depositor.account!.address); + assert.strictEqual( + originChainDepositorBalance, + originChainInitialTokenAmount + ); + }); + + it("[sanity] test ERC20HandlerInstance.address' allowance", async () => { + const originChainHandlerAllowance = await ERC20MintableInstance.read.allowance([ + depositor.account!.address, + ERC20HandlerInstance.address + ]); + assert.strictEqual( + originChainHandlerAllowance, + depositAmount + ); + }); + + it("ERC20 deposit can be made", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const depositCount = await BridgeInstance.read._depositCounts([ + destinationDomainID + ]); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("ERC20 can be deposited with correct balances", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData], + { + account: depositor.account + } + ); + + const originChainDepositorBalance = + await ERC20MintableInstance.read.balanceOf([depositor.account!.address]); + assert.strictEqual( + originChainDepositorBalance, + originChainInitialTokenAmount - depositAmount + ); + + const originChainHandlerBalance = + await ERC20MintableInstance.read.balanceOf([ + ERC20HandlerInstance.address + ]); + assert.strictEqual(originChainHandlerBalance, depositAmount); + }); + + it("Deposit event is fired with expected value", async () => { + let depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID1.toLowerCase(), + expectedDepositNonce + ); + }); + + it("deposit requires resourceID that is mapped to a handler", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + "0x0", + depositData, + feeData + ], + { + account: depositor.account, + } + ), + ).to.be.revertedWithCustomError(BridgeInstance, "ResourceIDNotMappedToHandler()"); + }); + + it("Deposit destination domain can not be current bridge domain ", async () => { + await expect( + BridgeInstance.write.deposit([ + originDomainID, + "0x0", + depositData, + feeData + ], + { + account: depositor.account, + } + ), + ).to.be.revertedWithCustomError(BridgeInstance, "DepositToCurrentDomain()"); + }); + + it("should revert if ERC20Safe contract call fails", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID2, + depositData, + feeData + ], + { + account: depositor.account + } + ), + ).to.be.revertedWith("ERC20: operation did not succeed") + }); +}); diff --git a/test/contractBridge/depositERC721.js b/test/contractBridge/depositERC721.js deleted file mode 100644 index 738c693e..00000000 --- a/test/contractBridge/depositERC721.js +++ /dev/null @@ -1,189 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); -const Helpers = require("../helpers"); - -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); - -contract("Bridge - [deposit - ERC721]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const originChainTokenID = 42; - const expectedDepositNonce = 1; - const genericBytes = "0x736f796c656e745f677265656e5f69735f70656f706c65"; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let OriginERC721MintableInstance; - let OriginERC721HandlerInstance; - let depositData; - - let originResourceID; - - beforeEach(async () => { - await Promise.all([ - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (OriginERC721MintableInstance = instance) - ), - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - originResourceID = Helpers.createResourceID( - OriginERC721MintableInstance.address, - originDomainID - ); - - await Promise.all([ - ERC721HandlerContract.new(BridgeInstance.address).then( - (instance) => (OriginERC721HandlerInstance = instance) - ), - ERC721HandlerContract.new(BridgeInstance.address).then( - (instance) => (DestinationERC721HandlerInstance = instance) - ), - ]); - - await Promise.all([ - BridgeInstance.adminSetResource( - OriginERC721HandlerInstance.address, - originResourceID, - OriginERC721MintableInstance.address, - emptySetResourceData - ), - OriginERC721MintableInstance.mint( - depositorAddress, - originChainTokenID, - genericBytes - ), - ]); - - await OriginERC721MintableInstance.approve( - OriginERC721HandlerInstance.address, - originChainTokenID, - {from: depositorAddress} - ); - - depositData = Helpers.createERCDepositData( - originChainTokenID, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] test depositorAddress' balance", async () => { - const originChainDepositorBalance = - await OriginERC721MintableInstance.balanceOf(depositorAddress); - assert.strictEqual(originChainDepositorBalance.toNumber(), 1); - }); - - it(`[sanity] test depositorAddress owns token with ID: ${originChainTokenID}`, async () => { - const tokenOwner = await OriginERC721MintableInstance.ownerOf( - originChainTokenID - ); - assert.strictEqual(tokenOwner, depositorAddress); - }); - - it("[sanity] test OriginERC721HandlerInstance.address' allowance", async () => { - const allowanceHolder = await OriginERC721MintableInstance.getApproved( - originChainTokenID - ); - assert.strictEqual(allowanceHolder, OriginERC721HandlerInstance.address); - }); - - it("ERC721 deposit can be made", async () => { - await BridgeInstance.deposit( - destinationDomainID, - originResourceID, - depositData, - feeData, - {from: depositorAddress} - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await BridgeInstance.deposit( - destinationDomainID, - originResourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("ERC721 can be deposited with correct owner and balances", async () => { - await BridgeInstance.deposit( - destinationDomainID, - originResourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - const tokenOwner = await OriginERC721MintableInstance.ownerOf( - originChainTokenID - ); - assert.strictEqual(tokenOwner, OriginERC721HandlerInstance.address); - - const originChainDepositorBalance = - await OriginERC721MintableInstance.balanceOf(depositorAddress); - assert.strictEqual(originChainDepositorBalance.toNumber(), 0); - - const originChainHandlerBalance = - await OriginERC721MintableInstance.balanceOf( - OriginERC721HandlerInstance.address - ); - assert.strictEqual(originChainHandlerBalance.toNumber(), 1); - }); - - it("Deposit event is fired with expected value", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - originResourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - const expectedMetaData = Ethers.utils.hexlify( - Ethers.utils.toUtf8Bytes(genericBytes) - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === originResourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === depositData.toLowerCase() && - event.handlerResponse === expectedMetaData - ); - }); - }); - - it("Deposit destination domain can not be current bridge domain ", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit(originDomainID, "0x0", depositData, feeData, { - from: depositorAddress, - }), - "DepositToCurrentDomain()" - ); - }); -}); diff --git a/test/contractBridge/depositERC721.test.ts b/test/contractBridge/depositERC721.test.ts new file mode 100644 index 00000000..14d3a758 --- /dev/null +++ b/test/contractBridge/depositERC721.test.ts @@ -0,0 +1,192 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {Hex, toHex} from "viem"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + +describe("Bridge - [deposit - ERC721]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const tokenID = BigInt(42); + const expectedDepositNonce = BigInt(1); + const genericBytes = "0x736f796c656e745f677265656e5f69735f70656f706c65"; + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + + let depositor: WalletClient; + let recipient: WalletCleint; + + let depositData: Hex; + let resourceID: Hex; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC721HandlerInstance, + ERC721MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC721MintableInstance.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + resourceID, + ERC721MintableInstance.address, + emptySetResourceData + ]); + await ERC721MintableInstance.write.mint([ + depositor, + tokenID, + genericBytes + ]); + + await ERC721MintableInstance.write.approve([ + ERC721HandlerInstance.address, + tokenID + ], + { + account: depositor.account + } + ); + + depositData = createERCDepositData( + tokenID, + 20, + recipient + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] test depositor' balance", async () => { + const depositorBalance = + await ERC721MintableInstance.read.balanceOf([depositor]); + assert.strictEqual(depositorBalance, BigInt(1)); + }); + + it(`[sanity] test depositor owns token with ID: ${tokenID}`, async () => { + const tokenOwner = await ERC721MintableInstance.read.ownerOf([ + tokenID + ]); + assert.strictEqual(tokenOwner, depositor); + }); + + it("[sanity] test ERC721HandlerInstance.address' allowance", async () => { + const allowanceHolder = await ERC721MintableInstance.read.getApproved([ + tokenID + ]); + assert.strictEqual(allowanceHolder, ERC721HandlerInstance.address); + }); + + it("ERC721 deposit can be made", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const depositCount = await BridgeInstance.read._depositCounts([ + destinationDomainID + ]); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("ERC721 can be deposited with correct owner and balances", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + {account: depositor.account} + ); + + const tokenOwner = await ERC721MintableInstance.read.ownerOf([ + tokenID + ]); + assert.strictEqual(tokenOwner, ERC721HandlerInstance.address); + + const depositorBalance = + await ERC721MintableInstance.read.balanceOf([depositor]); + assert.strictEqual(depositorBalance, BigInt(0)); + + const originChainHandlerBalance = + await ERC721MintableInstance.read.balanceOf([ + ERC721HandlerInstance.address + ]); + assert.strictEqual(originChainHandlerBalance, BigInt(1)); + }); + + it("Deposit event is fired with expected value", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const expectedMetaData = toHex(genericBytes); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositData.toLowerCase(), + expectedMetaData + ); + }); + + it("Deposit destination domain can not be current bridge domain ", async () => { + await expect( + BridgeInstance.write.deposit([originDomainID, "0x0", depositData, feeData], + { + account: depositor.account, + } + ), + ).to.be.revertedWithCustomError(BridgeInstance, "DepositToCurrentDomain()"); + }); +}); diff --git a/test/contractBridge/depositXC20.js b/test/contractBridge/depositXC20.js deleted file mode 100644 index bb10493f..00000000 --- a/test/contractBridge/depositXC20.js +++ /dev/null @@ -1,363 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../helpers"); - -const XC20HandlerContract = artifacts.require("XC20Handler"); -const XC20TestContract = artifacts.require("XC20Test"); -const XC20TestContractMock = artifacts.require("XC20TestMock"); - -contract("Bridge - [deposit - XRC20]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const originChainInitialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let OriginXC20TestInstance; - let OriginXC20TestInstanceMock; - let OriginXC20HandlerInstance; - let depositData; - let initialResourceIDs; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - XC20TestContract.new().then( - (instance) => (OriginXC20TestInstance = instance) - ), - XC20TestContractMock.new().then( - (instance) => (OriginXC20TestInstanceMock = instance) - ), - ]); - - const resourceID1 = Helpers.createResourceID( - OriginXC20TestInstance.address, - originDomainID - ); - const resourceID2 = Helpers.createResourceID( - OriginXC20TestInstanceMock.address, - originDomainID - ); - - initialResourceIDs = [resourceID1, resourceID2]; - - OriginXC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - - await Promise.all([ - BridgeInstance.adminSetResource( - OriginXC20HandlerInstance.address, - initialResourceIDs[0], - OriginXC20TestInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - OriginXC20HandlerInstance.address, - initialResourceIDs[1], - OriginXC20TestInstanceMock.address, - emptySetResourceData - ), - OriginXC20TestInstance.mint( - depositorAddress, - originChainInitialTokenAmount - ), - OriginXC20TestInstanceMock.mint( - depositorAddress, - originChainInitialTokenAmount - ), - ]); - await OriginXC20TestInstance.approve( - OriginXC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - await OriginXC20TestInstanceMock.approve( - OriginXC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - describe("lock/release strategy", async () => { - it("[sanity] test depositorAddress' balance", async () => { - const originChainDepositorBalance = - await OriginXC20TestInstance.balanceOf(depositorAddress); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - ); - }); - - it("XC20 deposit can be made", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ) - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("XC20 can be deposited with correct balances", async () => { - await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - const originChainDepositorBalance = - await OriginXC20TestInstance.balanceOf(depositorAddress); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - depositAmount - ); - - const originChainHandlerBalance = await OriginXC20TestInstance.balanceOf( - OriginXC20HandlerInstance.address - ); - assert.strictEqual(originChainHandlerBalance.toNumber(), depositAmount); - }); - - it("Deposit event is fired with expected value", async () => { - // set allowance to 2 * depositAmount since 2 deposits are made in this test - await OriginXC20TestInstance.approve( - OriginXC20HandlerInstance.address, - depositAmount * 2, - {from: depositorAddress} - ); - - let depositTx = await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === initialResourceIDs[0].toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce - ); - }); - - depositTx = await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === initialResourceIDs[0].toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce + 1 - ); - }); - }); - - it("deposit requires resourceID that is mapped to a handler", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit( - destinationDomainID, - "0x0", - depositData, - feeData, - {from: depositorAddress} - ), - "ResourceIDNotMappedToHandler()" - ); - }); - - it("Deposit destination domain can not be current bridge domain ", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit(originDomainID, "0x0", depositData, feeData, { - from: depositorAddress, - }), - "DepositToCurrentDomain()" - ); - }); - - it("should if XC20Safe contract call fails", async () => { - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[1], - depositData, - feeData, - {from: depositorAddress} - ), - "ERC20: operation did not succeed" - ); - }); - }); - - describe("mint/burn strategy", async () => { - beforeEach(async () => { - await BridgeInstance.adminSetBurnable( - OriginXC20HandlerInstance.address, - OriginXC20TestInstance.address - ); - }); - - it("[sanity] test depositorAddress' balance", async () => { - const originChainDepositorBalance = - await OriginXC20TestInstance.balanceOf(depositorAddress); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - ); - }); - - it("XC20 deposit can be made", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ) - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("XC20 can be deposited with correct balances", async () => { - await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - const originChainDepositorBalance = - await OriginXC20TestInstance.balanceOf(depositorAddress); - assert.strictEqual( - originChainDepositorBalance.toNumber(), - originChainInitialTokenAmount - depositAmount - ); - - const originChainHandlerAllowance = await OriginXC20TestInstance.allowance( - depositorAddress, - OriginXC20HandlerInstance.address - ); - assert.strictEqual(originChainHandlerAllowance.toNumber(), depositAmount); - }); - - it("Deposit event is fired with expected value", async () => { - let depositTx = await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === initialResourceIDs[0].toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce - ); - }); - - depositTx = await BridgeInstance.deposit( - destinationDomainID, - initialResourceIDs[0], - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === initialResourceIDs[0].toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce + 1 - ); - }); - }); - - it("deposit requires initialResourceIDs[0] that is mapped to a handler", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit( - destinationDomainID, - "0x0", - depositData, - feeData, - {from: depositorAddress} - ), - "ResourceIDNotMappedToHandler()" - ); - }); - - it("Deposit destination domain can not be current bridge domain ", async () => { - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit(originDomainID, "0x0", depositData, feeData, { - from: depositorAddress, - }), - "DepositToCurrentDomain()" - ); - }); - }); -}); diff --git a/test/contractBridge/depositXC20.test.ts b/test/contractBridge/depositXC20.test.ts new file mode 100644 index 00000000..92b015fa --- /dev/null +++ b/test/contractBridge/depositXC20.test.ts @@ -0,0 +1,401 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../helpers"; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Hex, WalletClient} from 'viem'; + + +describe("Bridge - [deposit - XRC20]", async () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let XC20TestInstance: ContractTypesMap["XC20Test"]; + const XC20TestInstanceMock = await hre.viem.deployContract("XC20TestMock"); + let XC20HandlerInstance: ContractTypesMap["XC20Handler"]; + + let depositor: WalletClient; + let recipient: WalletClient; + + let depositData: Hex; + let resourceID1: Hex; + let resourceID2: Hex + + before(async () => { + ({ + XC20TestInstance, + BridgeInstance, + XC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + XC20TestInstance.address, + originDomainID + ); + resourceID2 = createResourceID( + XC20TestInstanceMock.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID1, + XC20TestInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID2, + XC20TestInstanceMock.address, + emptySetResourceData + ]); + await XC20TestInstance.write.mint([ + depositor.account!.address, + initialTokenAmount + ]), + await XC20TestInstanceMock.write.mint([ + depositor.account!.address, + initialTokenAmount + ]); + await XC20TestInstance.write.approve([ + XC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + await XC20TestInstanceMock.write.approve([ + XC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + describe("lock/release strategy", async () => { + it("[sanity] test depositor' balance", async () => { + const originChainDepositorBalance = + await XC20TestInstance.read.balanceOf([depositor.account!.address]); + assert.strictEqual( + originChainDepositorBalance, + initialTokenAmount + ); + }); + + it("XC20 deposit can be made", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const depositCount = await BridgeInstance.read._depositCounts([ + destinationDomainID + ]); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("XC20 can be deposited with correct balances", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const originChainDepositorBalance = + await XC20TestInstance.read.balanceOf([depositor.account!.address]); + + assert.strictEqual( + originChainDepositorBalance, + initialTokenAmount - depositAmount + ); + + const originChainHandlerBalance = await XC20TestInstance.read.balanceOf([ + XC20HandlerInstance.address + ]); + assert.strictEqual(originChainHandlerBalance, depositAmount); + }); + + it("Deposit event is fired with expected value", async () => { + // set allowance to 2 * depositAmount since 2 deposits are made in this test + await XC20TestInstance.write.approve([ + XC20HandlerInstance.address, + depositAmount * BigInt(2) + ], + { + account: depositor.account + } + ); + + let depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID1.toLowerCase(), + expectedDepositNonce + ); + + depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID1.toLowerCase(), + expectedDepositNonce + BigInt(1) + ); + }); + + it("deposit requires resourceID that is mapped to a handler", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + "0x0", + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "ResourceIDNotMappedToHandler()"); + }); + + it("Deposit destination domain can not be current bridge domain ", async () => { + await expect( + BridgeInstance.write.deposit([ + originDomainID, + "0x0", + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "DepositToCurrentDomain()"); + }); + + it("should if XC20Safe contract call fails", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID2, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).to.be.revertedWith("ERC20: operation did not succeed"); + }); + }); + + describe("mint/burn strategy", async () => { + before(async () => { + await BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + XC20TestInstance.address + ]); + }); + + it("[sanity] test depositor' balance", async () => { + const originChainDepositorBalance = + await XC20TestInstance.read.balanceOf([depositor.account!.address]); + assert.strictEqual( + originChainDepositorBalance, + initialTokenAmount + ); + }); + + it("XC20 deposit can be made", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const depositCount = await BridgeInstance.read._depositCounts([ + destinationDomainID + ]); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("XC20 can be deposited with correct balances", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const originChainDepositorBalance = + await XC20TestInstance.read.balanceOf([depositor.account!.address]); + assert.strictEqual( + originChainDepositorBalance, + initialTokenAmount - depositAmount + ); + + const originChainHandlerAllowance = await XC20TestInstance.read.allowance([ + depositor.account!.address, + XC20HandlerInstance.address + ]); + assert.strictEqual(originChainHandlerAllowance, depositAmount); + }); + + it("Deposit event is fired with expected value", async () => { + let depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID1.toLowerCase(), + expectedDepositNonce + ); + + depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID1.toLowerCase(), + expectedDepositNonce + BigInt(1) + ); + }); + + it("deposit requires resourceID1 that is mapped to a handler", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + "0x0", + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "ResourceIDNotMappedToHandler()"); + }); + + it("Deposit destination domain can not be current bridge domain ", async () => { + await expect( + BridgeInstance.write.deposit([originDomainID, "0x0", depositData, feeData], + { + account: depositor.account, + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "DepositToCurrentDomain()"); + }); + }); +}); diff --git a/test/contractBridge/executeProposalERC20.js b/test/contractBridge/executeProposalERC20.js deleted file mode 100644 index 91a71186..00000000 --- a/test/contractBridge/executeProposalERC20.js +++ /dev/null @@ -1,262 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("Bridge - [execute proposal - ERC20]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let ERC20HandlerInstance; - - let resourceID; - let depositData; - let depositProposalData; - - let data = ""; - let dataHash = ""; - let proposal; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - destinationDomainID - ); - - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC20MintableInstance.address]; - burnableContractAddresses = []; - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await Promise.all([ - ERC20MintableInstance.mint(depositorAddress, initialTokenAmount), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ]); - - data = Helpers.createERCDepositData(depositAmount, 20, recipientAddress); - dataHash = Ethers.utils.keccak256( - ERC20HandlerInstance.address + data.substr(2) - ); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - depositProposalData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - depositProposalDataHash = Ethers.utils.keccak256( - ERC20HandlerInstance.address + depositProposalData.substr(2) - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData, - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }) - ); - - await Helpers.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalance = await ERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }) - ); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [ERC20MintableInstance.address, recipientAddress, depositAmount] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalance = await ERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); - - it(`should fail to executeProposal if signed Proposal has different - chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); -}); diff --git a/test/contractBridge/executeProposalERC20.test.ts b/test/contractBridge/executeProposalERC20.test.ts new file mode 100644 index 00000000..b4639571 --- /dev/null +++ b/test/contractBridge/executeProposalERC20.test.ts @@ -0,0 +1,282 @@ +import hre from 'hardhat'; +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {concat, encodeAbiParameters, Hex, keccak256, parseAbiParameters, WalletClient} from "viem"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mockSignTypedProposalWithInvalidChainID, mpcAddress, signTypedProposal, trimPrefix} from "../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; +import {Proposal} from '../../types'; + + +describe("Bridge - [execute proposal - ERC20]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + + let dataHash = ""; + let proposal: Proposal; + + before(async () => { + ({ + BridgeInstance, + ERC20HandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + relayer1 + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + destinationDomainID + ); + + await ERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + + depositData = createERCDepositData(depositAmount, 20, recipient.account!.address); + dataHash = keccak256( + concat([ + ERC20HandlerInstance.address, + trimPrefix(depositData) + ]) + ); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositData, + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + + }); + + it("isProposalExecuted returns false if depositNonce is not used", async () => { + const destinationDomainID = await BridgeInstance.read._domainID(); + + assert.isFalse( + await BridgeInstance.read.isProposalExecuted([ + destinationDomainID, + expectedDepositNonce + ]) + ); + }); + + it("should create and execute executeProposal successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], { + account: depositor.account, + }) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account, + } + ) + ).not.to.be.reverted; + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalance = await ERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, depositAmount); + }); + + it("should skip executing proposal if deposit nonce is already used", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account, + } + ) + ).not.to.be.reverted; + + const skipExecuteTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + // check that no ProposalExecution events are emitted + await expect(skipExecuteTx).not.to.emit(BridgeInstance, "ProposalExecution"); + }); + + it("executeProposal event should be emitted with expected values", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [ERC20MintableInstance.address, recipient.account!.address, depositAmount] + ) + ); + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalance = await ERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, depositAmount); + }); + + it(`should fail to executeProposal if signed Proposal has different + chainID than the one on which it should be executed`, async () => { + const proposalSignedData = + await mockSignTypedProposalWithInvalidChainID( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account, + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "InvalidProposalSigner()"); + }); +}); diff --git a/test/contractBridge/executeProposalXC20.js b/test/contractBridge/executeProposalXC20.js deleted file mode 100644 index 4497ca44..00000000 --- a/test/contractBridge/executeProposalXC20.js +++ /dev/null @@ -1,518 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../helpers"); - -const XC20TestContract = artifacts.require("XC20Test"); -const XC20HandlerContract = artifacts.require("XC20Handler"); - -contract("Bridge - [execute proposal - XC20]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let XC20TestInstance; - let XC20HandlerInstance; - - let resourceID; - let depositData; - let depositProposalData; - - let data = ""; - let dataHash = ""; - let proposal; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - XC20TestContract.new().then( - (instance) => (OriginXC20TestInstance = instance) - ), - ]); - - await XC20TestContract.new().then( - (instance) => (XC20TestInstance = instance) - ), - (resourceID = Helpers.createResourceID( - XC20TestInstance.address, - destinationDomainID - )); - - initialResourceIDs = [resourceID]; - initialContractAddresses = [XC20TestInstance.address]; - burnableContractAddresses = []; - - XC20HandlerInstance = await XC20HandlerContract.new(BridgeInstance.address); - - await Promise.all([ - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - resourceID, - XC20TestInstance.address, - emptySetResourceData - ), - XC20TestInstance.mint( - depositorAddress, - initialTokenAmount - ), - ]); - - await BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - XC20TestInstance.address - ); - - data = Helpers.createERCDepositData(depositAmount, 20, recipientAddress); - dataHash = Ethers.utils.keccak256( - XC20HandlerInstance.address + data.substr(2) - ); - - await XC20TestInstance.approve(XC20HandlerInstance.address, depositAmount, { - from: depositorAddress, - }); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - depositProposalData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - depositProposalDataHash = Ethers.utils.keccak256( - XC20HandlerInstance.address + depositProposalData.substr(2) - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData, - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - - }); - - describe("lock/release strategy", async () => { - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalance = await XC20TestInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalance = await XC20TestInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); - - it(`should fail to executeProposal if signed Proposal has - different chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); - }); - - describe("mint/burn strategy", async () => { - beforeEach(async () => { - await BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - XC20TestInstance.address - ); - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalance = await XC20TestInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalance = await XC20TestInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); - - it(`should fail to executeProposal if signed Proposal - has different chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); - }); - - it(`transfer event should be emitted with expected values when executing proposal - - mint to handler and then transfer to recipient`, async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [XC20TestInstance.address, recipientAddress, depositAmount] - ) - ); - }); - - const internalTx = await TruffleAssert.createTransactionResult( - XC20TestInstance, - proposalTx.tx - ); - - // check that tokens are minted to handler - TruffleAssert.eventEmitted(internalTx, "Transfer", (event) => { - return ( - event.from === Ethers.constants.AddressZero && - event.to === XC20HandlerInstance.address && - event.value.toNumber() === depositAmount - ); - }); - - // check that tokens are transferred from handler to recipient - TruffleAssert.eventEmitted(internalTx, "Transfer", (event) => { - return ( - event.from === XC20HandlerInstance.address && - event.to === recipientAddress && - event.value.toNumber() === depositAmount - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientBalance = await XC20TestInstance.balanceOf(recipientAddress); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); -}); diff --git a/test/contractBridge/executeProposalXC20.test.ts b/test/contractBridge/executeProposalXC20.test.ts new file mode 100644 index 00000000..30055ee7 --- /dev/null +++ b/test/contractBridge/executeProposalXC20.test.ts @@ -0,0 +1,556 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, Hex, keccak256, parseAbiParameters, WalletClient, zeroAddress} from "viem"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mockSignTypedProposalWithInvalidChainID, mpcAddress, signTypedProposal, trimPrefix} from "../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from "chai"; +import {Proposal} from '../../types'; + +const Helpers = require("../helpers"); + +describe("Bridge - [execute proposal - XC20]", async () => { + const originDomainID = 1; + const destinationDomainID = 2; + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let XC20TestInstance: ContractTypesMap["XC20Test"]; + let XC20HandlerInstance: ContractTypesMap["XC20Handler"]; + + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + let depositProposalData; + + let dataHash: Hex; + let proposal: Proposal; + + before(async () => { + ({ + XC20TestInstance, + BridgeInstance, + XC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + relayer1, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + XC20TestInstance.address, + destinationDomainID + ); + + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID, + XC20TestInstance.address, + emptySetResourceData + ]); + await XC20TestInstance.write.mint([ + depositor.account!.address, + initialTokenAmount + ]); + + await BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + XC20TestInstance.address + ]); + + depositData = createERCDepositData(depositAmount, 20, recipient.account!.address); + dataHash = keccak256( + concat([ + XC20HandlerInstance.address, + trimPrefix(depositData) + ]) + ); + + await XC20TestInstance.write.approve([ + XC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account, + } + ); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + depositProposalData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData, + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + + }); + + describe("lock/release strategy", async () => { + it("isProposalExecuted returns false if depositNonce is not used", async () => { + const destinationDomainID = await BridgeInstance.read._domainID(); + + assert.isFalse( + await BridgeInstance.read.isProposalExecuted([ + destinationDomainID, + expectedDepositNonce + ]) + ); + }); + + it("should create and execute executeProposal successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ) + ).not.to.be.reverted; + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalance = await XC20TestInstance.read.balanceOf([ + recipient + ]); + assert.strictEqual(recipientBalance, depositAmount); + }); + + it("should skip executing proposal if deposit nonce is already used", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, proposalSignedData + ], + { + account: relayer1.account + } + ) + ).not.to.be.reverted; + + const skipExecuteTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + // check that no ProposalExecution events are emitted + await expect(skipExecuteTx).not.to.emit(BridgeInstance, "ProposalExecution"); + }); + + it("executeProposal event should be emitted with expected values", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + {account: relayer1} + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash + ); + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalance = await XC20TestInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, depositAmount); + }); + + it(`should fail to executeProposal if signed Proposal has + different chainID than the one on which it should be executed`, async () => { + const proposalSignedData = + await mockSignTypedProposalWithInvalidChainID( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "InvalidProposalSigner()"); + }); + }); + + describe("mint/burn strategy", async () => { + before(async () => { + await BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + XC20TestInstance.address + ]); + }); + + it("isProposalExecuted returns false if depositNonce is not used", async () => { + const destinationDomainID = await BridgeInstance.read._domainID(); + + assert.isFalse( + await BridgeInstance.read.isProposalExecuted([ + destinationDomainID, + expectedDepositNonce + ]) + ); + }); + + it("should create and execute executeProposal successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ) + ).not.to.be.reverted; + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalance = await XC20TestInstance.read.balanceOf( + recipient.account!.address + ); + assert.strictEqual(recipientBalance, depositAmount); + }); + + it("should skip executing proposal if deposit nonce is already used", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, proposalSignedData + ], + { + account: relayer1.account, + } + ) + ).not.to.be.reverted; + + const skipExecuteTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + // check that no ProposalExecution events are emitted + await expect(skipExecuteTx).not.to.emit(BridgeInstance, "ProposalExecution"); + }); + + it("executeProposal event should be emitted with expected values", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash + ); + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalance = await XC20TestInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, depositAmount); + }); + + it(`should fail to executeProposal if signed Proposal + has different chainID than the one on which it should be executed`, async () => { + const proposalSignedData = + await mockSignTypedProposalWithInvalidChainID( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ) + ).revertedWithCustomError(BridgeInstance, "InvalidProposalSigner()"); + }); + }); + + it(`transfer event should be emitted with expected values when executing proposal - + mint to handler and then transfer to recipient`, async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [XC20TestInstance.address, recipient.account!.address, depositAmount] + ) + ); + + // check that tokens are minted to handler + await expect(proposalTx).to.emit(XC20TestInstance, "Transfer").withArgs( + zeroAddress, + XC20HandlerInstance.address, + depositAmount + ) + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientBalance = await XC20TestInstance.read.balanceOf([recipient.account!.address]); + assert.strictEqual(recipientBalance, depositAmount); + }); +}); diff --git a/test/contractBridge/executeProposals.js b/test/contractBridge/executeProposals.js deleted file mode 100644 index 79d0ecc9..00000000 --- a/test/contractBridge/executeProposals.js +++ /dev/null @@ -1,553 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); - -contract("Bridge - [execute proposals]", async (accounts) => { - const destinationDomainID = 1; - const originDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const tokenID = 1; - const erc721DepositMetadata = "0xf00d"; - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonces = [1, 2, 3]; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let ERC20HandlerInstance; - let ERC721MintableInstance; - let ERC721HandlerInstance; - let ERC1155MintableInstance; - let ERC1155HandlerInstance; - - let erc20ResourceID; - let erc721ResourceID; - let erc1155ResourceID; - let erc20DepositData; - let erc20DepositProposalData; - let erc20DataHash; - let erc721DepositData; - let erc721DepositProposalData; - let erc721DataHash; - let erc1155DepositData; - let erc1155DepositProposalData; - let erc1155DataHash; - - let proposalsForExecution; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )), - ERC20MintableContract.new("ERC20token", "ERC20TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ERC721MintableContract.new("ERC721token", "ERC721TOK", "").then( - (instance) => (ERC721MintableInstance = instance) - ), - ERC1155MintableContract.new("ERC1155TOK").then( - (instance) => (ERC1155MintableInstance = instance) - ), - ]); - - (erc20ResourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - destinationDomainID - )), - (erc721ResourceID = Helpers.createResourceID( - ERC721MintableInstance.address, - destinationDomainID - )), - (erc1155ResourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - destinationDomainID - )); - resourceIDs = [erc20ResourceID, erc721ResourceID, erc1155ResourceID]; - contractAddresses = [ - ERC20MintableInstance.address, - ERC721MintableInstance.address, - ERC1155MintableInstance.address, - ]; - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - await Promise.all([ - ERC20MintableInstance.mint(depositorAddress, initialTokenAmount), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - erc20ResourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ERC721MintableInstance.grantRole( - await ERC721MintableInstance.MINTER_ROLE(), - ERC721HandlerInstance.address - ), - ERC721MintableInstance.mint(depositorAddress, tokenID, ""), - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - erc721ResourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - erc1155ResourceID, - ERC1155MintableInstance.address, - emptySetResourceData - ), - ERC1155MintableInstance.mintBatch( - depositorAddress, - [tokenID], - [initialTokenAmount], - "0x0" - ), - ]); - - await Promise.all([ - ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ), - ERC721MintableInstance.approve(ERC721HandlerInstance.address, tokenID, { - from: depositorAddress, - }), - ERC1155MintableInstance.setApprovalForAll( - ERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ), - ]); - - erc20DepositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - erc20DepositProposalData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - erc20DataHash = Ethers.utils.keccak256( - ERC20HandlerInstance.address + erc20DepositProposalData.substr(2) - ); - - erc721DepositData = Helpers.createERCDepositData( - tokenID, - 20, - recipientAddress - ); - erc721DepositProposalData = Helpers.createERC721DepositProposalData( - tokenID, - 20, - recipientAddress, - erc721DepositMetadata.length, - erc721DepositMetadata - ); - erc721DataHash = Ethers.utils.keccak256( - ERC721HandlerInstance.address + erc721DepositProposalData.substr(2) - ); - - erc1155DepositData = Helpers.createERC1155DepositData( - [tokenID], - [depositAmount] - ); - erc1155DepositProposalData = Helpers.createERC1155DepositProposalData( - [tokenID], - [depositAmount], - recipientAddress, - "0x" - ); - erc1155DataHash = Ethers.utils.keccak256( - ERC1155HandlerInstance.address + erc1155DepositProposalData.substr(2) - ); - - proposalsForExecution = [ - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[0], - resourceID: erc20ResourceID, - data: erc20DepositProposalData, - }, - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[1], - resourceID: erc721ResourceID, - data: erc721DepositProposalData, - }, - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[2], - resourceID: erc1155ResourceID, - data: erc1155DepositProposalData, - }, - ]; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - proposalsForExecution - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc20ResourceID, - erc20DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc721ResourceID, - erc721DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc1155ResourceID, - erc1155DepositData, - feeData, - {from: depositorAddress} - ) - ); - - const executeTx = await BridgeInstance.executeProposals( - proposalsForExecution, - proposalSignedData, - {from: relayer1Address} - ); - - await TruffleAssert.passes(executeTx); - - // check that deposit nonces had been marked as used in bitmap - expectedDepositNonces.forEach(async (_, index) => { - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[index] - ) - ); - }); - - // check that tokens are transferred to recipient address - const recipientERC20Balance = await ERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC20Balance.toNumber(), depositAmount); - - const recipientERC721Balance = await ERC721MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC721Balance.toNumber(), 1); - - const recipientERC1155Balance = await ERC1155MintableInstance.balanceOf( - recipientAddress, - destinationDomainID - ); - assert.strictEqual(recipientERC1155Balance.toNumber(), depositAmount); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - proposalsForExecution - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc20ResourceID, - erc20DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc721ResourceID, - erc721DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc1155ResourceID, - erc1155DepositData, - feeData, - {from: depositorAddress} - ) - ); - - const executeTx = await BridgeInstance.executeProposals( - proposalsForExecution, - proposalSignedData, - {from: relayer1Address} - ); - - await TruffleAssert.passes(executeTx); - - // check that deposit nonces had been marked as used in bitmap - expectedDepositNonces.forEach(async (_, index) => { - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[index] - ) - ); - }); - - // check that tokens are transferred to recipient address - const recipientERC20Balance = await ERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC20Balance.toNumber(), depositAmount); - - const recipientERC721Balance = await ERC721MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC721Balance.toNumber(), 1); - - const recipientERC1155Balance = await ERC1155MintableInstance.balanceOf( - recipientAddress, - destinationDomainID - ); - assert.strictEqual(recipientERC1155Balance.toNumber(), depositAmount); - - const skipExecuteTx = await BridgeInstance.executeProposals( - proposalsForExecution, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("should fail executing proposals if empty array is passed for execution", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - proposalsForExecution - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposals([], proposalSignedData, { - from: relayer1Address, - }), - "EmptyProposalsArray()" - ); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - proposalsForExecution - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc20ResourceID, - erc20DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc721ResourceID, - erc721DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc1155ResourceID, - erc1155DepositData, - feeData, - {from: depositorAddress} - ) - ); - - const executeTx = await BridgeInstance.executeProposals( - proposalsForExecution, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(executeTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonces[0] && - event.dataHash === erc20DataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [ERC20MintableInstance.address, recipientAddress, depositAmount] - ) - ); - }); - - // check that ProposalExecution has been emitted with expected values for ERC721 - assert.equal(executeTx.logs[1].args.originDomainID, originDomainID); - assert.equal(executeTx.logs[1].args.depositNonce, expectedDepositNonces[1]); - assert.equal(executeTx.logs[1].args.dataHash, erc721DataHash); - assert.equal( - executeTx.logs[1].args.handlerResponse, - Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256"], - [ERC721MintableInstance.address ,recipientAddress, tokenID] - ) - ); - - // check that ProposalExecution has been emitted with expected values for ERC1155 - assert.equal(executeTx.logs[2].args.originDomainID, originDomainID); - assert.equal(executeTx.logs[2].args.depositNonce, expectedDepositNonces[2]); - assert.equal(executeTx.logs[2].args.dataHash, erc1155DataHash); - assert.equal( - executeTx.logs[2].args.handlerResponse, - Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256[]", "uint256[]"], - [ERC1155MintableInstance.address, recipientAddress, [tokenID], [depositAmount]] - ) - ); - - // check that deposit nonces had been marked as used in bitmap - expectedDepositNonces.forEach(async (_, index) => { - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[index] - ) - ); - }); - - // check that tokens are transferred to recipient address - const recipientERC20Balance = await ERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC20Balance.toNumber(), depositAmount); - - const recipientERC721Balance = await ERC721MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC721Balance.toNumber(), 1); - - const recipientERC1155Balance = await ERC1155MintableInstance.balanceOf( - recipientAddress, - destinationDomainID - ); - assert.strictEqual(recipientERC1155Balance.toNumber(), depositAmount); - }); - - it(`should fail to executeProposals if signed Proposal has - different chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - proposalsForExecution - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc20ResourceID, - erc20DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc721ResourceID, - erc721DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc1155ResourceID, - erc1155DepositData, - feeData, - {from: depositorAddress} - ) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposals( - proposalsForExecution, - proposalSignedData, - {from: relayer1Address} - ), - "InvalidProposalSigner()" - ); - }); -}); diff --git a/test/contractBridge/executeProposals.test.ts b/test/contractBridge/executeProposals.test.ts new file mode 100644 index 00000000..306dea23 --- /dev/null +++ b/test/contractBridge/executeProposals.test.ts @@ -0,0 +1,592 @@ +import hre from 'hardhat'; +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {concat, encodeAbiParameters, Hex, keccak256, parseAbiParameters, WalletClient} from "viem"; +import {deploySourceChainContracts, mpcAddress, trimPrefix, createResourceID, createERCDepositData, createERC721DepositProposalData, createERC1155DepositData, createERC1155DepositProposalData} from "../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; +import {Proposal} from '../../types'; + + +describe("Bridge - [execute proposals]", () => { + const destinationDomainID = 1; + const originDomainID = 2; + + + const tokenID = BigInt(1); + const erc721DepositMetadata = "0xf00d"; + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonces = [1, 2, 3]; + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + let ERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let erc20ResourceID: Hex; + let erc721ResourceID: Hex; + let erc1155ResourceID: Hex; + let erc20DepositData: Hex; + let erc20DepositProposalData: Hex; + let erc20DataHash: Hex; + let erc721DepositData: Hex; + let erc721DepositProposalData: Hex; + let erc721DataHash: Hex; + let erc1155DepositData: Hex; + let erc1155DepositProposalData: Hex; + let erc1155DataHash: Hex; + + let proposalsForExecution: Array; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + ERC721HandlerInstance, + ERC1155MintableInstance, + ERC1155HandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + relayer1 + ] = await hre.viem.getWalletClients(); + + erc20ResourceID = createResourceID( + ERC20MintableInstance.address, + destinationDomainID + ); + erc721ResourceID = createResourceID( + ERC721MintableInstance.address, + destinationDomainID + ); + erc1155ResourceID = createResourceID( + ERC1155MintableInstance.address, + destinationDomainID + ); + + await ERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]), + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + erc20ResourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await ERC721MintableInstance.write.grantRole([ + await ERC721MintableInstance.read.MINTER_ROLE(), + ERC721HandlerInstance.address + ]); + await ERC721MintableInstance.write.mint([depositor.account!.address, tokenID, ""]); + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + erc721ResourceID, + ERC721MintableInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + erc1155ResourceID, + ERC1155MintableInstance.address, + emptySetResourceData + ]), + await ERC1155MintableInstance.write.mintBatch([ + depositor.account!.address, + [tokenID], + [initialTokenAmount], + "0x0" + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + await ERC721MintableInstance.write.approve([ + ERC721HandlerInstance.address, + tokenID + ], + { + account: depositor.account, + }); + await ERC1155MintableInstance.write.setApprovalForAll([ + ERC1155HandlerInstance.address, + true + ], + { + account: depositor.account + } + ); + + erc20DepositData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + erc20DepositProposalData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + erc20DataHash = keccak256( + concat([ + ERC20HandlerInstance.address, + trimPrefix(erc20DepositProposalData) + ]) + ); + + erc721DepositData = createERCDepositData( + tokenID, + 20, + recipient.account!.address + ); + erc721DepositProposalData = createERC721DepositProposalData( + tokenID, + 20, + recipient.account!.address, + erc721DepositMetadata.length, + erc721DepositMetadata + ); + erc721DataHash = keccak256( + concat([ + ERC721HandlerInstance.address, + trimPrefix(erc721DepositProposalData) + ]) + ); + + erc1155DepositData = createERC1155DepositData( + [tokenID], + [depositAmount] + ); + erc1155DepositProposalData = createERC1155DepositProposalData( + [tokenID], + [depositAmount], + recipient.account!.address, + "0x" + ); + erc1155DataHash = keccak256( + concat([ + ERC1155HandlerInstance.address, + trimPrefix(erc1155DepositProposalData) + ]) + ); + + proposalsForExecution = [ + { + originDomainID: originDomainID, + depositNonce: BigInt(expectedDepositNonces[0]), + resourceID: erc20ResourceID, + data: erc20DepositProposalData, + }, + { + originDomainID: originDomainID, + depositNonce: BigInt(expectedDepositNonces[1]), + resourceID: erc721ResourceID, + data: erc721DepositProposalData, + }, + { + originDomainID: originDomainID, + depositNonce: BigInt(expectedDepositNonces[2]), + resourceID: erc1155ResourceID, + data: erc1155DepositProposalData, + }, + ]; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should create and execute executeProposal successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + proposalsForExecution + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc20ResourceID, + erc20DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc721ResourceID, + erc721DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc1155ResourceID, + erc1155DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + const executeTx = await BridgeInstance.write.executeProposals([ + proposalsForExecution, + proposalSignedData + ], + { + account: relayer1.account!.address + } + ); + + await expect(executeTx).not.to.be.reverted; + + // check that deposit nonces had been marked as used in bitmap + expectedDepositNonces.forEach(async (_, index) => { + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[index]) + ]) + ); + }); + + // check that tokens are transferred to recipient address + const recipientERC20Balance = await ERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientERC20Balance, depositAmount); + + const recipientERC721Balance = await ERC721MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientERC721Balance, BigInt(1)); + + const recipientERC1155Balance = await ERC1155MintableInstance.read.balanceOf([ + recipient.account!.address, + BigInt(destinationDomainID) + ]); + assert.strictEqual(recipientERC1155Balance, depositAmount); + }); + + it("should skip executing proposal if deposit nonce is already used", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + proposalsForExecution + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc20ResourceID, + erc20DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc721ResourceID, + erc721DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc1155ResourceID, + erc1155DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + const executeTx = await BridgeInstance.write.executeProposals([ + proposalsForExecution, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + await expect(executeTx).not.to.be.reverted; + + // check that deposit nonces had been marked as used in bitmap + expectedDepositNonces.forEach(async (_, index) => { + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[index]) + ]) + ); + }); + + // check that tokens are transferred to recipient address + const recipientERC20Balance = await ERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientERC20Balance, depositAmount); + + const recipientERC721Balance = await ERC721MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientERC721Balance, BigInt(1)); + + const recipientERC1155Balance = await ERC1155MintableInstance.read.balanceOf([ + recipient.account!.address, + BigInt(destinationDomainID) + ]); + assert.strictEqual(recipientERC1155Balance, depositAmount); + + const skipExecuteTx = await BridgeInstance.write.executeProposals([ + proposalsForExecution, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + // check that no ProposalExecution events are emitted + await expect(skipExecuteTx).not.to.emit(BridgeInstance, "ProposalExecution"); + }); + + it("should fail executing proposals if empty array is passed for execution", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + proposalsForExecution + ); + + await expect( + BridgeInstance.write.executeProposals([[], proposalSignedData + ], + { + account: relayer1.account + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "EmptyProposalsArray()"); + }); + + it("executeProposal event should be emitted with expected values", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + proposalsForExecution + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc20ResourceID, + erc20DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc721ResourceID, + erc721DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc1155ResourceID, + erc1155DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + const executeTx = await BridgeInstance.write.executeProposals([ + proposalsForExecution, + proposalSignedData + ], + { + account: relayer1.account!.address + } + ); + + // check that ProposalExecution has been emitted with expected values for ERC20 + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonces[0], + erc20DataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [ERC20MintableInstance.address, recipient.account!.address, depositAmount] + ) + ); + // check that ProposalExecution has been emitted with expected values for ERC721 + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonces[1], + erc721DataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [ERC721MintableInstance.address, recipient.account!.address, tokenID] + ) + ); + + // check that ProposalExecution has been emitted with expected values for ERC1155 + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonces[2], + erc1155DataHash, + encodeAbiParameters( + parseAbiParameters(["address", "address", "uint256"]), + [ERC1155MintableInstance.address, recipient.account!.address, tokenID] + ) + ); + + // check that deposit nonces had been marked as used in bitmap + expectedDepositNonces.forEach(async (_, index) => { + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[index]) + ]) + ); + }); + + // check that tokens are transferred to recipient address + const recipientERC20Balance = await ERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientERC20Balance, depositAmount); + + const recipientERC721Balance = await ERC721MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientERC721Balance, BigInt(1)); + + const recipientERC1155Balance = await ERC1155MintableInstance.read.balanceOf([ + recipient.account!.address, + BigInt(destinationDomainID) + ]); + assert.strictEqual(recipientERC1155Balance, depositAmount); + }); + + it(`should fail to executeProposals if signed Proposal has + different chainID than the one on which it should be executed`, async () => { + const proposalSignedData = + await mockSignTypedProposalWithInvalidChainID( + BridgeInstance.address, + proposalsForExecution + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc20ResourceID, + erc20DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc721ResourceID, + erc721DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc1155ResourceID, + erc1155DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposals([ + proposalsForExecution, + proposalSignedData + ], + { + account: relayer1.account + } + ) + ).to.be.revertedWithCustomError(BridgeInstance, "InvalidProposalSigner()"); + }); +}); diff --git a/test/contractBridge/executeWithFailedHandler.js b/test/contractBridge/executeWithFailedHandler.js deleted file mode 100644 index ce19d762..00000000 --- a/test/contractBridge/executeWithFailedHandler.js +++ /dev/null @@ -1,697 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC20HandlerContract = artifacts.require("HandlerRevert"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); -const ERC721RevertMintableContract = artifacts.require( - "ERC721MinterBurnerPauser" -); -const ERC721RevertHandlerContract = artifacts.require("HandlerRevert"); -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("HandlerRevert"); -const XC20TestContract = artifacts.require("XC20Test"); -const XC20HandlerContract = artifacts.require("XC20Handler"); -const TestStoreContract = artifacts.require("TestStore"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); - -contract("Bridge - [execute - FailedHandlerExecution]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const tokenID = 1; - const erc721DepositMetadata = "0xf00d"; - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonces = [1, 2, 3, 4, 5, 6]; - const destinationMaxFee = 900000; - const hashOfTestStore = Ethers.utils.keccak256("0xc0ffee"); - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let ERC20HandlerInstance; - let ERC721MintableInstance; - let ERC721HandlerInstance; - let ERC721RevertMintableInstance; - let ERC721RevertHandlerInstance; - let ERC1155MintableInstance; - let ERC1155HandlerInstance; - let GmpHandlerInstance; - let XC20TestInstance; - let XC20HandlerInstance; - - let depositFunctionSignature; - let GmpHandlerSetResourceData; - - let erc20ResourceID; - let erc721ResourceID; - let erc721RevertResourceID; - let erc1155ResourceID; - let genericResourceID; - let erc20DepositProposalData; - let erc721DepositData; - let erc721DepositProposalData; - let erc721RevertDepositProposalData; - let erc1155DepositProposalData; - let xc20ResourceID; - let xc20DepositProposalData; - let genericProposalData; - let genericDepositProposalDataHash; - - let proposalsForExecution; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC20MintableContract.new("token20", "TOK20").then( - (instance) => (ERC20MintableInstance = instance) - ), - ERC721MintableContract.new("token721", "TOK721", "").then( - (instance) => (ERC721MintableInstance = instance) - ), - ERC721RevertMintableContract.new("Rtoken721", "RTOK721", "").then( - (instance) => (ERC721RevertMintableInstance = instance) - ), - ERC1155MintableContract.new("TOK1155").then( - (instance) => (ERC1155MintableInstance = instance) - ), - TestStoreContract.new().then( - (instance) => (TestStoreInstance = instance) - ), - XC20TestContract.new().then( - (instance) => (XC20TestInstance = instance) - ) - ]); - - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address - ); - ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - ERC721RevertHandlerInstance = await ERC721RevertHandlerContract.new( - BridgeInstance.address - ); - ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - GmpHandlerInstance = - await GmpHandlerContract.new(BridgeInstance.address); - - erc20ResourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - erc721ResourceID = Helpers.createResourceID( - ERC721MintableInstance.address, - originDomainID - ); - erc721RevertResourceID = Helpers.createResourceID( - ERC721RevertMintableInstance.address, - originDomainID - ); - erc1155ResourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - originDomainID - ); - xc20ResourceID = Helpers.createResourceID( - XC20TestInstance.address, - destinationDomainID - ); - genericResourceID = Helpers.createResourceID( - GmpHandlerInstance.address, - originDomainID - ); - - depositFunctionSignature = Helpers.getFunctionSignature( - TestStoreInstance, - "storeWithDepositor" - ); - initialGenericExecuteFunctionSignature = Helpers.getFunctionSignature( - ERC20MintableContract, - "mint" - ); - - depositFunctionSignature = Helpers.getFunctionSignature( - TestStoreInstance, - "storeWithDepositor" - ); - - GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - - await Promise.all([ - ERC20MintableInstance.mint(depositorAddress, initialTokenAmount), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - erc20ResourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ERC721MintableInstance.grantRole( - await ERC721MintableInstance.MINTER_ROLE(), - ERC721HandlerInstance.address - ), - ERC721RevertMintableInstance.grantRole( - await ERC721RevertMintableInstance.MINTER_ROLE(), - ERC721RevertHandlerInstance.address - ), - ERC721MintableInstance.mint( - depositorAddress, - tokenID, - erc721DepositMetadata - ), - ERC721RevertMintableInstance.mint( - depositorAddress, - tokenID, - erc721DepositMetadata - ), - XC20TestInstance.mint( - depositorAddress, - initialTokenAmount - ), - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - erc721ResourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - ERC721RevertHandlerInstance.address, - erc721RevertResourceID, - ERC721RevertMintableInstance.address, - emptySetResourceData - ), - ERC1155MintableInstance.mintBatch( - depositorAddress, - [tokenID], - [initialTokenAmount], - "0x0" - ), - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - erc1155ResourceID, - ERC1155MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - xc20ResourceID, - XC20TestInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - genericResourceID, - TestStoreInstance.address, - GmpHandlerSetResourceData - ), - ]); - - await Promise.all([ - ERC20MintableInstance.approve(ERC20HandlerInstance.address, 5000, { - from: depositorAddress, - }), - ERC721MintableInstance.approve(ERC721HandlerInstance.address, tokenID, { - from: depositorAddress, - }), - ERC721RevertMintableInstance.approve( - ERC721RevertHandlerInstance.address, - tokenID, - {from: depositorAddress} - ), - ERC1155MintableInstance.setApprovalForAll( - ERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ), - XC20TestInstance.approve(XC20HandlerInstance.address, depositAmount, - {from: depositorAddress} - ), - ]); - - erc20DepositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - erc20DepositProposalData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - erc20DepositProposalDataHash = Ethers.utils.keccak256( - ERC20HandlerInstance.address + erc20DepositProposalData.substr(2) - ); - - erc721DepositData = Helpers.createERCDepositData( - tokenID, - 20, - recipientAddress - ); - erc721DepositProposalData = Helpers.createERC721DepositProposalData( - tokenID, - 20, - recipientAddress, - erc721DepositMetadata.length, - erc721DepositMetadata - ); - erc721DepositProposalDataHash = Ethers.utils.keccak256( - ERC721HandlerInstance.address + erc721DepositProposalData.substr(2) - ); - xc20DepositProposalData = Helpers.createERCDepositData( - depositAmount * 5, // amount greater than allowance - 20, - recipientAddress - ); - - erc721RevertDepositData = Helpers.createERCDepositData( - tokenID, - 20, - recipientAddress - ); - erc721RevertDepositProposalData = Helpers.createERC721DepositProposalData( - tokenID, - 20, - recipientAddress, - erc721DepositMetadata.length, - erc721DepositMetadata - ); - erc721RevertDepositProposalDataHash = Ethers.utils.keccak256( - ERC721RevertHandlerInstance.address + - erc721RevertDepositProposalData.substr(2) - ); - - erc1155DepositData = Helpers.createERC1155DepositData( - [tokenID], - [depositAmount] - ); - erc1155DepositProposalData = Helpers.createERC1155DepositProposalData( - [tokenID], - [depositAmount], - recipientAddress, - "0x" - ); - - genericProposalData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestStoreInstance.address, - destinationMaxFee, - depositorAddress, - hashOfTestStore - ); - genericDepositProposalDataHash = Ethers.utils.keccak256( - GmpHandlerInstance.address + genericProposalData.substr(2) - ); - - proposalsForExecution = [ - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[0], - resourceID: erc20ResourceID, - data: erc20DepositProposalData, - }, - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[1], - resourceID: erc721ResourceID, - data: erc721DepositProposalData, - }, - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[2], - resourceID: erc721RevertResourceID, - data: erc721RevertDepositProposalData, - }, - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[3], - data: erc1155DepositProposalData, - resourceID: erc1155ResourceID, - }, - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[4], - resourceID: genericResourceID, - data: genericProposalData, - }, - { - originDomainID: originDomainID, - depositNonce: expectedDepositNonces[5], - resourceID: xc20ResourceID, - data: xc20DepositProposalData, - }, - ]; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it(`[executeProposal - ERC20] - Should not revert if handler execution failed. - FailedHandlerExecution event should be emitted`, async () => { - const depositProposalBeforeFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[0] - ); - - // depositNonce is not used - assert.isFalse(depositProposalBeforeFailedExecute); - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposalsForExecution[0]] - ); - - const executeTx = await BridgeInstance.executeProposal( - proposalsForExecution[0], - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonces[0] && - Ethers.utils.parseBytes32String( - "0x" + event.lowLevelData.slice(-64) - ) === "Something bad happened" - ); - }); - - const depositProposalAfterFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[0] - ); - - // depositNonce is not used - assert.isFalse(depositProposalAfterFailedExecute); - }); - - it(`[executeProposal - ERC721] - Should not revert if handler execution failed. - FailedHandlerExecution event should be emitted`, async () => { - const depositProposalBeforeFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[2] - ); - - // depositNonce is not used - assert.isFalse(depositProposalBeforeFailedExecute); - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposalsForExecution[2]] - ); - - const executeTx = await BridgeInstance.executeProposal( - proposalsForExecution[2], - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonces[2] && - Ethers.utils.parseBytes32String( - "0x" + event.lowLevelData.slice(-64) - ) === "Something bad happened" - ); - }); - - const depositProposalAfterFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[2] - ); - - // depositNonce is not used - assert.isFalse(depositProposalAfterFailedExecute); - }); - - it(`[executeProposal - ERC1155] - Should not revert if handler execution failed. - FailedHandlerExecution event should be emitted`, async () => { - const depositProposalBeforeFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[3] - ); - - // depositNonce is not used - assert.isFalse(depositProposalBeforeFailedExecute); - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposalsForExecution[3]] - ); - - const executeTx = await BridgeInstance.executeProposal( - proposalsForExecution[3], - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonces[3] && - Ethers.utils.parseBytes32String( - "0x" + event.lowLevelData.slice(-64) - ) === "Something bad happened" - ); - }); - - const depositProposalAfterFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[3] - ); - - // depositNonce is not used - assert.isFalse(depositProposalAfterFailedExecute); - }); - - it(`[executeProposal - Generic] - Should not revert if handler execution failed. - FailedHandlerExecution event should be emitted`, async () => { - const depositProposalBeforeFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[4] - ); - - // depositNonce is not used - assert.isFalse(depositProposalBeforeFailedExecute); - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposalsForExecution[4]] - ); - - const executeTx = await BridgeInstance.executeProposal( - proposalsForExecution[4], - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(executeTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonces[4] && - event.dataHash === genericDepositProposalDataHash - ); - }); - - const depositProposalAfterFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[4] - ); - - // depositNonce is used - assert.isTrue(depositProposalAfterFailedExecute); - }); - - it(`[executeProposal - XC20] - Should not revert if transferring tokens from XC20Safe to recipient failed. - FailedHandlerExecution event should be emitted`, async () => { - const depositProposalBeforeFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[0] - ); - - // depositNonce is not used - assert.isFalse(depositProposalBeforeFailedExecute); - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposalsForExecution[5]] - ); - - const executeTx = await BridgeInstance.executeProposal( - proposalsForExecution[5], - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonces[5] && - Ethers.utils.parseBytes32String( - "0x" + event.lowLevelData.slice(-64) - ) === "ERC20: call failed" - ); - }); - - const depositProposalAfterFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[0] - ); - - // depositNonce is not used - assert.isFalse(depositProposalAfterFailedExecute); - }); - - it(`[executeProposals] - Should not revert if handler execute is reverted and continue to process next execution. - FailedHandlerExecution event should be emitted with expected values.`, async () => { - const depositProposalBeforeFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[0] - ); - - // depositNonce is not used - assert.isFalse(depositProposalBeforeFailedExecute); - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - proposalsForExecution - ); - - // depositorAddress makes initial deposit of depositAmount - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - erc721ResourceID, - erc721DepositData, - feeData, - {from: depositorAddress} - ) - ); - - // check that all nonces in nonce set are 0 - const noncesSetBeforeDeposit = await BridgeInstance.usedNonces( - originDomainID, - 0 - ); - assert.equal( - Helpers.decimalToPaddedBinary(noncesSetBeforeDeposit.toNumber()), - // nonces: ...9876543210 - "0000000000000000000000000000000000000000000000000000000000000000" - ); - - const executeTx = await BridgeInstance.executeProposals( - proposalsForExecution, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonces[0] && - Ethers.utils.parseBytes32String( - "0x" + event.lowLevelData.slice(-64) - ) === "Something bad happened" - ); - }); - - const erc20depositProposalAfterFailedExecute = - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[0] - ); - // depositNonce for failed ERC20 deposit is unset - assert.isFalse(erc20depositProposalAfterFailedExecute); - - const erc721depositProposal = await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[1] - ); - // depositNonce for ERC721 deposit is used - assert.isTrue(erc721depositProposal); - - const genericDepositProposal = await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonces[4] - ); - // depositNonce for generic deposit is used - assert.isTrue(genericDepositProposal); - - // recipient ERC20 token balances hasn't changed - const recipientERC20Balance = await ERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC20Balance.toNumber(), 0); - - // recipient ERC721 token balance has changed to 1 token - const recipientERC721Balance = await ERC721MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientERC721Balance.toNumber(), 1); - - // check that other nonces in nonce set are not affected after failed deposit - const noncesSetAfterDeposit = await BridgeInstance.usedNonces( - originDomainID, - 0 - ); - assert.equal( - Helpers.decimalToPaddedBinary(noncesSetAfterDeposit.toNumber()), - // nonces: ...9876543210 - "0000000000000000000000000000000000000000000000000000000000100100" - ); - - // check that 'ProposalExecution' event has been emitted with proper values for ERC721Revert deposit - assert.equal(executeTx.logs[1].args.originDomainID, 1); - assert.equal(executeTx.logs[1].args.depositNonce, expectedDepositNonces[1]); - assert.equal( - executeTx.logs[1].args.dataHash, - erc721DepositProposalDataHash - ); - - // check that 'ProposalExecution' event has been emitted with proper values for generic deposit - assert.equal(executeTx.logs[4].args.originDomainID, 1); - assert.equal(executeTx.logs[4].args.depositNonce, expectedDepositNonces[4]); - assert.equal( - executeTx.logs[4].args.dataHash, - genericDepositProposalDataHash - ); - }); -}); diff --git a/test/contractBridge/executeWithFailedHandler.test.ts b/test/contractBridge/executeWithFailedHandler.test.ts new file mode 100644 index 00000000..ed8c63e3 --- /dev/null +++ b/test/contractBridge/executeWithFailedHandler.test.ts @@ -0,0 +1,667 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, fromBytes, Hex, keccak256, toBytes, toFunctionSelector, toHex} from "viem"; +import {deploySourceChainContracts, mpcAddress, trimPrefix, decimalToPaddedBinary} from "../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + +const Helpers = require("../helpers"); + +describe("Bridge - [execute - FailedHandlerExecution]", async () => { + const originDomainID = 1; + const destinationDomainID = 2; + const admin = accounts[0]; + const depositor = accounts[1]; + const recipient = accounts[2]; + const relayer1 = accounts[3]; + + const tokenID = BigInt(1); + const erc721DepositMetadata = "0xf00d"; + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const erc20Allowance = BigInt(5000); + const expectedDepositNonces = [1, 2, 3, 4, 5, 6]; + const destinationMaxFee = 900000; + const hashOfTestStore = keccak256("0xc0ffee"); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + let ERC721RevertMintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC721RevertHandlerInstance: ContractTypesMap["HandlerRevert"]; + let ERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + let GmpHandlerInstance: ContractTypesMap["GmpHandler"]; + let XC20TestInstance: ContractTypesMap["XC20Test"]; + let XC20HandlerInstance: ContractTypesMap["XC20Handler"];; + let TestStoreInstance: ContractTypesMap["TestStore"]; + + let depositFunctionSignature: Hex; + let GmpHandlerSetResourceData; + let erc721DepositProposalDataHash: Hex; + let erc721RevertDepositProposalDataHash: Hex; + + let erc20ResourceID: Hex; + let erc721ResourceID: Hex; + let erc721RevertResourceID: Hex; + let erc1155ResourceID: Hex; + let genericResourceID: Hex; + let erc20DepositProposalData: Hex; + let erc721DepositData: Hex; + let erc721DepositProposalData: Hex; + let erc721RevertDepositProposalData: Hex; + let erc1155DepositProposalData: Hex; + let xc20ResourceID: Hex; + let xc20DepositProposalData: Hex; + let genericProposalData: Hex; + let genericDepositProposalDataHash: Hex; + + let proposalsForExecution: Array; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + ERC721HandlerInstance, + ERC721MintableInstance: ERC721RevertMintableInstance, + ERC1155MintableInstance, + ERC1155HandlerInstance, + XC20TestInstance, + XC20HandlerInstance, + TestStoreInstance, + GmpHandlerInstance, + HandlerRevert: ERC721RevertHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + evmRecipient, + relayer1 + ] = await hre.viem.getWalletClients(); + + erc20ResourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + erc721ResourceID = createResourceID( + ERC721MintableInstance.address, + originDomainID + ); + erc721RevertResourceID = createResourceID( + ERC721RevertMintableInstance.address, + originDomainID + ); + erc1155ResourceID = createResourceID( + ERC1155MintableInstance.address, + originDomainID + ); + xc20ResourceID = createResourceID( + XC20TestInstance.address, + destinationDomainID + ); + genericResourceID = createResourceID( + GmpHandlerInstance.address, + originDomainID + ); + + depositFunctionSignature = toFunctionSelector( + TestStoreInstance.write.storeWithDepositor.toString() + ); + + GmpHandlerSetResourceData = + constructGenericHandlerSetResourceData( + depositFunctionSignature, + blankFunctionDepositorOffset, + blankFunctionSig + ); + + await ERC20MintableInstance.write.mint([depositor, initialTokenAmount]); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + erc20ResourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await ERC721MintableInstance.write.grantRole([ + await ERC721MintableInstance.read.MINTER_ROLE(), + ERC721HandlerInstance.address + ]); + await ERC721RevertMintableInstance.write.grantRole([ + await ERC721RevertMintableInstance.read.MINTER_ROLE(), + ERC721RevertHandlerInstance.address + ]); + await ERC721MintableInstance.write.mint([ + depositor, + tokenID, + erc721DepositMetadata + ]); + await ERC721RevertMintableInstance.write.mint([ + depositor, + tokenID, + erc721DepositMetadata + ]); + await XC20TestInstance.write.mint([ + depositor, + initialTokenAmount + ]); + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + erc721ResourceID, + ERC721MintableInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC721RevertHandlerInstance.address, + erc721RevertResourceID, + ERC721RevertMintableInstance.address, + emptySetResourceData + ]); + await ERC1155MintableInstance.write.mintBatch([ + depositor, + [tokenID], + [initialTokenAmount], + "0x0" + ]); + await BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + erc1155ResourceID, + ERC1155MintableInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + xc20ResourceID, + XC20TestInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + GmpHandlerInstance.address, + genericResourceID, + TestStoreInstance.address, + GmpHandlerSetResourceData + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + erc20Allowance + ], + { + account: depositor.account, + } + ); + await ERC721MintableInstance.write.approve([ + ERC721HandlerInstance.address, + tokenID + ], + { + account: depositor.account, + } + ); + await ERC721RevertMintableInstance.write.approve([ + ERC721RevertHandlerInstance.address, + tokenID + ], + { + account: depositor.account + } + ); + await ERC1155MintableInstance.write.setApprovalForAll([ + ERC1155HandlerInstance.address, + true + ], + { + account: depositor.account + } + ); + await XC20TestInstance.write.approve([ + XC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + erc20DepositProposalData = createERCDepositData( + depositAmount, + 20, + recipient + ); + + erc721DepositData = createERCDepositData( + tokenID, + 20, + recipient + ); + erc721DepositProposalData = createERC721DepositProposalData( + tokenID, + 20, + recipient, + erc721DepositMetadata.length, + erc721DepositMetadata + ); + erc721DepositProposalDataHash = keccak256( + concat([ + ERC721HandlerInstance.address, + trimPrefix(erc721DepositProposalData) + ]) + ); + xc20DepositProposalData = createERCDepositData( + depositAmount * BigInt(5), // amount greater than allowance + 20, + recipient + ); + + erc721RevertDepositProposalData = createERC721DepositProposalData( + tokenID, + 20, + recipient, + erc721DepositMetadata.length, + erc721DepositMetadata + ); + erc721RevertDepositProposalDataHash = keccak256( + concat([ + ERC721RevertHandlerInstance.address, + trimPrefix(erc721RevertDepositProposalData) + ]) + ); + + + erc1155DepositData = createERC1155DepositData( + [tokenID], + [depositAmount] + ); + erc1155DepositProposalData = createERC1155DepositProposalData( + [tokenID], + [depositAmount], + recipient, + "0x" + ); + + genericProposalData = createGmpDepositData( + depositFunctionSignature, + TestStoreInstance.address, + destinationMaxFee, + depositor, + hashOfTestStore + ); + genericDepositProposalDataHash = keccak256( + concat([ + GmpHandlerInstance.address, + trimPrefix(genericProposalData) + ]) + ); + + proposalsForExecution = [ + { + originDomainID: originDomainID, + depositNonce: expectedDepositNonces[0], + resourceID: erc20ResourceID, + data: erc20DepositProposalData, + }, + { + originDomainID: originDomainID, + depositNonce: expectedDepositNonces[1], + resourceID: erc721ResourceID, + data: erc721DepositProposalData, + }, + { + originDomainID: originDomainID, + depositNonce: expectedDepositNonces[2], + resourceID: erc721RevertResourceID, + data: erc721RevertDepositProposalData, + }, + { + originDomainID: originDomainID, + depositNonce: expectedDepositNonces[3], + data: erc1155DepositProposalData, + resourceID: erc1155ResourceID, + }, + { + originDomainID: originDomainID, + depositNonce: expectedDepositNonces[4], + resourceID: genericResourceID, + data: genericProposalData, + }, + { + originDomainID: originDomainID, + depositNonce: expectedDepositNonces[5], + resourceID: xc20ResourceID, + data: xc20DepositProposalData, + }, + ]; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it(`[executeProposal - ERC20] - Should not revert if handler execution failed. + FailedHandlerExecution event should be emitted`, async () => { + const depositProposalBeforeFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[0]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalBeforeFailedExecute); + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposalsForExecution[0]] + ); + + const executeTx = await BridgeInstance.write.executeProposal([ + proposalsForExecution[0], + proposalSignedData + ], + { + account: relayer1 + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonces[0], + toHex(toBytes("Something bad happened")) + ) + + const depositProposalAfterFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[0]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalAfterFailedExecute); + }); + + it(`[executeProposal - ERC721] - Should not revert if handler execution failed. + FailedHandlerExecution event should be emitted`, async () => { + const depositProposalBeforeFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[2]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalBeforeFailedExecute); + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposalsForExecution[2]] + ); + + const executeTx = await BridgeInstance.write.executeProposal([ + proposalsForExecution[2], + proposalSignedData + ], + { + account: relayer1 + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonces[0], + toHex(toBytes("Something bad happened")) + ) + + const depositProposalAfterFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[2]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalAfterFailedExecute); + }); + + it(`[executeProposal - ERC1155] - Should not revert if handler execution failed. + FailedHandlerExecution event should be emitted`, async () => { + const depositProposalBeforeFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[3]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalBeforeFailedExecute); + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposalsForExecution[3]] + ); + + const executeTx = await BridgeInstance.write.executeProposal([ + proposalsForExecution[3], + proposalSignedData + ], + { + account: relayer1 + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonces[0], + toHex(toBytes("Something bad happened")) + ); + + const depositProposalAfterFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[3]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalAfterFailedExecute); + }); + + it(`[executeProposal - Generic] - Should not revert if handler execution failed. + FailedHandlerExecution event should be emitted`, async () => { + const depositProposalBeforeFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[4]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalBeforeFailedExecute); + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposalsForExecution[4]] + ); + + const executeTx = await BridgeInstance.write.executeProposal([ + proposalsForExecution[4], + proposalSignedData + ], + { + account: relayer1 + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonces[4], + genericDepositProposalDataHash + ); + + const depositProposalAfterFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[4]) + ]); + + // depositNonce is used + assert.isTrue(depositProposalAfterFailedExecute); + }); + + it(`[executeProposal - XC20] - Should not revert if transferring tokens from XC20Safe to recipient failed. + FailedHandlerExecution event should be emitted`, async () => { + const depositProposalBeforeFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[0]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalBeforeFailedExecute); + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposalsForExecution[5]] + ); + + const executeTx = await BridgeInstance.write.executeProposal([ + proposalsForExecution[5], + proposalSignedData + ], + { + account: relayer1 + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonces[0], + toHex(toBytes("ERC20: call failed")) + ) + + const depositProposalAfterFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[0]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalAfterFailedExecute); + }); + + it(`[executeProposals] - Should not revert if handler execute is reverted and continue to process next execution. + FailedHandlerExecution event should be emitted with expected values.`, async () => { + const depositProposalBeforeFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[0]) + ]); + + // depositNonce is not used + assert.isFalse(depositProposalBeforeFailedExecute); + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + proposalsForExecution + ); + + // depositor makes initial deposit of depositAmount + await expect( + BridgeInstance.write.deposit([ + originDomainID, + erc721ResourceID, + erc721DepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + // check that all nonces in nonce set are 0 + const noncesSetBeforeDeposit = await BridgeInstance.read.usedNonces([ + originDomainID, + BigInt(0) + ]); + assert.equal( + decimalToPaddedBinary(noncesSetBeforeDeposit), + // nonces: ...9876543210 + "0000000000000000000000000000000000000000000000000000000000000000" + ); + + const executeTx = await BridgeInstance.write.executeProposals([ + proposalsForExecution, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonces[0], + toHex(toBytes("Something bad happened")) + ); + + const erc20depositProposalAfterFailedExecute = + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[0]) + ]); + // depositNonce for failed ERC20 deposit is unset + assert.isFalse(erc20depositProposalAfterFailedExecute); + + const erc721depositProposal = await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[1]) + ]); + // depositNonce for ERC721 deposit is used + assert.isTrue(erc721depositProposal); + + const genericDepositProposal = await BridgeInstance.read.isProposalExecuted([ + originDomainID, + BigInt(expectedDepositNonces[4]) + ]); + // depositNonce for generic deposit is used + assert.isTrue(genericDepositProposal); + + // recipient ERC20 token balances hasn't changed + const recipientERC20Balance = await ERC20MintableInstance.read.balanceOf([ + recipient + ]); + assert.strictEqual(recipientERC20Balance, BigInt(0)); + + // recipient ERC721 token balance has changed to 1 token + const recipientERC721Balance = await ERC721MintableInstance.read.balanceOf([ + recipient + ]); + assert.strictEqual(recipientERC721Balance, BigInt(1)); + + // check that other nonces in nonce set are not affected after failed deposit + const noncesSetAfterDeposit = await BridgeInstance.read.usedNonces([ + originDomainID, + BigInt(0) + ]); + assert.equal( + decimalToPaddedBinary(noncesSetAfterDeposit), + // nonces: ...9876543210 + "0000000000000000000000000000000000000000000000000000000000100100" + ); + + // check that 'ProposalExecution' event has been emitted with proper values for ERC721Revert deposit + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonces[1], + erc721DepositProposalDataHash + ); + + // check that 'ProposalExecution' event has been emitted with proper values for generic deposit + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonces[4], + genericDepositProposalDataHash + ); + }); +}); diff --git a/test/defaultMessageReceiver/direct.js b/test/defaultMessageReceiver/direct.js deleted file mode 100644 index 0dd8dabf..00000000 --- a/test/defaultMessageReceiver/direct.js +++ /dev/null @@ -1,537 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const TestForwarderContract = artifacts.require("TestForwarder"); - -contract("DefaultMessageReceiver - direct interaction", async (accounts) => { - const adminAddress = accounts[0]; - const handlerAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000111"; - const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; - - let DefaultMessageReceiverInstance; - let ERC20MintableInstance; - let TestForwarderInstance; - let TestForwarderInstance2; - let SYGMA_HANDLER_ROLE; - - beforeEach(async () => { - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([handlerAddress], 100000); - SYGMA_HANDLER_ROLE = await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(); - - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - TestForwarderInstance = await TestForwarderContract.new(); - TestForwarderInstance2 = await TestForwarderContract.new(); - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - adminAddress - ); - }); - - it("should have valid defaults", async () => { - assert.equal(await DefaultMessageReceiverInstance._recoverGas(), 100000); - assert.isTrue(await DefaultMessageReceiverInstance.hasRole(SYGMA_HANDLER_ROLE, handlerAddress)); - }); - - it("should revert if caller doesn't have sygma handler role", async () => { - await Helpers.expectToRevertWithCustomError( - DefaultMessageReceiverInstance.handleSygmaMessage.call(ZERO_ADDRESS, 0, "0x", { - from: adminAddress, - }), - "InsufficientPermission()" - ); - }); - - it("should revert on performActions if caller is not itself", async () => { - await Helpers.expectToRevertWithCustomError( - DefaultMessageReceiverInstance.performActions.call(ZERO_ADDRESS, ZERO_ADDRESS, 0, [], { - from: adminAddress, - }), - "InsufficientPermission()" - ); - }); - - it("should revert on transferBalanceAction if caller is not itself", async () => { - await Helpers.expectToRevertWithCustomError( - DefaultMessageReceiverInstance.transferBalanceAction.call(ZERO_ADDRESS, ZERO_ADDRESS, { - from: adminAddress, - }), - "InsufficientPermission()" - ); - }); - - it("should revert if message encoding is invalid", async () => { - await Helpers.reverts( - DefaultMessageReceiverInstance.handleSygmaMessage(ZERO_ADDRESS, 0, "0x11", { - from: handlerAddress, - }) - ); - }); - - it("should revert if insufficient gas limit left for executing action", async () => { - const actions = []; - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - await Helpers.expectToRevertWithCustomError( - DefaultMessageReceiverInstance.handleSygmaMessage.call(ZERO_ADDRESS, 0, message, { - from: handlerAddress, - gas: 100000, - }), - "InsufficientGasLimit()" - ); - }); - - it("should pass without actions", async () => { - const actions = []; - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - await DefaultMessageReceiverInstance.handleSygmaMessage(ZERO_ADDRESS, 0, message, { - from: handlerAddress, - gas: 200000, - }); - }); - - it("should not return native token if not received during handling", async () => { - const actions = []; - await web3.eth.sendTransaction({ - from: adminAddress, - to: DefaultMessageReceiverInstance.address, - value: 100, - }); - const message = Helpers.createMessageCallData( - transactionId, - actions, - TestForwarderInstance.address // will revert if received native - ); - await DefaultMessageReceiverInstance.handleSygmaMessage(ZERO_ADDRESS, 0, message, { - from: handlerAddress, - gas: 200000, - }); - assert.equal(await web3.eth.getBalance(DefaultMessageReceiverInstance.address), 100); - }); - - it("should return full native token balance if contract balance increased during handling", async () => { - const actions = []; - await web3.eth.sendTransaction({ - from: adminAddress, - to: DefaultMessageReceiverInstance.address, - value: 100, - }); - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const balanceBefore = await Helpers.getBalance(evmRecipientAddress); - await DefaultMessageReceiverInstance.handleSygmaMessage(ZERO_ADDRESS, 0, message, { - from: handlerAddress, - gas: 200000, - value: 100, - }); - const balanceAfter = await Helpers.getBalance(evmRecipientAddress); - assert.equal(balanceAfter, balanceBefore + 200n); - assert.equal(await Helpers.getBalance(DefaultMessageReceiverInstance.address), 0n); - }); - - it("should return full original token sent balance", async () => { - const actions = []; - await ERC20MintableInstance.mint(DefaultMessageReceiverInstance.address, 333); - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - await DefaultMessageReceiverInstance.handleSygmaMessage( - ERC20MintableInstance.address, - 333, - message, - { - from: handlerAddress, - gas: 200000, - } - ); - const balanceAfter = await Helpers.getTokenBalance(ERC20MintableInstance, evmRecipientAddress); - assert.equal(balanceAfter, 333n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, DefaultMessageReceiverInstance.address), 0n); - }); - - it("should return full native token balance if contract balance increased during handling and actions reverted", - async () => { - const actions = [{ - nativeValue: 100, - callTo: TestForwarderInstance.address, - approveTo: ZERO_ADDRESS, - tokenSend: ZERO_ADDRESS, - tokenReceive: ZERO_ADDRESS, - data: "0x", - }]; - await web3.eth.sendTransaction({ - from: adminAddress, - to: DefaultMessageReceiverInstance.address, - value: 100, - }); - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const balanceBefore = await Helpers.getBalance(evmRecipientAddress); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage(ZERO_ADDRESS, 0, message, { - from: handlerAddress, - gas: 200000, - value: 100, - }); - const balanceAfter = await Helpers.getBalance(evmRecipientAddress); - assert.equal(balanceAfter, balanceBefore + 200n); - assert.equal(await Helpers.getBalance(DefaultMessageReceiverInstance.address), 0n); - TruffleAssert.eventEmitted(tx, "TransferRecovered", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ZERO_ADDRESS && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 0 - ); - }); - }); - - it("should return full original token sent balance if actions reverted", async () => { - const actions = [{ - nativeValue: 0, - callTo: TestForwarderInstance.address, - approveTo: ZERO_ADDRESS, - tokenSend: ERC20MintableInstance.address, - tokenReceive: ZERO_ADDRESS, - data: "0x", - }]; - await ERC20MintableInstance.mint(DefaultMessageReceiverInstance.address, 333); - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage( - ERC20MintableInstance.address, - 333, - message, - { - from: handlerAddress, - gas: 200000, - } - ); - const balanceAfter = await Helpers.getTokenBalance(ERC20MintableInstance, evmRecipientAddress); - assert.equal(balanceAfter, 333n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, DefaultMessageReceiverInstance.address), 0n); - TruffleAssert.eventEmitted(tx, "TransferRecovered", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ERC20MintableInstance.address && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 333 - ); - }); - }); - - it("should return action tokens leftovers", async () => { - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: ZERO_ADDRESS, - tokenSend: ZERO_ADDRESS, - tokenReceive: ERC20MintableInstance.address, - data: (await ERC20MintableInstance.transfer.request(adminAddress, 33)).data, - }]; - await ERC20MintableInstance.mint(DefaultMessageReceiverInstance.address, 333); - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage( - ZERO_ADDRESS, - 0, - message, - { - from: handlerAddress, - gas: 200000, - } - ); - const balanceAfter = await Helpers.getTokenBalance(ERC20MintableInstance, evmRecipientAddress); - assert.equal(balanceAfter, 300n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, DefaultMessageReceiverInstance.address), 0n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, adminAddress), 33n); - TruffleAssert.eventEmitted(tx, "Executed", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ZERO_ADDRESS && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 0 - ); - }); - }); - - it("should give approval to the approveTo then revoke it", async () => { - // DMR -> TestForwarder.execute -> TestForwarder2.execute -> Token.transferFrom(DMR, admin) - const transferFrom = (await ERC20MintableInstance.transferFrom.request( - DefaultMessageReceiverInstance.address, adminAddress, 33) - ).data; - const transferFromExecute = (await TestForwarderInstance2.execute.request( - transferFrom, ERC20MintableInstance.address, ZERO_ADDRESS) - ).data; - const actions = [{ - nativeValue: 0, - callTo: TestForwarderInstance.address, - approveTo: TestForwarderInstance2.address, - tokenSend: ERC20MintableInstance.address, - tokenReceive: ZERO_ADDRESS, - data: (await TestForwarderInstance.execute.request( - transferFromExecute, TestForwarderInstance2.address, ZERO_ADDRESS) - ).data, - }]; - await ERC20MintableInstance.mint(DefaultMessageReceiverInstance.address, 333); - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage( - ERC20MintableInstance.address, - 333, - message, - { - from: handlerAddress, - gas: 500000, - } - ); - const balanceAfter = await Helpers.getTokenBalance(ERC20MintableInstance, evmRecipientAddress); - assert.equal(balanceAfter, 300n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, DefaultMessageReceiverInstance.address), 0n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, adminAddress), 33n); - TruffleAssert.eventEmitted(tx, "Executed", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ERC20MintableInstance.address && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 333 - ); - }); - assert.equal(await ERC20MintableInstance.allowance( - DefaultMessageReceiverInstance.address, TestForwarderInstance2.address), - 0n); - assert.equal(await ERC20MintableInstance.allowance( - DefaultMessageReceiverInstance.address, TestForwarderInstance.address), - 0n); - }); - - it("should revert if callTo is EOA and data is not empty", async () => { - const actions = [{ - nativeValue: 0, - callTo: adminAddress, - approveTo: ZERO_ADDRESS, - tokenSend: ZERO_ADDRESS, - tokenReceive: ZERO_ADDRESS, - data: "0x11", - }]; - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage( - ZERO_ADDRESS, - 0, - message, - { - from: handlerAddress, - gas: 200000, - } - ); - TruffleAssert.eventEmitted(tx, "TransferRecovered", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ZERO_ADDRESS && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 0 - ); - }); - }); - - it("should succeed if callTo is EOA and data is empty", async () => { - const actions = [{ - nativeValue: 0, - callTo: adminAddress, - approveTo: ZERO_ADDRESS, - tokenSend: ZERO_ADDRESS, - tokenReceive: ZERO_ADDRESS, - data: "0x", - }]; - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage( - ZERO_ADDRESS, - 0, - message, - { - from: handlerAddress, - gas: 200000, - } - ); - TruffleAssert.eventEmitted(tx, "Executed", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ZERO_ADDRESS && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 0 - ); - }); - }); - - it("should send native token as part of the action", async () => { - const actions = [{ - nativeValue: 100, - callTo: relayer1Address, - approveTo: ZERO_ADDRESS, - tokenSend: ZERO_ADDRESS, - tokenReceive: ZERO_ADDRESS, - data: "0x", - }]; - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - const balanceBefore = await Helpers.getBalance(relayer1Address); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage( - ZERO_ADDRESS, - 0, - message, - { - from: handlerAddress, - gas: 200000, - value: 300, - } - ); - const balanceAfter = await Helpers.getBalance(relayer1Address); - assert.equal(balanceAfter, balanceBefore + 100n); - assert.equal(await Helpers.getBalance(DefaultMessageReceiverInstance.address), 0n); - TruffleAssert.eventEmitted(tx, "Executed", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ZERO_ADDRESS && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 0 - ); - }); - }); - - it("should revert if has too little gas after actions", async () => { - // DMR -> TestForwarder.execute -> TestForwarder2.execute -> Token.transferFrom(DMR, admin) - const transferFrom = (await ERC20MintableInstance.transferFrom.request( - DefaultMessageReceiverInstance.address, adminAddress, 33) - ).data; - const transferFromExecute = (await TestForwarderInstance2.execute.request( - transferFrom, ERC20MintableInstance.address, ZERO_ADDRESS) - ).data; - const actions = [{ - nativeValue: 0, - callTo: TestForwarderInstance.address, - approveTo: TestForwarderInstance2.address, - tokenSend: ERC20MintableInstance.address, - tokenReceive: ZERO_ADDRESS, - data: (await TestForwarderInstance.execute.request( - transferFromExecute, TestForwarderInstance2.address, ZERO_ADDRESS) - ).data, - }]; - await ERC20MintableInstance.mint(DefaultMessageReceiverInstance.address, 333); - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - await Helpers.expectToRevertWithCustomError( - DefaultMessageReceiverInstance.handleSygmaMessage.call( - ERC20MintableInstance.address, - 333, - message, - { - from: handlerAddress, - gas: 200000, - } - ), - "InsufficientGasLimit()" - ); - }); - - it("should execute transferBalanceAction", async () => { - const actions = [{ - nativeValue: 0, - callTo: DefaultMessageReceiverInstance.address, - approveTo: ZERO_ADDRESS, - tokenSend: ZERO_ADDRESS, - tokenReceive: ZERO_ADDRESS, - data: (await DefaultMessageReceiverInstance.transferBalanceAction.request( - ZERO_ADDRESS, relayer1Address) - ).data, - }, { - nativeValue: 0, - callTo: DefaultMessageReceiverInstance.address, - approveTo: ZERO_ADDRESS, - tokenSend: ZERO_ADDRESS, - tokenReceive: ZERO_ADDRESS, - data: (await DefaultMessageReceiverInstance.transferBalanceAction.request( - ERC20MintableInstance.address, relayer1Address) - ).data, - }]; - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - await ERC20MintableInstance.mint(DefaultMessageReceiverInstance.address, 333); - const balanceBefore = await Helpers.getBalance(relayer1Address); - const tx = await DefaultMessageReceiverInstance.handleSygmaMessage( - ZERO_ADDRESS, - 0, - message, - { - from: handlerAddress, - gas: 200000, - value: 300, - } - ); - const balanceAfter = await Helpers.getBalance(relayer1Address); - assert.equal(balanceAfter, balanceBefore + 300n); - assert.equal(await Helpers.getBalance(DefaultMessageReceiverInstance.address), 0n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, DefaultMessageReceiverInstance.address), 0n); - assert.equal(await Helpers.getTokenBalance(ERC20MintableInstance, relayer1Address), 333n); - TruffleAssert.eventEmitted(tx, "Executed", (event) => { - return ( - event.transactionId === transactionId && - event.tokenSend === ZERO_ADDRESS && - event.receiver === evmRecipientAddress && - event.amount.toNumber() === 0 - ); - }); - }); -}); diff --git a/test/defaultMessageReceiver/direct.test.ts b/test/defaultMessageReceiver/direct.test.ts new file mode 100644 index 00000000..51c509f3 --- /dev/null +++ b/test/defaultMessageReceiver/direct.test.ts @@ -0,0 +1,560 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {encodeFunctionData, Hex, toHex, WalletClient, zeroAddress} from "viem"; +import {createMessageCallData, deploySourceChainContracts, getBalance} from "../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; +import {Action} from '../../types'; + + +describe("DefaultMessageReceiver - direct interaction", () => { + const transactionId = toHex(11, {size:32}); + + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ForwarderInstance1: ContractTypesMap["Forwarder"]; + let ForwarderInstance2: ContractTypesMap["Forwarder"]; + + let admin: WalletClient; + let handlerMock: WalletClient + let recipient: WalletClient; + let relayer1: WalletClient; + + let SYGMA_HANDLER_ROLE: Hex; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + ERC20MintableInstance, + ERC20MintableInstance, + ForwarderInstance: ForwarderInstance1, + ForwarderInstance: ForwarderInstance2, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + handlerMock, + recipient, + relayer1, + ] = await hre.viem.getWalletClients(); + SYGMA_HANDLER_ROLE = await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + admin.account!.address + ]); + }); + + it("should have valid defaults", async () => { + assert.equal(await DefaultMessageReceiverInstance.read._recoverGas(), recoveredGas); + assert.isTrue(await DefaultMessageReceiverInstance.read.hasRole([SYGMA_HANDLER_ROLE, handlerMock.account!.address])); + }); + + it("should revert if caller doesn't have sygma handler role", async () => { + await expect( + DefaultMessageReceiverInstance.write.handleSygmaMessage([zeroAddress, 0, "0x"], { + account: admin.account, + }), + ).to.be.revertedWithCustomError(DefaultMessageReceiverInstance, "InsufficientPermission()"); + }); + + it("should revert on performActions if caller is not itself", async () => { + await expect( + DefaultMessageReceiverInstance.write.performActions([zeroAddress, zeroAddress, BigInt(0), []], { + account: admin.account, + }), + ).to.be.revertedWithCustomError(DefaultMessageReceiverInstance, "InsufficientPermission()"); + }); + + it("should revert on transferBalanceAction if caller is not itself", async () => { + await expect( + DefaultMessageReceiverInstance.write.transferBalanceAction([zeroAddress, zeroAddress], { + account: admin.account, + }), + ).to.be.revertedWithCustomError(DefaultMessageReceiverInstance, "InsufficientPermission()"); + }); + + it("should revert if message encoding is invalid", async () => { + await expect( + DefaultMessageReceiverInstance.write.handleSygmaMessage([zeroAddress, 0, "0x11"], { + account: handlerMock.account, + }) + ).to.be.reverted; + }); + + it("should revert if insufficient gas limit left for executing action", async () => { + const actions: Array = []; + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + await expect( + DefaultMessageReceiverInstance.write.handleSygmaMessage([zeroAddress, BigInt(0), message], { + account: handlerMock.account, + gas: recoveredGas, + }), + ).to.be.revertedWithCustomError(DefaultMessageReceiverInstance, "InsufficientGasLimit()"); + }); + + it("should pass without actions", async () => { + const actions: Array = []; + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + await DefaultMessageReceiverInstance.write.handleSygmaMessage([zeroAddress, 0, message], { + account: handlerMock.account, + gas: 200000, + }); + }); + + it("should not return native token if not received during handling", async () => { + const actions: Array = []; + await web3.eth.sendTransaction({ + account: admin.account, + to: DefaultMessageReceiverInstance.address, + value: 100, + }); + const message = createMessageCallData( + transactionId, + actions, + ForwarderInstance1.address // will revert if received native + ); + await DefaultMessageReceiverInstance.write.handleSygmaMessage([zeroAddress, BigInt(0), message], { + account: handlerMock.account, + gas: 200000, + }); + assert.equal(await getBalance(DefaultMessageReceiverInstance), BigInt(100)); + }); + + it("should return full native token balance if contract balance increased during handling", async () => { + const actions: Array = []; + await web3.eth.sendTransaction({ + account: admin.account, + to: DefaultMessageReceiverInstance.address, + value: 100, + }); + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + const relayerBalanceBefore = await getBalance(recipient); + await DefaultMessageReceiverInstance.write.handleSygmaMessage([zeroAddress, BigInt(0), message], { + account: handlerMock.account, + gas: BigInt(200000), + value: BigInt(100), + }); + const balanceAfter = await getBalance(recipient); + assert.equal(balanceAfter, relayerBalanceBefore + BigInt(200)); + assert.equal(await getBalance(DefaultMessageReceiverInstance), BigInt(0)); + }); + + it("should return full original token sent balance", async () => { + const actions: Array = []; + await ERC20MintableInstance.write.mint([DefaultMessageReceiverInstance.address, BigInt(333)]); + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + ERC20MintableInstance.address, + BigInt(333), + message], + { + from: handlerMock, + gas: BigInt(200000), + } + ); + const balanceAfter = await ERC20MintableInstance.read.balanceOf([recipient.account!.address]); + assert.equal(balanceAfter, BigInt(333)); + assert.equal(await ERC20MintableInstance.read.balanceOf([DefaultMessageReceiverInstance.address]), BigInt(0)); + }); + + it("should return full native token balance if contract balance increased during handling and actions reverted", + async () => { + const actions = [{ + nativeValue: BigInt(100), + callTo: ForwarderInstance1.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: "0x" as unknown as Hex, + }]; + await web3.eth.sendTransaction({ + from: admin, + to: DefaultMessageReceiverInstance.address, + value: 100, + }); + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + const relayerBalanceBefore = await getBalance(recipient); + const handlerMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([zeroAddress, BigInt(0), message], { + account: handlerMock.account, + gas: BigInt(200000), + value: BigInt(100), + }); + const balanceAfter = await getBalance(recipient); + assert.equal(balanceAfter, relayerBalanceBefore + BigInt(200)); + assert.equal(await getBalance(DefaultMessageReceiverInstance), BigInt(0)); + + await expect(handlerMessageTx).to.emit(DefaultMessageReceiverInstance, "TransferRecovered").withArgs( + transactionId, + zeroAddress, + [recipient.account!.address], + 0 + ); + }); + + it("should return full original token sent balance if actions reverted", async () => { + const actions = [{ + nativeValue: BigInt(0), + callTo: ForwarderInstance1.address, + approveTo: zeroAddress, + tokenSend: ERC20MintableInstance.address, + tokenReceive: zeroAddress, + data: "0x" as unknown as Hex, + }]; + await ERC20MintableInstance.write.mint([DefaultMessageReceiverInstance.address, BigInt(333)]); + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + const handlerMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + ERC20MintableInstance.address, + BigInt(333), + message], + { + from: handlerMock, + gas: BigInt(200000), + } + ); + const balanceAfter = await ERC20MintableInstance.read.balanceOf([recipient.account!.address]); + assert.equal(balanceAfter, BigInt(333)); + assert.equal(await ERC20MintableInstance.read.balanceOf([DefaultMessageReceiverInstance.address]), BigInt(0)); + + await expect(handlerMessageTx).to.emit(DefaultMessageReceiverInstance,"TransferRecovered").withArgs( + transactionId, + ERC20MintableInstance.address, + [recipient.account!.address], + 333 + ); + }); + + it("should return action tokens leftovers", async () => { + const actionData = encodeFunctionData({ + abi: ["transfer(address recipient, uint256 amount)"], + functionName: "transfer", + args: [admin, 33] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC20MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: ERC20MintableInstance.address, + data: actionData as unknown as Hex, + }]; + await ERC20MintableInstance.write.mint([DefaultMessageReceiverInstance.address, BigInt(333)]); + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + const handleMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + zeroAddress, + BigInt(0), + message], + { + account: handlerMock.account, + gas: BigInt(200000), + } + ); + const balanceAfter = await ERC20MintableInstance.read.balanceOf([recipient.account!.address]); + assert.equal(balanceAfter, BigInt(300)); + assert.equal(await ERC20MintableInstance.read.balanceOf([DefaultMessageReceiverInstance.address]), BigInt(0)); + assert.equal(await ERC20MintableInstance.read.balanceOf([admin.account!.address]), BigInt(33)); + + await expect(handleMessageTx).to.emit(DefaultMessageReceiverInstance, "Executed").withArgs( + transactionId, + zeroAddress, + recipient.account!.address, + 0 + ); + }); + + it("should give approval to the approveTo then revoke it", async () => { + // DMR -> Forwarder.execute -> Forwarder2.execute -> Token.transferFrom(DMR, admin) + const transferFromActionData = encodeFunctionData({ + abi: ["transferFrom(address sender, address recipient, uint256 amount)"], + functionName: "transferFrom", + args: [DefaultMessageReceiverInstance.address, admin.account!.address, 33] + }); + const transferFromExecuteActionData = encodeFunctionData({ + abi: ["execute(ForwardRequest req, bytes signature)"], + functionName: "execute", + args: [transferFromActionData, ERC20MintableInstance.address, zeroAddress] + }); + const actionData = encodeFunctionData({ + abi: ["execute(ForwardRequest req, bytes signature)"], + functionName: "execute", + args: [transferFromExecuteActionData, ForwarderInstance2.address, zeroAddress] + }); + const actions = [{ + nativeValue: BigInt(0), + callTo: ForwarderInstance1.address, + approveTo: ForwarderInstance2.address, + tokenSend: ERC20MintableInstance.address, + tokenReceive: zeroAddress, + data: actionData, + }]; + + await ERC20MintableInstance.write.mint([DefaultMessageReceiverInstance.address, BigInt(333)]); + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + const handlerMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + ERC20MintableInstance.address, + BigInt(333), + message], + { + from: handlerMock.account, + gas: BigInt(500000), + } + ); + const balanceAfter = await ERC20MintableInstance.read.balanceOf([recipient.account!.address]); + assert.equal(balanceAfter, BigInt(300)); + assert.equal(await ERC20MintableInstance.read.balanceOf([DefaultMessageReceiverInstance.address]), BigInt(0)); + assert.equal(await ERC20MintableInstance.read.balanceOf([admin.account!.address]), BigInt(33)); + await expect(handlerMessageTx).to.emit(DefaultMessageReceiverInstance, "Executed").withArgs( + transactionId, + ERC20MintableInstance.address, + recipient, + BigInt(333) + ); + assert.equal(await ERC20MintableInstance.read.allowance([ + DefaultMessageReceiverInstance.address, ForwarderInstance2.address]), + BigInt(0) + ); + assert.equal(await ERC20MintableInstance.read.allowance([ + DefaultMessageReceiverInstance.address, ForwarderInstance1.address]), + BigInt(0) + ); + }); + + it("should revert if callTo is EOA and data is not empty", async () => { + const actions = [{ + nativeValue: BigInt(0), + callTo: admin.account!.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: "0x11" as unknown as Hex, + }]; + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + const handlerMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + zeroAddress, + BigInt(0), + message], + { + account: handlerMock.account, + gas: BigInt(200000), + } + ); + await expect(handlerMessageTx).to.emit(DefaultMessageReceiverInstance, "TransferRecovered").withArgs( + transactionId, + zeroAddress, + recipient, + BigInt(0) + ); + }); + + it("should succeed if callTo is EOA and data is empty", async () => { + const actions = [{ + nativeValue: BigInt(0), + callTo: admin.account!.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: "0x" as unknown as Hex, + }]; + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + const handlerMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + zeroAddress, + BigInt(0), + message], + { + account: handlerMock.account, + gas: BigInt(200000), + } + ); + + await expect(handlerMessageTx).to.emit(DefaultMessageReceiverInstance, "Executed").withArgs( + transactionId, + zeroAddress, + recipient.account!.address, + 0 + ); + }); + + it("should send native token as part of the action", async () => { + const actions = [{ + nativeValue: BigInt(100), + callTo: relayer1.account!.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: "0x" as unknown as Hex, + }]; + const message = createMessageCallData( + transactionId, + actions, + recipient + ); + const relayerBalanceBefore = await getBalance(relayer1); + const handleMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + zeroAddress, + BigInt(0), + message], + { + from: handlerMock, + gas: BigInt(200000), + value: BigInt(300), + } + ); + const balanceAfter = await getBalance(relayer1); + assert.equal(balanceAfter, relayerBalanceBefore + BigInt(100)); + assert.equal(await getBalance(DefaultMessageReceiverInstance), BigInt(0)); + + await expect(handleMessageTx).to.emit(DefaultMessageReceiverInstance, "Executed").withArgs( + transactionId, + zeroAddress, + recipient.account!.address, + 0 + ); + }); + + it("should revert if has too little gas after actions", async () => { + // DMR -> Forwarder.execute -> Forwarder2.execute -> Token.transferFrom(DMR, admin) + const transferFromActionData = encodeFunctionData({ + abi: ["transferFrom(address sender, address recipient, uint256 amount)"], + functionName: "transferFrom", + args: [DefaultMessageReceiverInstance.address, admin.account!.address, 33] + }); + const transferFromExecuteActionData = encodeFunctionData({ + abi: ["execute(ForwardRequest req, bytes signature)"], + functionName: "execute", + args: [transferFromActionData, ERC20MintableInstance.address, zeroAddress] + }); + const actionData = encodeFunctionData({ + abi: ["execute(ForwardRequest req, bytes signature)"], + functionName: "execute", + args: [transferFromExecuteActionData, ForwarderInstance2.address, zeroAddress] + }); + const actions = [{ + nativeValue: BigInt(0), + callTo: ForwarderInstance1.address, + approveTo: ForwarderInstance2.address, + tokenSend: ERC20MintableInstance.address, + tokenReceive: zeroAddress, + data: actionData, + }]; + + await ERC20MintableInstance.write.mint([DefaultMessageReceiverInstance.address, BigInt(333)]); + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + await expect( + DefaultMessageReceiverInstance.write.handleSygmaMessage([ + ERC20MintableInstance.address, + BigInt(333), + message], + { + account: handlerMock.account, + gas: BigInt(200000), + } + ), + ).to.be.revertedWithCustomError(DefaultMessageReceiverInstance, "InsufficientGasLimit()"); + }); + + it("should execute transferBalanceAction", async () => { + const transferBalanceActionData1 = encodeFunctionData({ + abi: ["transferBalanceAction(address token, address receiver)"], + functionName: "transferBalanceAction", + args: [zeroAddress, relayer1.account!.address] + }); + + const transferBalanceActionData2 = encodeFunctionData({ + abi: ["transferBalanceAction(address token, address receiver)"], + functionName: "transferBalanceAction", + args: [ERC20MintableInstance.address, relayer1.account!.address] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: DefaultMessageReceiverInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: transferBalanceActionData1, + }, { + nativeValue: BigInt(0), + callTo: DefaultMessageReceiverInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: transferBalanceActionData2, + }]; + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + await ERC20MintableInstance.write.mint([DefaultMessageReceiverInstance.address, BigInt(333)]); + const relayerBalanceBefore = await getBalance(relayer1); + const handlerMessageTx = await DefaultMessageReceiverInstance.write.handleSygmaMessage([ + zeroAddress, + BigInt(0), + message], + { + from: handlerMock, + gas: BigInt(200000), + value: BigInt(300), + } + ); + const balanceAfter = await getBalance(relayer1); + assert.equal(balanceAfter, relayerBalanceBefore + BigInt(300)); + assert.equal(await getBalance(DefaultMessageReceiverInstance), BigInt(0)); + assert.equal(await ERC20MintableInstance.read.balanceOf([DefaultMessageReceiverInstance.address]), BigInt(0)); + assert.equal(await ERC20MintableInstance.read.balanceOf([relayer1.account!.address]), BigInt(333)); + + await expect(handlerMessageTx).to.emit(DefaultMessageReceiverInstance, "Executed").withArgs( + transactionId, + zeroAddress, + recipient, + 0 + ); + }); +}); diff --git a/test/defaultMessageReceiver/executeProposal.js b/test/defaultMessageReceiver/executeProposal.js deleted file mode 100644 index 5d73c9ab..00000000 --- a/test/defaultMessageReceiver/executeProposal.js +++ /dev/null @@ -1,263 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler"); -const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("Bridge - [execute proposal - native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const depositAmount = Ethers.utils.parseEther("1"); - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = depositAmount.sub(fee); - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let NativeTokenHandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let NativeTokenAdapterInstance; - let ERC20MintableInstance; - let proposal; - let depositProposalData; - let message; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - NativeTokenAdapterInstance = await NativeTokenAdapterContract.new( - BridgeInstance.address, - resourceID - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - NativeTokenHandlerInstance = await NativeTokenHandlerContract.new( - BridgeInstance.address, - NativeTokenAdapterInstance.address, - DefaultMessageReceiverInstance.address, - ); - await DefaultMessageReceiverInstance.grantRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - NativeTokenHandlerInstance.address - ); - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - - await BridgeInstance.adminSetResource( - NativeTokenHandlerInstance.address, - resourceID, - Ethers.constants.AddressZero, - emptySetResourceData - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should revert if handler does not have SYGMA_HANDLER_ROLE", async () => { - await DefaultMessageReceiverInstance.revokeRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - NativeTokenHandlerInstance.address - ); - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - executionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.lowLevelData === "0xdeda9030" // InsufficientPermission() - ); - }); - }); - - it("should revert if insufficient gas limit left for executing action", async () => { - const insufficientExecutionGasAmount = 100000; - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - NativeTokenAdapterInstance.depositToEVMWithMessage( - originDomainID, - Ethers.constants.AddressZero, - insufficientExecutionGasAmount, - message, - { - from: depositorAddress, - value: depositAmount - }) - ); - - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: insufficientExecutionGasAmount - } - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.lowLevelData === "0x60ee1247" // InsufficientGasLimit() - ); - }); - }); - - it("should fail to transfer funds if invalid message is provided", async () => { - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: Ethers.constants.AddressZero, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]), - }] - const message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - const depositProposalData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - const proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.lowLevelData === "0x2ed7fc0e" // FailedFundsTransfer() - ); - }); - }); -}); diff --git a/test/defaultMessageReceiver/executeProposal.test.ts b/test/defaultMessageReceiver/executeProposal.test.ts new file mode 100644 index 00000000..35c8a2bd --- /dev/null +++ b/test/defaultMessageReceiver/executeProposal.test.ts @@ -0,0 +1,254 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {encodeFunctionData, Hex, parseEther, toHex, WalletClient, zeroAddress} from "viem"; +import {createMessageCallData, createMessageCallData, createOptionalContractCallDepositData, deploySourceChainContracts, mpcAddress} from "../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; +import {Action, Proposal} from '../../types'; + + +describe("Bridge - [execute proposal - native token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const depositAmount = parseEther("1"); + const fee = parseEther("0.1"); + const transferredAmount = depositAmount - fee; + const transactionId = toHex(11, {size:32}); + const executionGasAmount = BigInt(30000000); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let NativeTokenHandlerInstance: ContractTypesMap["NativeTokenHandler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let NativeTokenTransferGatewayInstance: ContractTypesMap["NativeTokenTransferGateway"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let proposal: Proposal; + let depositProposalData: Hex; + let message: Hex; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + NativeTokenHandlerInstance, + BasicFeeHandlerInstance, + FeeHandlerRouterInstance, + NativeTokenTransferGatewayInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + relayer1, + ] = await hre.viem.getWalletClients(); + + await DefaultMessageReceiverInstance.write.grantRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + NativeTokenHandlerInstance.address + ]); + + await BridgeInstance.write.adminSetResource([ + NativeTokenHandlerInstance.address, + resourceID, + zeroAddress, + emptySetResourceData + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + originDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 amount)"], + functionName: "mint", + args: [recipient, "20"] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC20MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + transferredAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should revert if handler does not have SYGMA_HANDLER_ROLE", async () => { + await DefaultMessageReceiverInstance.write.revokeRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + NativeTokenHandlerInstance.address + ]); + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + executionGasAmount, + message], + { + account: depositor.account, + value: depositAmount + }) + ).not.to.be.reverted; + + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonce, + "0xdeda9030" // InsufficientPermission() + ); + }); + + it("should revert if insufficient gas limit left for executing action", async () => { + const insufficientExecutionGasAmount = BigInt(100000); + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + NativeTokenTransferGatewayInstance.write.depositToEVMWithMessage([ + originDomainID, + zeroAddress, + insufficientExecutionGasAmount, + message], + { + from: depositor, + value: depositAmount + }) + ).not.to.be.reverted; + + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + { + account: relayer1.account, + gas: insufficientExecutionGasAmount + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonce, + "0x60ee1247" // InsufficientGasLimit() + ); + }); + + it("should fail to transfer funds if invalid message is provided", async () => { + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 amount)"], + functionName: "mint", + args: [recipient.account!.address, "20"] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: zeroAddress, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData + }] + const message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + + const depositProposalData = createOptionalContractCallDepositData( + transferredAmount, + zeroAddress, + executionGasAmount, + message + ); + + const proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + + await expect(executeTx).to.emit(BridgeInstance, "FailedHandlerExecution").withArgs( + originDomainID, + expectedDepositNonce, + "0x2ed7fc0e" // FailedFundsTransfer() + ); + }); +}); diff --git a/test/e2e/erc1155/differentChainsMock.js b/test/e2e/erc1155/differentChainsMock.js deleted file mode 100644 index 8da668a9..00000000 --- a/test/e2e/erc1155/differentChainsMock.js +++ /dev/null @@ -1,293 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../helpers"); - -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); - -contract("E2E ERC1155 - Two EVM Chains", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const originRelayer2Address = accounts[3]; - const destinationRelayer1Address = accounts[4]; - - const tokenID = 1; - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let OriginBridgeInstance; - let OriginERC1155MintableInstance; - let OriginERC1155HandlerInstance; - let originDepositData; - let originDepositProposalData; - let originResourceID; - - let DestinationBridgeInstance; - let DestinationERC1155MintableInstance; - let DestinationERC1155HandlerInstance; - let destinationDepositData; - let destinationDepositProposalData; - let destinationResourceID; - let destinationBurnableContractAddresses; - - let originDomainProposal; - let destinationDomainProposal; - - beforeEach(async () => { - await Promise.all([ - (OriginBridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - (DestinationBridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC1155MintableContract.new("TOK").then( - (instance) => (OriginERC1155MintableInstance = instance) - ), - ERC1155MintableContract.new("TOK").then( - (instance) => (DestinationERC1155MintableInstance = instance) - ), - ]); - - originResourceID = Helpers.createResourceID( - OriginERC1155MintableInstance.address, - originDomainID - ); - originInitialResourceIDs = [originResourceID]; - originInitialContractAddresses = [OriginERC1155MintableInstance.address]; - originBurnableContractAddresses = []; - - destinationResourceID = Helpers.createResourceID( - DestinationERC1155MintableInstance.address, - originDomainID - ); - destinationInitialResourceIDs = [destinationResourceID]; - destinationInitialContractAddresses = [ - DestinationERC1155MintableInstance.address, - ]; - destinationBurnableContractAddresses = [ - DestinationERC1155MintableInstance.address, - ]; - - await Promise.all([ - ERC1155HandlerContract.new(OriginBridgeInstance.address).then( - (instance) => (OriginERC1155HandlerInstance = instance) - ), - ERC1155HandlerContract.new(DestinationBridgeInstance.address).then( - (instance) => (DestinationERC1155HandlerInstance = instance) - ), - ]); - - await OriginERC1155MintableInstance.mintBatch( - depositorAddress, - [tokenID], - [initialTokenAmount], - "0x0" - ); - - await Promise.all([ - OriginERC1155MintableInstance.setApprovalForAll( - OriginERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ), - DestinationERC1155MintableInstance.grantRole( - await DestinationERC1155MintableInstance.MINTER_ROLE(), - DestinationERC1155HandlerInstance.address - ), - await OriginBridgeInstance.adminSetResource( - OriginERC1155HandlerInstance.address, - originResourceID, - OriginERC1155MintableInstance.address, - emptySetResourceData - ), - await DestinationBridgeInstance.adminSetResource( - DestinationERC1155HandlerInstance.address, - destinationResourceID, - DestinationERC1155MintableInstance.address, - emptySetResourceData - ), - DestinationBridgeInstance.adminSetBurnable( - DestinationERC1155HandlerInstance.address, - destinationBurnableContractAddresses[0] - ), - ]); - - originDepositData = Helpers.createERC1155DepositData( - [tokenID], - [depositAmount] - ); - originDepositProposalData = Helpers.createERC1155DepositProposalData( - [tokenID], - [depositAmount], - recipientAddress, - "0x" - ); - - destinationDepositData = Helpers.createERC1155DepositData( - [tokenID], - [depositAmount] - ); - destinationDepositProposalData = Helpers.createERC1155DepositProposalData( - [tokenID], - [depositAmount], - depositorAddress, - "0x" - ); - - originDomainProposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: originDepositProposalData, - resourceID: destinationResourceID, - }; - - destinationDomainProposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - data: destinationDepositProposalData, - resourceID: originResourceID, - }; - - // set MPC address to unpause the Bridge - await OriginBridgeInstance.endKeygen(Helpers.mpcAddress); - await DestinationBridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositorAddress' balance of tokenID should be equal to initialTokenAmount", async () => { - const depositorBalance = await OriginERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.strictEqual(depositorBalance.toNumber(), initialTokenAmount); - }); - - it(`[sanity] DestinationERC1155HandlerInstance.address should have - minterRole for DestinationERC1155MintableInstance`, async () => { - const isMinter = await DestinationERC1155MintableInstance.hasRole( - await DestinationERC1155MintableInstance.MINTER_ROLE(), - DestinationERC1155HandlerInstance.address - ); - assert.isTrue(isMinter); - }); - - it(`E2E: tokenID of Origin ERC1155 owned by depositAddress to Destination ERC1155 - owned by recipientAddress and back again`, async () => { - const originProposalSignedData = await Helpers.signTypedProposal( - DestinationBridgeInstance.address, - [originDomainProposal] - ); - const destinationProposalSignedData = await Helpers.signTypedProposal( - OriginBridgeInstance.address, - [destinationDomainProposal] - ); - - let depositorBalance; - let recipientBalance; - - // depositorAddress makes initial deposit of tokenID - await TruffleAssert.passes( - OriginBridgeInstance.deposit( - destinationDomainID, - originResourceID, - originDepositData, - feeData, - {from: depositorAddress} - ) - ); - - depositorBalance = await OriginERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.strictEqual( - depositorBalance.toNumber(), - initialTokenAmount - depositAmount - ); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - DestinationBridgeInstance.executeProposal( - originDomainProposal, - originProposalSignedData, - {from: destinationRelayer1Address} - ) - ); - - depositorBalance = await OriginERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.strictEqual( - depositorBalance.toNumber(), - initialTokenAmount - depositAmount, - "depositAmount wasn't transferred from depositorAddress" - ); - - recipientBalance = await DestinationERC1155MintableInstance.balanceOf( - recipientAddress, - tokenID - ); - assert.strictEqual( - recipientBalance.toNumber(), - depositAmount, - "depositAmount wasn't transferred to recipientAddress" - ); - - await DestinationERC1155MintableInstance.setApprovalForAll( - DestinationERC1155HandlerInstance.address, - true, - {from: recipientAddress} - ); - - // recipientAddress makes a deposit of the received depositAmount - await TruffleAssert.passes( - DestinationBridgeInstance.deposit( - originDomainID, - destinationResourceID, - destinationDepositData, - feeData, - {from: recipientAddress} - ) - ); - - // Recipient should have a balance of 0 (deposit amount - deposit amount) - recipientBalance = await DestinationERC1155MintableInstance.balanceOf( - recipientAddress, - tokenID - ); - assert.strictEqual(recipientBalance.toNumber(), 0); - - // originRelayer2 executes the proposal - await TruffleAssert.passes( - OriginBridgeInstance.executeProposal( - destinationDomainProposal, - destinationProposalSignedData, - {from: originRelayer2Address} - ) - ); - recipientBalance = await DestinationERC1155MintableInstance.balanceOf( - recipientAddress, - tokenID - ); - assert.strictEqual(recipientBalance.toNumber(), 0); - - depositorBalance = await OriginERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.strictEqual(depositorBalance.toNumber(), initialTokenAmount); - }); -}); diff --git a/test/e2e/erc1155/differentChainsMock.test.ts b/test/e2e/erc1155/differentChainsMock.test.ts new file mode 100644 index 00000000..5fd6c544 --- /dev/null +++ b/test/e2e/erc1155/differentChainsMock.test.ts @@ -0,0 +1,281 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; +import { deploySourceChainContracts, deployDestinationChainContracts, mpcAddress, signTypedProposal, createERC1155DepositData, createERC1155DepositProposalData, createResourceID} from "../../helpers"; + +describe("E2E ERC1155 - Two EVM Chains", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const tokenID = BigInt(1); + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = 1; + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let OriginBridgeInstance: ContractTypesMap["Bridge"]; + let OriginDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let OriginERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let OriginERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + + let originDepositProposalData: Hex; + let originDepositData: Hex; + let originResourceID: Hex;; + let originDomainProposal: Proposal; + let originDepositProposalDataHash: Hex; + + let DestinationBridgeInstance: ContractTypesMap["Bridge"];; + let DestinationDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let DestinationERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let DestinationERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + + let destinationDepositData: Hex; + let destinationDepositProposalData: Hex; + let destinationResourceID: Hex; + let destinationDomainProposal: Proposal; + let destinationDepositProposalDataHash: Hex; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let originRelayer1: WalletClient; + let destinationRelayer1: WalletClient; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance: OriginDefaultMessageReceiverInstance, + BridgeInstance: OriginBridgeInstance, + ERC1155MintableInstance: OriginERC1155MintableInstance, + ERC1155HandlerInstance: OriginERC1155HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + ({ + DefaultMessageReceiverInstance: DestinationDefaultMessageReceiverInstance, + BridgeInstance: DestinationBridgeInstance, + ERC1155MintableInstance: DestinationERC1155MintableInstance, + ERC1155HandlerInstance: DestinationERC1155HandlerInstance, + } = await loadFixture(deployDestinationChainContracts)); + [ + admin, + depositor, + recipient, + originRelayer1, + + destinationRelayer1, + ] = await hre.viem.getWalletClients(); + + + originResourceID = createResourceID( + OriginERC1155MintableInstance.address, + originDomainID + ); + + destinationResourceID = createResourceID( + DestinationERC1155MintableInstance.address, + originDomainID + ); + + await OriginERC1155MintableInstance.write.mintBatch([ + depositor.account!.address, + [tokenID], + [initialTokenAmount], + "0x0" + ]); + + await OriginERC1155MintableInstance.write.setApprovalForAll([ + OriginERC1155HandlerInstance.address, + true], + {account: depositor.account} + ); + await DestinationERC1155MintableInstance.write.grantRole([ + await DestinationERC1155MintableInstance.read.MINTER_ROLE(), + DestinationERC1155HandlerInstance.address + ]); + await OriginBridgeInstance.write.adminSetResource([ + OriginERC1155HandlerInstance.address, + originResourceID, + OriginERC1155MintableInstance.address, + emptySetResourceData + ]); + await DestinationBridgeInstance.write.adminSetResource([ + DestinationERC1155HandlerInstance.address, + destinationResourceID, + DestinationERC1155MintableInstance.address, + emptySetResourceData + ]); + await DestinationBridgeInstance.write.adminSetBurnable([ + DestinationERC1155HandlerInstance.address, + DestinationERC1155MintableInstance.address + ]); + + originDepositData = createERC1155DepositData( + [tokenID], + [depositAmount] + ); + originDepositProposalData = createERC1155DepositProposalData( + [tokenID], + [depositAmount], + recipient.account!.address, + "0x" + ); + + destinationDepositData = createERC1155DepositData( + [tokenID], + [depositAmount] + ); + destinationDepositProposalData = createERC1155DepositProposalData( + [tokenID], + [depositAmount], + depositor.account!.address, + "0x" + ); + + originDomainProposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: originDepositProposalData, + resourceID: destinationResourceID, + }; + + destinationDomainProposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + data: destinationDepositProposalData, + resourceID: originResourceID, + }; + + // set MPC address to unpause the Bridge + await OriginBridgeInstance.write.endKeygen([mpcAddress]); + await DestinationBridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor' balance of tokenID should be equal to initialTokenAmount", async () => { + const depositorBalance = await OriginERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); + + it(`[sanity] DestinationERC1155HandlerInstance.address should have + minterRole for DestinationERC1155MintableInstance`, async () => { + const isMinter = await DestinationERC1155MintableInstance.read.hasRole([ + await DestinationERC1155MintableInstance.read.MINTER_ROLE(), + DestinationERC1155HandlerInstance.address + ]); + assert.isTrue(isMinter); + }); + + it(`E2E: tokenID of Origin ERC1155 owned by depositAddress to Destination ERC1155 + owned by recipient and back again`, async () => { + const originProposalSignedData = await signTypedProposal( + DestinationBridgeInstance.address, + [originDomainProposal] + ); + const destinationProposalSignedData = await signTypedProposal( + OriginBridgeInstance.address, + [destinationDomainProposal] + ); + + let depositorBalance; + let recipientBalance; + + // depositor makes initial deposit of tokenID + await expect( + OriginBridgeInstance.write.deposit([ + destinationDomainID, + originResourceID, + originDepositData, + feeData], + {account: depositor.account} + ) + ).not.to.be.reverted; + + depositorBalance = await OriginERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - depositAmount + ); + + // destinationRelayer1 executes the proposal + await expect( + DestinationBridgeInstance.write.executeProposal([ + originDomainProposal, + originProposalSignedData], + {account: destinationRelayer1.account} + ) + ).not.to.be.reverted; + + depositorBalance = await OriginERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - depositAmount, + "depositAmount wasn't transferred from depositor" + ); + + recipientBalance = await DestinationERC1155MintableInstance.read.balanceOf([ + recipient.account!.address, + tokenID + ]); + assert.strictEqual( + recipientBalance, + depositAmount, + "depositAmount wasn't transferred to recipient" + ); + + await DestinationERC1155MintableInstance.write.setApprovalForAll([ + DestinationERC1155HandlerInstance.address, + true], + {account: recipient.account} + ); + + // recipient makes a deposit of the received depositAmount + await expect( + DestinationBridgeInstance.write.deposit([ + originDomainID, + destinationResourceID, + destinationDepositData, + feeData], + {account: recipient.account} + ) + ).not.to.be.reverted; + + // Recipient should have a balance of 0 (deposit amount - deposit amount) + recipientBalance = await DestinationERC1155MintableInstance.read.balanceOf([ + recipient.account!.address, + tokenID + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // originRelayer1 executes the proposal + await expect( + OriginBridgeInstance.write.executeProposal([ + destinationDomainProposal, + destinationProposalSignedData], + {account: originRelayer1.account} + ) + ).not.to.be.reverted; + recipientBalance = await DestinationERC1155MintableInstance.read.balanceOf([ + recipient.account!.address, + tokenID + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + depositorBalance = await OriginERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); +}); diff --git a/test/e2e/erc1155/sameChain.js b/test/e2e/erc1155/sameChain.js deleted file mode 100644 index b46f2df6..00000000 --- a/test/e2e/erc1155/sameChain.js +++ /dev/null @@ -1,240 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../helpers"); - -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); - -contract("E2E ERC1155 - Same Chain", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const tokenID = 1; - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC1155MintableInstance; - let ERC1155HandlerInstance; - - let resourceID; - let depositData; - let proposalData; - let proposal; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC1155MintableInstance.address]; - burnableContractAddresses = []; - - ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - await Promise.all([ - ERC1155MintableInstance.mintBatch( - depositorAddress, - [tokenID], - [initialTokenAmount], - "0x0" - ), - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - resourceID, - ERC1155MintableInstance.address, - emptySetResourceData - ), - ]); - - await ERC1155MintableInstance.setApprovalForAll( - ERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ); - - depositData = Helpers.createERC1155DepositData([tokenID], [depositAmount]); - proposalData = Helpers.createERC1155DepositProposalData( - [tokenID], - [depositAmount], - recipientAddress, - "0x" - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: proposalData, - resourceID: resourceID, - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositorAddress' balance should be equal to initialTokenAmount", async () => { - const depositorBalance = await ERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.strictEqual(depositorBalance.toNumber(), initialTokenAmount); - }); - - it("depositAmount of Destination ERC1155 should be transferred to recipientAddress", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - await TruffleAssert.passes( - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }) - ); - - // Handler should have a balance of depositAmount - const handlerBalance = await ERC1155MintableInstance.balanceOf( - ERC1155HandlerInstance.address, - tokenID - ); - assert.strictEqual(handlerBalance.toNumber(), depositAmount); - - // relayer1 executes the proposal - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // Assert ERC1155 balance was transferred from depositorAddress - const depositorBalance = await ERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.strictEqual( - depositorBalance.toNumber(), - initialTokenAmount - depositAmount - ); - - // Assert ERC1155 balance was transferred to recipientAddress - const recipientBalance = await ERC1155MintableInstance.balanceOf( - recipientAddress, - tokenID - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); - - it("Handler's deposit function can be called by only bridge", async () => { - await Helpers.reverts( - ERC1155HandlerInstance.deposit( - resourceID, - depositorAddress, - depositData, - {from: depositorAddress} - ), - "sender must be bridge contract" - ); - }); - - it("Handler's executeProposal function can be called by only bridge", async () => { - await Helpers.reverts( - ERC1155HandlerInstance.executeProposal(resourceID, proposalData, { - from: depositorAddress, - }), - "sender must be bridge contract" - ); - }); - - it("Handler's withdraw function can be called only by authorized address", async () => { - const withdrawData = Helpers.createERC1155WithdrawData( - ERC1155MintableInstance.address, - depositorAddress, - [tokenID], - [depositAmount], - "0x" - ); - - await Helpers.expectToRevertWithCustomError( - ERC1155HandlerInstance.withdraw.call(withdrawData, {from: depositorAddress}), - "NotAuthorized()" - ); - }); - - it("Should withdraw funds", async () => { - let depositorBalance; - - depositorBalance = await ERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.equal(depositorBalance, initialTokenAmount); - - await ERC1155MintableInstance.safeTransferFrom( - depositorAddress, - ERC1155HandlerInstance.address, - tokenID, - depositAmount, - "0x0", - {from: depositorAddress} - ); - - depositorBalance = await ERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.equal( - depositorBalance.toNumber(), - initialTokenAmount - depositAmount - ); - - const handlerBalance = await ERC1155MintableInstance.balanceOf( - ERC1155HandlerInstance.address, - tokenID - ); - assert.equal(handlerBalance, depositAmount); - - const withdrawData = Helpers.createERC1155WithdrawData( - ERC1155MintableInstance.address, - depositorAddress, - [tokenID], - [depositAmount], - "0x" - ); - - await BridgeInstance.adminWithdraw( - ERC1155HandlerInstance.address, - withdrawData - ); - - depositorBalance = await ERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.equal(depositorBalance, initialTokenAmount); - }); -}); diff --git a/test/e2e/erc1155/sameChain.test.ts b/test/e2e/erc1155/sameChain.test.ts new file mode 100644 index 00000000..ca380183 --- /dev/null +++ b/test/e2e/erc1155/sameChain.test.ts @@ -0,0 +1,238 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; +import { deploySourceChainContracts, deployDestinationChainContracts, mpcAddress, signTypedProposal, createERC1155DepositData, createERC1155DepositProposalData, createResourceID} from "../../helpers"; + + + +describe("E2E ERC1155 - Same Chain", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const tokenID = BigInt(1); + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + let depositProposalData: Hex; + let proposalData: Hex; + let proposal: Proposal; + let depositProposalDataHash: Hex; + + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC1155MintableInstance, + ERC1155HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + relayer1, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC1155MintableInstance.address, + originDomainID + ); + + await ERC1155MintableInstance.write.mintBatch([ + depositor.account!.address, + [tokenID], + [initialTokenAmount], + "0x0" + ]); + await BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + resourceID, + ERC1155MintableInstance.address, + emptySetResourceData + ]); + + await ERC1155MintableInstance.write.setApprovalForAll([ + ERC1155HandlerInstance.address, + true], + {account: depositor.account} + ); + + depositData = createERC1155DepositData([tokenID], [depositAmount]); + proposalData = createERC1155DepositProposalData( + [tokenID], + [depositAmount], + recipient.account!.address, + "0x" + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: proposalData, + resourceID: resourceID, + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor' balance should be equal to initialTokenAmount", async () => { + const depositorBalance = await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); + + it("depositAmount of Destination ERC1155 should be transferred to recipient", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + await expect( + BridgeInstance.write.deposit([originDomainID, resourceID, depositData, feeData], { + account: depositor.account, + }) + ).not.to.be.reverted; + + // Handler should have a balance of depositAmount + const handlerBalance = await ERC1155MintableInstance.read.balanceOf([ + ERC1155HandlerInstance.address, + tokenID + ]); + assert.strictEqual(handlerBalance, depositAmount); + + // relayer1 executes the proposal + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }) + ).not.to.be.reverted; + + // Assert ERC1155 balance was transferred from depositor + const depositorBalance = await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - depositAmount + ); + + // Assert ERC1155 balance was transferred to recipient + const recipientBalance = await ERC1155MintableInstance.read.balanceOf([ + recipient.account!.address, + tokenID + ]); + assert.strictEqual(recipientBalance, depositAmount); + }); + + it("Handler's deposit function can be called by only bridge", async () => { + await expect( + ERC1155HandlerInstance.write.deposit([ + resourceID, + depositor.account!.address, + depositData], + {account: depositor.account} + ), + ).to.be.rejectedWith("sender must be bridge contract"); + }); + + it("Handler's executeProposal function can be called by only bridge", async () => { + await expect( + ERC1155HandlerInstance.write.executeProposal([resourceID, proposalData], { + account: depositor.account, + }), + ).to.be.revertedWith("sender must be bridge contract"); + }); + + it("Handler's withdraw function can be called only by authorized address", async () => { + const withdrawData = createERC1155WithdrawData( + ERC1155MintableInstance.address, + depositor.account!.address, + [tokenID], + [depositAmount], + "0x" + ); + + await expect( + ERC1155HandlerInstance.write.withdraw([withdrawData], {account: depositor.account}), + ).to.be.revertedWithCustomError(BridgeInstance, "NotAuthorized()"); + }); + + it("Should withdraw funds", async () => { + let depositorBalance; + + depositorBalance = await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.equal(depositorBalance, initialTokenAmount); + + await ERC1155MintableInstance.write.safeTransferFrom([ + depositor.account!.address, + ERC1155HandlerInstance.address, + tokenID, + depositAmount, + "0x0"], + {account: depositor.account} + ); + + depositorBalance = await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.equal( + depositorBalance, + initialTokenAmount - depositAmount + ); + + const handlerBalance = await ERC1155MintableInstance.read.balanceOf([ + ERC1155HandlerInstance.address, + tokenID + ]); + assert.equal(handlerBalance, depositAmount); + + const withdrawData = createERC1155WithdrawData( + ERC1155MintableInstance.address, + depositor.account!.address, + [tokenID], + [depositAmount], + "0x" + ); + + await BridgeInstance.write.adminWithdraw([ + ERC1155HandlerInstance.address, + withdrawData + ]); + + depositorBalance = await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.equal(depositorBalance, initialTokenAmount); + }); +}); diff --git a/test/e2e/erc20/decimals/bothChainsNot18Decimals.js b/test/e2e/erc20/decimals/bothChainsNot18Decimals.js deleted file mode 100644 index 8d9f810d..00000000 --- a/test/e2e/erc20/decimals/bothChainsNot18Decimals.js +++ /dev/null @@ -1,318 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauserDecimals"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("E2E ERC20 - Two EVM Chains both with decimal places != 18", async accounts => { - const adminAddress = accounts[0] - - const originDomainID = 1; - const originRelayer1Address = accounts[3]; - - const destinationDomainID = 2; - const destinationRelayer1Address = accounts[3]; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const originDecimalPlaces = 20; - const destinationDecimalPlaces = 14; - const bridgeDefaultDecimalPlaces = 18; - const initialTokenAmount = Ethers.utils.parseUnits("100", originDecimalPlaces); - const originDepositAmount = Ethers.utils.parseUnits("14", originDecimalPlaces); - const destinationDepositAmount = Ethers.utils.parseUnits("14", destinationDecimalPlaces); - const relayerConvertedAmount = Ethers.utils.parseUnits("14", bridgeDefaultDecimalPlaces); - const expectedDepositNonce = 1; - const feeData = "0x"; - - let OriginBridgeInstance; - let OriginERC20MintableInstance; - let OriginDefaultMessageReceiverInstance; - let OriginERC20HandlerInstance; - let originDepositData; - let originResourceID; - let originInitialContractAddresses; - let originBurnableContractAddresses; - - let DestinationBridgeInstance; - let DestinationERC20MintableInstance; - let DestinationDefaultMessageReceiverInstance; - let DestinationERC20HandlerInstance; - let destinationDepositData; - let destinationResourceID; - let destinationInitialContractAddresses; - let destinationBurnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - OriginBridgeInstance = await Helpers.deployBridge(originDomainID, adminAddress), - DestinationBridgeInstance = await Helpers.deployBridge(destinationDomainID, adminAddress), - ERC20MintableContract.new("token", "TOK", originDecimalPlaces).then( - instance => OriginERC20MintableInstance = instance - ), - ERC20MintableContract.new("token", "TOK", destinationDecimalPlaces).then( - instance => DestinationERC20MintableInstance = instance - ) - ]); - - originResourceID = Helpers.createResourceID(OriginERC20MintableInstance.address, originDomainID); - originInitialContractAddresses = [OriginERC20MintableInstance.address]; - originBurnableContractAddresses = [OriginERC20MintableInstance.address]; - - destinationResourceID = Helpers.createResourceID(DestinationERC20MintableInstance.address, originDomainID); - destinationInitialContractAddresses = [DestinationERC20MintableInstance.address]; - destinationBurnableContractAddresses = [DestinationERC20MintableInstance.address]; - - OriginDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - DestinationDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - await Promise.all([ - ERC20HandlerContract.new( - OriginBridgeInstance.address, - OriginDefaultMessageReceiverInstance.address - ).then(instance => OriginERC20HandlerInstance = instance), - ERC20HandlerContract.new( - DestinationBridgeInstance.address, - DestinationDefaultMessageReceiverInstance.address - ).then(instance => DestinationERC20HandlerInstance = instance), - ]); - - await OriginERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - - await OriginERC20MintableInstance.approve( - OriginERC20HandlerInstance.address, - originDepositAmount, - {from: depositorAddress} - ), - await OriginERC20MintableInstance.grantRole( - await OriginERC20MintableInstance.MINTER_ROLE(), - OriginERC20HandlerInstance.address - ), - await DestinationERC20MintableInstance.grantRole( - await DestinationERC20MintableInstance.MINTER_ROLE(), - DestinationERC20HandlerInstance.address - ), - await OriginBridgeInstance.adminSetResource( - OriginERC20HandlerInstance.address, - originResourceID, - originInitialContractAddresses[0], - // set decimal places for handler and token - originDecimalPlaces - ), - await OriginBridgeInstance.adminSetBurnable( - OriginERC20HandlerInstance.address, - originBurnableContractAddresses[0] - ), - await DestinationBridgeInstance.adminSetResource( - DestinationERC20HandlerInstance.address, - destinationResourceID, - destinationInitialContractAddresses[0], - // set decimal places for handler and token - destinationDecimalPlaces - ), - await DestinationBridgeInstance.adminSetBurnable( - DestinationERC20HandlerInstance.address, - destinationBurnableContractAddresses[0] - ); - - originDepositData = Helpers.createERCDepositData(originDepositAmount, 20, recipientAddress); - destinationDepositData = Helpers.createERCDepositData(destinationDepositAmount, 20, depositorAddress); - - // set MPC address to unpause the Bridge - await OriginBridgeInstance.endKeygen(Helpers.mpcAddress); - await DestinationBridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] check token contract decimals match set decimals on handlers", async () => { - const originTokenContractDecimals = (await OriginERC20MintableInstance.decimals()).toNumber(); - const originDecimalsSetOnHandler = ( - await OriginERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - OriginERC20MintableInstance.address - )).decimals - - const destinationTokenContractDecimals = (await DestinationERC20MintableInstance.decimals()).toNumber(); - const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance - ._tokenContractAddressToTokenProperties.call(DestinationERC20MintableInstance.address - )).decimals - - assert.strictEqual( - originTokenContractDecimals.toString(), - originDecimalsSetOnHandler["externalDecimals"] - ); - assert.strictEqual( - destinationTokenContractDecimals.toString(), - destinationDecimalsSetOnHandler["externalDecimals"] - ); - }); - - it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 - owned by recipientAddress and back again`, async () => { - - - let depositorBalance; - let recipientBalance; - - // depositorAddress makes initial deposit of depositAmount - const originDepositTx = await OriginBridgeInstance.deposit( - destinationDomainID, - originResourceID, - originDepositData, - feeData, - {from: depositorAddress} - ); - await TruffleAssert.passes(originDepositTx); - - - // check that deposited amount converted to 18 decimal places is - // emitted in handlerResponse - TruffleAssert.eventEmitted(originDepositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === originResourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.data === originDepositData.toLowerCase() && - event.handlerResponse === Helpers.toHex(relayerConvertedAmount, 32) - ); - }); - - // this mocks depositProposal data for executing on - // destination chain which is returned from relayers - const originDepositProposalData = Helpers.createDepositProposalDataFromHandlerResponse( - originDepositTx, - 20, - recipientAddress - ); - - const originDomainProposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: originDepositProposalData, - resourceID: destinationResourceID - }; - - const originProposalSignedData = await Helpers.signTypedProposal( - DestinationBridgeInstance.address, - [originDomainProposal] - ); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - DestinationBridgeInstance.executeProposal( - originDomainProposal, - originProposalSignedData, - {from: destinationRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from depositorAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual( - depositorBalance.toString(), - (initialTokenAmount.sub(originDepositAmount)).toString(), - "originDepositAmount wasn't transferred from depositorAddress" - ); - - // Assert ERC20 balance was transferred to recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual( - recipientBalance.toString(), - destinationDepositAmount.toString(), - "originDepositAmount wasn't transferred to recipientAddress" - ); - - // At this point a representation of OriginERC20Mintable has been transferred from - // depositor to the recipient using Both Bridges and DestinationERC20Mintable. - // Next we will transfer DestinationERC20Mintable back to the depositor - - await DestinationERC20MintableInstance.approve( - DestinationERC20HandlerInstance.address, - destinationDepositAmount, - {from: recipientAddress} - ); - - // recipientAddress makes a deposit of the received depositAmount - const destinationDepositTx = await DestinationBridgeInstance.deposit( - originDomainID, - destinationResourceID, - destinationDepositData, - feeData, - {from: recipientAddress} - ); - await TruffleAssert.passes(destinationDepositTx); - - // check that deposited amount converted to 18 decimal places is - // emitted in handlerResponse - TruffleAssert.eventEmitted(destinationDepositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === originDomainID && - event.resourceID === destinationResourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.data === destinationDepositData.toLowerCase() && - event.handlerResponse === Helpers.toHex(relayerConvertedAmount, 32) - - ); - }); - - // this mocks depositProposal data for executing on - // destination chain which is returned from relayers - const destinationDepositProposalData = Helpers.createDepositProposalDataFromHandlerResponse( - destinationDepositTx, - 20, - depositorAddress - ); - - const destinationDomainProposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - data: destinationDepositProposalData, - resourceID: originResourceID - }; - - const destinationProposalSignedData = await Helpers.signTypedProposal( - OriginBridgeInstance.address, - [destinationDomainProposal] - ); - - // Recipient should have a balance of 0 (deposit amount) - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - OriginBridgeInstance.executeProposal( - destinationDomainProposal, - destinationProposalSignedData, - {from: originRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // Assert ERC20 balance was transferred to recipientAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toString(), initialTokenAmount.toString()); - }); -}); diff --git a/test/e2e/erc20/decimals/bothChainsNot18Decimals.test.ts b/test/e2e/erc20/decimals/bothChainsNot18Decimals.test.ts new file mode 100644 index 00000000..fd226a46 --- /dev/null +++ b/test/e2e/erc20/decimals/bothChainsNot18Decimals.test.ts @@ -0,0 +1,299 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; +import {createResourceID} from "../../../helpers"; + + + +describe("E2E ERC20 - Two EVM Chains both with decimal places != 18", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const originDecimalPlaces = 20; + const destinationDecimalPlaces = 14; + const bridgeDefaultDecimalPlaces = 18; + const initialTokenAmount = parseUnits("100", originDecimalPlaces); + const originDepositAmount = parseUnits("14", originDecimalPlaces); + const destinationDepositAmount = parseUnits("14", destinationDecimalPlaces); + const relayerConvertedAmount = parseUnits("14", bridgeDefaultDecimalPlaces); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + + let OriginBridgeInstance: ContractTypesMap["Bridge"];; + let OriginERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let OriginDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let OriginERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let originDepositData: Hex; + let originResourceID: Hex; + + let DestinationBridgeInstance: ContractTypesMap["Bridge"]; + let DestinationERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let DestinationDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let DestinationERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let destinationDepositData: Hex; + let destinationResourceID: Hex; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let originRelayer1: WalletClient; + let destinationRelayer1: WalletClient; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance: OriginDefaultMessageReceiverInstance, + BridgeInstance: OriginBridgeInstance, + ERC20MintableInstance: OriginERC20MintableInstance, + ERC20HandlerInstance: OriginERC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + ({ + DefaultMessageReceiverInstance: DestinationDefaultMessageReceiverInstance, + BridgeInstance: DestinationBridgeInstance, + ERC20MintableInstance: DestinationERC20MintableInstance, + ERC20HandlerInstance: DestinationERC20HandlerInstance, + } = await loadFixture(deployDestinationChainContracts)); + [ + admin, + depositor, + recipient, + originRelayer1 + ] = await hre.viem.getWalletClients(); + + + originResourceID = createResourceID(OriginERC20MintableInstance.address, originDomainID); + destinationResourceID = createResourceID(DestinationERC20MintableInstance.address, originDomainID); + + await OriginERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + + await OriginERC20MintableInstance.write.approve([ + OriginERC20HandlerInstance.address, + originDepositAmount], + {account: depositor.account} + ), + await OriginERC20MintableInstance.write.grantRole([ + await OriginERC20MintableInstance.read.MINTER_ROLE(), + OriginERC20HandlerInstance.address + ]); + await DestinationERC20MintableInstance.write.grantRole([ + await DestinationERC20MintableInstance.read.MINTER_ROLE(), + DestinationERC20HandlerInstance.address + ]); + await OriginBridgeInstance.write.adminSetResource([ + OriginERC20HandlerInstance.address, + originResourceID, + OriginERC20MintableInstance.address, + // set decimal places for handler and token + toHex(originDecimalPlaces) + ]); + await OriginBridgeInstance.write.adminSetBurnable([ + OriginERC20HandlerInstance.address, + OriginERC20MintableInstance.address + ]); + await DestinationBridgeInstance.write.adminSetResource([ + DestinationERC20HandlerInstance.address, + destinationResourceID, + DestinationERC20MintableInstance.address, + // set decimal places for handler and token + toHex(destinationDecimalPlaces) + ]); + await DestinationBridgeInstance.write.adminSetBurnable([ + DestinationERC20HandlerInstance.address, + DestinationERC20MintableInstance.address + ]); + + originDepositData = createERCDepositData(originDepositAmount, 20, recipient.account!.address); + destinationDepositData = createERCDepositData(destinationDepositAmount, 20, depositor.account!.address); + + // set MPC address to unpause the Bridge + await OriginBridgeInstance.write.endKeygen([mpcAddress]); + await DestinationBridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] check token contract decimals match set decimals on handlers", async () => { + const originTokenContractDecimals = (await OriginERC20MintableInstance.read.decimals()); + const originDecimalsSetOnHandler = ( + await OriginERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + OriginERC20MintableInstance.address + ]))[0]; + + const destinationTokenContractDecimals = (await DestinationERC20MintableInstance.read.decimals()); + const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance.read + ._tokenContractAddressToTokenProperties([DestinationERC20MintableInstance.address] + ))[0] + + assert.strictEqual( + originTokenContractDecimals, + originDecimalsSetOnHandler["externalDecimals"] + ); + assert.strictEqual( + destinationTokenContractDecimals, + destinationDecimalsSetOnHandler["externalDecimals"] + ); + }); + + it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 + owned by recipient.account!.address and back again`, async () => { + + + let depositorBalance; + let recipientBalance; + + // depositor.account!.address makes initial deposit of depositAmount + const originDepositTx = await OriginBridgeInstance.write.deposit([ + destinationDomainID, + originResourceID, + originDepositData, + feeData], + {account: depositor.account!.address} + ); + await expect(originDepositTx).not.to.be.reverted; + + + // check that deposited amount converted to 18 decimal places is + // emitted in handlerResponse + await expect(originDepositTx).to.emit(OriginBridgeInstance, "Depost").withArgs( + destinationDomainID, + originResourceID.toLowerCase(), + expectedDepositNonce, + originDepositData.toLowerCase(), + toHex(relayerConvertedAmount, {size:32}) + ); + + // this mocks depositProposal data for executing on + // destination chain which is returned from relayers + const originDepositProposalData = await createDepositProposalDataFromHandlerResponse( + OriginBridgeInstance.address, + originDepositTx, + 20, + recipient.account!.address + ); + + const originDomainProposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: originDepositProposalData, + resourceID: destinationResourceID + }; + + const originProposalSignedData = await signTypedProposal( + DestinationBridgeInstance.address, + [originDomainProposal] + ); + + // destinationRelayer1 executes the proposal + await expect( + DestinationBridgeInstance.write.executeProposal([ + originDomainProposal, + originProposalSignedData], + {account: destinationRelayer1!.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from depositor.account!.address + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - originDepositAmount, + "originDepositAmount wasn't transferred from depositor.account!.address" + ); + + // Assert ERC20 balance was transferred to recipient.account!.address + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual( + recipientBalance.toString(), + destinationDepositAmount.toString(), + "originDepositAmount wasn't transferred to recipient.account!.address" + ); + + // At this point a representation of OriginERC20Mintable has been transferred from + // depositor to the recipient using Both Bridges and DestinationERC20Mintable. + // Next we will transfer DestinationERC20Mintable back to the depositor + + await DestinationERC20MintableInstance.write.approve([ + DestinationERC20HandlerInstance.address, + destinationDepositAmount], + {account: recipient.account!.address} + ); + + // recipient.account!.address makes a deposit of the received depositAmount + const destinationDepositTx = await DestinationBridgeInstance.write.deposit([ + originDomainID, + destinationResourceID, + destinationDepositData, + feeData], + {account: recipient.account!.address} + ); + await expect(destinationDepositTx).not.to.be.reverted; + + // check that deposited amount converted to 18 decimal places is + // emitted in handlerResponse + await expect(destinationDepositTx).to.emit(DestinationBridgeInstance, "Deposit").withArgs( + originDomainID, + destinationResourceID.toLowerCase(), + expectedDepositNonce, + destinationDepositData.toLowerCase(), + toHex(relayerConvertedAmount, {size: 32}) + ); + + // this mocks depositProposal data for executing on + // destination chain which is returned from relayers + const destinationDepositProposalData = createDepositProposalDataFromHandlerResponse( + DestinationBridgeInstance.address, + destinationDepositTx, + 20, + depositor.account!.address + ); + + const destinationDomainProposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + data: destinationDepositProposalData, + resourceID: originResourceID + }; + + const destinationProposalSignedData = await signTypedProposal( + OriginBridgeInstance.address, + [destinationDomainProposal] + ); + + // Recipient should have a balance of 0 (deposit amount) + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance.toString(), "0"); + + // destinationRelayer1 executes the proposal + await expect( + OriginBridgeInstance.write.executeProposal([ + destinationDomainProposal, + destinationProposalSignedData], + {account: originRelayer1Address.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from recipient.account!.address + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance.toString(), "0"); + + // Assert ERC20 balance was transferred to recipient.account!.address + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance.toString(), initialTokenAmount.toString()); + }); +}); diff --git a/test/e2e/erc20/decimals/oneChainNot18Decimals.js b/test/e2e/erc20/decimals/oneChainNot18Decimals.js deleted file mode 100644 index a7d32e19..00000000 --- a/test/e2e/erc20/decimals/oneChainNot18Decimals.js +++ /dev/null @@ -1,300 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauserDecimals"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("E2E ERC20 - Two EVM Chains, one with decimal places == 18, other with != 18", async accounts => { - const adminAddress = accounts[0] - - const originDomainID = 1; - const originRelayer1Address = accounts[3]; - - const destinationDomainID = 2; - const destinationRelayer1Address = accounts[3]; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const originDecimalPlaces = 20; - const destinationDecimalPlaces = 18; - const bridgeDefaultDecimalPlaces = 18; - const initialTokenAmount = Ethers.utils.parseUnits("100", originDecimalPlaces); - const originDepositAmount = Ethers.utils.parseUnits("14", originDecimalPlaces); - const destinationDepositAmount = Ethers.utils.parseUnits("14", destinationDecimalPlaces); - const relayerConvertedAmount = Ethers.utils.parseUnits("14", bridgeDefaultDecimalPlaces); - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - - let OriginBridgeInstance; - let OriginERC20MintableInstance; - let OriginDefaultMessageReceiverInstance; - let OriginERC20HandlerInstance; - let originDepositData; - let originResourceID; - let originInitialContractAddresses; - let originBurnableContractAddresses; - - let DestinationBridgeInstance; - let DestinationERC20MintableInstance; - let DestinationDefaultMessageReceiverInstance; - let DestinationERC20HandlerInstance; - let destinationDepositData; - let destinationDepositProposalData; - let destinationResourceID; - let destinationInitialContractAddresses; - let destinationBurnableContractAddresses; - - let destinationDomainProposal; - - beforeEach(async () => { - await Promise.all([ - OriginBridgeInstance = await Helpers.deployBridge(originDomainID, adminAddress), - DestinationBridgeInstance = await Helpers.deployBridge(destinationDomainID, adminAddress), - ERC20MintableContract.new("token", "TOK", originDecimalPlaces).then( - instance => OriginERC20MintableInstance = instance - ), - ERC20MintableContract.new("token", "TOK", destinationDecimalPlaces).then( - instance => DestinationERC20MintableInstance = instance - ) - ]); - - originResourceID = Helpers.createResourceID(OriginERC20MintableInstance.address, originDomainID); - originInitialContractAddresses = [OriginERC20MintableInstance.address]; - originBurnableContractAddresses = [OriginERC20MintableInstance.address]; - - destinationResourceID = Helpers.createResourceID(DestinationERC20MintableInstance.address, originDomainID); - destinationInitialContractAddresses = [DestinationERC20MintableInstance.address]; - destinationBurnableContractAddresses = [DestinationERC20MintableInstance.address]; - - OriginDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - DestinationDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - await Promise.all([ - ERC20HandlerContract.new( - OriginBridgeInstance.address, - OriginDefaultMessageReceiverInstance.address - ).then(instance => OriginERC20HandlerInstance = instance), - ERC20HandlerContract.new( - DestinationBridgeInstance.address, - DestinationDefaultMessageReceiverInstance.address - ).then(instance => DestinationERC20HandlerInstance = instance), - ]); - - await OriginERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - - await OriginERC20MintableInstance.approve( - OriginERC20HandlerInstance.address, - originDepositAmount, - {from: depositorAddress} - ), - await OriginERC20MintableInstance.grantRole( - await OriginERC20MintableInstance.MINTER_ROLE(), - OriginERC20HandlerInstance.address - ), - await DestinationERC20MintableInstance.grantRole( - await DestinationERC20MintableInstance.MINTER_ROLE(), - DestinationERC20HandlerInstance.address - ), - await OriginBridgeInstance.adminSetResource( - OriginERC20HandlerInstance.address, - originResourceID, - originInitialContractAddresses[0], - // set decimal places for handler and token - originDecimalPlaces - ), - await OriginBridgeInstance.adminSetBurnable( - OriginERC20HandlerInstance.address, - originBurnableContractAddresses[0] - ), - await DestinationBridgeInstance.adminSetResource( - DestinationERC20HandlerInstance.address, - destinationResourceID, - destinationInitialContractAddresses[0], - emptySetResourceData - ), - await DestinationBridgeInstance.adminSetBurnable( - DestinationERC20HandlerInstance.address, - destinationBurnableContractAddresses[0] - ); - - originDepositData = Helpers.createERCDepositData(originDepositAmount, 20, recipientAddress); - - destinationDepositData = Helpers.createERCDepositData(destinationDepositAmount, 20, depositorAddress); - destinationDepositProposalData = Helpers.createERCDepositData(relayerConvertedAmount, 20, depositorAddress); - - destinationDomainProposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - data: destinationDepositProposalData, - resourceID: originResourceID - }; - - // set MPC address to unpause the Bridge - await OriginBridgeInstance.endKeygen(Helpers.mpcAddress); - await DestinationBridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] check token contract decimals match set decimals on handlers", async () => { - const originTokenContractDecimals = (await OriginERC20MintableInstance.decimals()).toNumber(); - const originDecimalsSetOnHandler = ( - await OriginERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - OriginERC20MintableInstance.address - )).decimals - - const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance - ._tokenContractAddressToTokenProperties.call(DestinationERC20MintableInstance.address - )).decimals - - assert.strictEqual( - originTokenContractDecimals.toString(), - originDecimalsSetOnHandler["externalDecimals"] - ); - assert.isFalse(destinationDecimalsSetOnHandler["isSet"]); - assert.strictEqual( - "0", - destinationDecimalsSetOnHandler["externalDecimals"] - ); - }); - - it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 - owned by recipientAddress and back again`, async () => { - const destinationProposalSignedData = await Helpers.signTypedProposal( - OriginBridgeInstance.address, - [destinationDomainProposal] - ); - - let depositorBalance; - let recipientBalance; - - // depositorAddress makes initial deposit of depositAmount - const originDepositTx = await OriginBridgeInstance.deposit( - destinationDomainID, - originResourceID, - originDepositData, - feeData, - {from: depositorAddress} - ); - await TruffleAssert.passes(originDepositTx); - - // this mocks depositProposal data for executing on - // destination chain which is returned from relayers - const originDepositProposalData = Helpers.createDepositProposalDataFromHandlerResponse( - originDepositTx, - 20, - recipientAddress - ); - - const originDomainProposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: originDepositProposalData, - resourceID: destinationResourceID - }; - - const originProposalSignedData = await Helpers.signTypedProposal( - DestinationBridgeInstance.address, - [originDomainProposal] - ); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - DestinationBridgeInstance.executeProposal( - originDomainProposal, - originProposalSignedData, - {from: destinationRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from depositorAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual( - depositorBalance.toString(), - (initialTokenAmount.sub(originDepositAmount)).toString(), - "originDepositAmount wasn't transferred from depositorAddress" - ); - - // Assert ERC20 balance was transferred to recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual( - recipientBalance.toString(), - destinationDepositAmount.toString(), - "originDepositAmount wasn't transferred to recipientAddress" - ); - - // At this point a representation of OriginERC20Mintable has been transferred from - // depositor to the recipient using Both Bridges and DestinationERC20Mintable. - // Next we will transfer DestinationERC20Mintable back to the depositor - - await DestinationERC20MintableInstance.approve( - DestinationERC20HandlerInstance.address, - destinationDepositAmount, - {from: recipientAddress} - ); - - // recipientAddress makes a deposit of the received depositAmount - const depositTx = await DestinationBridgeInstance.deposit( - originDomainID, - destinationResourceID, - destinationDepositData, - feeData, - {from: recipientAddress} - ); - await TruffleAssert.passes(depositTx); - - // check that handlerResponse is empty - deposits from networks with 18 decimal - // places shouldn't return handlerResponse - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === originDomainID && - event.resourceID === destinationResourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.data === destinationDepositData.toLowerCase() && - event.handlerResponse === null - ); - }); - - // Recipient should have a balance of 0 (deposit amount) - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - OriginBridgeInstance.executeProposal( - destinationDomainProposal, - destinationProposalSignedData, - {from: originRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // Assert ERC20 balance was transferred to recipientAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toString(), initialTokenAmount.toString()); - }); -}); diff --git a/test/e2e/erc20/decimals/oneChainNot18Decimals.test.ts b/test/e2e/erc20/decimals/oneChainNot18Decimals.test.ts new file mode 100644 index 00000000..a8a84250 --- /dev/null +++ b/test/e2e/erc20/decimals/oneChainNot18Decimals.test.ts @@ -0,0 +1,280 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; +import {createResourceID} from "../../../helpers"; + + +describe("E2E ERC20 - Two EVM Chains, one with decimal places == 18, other with != 18", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const originDecimalPlaces = 20; + const destinationDecimalPlaces = 18; + const bridgeDefaultDecimalPlaces = 18; + const initialTokenAmount = parseUnits("100", originDecimalPlaces); + const originDepositAmount = parseUnits("14", originDecimalPlaces); + const destinationDepositAmount = parseUnits("14", destinationDecimalPlaces); + const relayerConvertedAmount = parseUnits("14", bridgeDefaultDecimalPlaces); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + + let OriginBridgeInstance: ContractTypesMap["Bridge"]; + let OriginERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let OriginDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let OriginERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let originDepositData: Hex; + let originResourceID: Hex;; + + let DestinationBridgeInstance: ContractTypesMap["Bridge"];; + let DestinationERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let DestinationDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let DestinationERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let destinationDepositData: Hex; + let destinationDepositProposalData: Hex; + let destinationResourceID: Hex; + + let destinationDomainProposal: Proposal; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let originRelayer1: WalletClient; + let destinationRelayer1: WalletClient; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance: OriginDefaultMessageReceiverInstance, + BridgeInstance: OriginBridgeInstance, + ERC20MintableInstance: OriginERC20MintableInstance, + ERC20HandlerInstance: OriginERC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + ({ + DefaultMessageReceiverInstance: DestinationDefaultMessageReceiverInstance, + BridgeInstance: DestinationBridgeInstance, + ERC20MintableInstance: DestinationERC20MintableInstance, + ERC20HandlerInstance: DestinationERC20HandlerInstance, + } = await loadFixture(deployDestinationChainContracts)); + [ + admin, + depositor, + recipient, + originRelayer1, + destinationRelayer1, + ] = await hre.viem.getWalletClients(); + + originResourceID = createResourceID(OriginERC20MintableInstance.address, originDomainID); + destinationResourceID = createResourceID(DestinationERC20MintableInstance.address, originDomainID); + + await OriginERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + await OriginERC20MintableInstance.write.approve([ + OriginERC20HandlerInstance.address, + originDepositAmount], + {account: depositor.account} + ), + await OriginERC20MintableInstance.write.grantRole([ + await OriginERC20MintableInstance.read.MINTER_ROLE(), + OriginERC20HandlerInstance.address + ]); + await DestinationERC20MintableInstance.write.grantRole([ + await DestinationERC20MintableInstance.read.MINTER_ROLE(), + DestinationERC20HandlerInstance.address + ]); + await OriginBridgeInstance.write.adminSetResource([ + OriginERC20HandlerInstance.address, + originResourceID, + OriginERC20MintableInstance.address, + // set decimal places for handler and token + toHex(originDecimalPlaces) + ]); + await OriginBridgeInstance.write.adminSetBurnable([ + OriginERC20HandlerInstance.address, + OriginERC20MintableInstance.address + ]); + await DestinationBridgeInstance.write.adminSetResource([ + DestinationERC20HandlerInstance.address, + destinationResourceID, + DestinationERC20MintableInstance.address, + emptySetResourceData + ]); + await DestinationBridgeInstance.write.adminSetBurnable([ + DestinationERC20HandlerInstance.address, + DestinationERC20MintableInstance.address + ]); + + originDepositData = createERCDepositData(originDepositAmount, 20, recipient.account!.address); + + destinationDepositData = createERCDepositData(destinationDepositAmount, 20, depositor.account!.address); + destinationDepositProposalData = createERCDepositData(relayerConvertedAmount, 20, depositor.account!.address); + + destinationDomainProposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + data: destinationDepositProposalData, + resourceID: originResourceID + }; + + // set MPC address to unpause the Bridge + await OriginBridgeInstance.write.endKeygen([mpcAddress]); + await DestinationBridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] check token contract decimals match set decimals on handlers", async () => { + const originTokenContractDecimals = (await OriginERC20MintableInstance.read.decimals()); + const originDecimalsSetOnHandler = ( + await OriginERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + OriginERC20MintableInstance.address + ]))[3] + + const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance.read + ._tokenContractAddressToTokenProperties([DestinationERC20MintableInstance.address + ]))[3] + + assert.strictEqual( + originTokenContractDecimals, + originDecimalsSetOnHandler["externalDecimals"] + ); + assert.isFalse(destinationDecimalsSetOnHandler["isSet"]); + assert.strictEqual( + 0, + destinationDecimalsSetOnHandler["externalDecimals"] + ); + }); + + it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 + owned by recipient and back again`, async () => { + const destinationProposalSignedData = await signTypedProposal( + OriginBridgeInstance.address, + [destinationDomainProposal] + ); + + let depositorBalance; + let recipientBalance; + + // depositor makes initial deposit of depositAmount + const originDepositTx = await OriginBridgeInstance.write.deposit([ + destinationDomainID, + originResourceID, + originDepositData, + feeData], + {account: depositor.account} + ); + await expect(originDepositTx).not.to.be.reverted; + + // this mocks depositProposal data for executing on + // destination chain which is returned from relayers + const originDepositProposalData = createDepositProposalDataFromHandlerResponse( + originDepositTx, + 20, + recipient + ); + + const originDomainProposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: originDepositProposalData, + resourceID: destinationResourceID + }; + + const originProposalSignedData = await signTypedProposal( + DestinationBridgeInstance.address, + [originDomainProposal] + ); + + // destinationRelayer1 executes the proposal + await expect( + DestinationBridgeInstance.write.executeProposal([ + originDomainProposal, + originProposalSignedData], + {account: destinationRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from depositor + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - originDepositAmount, + "originDepositAmount wasn't transferred from depositor" + ); + + // Assert ERC20 balance was transferred to recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual( + recipientBalance, + destinationDepositAmount, + "originDepositAmount wasn't transferred to recipient" + ); + + // At this point a representation of OriginERC20Mintable has been transferred from + // depositor to the recipient using Both Bridges and DestinationERC20Mintable. + // Next we will transfer DestinationERC20Mintable back to the depositor + + await DestinationERC20MintableInstance.write.approve([ + DestinationERC20HandlerInstance.address, + destinationDepositAmount], + {account: recipient.account} + ); + + // recipient makes a deposit of the received depositAmount + const depositTx = await DestinationBridgeInstance.write.deposit([ + originDomainID, + destinationResourceID, + destinationDepositData, + feeData], + {account: recipient.account} + ); + await expect(depositTx).not.to.be.reverted; + + // check that handlerResponse is empty - deposits from networks with 18 decimal + // places shouldn't return handlerResponse + await expect(depositTx).to.emit(OriginBridgeInstance, "Deposit").withArgs( + originDomainID, + destinationResourceID.toLowerCase(), + expectedDepositNonce, + destinationDepositData.toLowerCase(), + null + ); + + // Recipient should have a balance of 0 (deposit amount) + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // destinationRelayer1 executes the proposal + await expect( + OriginBridgeInstance.write.executeProposal([ + destinationDomainProposal, + destinationProposalSignedData], + {account: originRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // Assert ERC20 balance was transferred to recipient + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); +}); diff --git a/test/e2e/erc20/decimals/oneChainWith0Decimals.js b/test/e2e/erc20/decimals/oneChainWith0Decimals.js deleted file mode 100644 index 7cfa7287..00000000 --- a/test/e2e/erc20/decimals/oneChainWith0Decimals.js +++ /dev/null @@ -1,300 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauserDecimals"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("E2E ERC20 - Two EVM Chains, one with decimal places == 18, other with == 0", async accounts => { - const adminAddress = accounts[0] - - const originDomainID = 1; - const originRelayer1Address = accounts[3]; - - const destinationDomainID = 2; - const destinationRelayer1Address = accounts[3]; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const originDecimalPlaces = 0; - const destinationDecimalPlaces = 18; - const bridgeDefaultDecimalPlaces = 18; - const initialTokenAmount = Ethers.BigNumber.from("10000000000000000"); - const originDepositAmount = Ethers.BigNumber.from("1400000000000000"); - const destinationDepositAmount = Ethers.utils.parseUnits(originDepositAmount.toString(), destinationDecimalPlaces); - const relayerConvertedAmount = Ethers.utils.parseUnits(originDepositAmount.toString(), bridgeDefaultDecimalPlaces); - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - - let OriginBridgeInstance; - let OriginERC20MintableInstance; - let OriginDefaultMessageReceiverInstance; - let OriginERC20HandlerInstance; - let originDepositData; - let originResourceID; - let originInitialContractAddresses; - let originBurnableContractAddresses; - - let DestinationBridgeInstance; - let DestinationERC20MintableInstance; - let DestinationDefaultMessageReceiverInstance; - let DestinationERC20HandlerInstance; - let destinationDepositData; - let destinationDepositProposalData; - let destinationResourceID; - let destinationInitialContractAddresses; - let destinationBurnableContractAddresses; - - let destinationDomainProposal; - - beforeEach(async () => { - await Promise.all([ - OriginBridgeInstance = await Helpers.deployBridge(originDomainID, adminAddress), - DestinationBridgeInstance = await Helpers.deployBridge(destinationDomainID, adminAddress), - ERC20MintableContract.new("token", "TOK", originDecimalPlaces).then( - instance => OriginERC20MintableInstance = instance - ), - ERC20MintableContract.new("token", "TOK", destinationDecimalPlaces).then( - instance => DestinationERC20MintableInstance = instance - ) - ]); - - originResourceID = Helpers.createResourceID(OriginERC20MintableInstance.address, originDomainID); - originInitialContractAddresses = [OriginERC20MintableInstance.address]; - originBurnableContractAddresses = [OriginERC20MintableInstance.address]; - - destinationResourceID = Helpers.createResourceID(DestinationERC20MintableInstance.address, originDomainID); - destinationInitialContractAddresses = [DestinationERC20MintableInstance.address]; - destinationBurnableContractAddresses = [DestinationERC20MintableInstance.address]; - - OriginDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - DestinationDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - await Promise.all([ - ERC20HandlerContract.new( - OriginBridgeInstance.address, - OriginDefaultMessageReceiverInstance.address - ).then(instance => OriginERC20HandlerInstance = instance), - ERC20HandlerContract.new( - DestinationBridgeInstance.address, - DestinationDefaultMessageReceiverInstance.address - ).then(instance => DestinationERC20HandlerInstance = instance), - ]); - - await OriginERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - - await OriginERC20MintableInstance.approve( - OriginERC20HandlerInstance.address, - originDepositAmount, - {from: depositorAddress} - ), - await OriginERC20MintableInstance.grantRole( - await OriginERC20MintableInstance.MINTER_ROLE(), - OriginERC20HandlerInstance.address - ), - await DestinationERC20MintableInstance.grantRole( - await DestinationERC20MintableInstance.MINTER_ROLE(), - DestinationERC20HandlerInstance.address - ), - await OriginBridgeInstance.adminSetResource( - OriginERC20HandlerInstance.address, - originResourceID, - originInitialContractAddresses[0], - // set decimal places for handler and token - originDecimalPlaces - ), - await OriginBridgeInstance.adminSetBurnable( - OriginERC20HandlerInstance.address, - originBurnableContractAddresses[0] - ), - await DestinationBridgeInstance.adminSetResource( - DestinationERC20HandlerInstance.address, - destinationResourceID, - destinationInitialContractAddresses[0], - emptySetResourceData - ), - await DestinationBridgeInstance.adminSetBurnable( - DestinationERC20HandlerInstance.address, - destinationBurnableContractAddresses[0] - ); - - originDepositData = Helpers.createERCDepositData(originDepositAmount, 20, recipientAddress); - - destinationDepositData = Helpers.createERCDepositData(destinationDepositAmount, 20, depositorAddress); - destinationDepositProposalData = Helpers.createERCDepositData(relayerConvertedAmount, 20, depositorAddress); - - destinationDomainProposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - data: destinationDepositProposalData, - resourceID: originResourceID - }; - - // set MPC address to unpause the Bridge - await OriginBridgeInstance.endKeygen(Helpers.mpcAddress); - await DestinationBridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] check token contract decimals match set decimals on handlers", async () => { - const originTokenContractDecimals = (await OriginERC20MintableInstance.decimals()).toNumber(); - const originDecimalsSetOnHandler = ( - await OriginERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - OriginERC20MintableInstance.address - )).decimals - - const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance - ._tokenContractAddressToTokenProperties.call(DestinationERC20MintableInstance.address - )).decimals - - assert.strictEqual( - originTokenContractDecimals.toString(), - originDecimalsSetOnHandler["externalDecimals"] - ); - assert.isFalse(destinationDecimalsSetOnHandler["isSet"]); - assert.strictEqual( - "0", - destinationDecimalsSetOnHandler["externalDecimals"] - ); - }); - - it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 - owned by recipientAddress and back again`, async () => { - const destinationProposalSignedData = await Helpers.signTypedProposal( - OriginBridgeInstance.address, - [destinationDomainProposal] - ); - - let depositorBalance; - let recipientBalance; - - // depositorAddress makes initial deposit of depositAmount - const originDepositTx = await OriginBridgeInstance.deposit( - destinationDomainID, - originResourceID, - originDepositData, - feeData, - {from: depositorAddress} - ); - await TruffleAssert.passes(originDepositTx); - - // this mocks depositProposal data for executing on - // destination chain which is returned from relayers - const originDepositProposalData = Helpers.createDepositProposalDataFromHandlerResponse( - originDepositTx, - 20, - recipientAddress - ); - - const originDomainProposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: originDepositProposalData, - resourceID: destinationResourceID - }; - - const originProposalSignedData = await Helpers.signTypedProposal( - DestinationBridgeInstance.address, - [originDomainProposal] - ); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - DestinationBridgeInstance.executeProposal( - originDomainProposal, - originProposalSignedData, - {from: destinationRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from depositorAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual( - depositorBalance.toString(), - (initialTokenAmount.sub(originDepositAmount)).toString(), - "originDepositAmount wasn't transferred from depositorAddress" - ); - - // Assert ERC20 balance was transferred to recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual( - recipientBalance.toString(), - destinationDepositAmount.toString(), - "originDepositAmount wasn't transferred to recipientAddress" - ); - - // At this point a representation of OriginERC20Mintable has been transferred from - // depositor to the recipient using Both Bridges and DestinationERC20Mintable. - // Next we will transfer DestinationERC20Mintable back to the depositor - - await DestinationERC20MintableInstance.approve( - DestinationERC20HandlerInstance.address, - destinationDepositAmount, - {from: recipientAddress} - ); - - // recipientAddress makes a deposit of the received depositAmount - const depositTx = await DestinationBridgeInstance.deposit( - originDomainID, - destinationResourceID, - destinationDepositData, - feeData, - {from: recipientAddress} - ); - await TruffleAssert.passes(depositTx); - - // check that handlerResponse is empty - deposits from networks with 18 decimal - // places shouldn't return handlerResponse - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === originDomainID && - event.resourceID === destinationResourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.data === destinationDepositData.toLowerCase() && - event.handlerResponse === null - ); - }); - - // Recipient should have a balance of 0 (deposit amount) - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - OriginBridgeInstance.executeProposal( - destinationDomainProposal, - destinationProposalSignedData, - {from: originRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // Assert ERC20 balance was transferred to recipientAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toString(), initialTokenAmount.toString()); - }); -}); diff --git a/test/e2e/erc20/decimals/oneChainWith0Decimals.test.ts b/test/e2e/erc20/decimals/oneChainWith0Decimals.test.ts new file mode 100644 index 00000000..fc4ad151 --- /dev/null +++ b/test/e2e/erc20/decimals/oneChainWith0Decimals.test.ts @@ -0,0 +1,281 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; +import {createResourceID} from "../../../helpers"; + + +describe("E2E ERC20 - Two EVM Chains, one with decimal places == 18, other with == 0", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const originDecimalPlaces = 0; + const destinationDecimalPlaces = 18; + const bridgeDefaultDecimalPlaces = 18; + const initialTokenAmount = BigInt(10000000000000000); + const originDepositAmount = BigInt(1400000000000000); + const destinationDepositAmount = parseUnits(originDepositAmount.toString(), destinationDecimalPlaces); + const relayerConvertedAmount = parseUnits(originDepositAmount.toString(), bridgeDefaultDecimalPlaces); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + + let OriginBridgeInstance: ContractTypesMap["Bridge"]; + let OriginERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let OriginDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let OriginERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let originDepositData: Hex; + let originResourceID: Hex;; + + let DestinationBridgeInstance: ContractTypesMap["Bridge"];; + let DestinationERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let DestinationDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let DestinationERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let destinationDepositData: Hex; + let destinationDepositProposalData: Hex; + let destinationResourceID: Hex; + + let destinationDomainProposal: Proposal; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let originRelayer1: WalletClient; + let destinationRelayer1: WalletClient; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance: OriginDefaultMessageReceiverInstance, + BridgeInstance: OriginBridgeInstance, + ERC20MintableInstance: OriginERC20MintableInstance, + ERC20HandlerInstance: OriginERC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + ({ + DefaultMessageReceiverInstance: DestinationDefaultMessageReceiverInstance, + BridgeInstance: DestinationBridgeInstance, + ERC20MintableInstance: DestinationERC20MintableInstance, + ERC20HandlerInstance: DestinationERC20HandlerInstance, + } = await loadFixture(deployDestinationChainContracts)); + [ + admin, + depositor, + recipient, + originRelayer1, + destinationRelayer1, + ] = await hre.viem.getWalletClients(); + + originResourceID = createResourceID(OriginERC20MintableInstance.address, originDomainID); + destinationResourceID = createResourceID(DestinationERC20MintableInstance.address, originDomainID); + + await OriginERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + + await OriginERC20MintableInstance.write.approve([ + OriginERC20HandlerInstance.address, + originDepositAmount], + {account: depositor.account} + ); + await OriginERC20MintableInstance.write.grantRole([ + await OriginERC20MintableInstance.read.MINTER_ROLE(), + OriginERC20HandlerInstance.address + ]); + await DestinationERC20MintableInstance.write.grantRole([ + await DestinationERC20MintableInstance.read.MINTER_ROLE(), + DestinationERC20HandlerInstance.address + ]); + await OriginBridgeInstance.write.adminSetResource([ + OriginERC20HandlerInstance.address, + originResourceID, + OriginERC20MintableInstance.address, + // set decimal places for handler and token + toHex(originDecimalPlaces) + ]); + await OriginBridgeInstance.write.adminSetBurnable([ + OriginERC20HandlerInstance.address, + OriginERC20MintableInstance.address + ]); + await DestinationBridgeInstance.write.adminSetResource([ + DestinationERC20HandlerInstance.address, + destinationResourceID, + DestinationERC20MintableInstance.address, + emptySetResourceData + ]); + await DestinationBridgeInstance.write.adminSetBurnable([ + DestinationERC20HandlerInstance.address, + DestinationERC20MintableInstance.address, + ]); + + originDepositData = createERCDepositData(originDepositAmount, 20, recipient.account!.address); + + destinationDepositData = createERCDepositData(destinationDepositAmount, 20, depositor.account!.address); + destinationDepositProposalData = createERCDepositData(relayerConvertedAmount, 20, depositor.account!.address); + + destinationDomainProposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + data: destinationDepositProposalData, + resourceID: originResourceID + }; + + // set MPC address to unpause the Bridge + await OriginBridgeInstance.write.endKeygen([mpcAddress]); + await DestinationBridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] check token contract decimals match set decimals on handlers", async () => { + const originTokenContractDecimals = (await OriginERC20MintableInstance.read.decimals()); + const originDecimalsSetOnHandler = ( + await OriginERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + OriginERC20MintableInstance.address + ]))[3] + + const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance.read + ._tokenContractAddressToTokenProperties([DestinationERC20MintableInstance.address + ])); + + assert.strictEqual( + originTokenContractDecimals, + originDecimalsSetOnHandler["externalDecimals"] + ); + assert.isFalse(destinationDecimalsSetOnHandler["isSet"][0]); + assert.strictEqual( + 0, + destinationDecimalsSetOnHandler["externalDecimals"] + ); + }); + + it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 + owned by recipient and back again`, async () => { + const destinationProposalSignedData = await signTypedProposal( + OriginBridgeInstance.address, + [destinationDomainProposal] + ); + + let depositorBalance; + let recipientBalance; + + // depositor.account!.address makes initial deposit of depositAmount + const originDepositTx = await OriginBridgeInstance.write.deposit([ + destinationDomainID, + originResourceID, + originDepositData, + feeData], + {account: depositor.account} + ); + await expect(originDepositTx).not.to.be.reverted; + + // this mocks depositProposal data for executing on + // destination chain which is returned from relayers + const originDepositProposalData = createDepositProposalDataFromHandlerResponse( + originDepositTx, + 20, + recipient + ); + + const originDomainProposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: originDepositProposalData, + resourceID: destinationResourceID + }; + + const originProposalSignedData = await signTypedProposal( + DestinationBridgeInstance.address, + [originDomainProposal] + ); + + // destinationRelayer1 executes the proposal + await expect( + DestinationBridgeInstance.write.executeProposal([ + originDomainProposal, + originProposalSignedData], + {account: destinationRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from depositor.account!.address + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - originDepositAmount, + "originDepositAmount wasn't transferred from depositor.account!.address" + ); + + // Assert ERC20 balance was transferred to recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual( + recipientBalance, + destinationDepositAmount, + "originDepositAmount wasn't transferred to recipient" + ); + + // At this point a representation of OriginERC20Mintable has been transferred from + // depositor to the recipient using Both Bridges and DestinationERC20Mintable. + // Next we will transfer DestinationERC20Mintable back to the depositor + + await DestinationERC20MintableInstance.write.approve([ + DestinationERC20HandlerInstance.address, + destinationDepositAmount], + {account: recipient.account} + ); + + // recipient makes a deposit of the received depositAmount + const depositTx = await DestinationBridgeInstance.write.deposit([ + originDomainID, + destinationResourceID, + destinationDepositData, + feeData], + {account: recipient.account} + ); + await expect(depositTx).not.to.be.reverted; + + // check that handlerResponse is empty - deposits from networks with 18 decimal + // places shouldn't return handlerResponse + await expect(depositTx).to.emit(OriginBridgeInstance, "Deposit").withArgs( + originDomainID, + destinationResourceID.toLowerCase(), + expectedDepositNonce, + destinationDepositData.toLowerCase(), + null + ); + + // Recipient should have a balance of 0 (deposit amount) + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // destinationRelayer1 executes the proposal + await expect( + OriginBridgeInstance.write.executeProposal([ + destinationDomainProposal, + destinationProposalSignedData], + {account: originRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // Assert ERC20 balance was transferred to recipient + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); +}); diff --git a/test/e2e/erc20/decimals/roundingLoss.js b/test/e2e/erc20/decimals/roundingLoss.js deleted file mode 100644 index 3ee5f900..00000000 --- a/test/e2e/erc20/decimals/roundingLoss.js +++ /dev/null @@ -1,319 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauserDecimals"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("E2E ERC20 - Two EVM Chains both with decimal places != 18 with rounding loss", async accounts => { - const adminAddress = accounts[0] - - const originDomainID = 1; - const originRelayer1Address = accounts[3]; - - const destinationDomainID = 2; - const destinationRelayer1Address = accounts[3]; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const originDecimalPlaces = 20; - const destinationDecimalPlaces = 14; - const bridgeDefaultDecimalPlaces = 18; - const initialTokenAmount = Ethers.utils.parseUnits("100", originDecimalPlaces); - const originDepositAmount = Ethers.utils.parseUnits("1.00000000000000005683", originDecimalPlaces); - const destinationDepositAmount = Ethers.utils.parseUnits("1", destinationDecimalPlaces); - const originRelayerConvertedAmount = Ethers.utils.parseUnits("1.000000000000000056", bridgeDefaultDecimalPlaces); - const destinationRelayerConvertedAmount = Ethers.utils.parseUnits("1", bridgeDefaultDecimalPlaces); - const roundingLoss = originDepositAmount.sub(Ethers.utils.parseUnits("1", originDecimalPlaces)); - const expectedDepositNonce = 1; - const feeData = "0x"; - - let OriginBridgeInstance; - let OriginERC20MintableInstance; - let OriginDefaultMessageReceiverInstance; - let OriginERC20HandlerInstance; - let originDepositData; - let originResourceID; - let originInitialContractAddresses; - let originBurnableContractAddresses; - - let DestinationBridgeInstance; - let DestinationERC20MintableInstance; - let DestinationDefaultMessageReceiverInstance; - let DestinationERC20HandlerInstance; - let destinationDepositData; - let destinationResourceID; - let destinationInitialContractAddresses; - let destinationBurnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - OriginBridgeInstance = await Helpers.deployBridge(originDomainID, adminAddress), - DestinationBridgeInstance = await Helpers.deployBridge(destinationDomainID, adminAddress), - ERC20MintableContract.new("token", "TOK", originDecimalPlaces).then( - instance => OriginERC20MintableInstance = instance - ), - ERC20MintableContract.new("token", "TOK", destinationDecimalPlaces).then( - instance => DestinationERC20MintableInstance = instance - ) - ]); - - originResourceID = Helpers.createResourceID(OriginERC20MintableInstance.address, originDomainID); - originInitialContractAddresses = [OriginERC20MintableInstance.address]; - originBurnableContractAddresses = [OriginERC20MintableInstance.address]; - - destinationResourceID = Helpers.createResourceID(DestinationERC20MintableInstance.address, originDomainID); - destinationInitialContractAddresses = [DestinationERC20MintableInstance.address]; - destinationBurnableContractAddresses = [DestinationERC20MintableInstance.address]; - - OriginDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - DestinationDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - await Promise.all([ - ERC20HandlerContract.new( - OriginBridgeInstance.address, - OriginDefaultMessageReceiverInstance.address - ).then(instance => OriginERC20HandlerInstance = instance), - ERC20HandlerContract.new( - DestinationBridgeInstance.address, - DestinationDefaultMessageReceiverInstance.address - ).then(instance => DestinationERC20HandlerInstance = instance), - ]); - - await OriginERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - - await OriginERC20MintableInstance.approve( - OriginERC20HandlerInstance.address, - originDepositAmount, - {from: depositorAddress} - ), - await OriginERC20MintableInstance.grantRole( - await OriginERC20MintableInstance.MINTER_ROLE(), - OriginERC20HandlerInstance.address - ), - await DestinationERC20MintableInstance.grantRole( - await DestinationERC20MintableInstance.MINTER_ROLE(), - DestinationERC20HandlerInstance.address - ), - await OriginBridgeInstance.adminSetResource( - OriginERC20HandlerInstance.address, - originResourceID, - originInitialContractAddresses[0], - // set decimal places for handler and token - originDecimalPlaces - ), - await OriginBridgeInstance.adminSetBurnable( - OriginERC20HandlerInstance.address, - originBurnableContractAddresses[0] - ), - await DestinationBridgeInstance.adminSetResource( - DestinationERC20HandlerInstance.address, - destinationResourceID, - destinationInitialContractAddresses[0], - // set decimal places for handler and token - destinationDecimalPlaces - ), - await DestinationBridgeInstance.adminSetBurnable( - DestinationERC20HandlerInstance.address, - destinationBurnableContractAddresses[0] - ); - - originDepositData = Helpers.createERCDepositData(originDepositAmount, 20, recipientAddress); - destinationDepositData = Helpers.createERCDepositData(destinationDepositAmount, 20, depositorAddress); - - // set MPC address to unpause the Bridge - await OriginBridgeInstance.endKeygen(Helpers.mpcAddress); - await DestinationBridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] check token contract decimals match set decimals on handlers", async () => { - const originTokenContractDecimals = (await OriginERC20MintableInstance.decimals()).toNumber(); - const originDecimalsSetOnHandler = ( - await OriginERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - OriginERC20MintableInstance.address - )).decimals - - const destinationTokenContractDecimals = (await DestinationERC20MintableInstance.decimals()).toNumber(); - const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance - ._tokenContractAddressToTokenProperties.call(DestinationERC20MintableInstance.address - )).decimals - - assert.strictEqual( - originTokenContractDecimals.toString(), - originDecimalsSetOnHandler["externalDecimals"] - ); - assert.strictEqual( - destinationTokenContractDecimals.toString(), - destinationDecimalsSetOnHandler["externalDecimals"] - ); - }); - - it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 - owned by recipientAddress and back again`, async () => { - - - let depositorBalance; - let recipientBalance; - - // depositorAddress makes initial deposit of depositAmount - const originDepositTx = await OriginBridgeInstance.deposit( - destinationDomainID, - originResourceID, - originDepositData, - feeData, - {from: depositorAddress} - ); - await TruffleAssert.passes(originDepositTx); - - - // check that deposited amount converted to 18 decimal places is - // emitted in handlerResponse - TruffleAssert.eventEmitted(originDepositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === originResourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.data === originDepositData.toLowerCase() && - event.handlerResponse === Helpers.toHex(originRelayerConvertedAmount, 32) - ); - }); - - // this mocks depositProposal data for executing on - // destination chain which is returned from relayers - const originDepositProposalData = Helpers.createDepositProposalDataFromHandlerResponse( - originDepositTx, - 20, - recipientAddress - ); - - const originDomainProposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: originDepositProposalData, - resourceID: destinationResourceID - }; - - const originProposalSignedData = await Helpers.signTypedProposal( - DestinationBridgeInstance.address, - [originDomainProposal] - ); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - DestinationBridgeInstance.executeProposal( - originDomainProposal, - originProposalSignedData, - {from: destinationRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from depositorAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual( - depositorBalance.toString(), - (initialTokenAmount.sub(originDepositAmount)).toString(), - "originDepositAmount wasn't transferred from depositorAddress" - ); - - // Assert ERC20 balance was transferred to recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual( - recipientBalance.toString(), - destinationDepositAmount.toString(), - "originDepositAmount wasn't transferred to recipientAddress" - ); - - // At this point a representation of OriginERC20Mintable has been transferred from - // depositor to the recipient using Both Bridges and DestinationERC20Mintable. - // Next we will transfer DestinationERC20Mintable back to the depositor - - await DestinationERC20MintableInstance.approve( - DestinationERC20HandlerInstance.address, - destinationDepositAmount, - {from: recipientAddress} - ); - - // recipientAddress makes a deposit of the received depositAmount - const destinationDepositTx = await DestinationBridgeInstance.deposit( - originDomainID, - destinationResourceID, - destinationDepositData, - feeData, - {from: recipientAddress} - ); - await TruffleAssert.passes(destinationDepositTx); - - // check that deposited amount converted to 18 decimal places is - // emitted in handlerResponse - TruffleAssert.eventEmitted(destinationDepositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === originDomainID && - event.resourceID === destinationResourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.data === destinationDepositData.toLowerCase() && - event.handlerResponse === Helpers.toHex(destinationRelayerConvertedAmount, 32) - ); - }); - - // this mocks depositProposal data for executing on - // destination chain which is returned from relayers - const destinationDepositProposalData = Helpers.createDepositProposalDataFromHandlerResponse( - destinationDepositTx, - 20, - depositorAddress - ); - - const destinationDomainProposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - data: destinationDepositProposalData, - resourceID: originResourceID - }; - - const destinationProposalSignedData = await Helpers.signTypedProposal( - OriginBridgeInstance.address, - [destinationDomainProposal] - ); - - // Recipient should have a balance of 0 (deposit amount) - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - OriginBridgeInstance.executeProposal( - destinationDomainProposal, - destinationProposalSignedData, - {from: originRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toString(), "0"); - - // Assert ERC20 balance was transferred to recipientAddress minus the roundingLoss - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toString(), initialTokenAmount.sub(roundingLoss).toString()); - }); -}); diff --git a/test/e2e/erc20/decimals/roundingLoss.test.ts b/test/e2e/erc20/decimals/roundingLoss.test.ts new file mode 100644 index 00000000..f9ff2f97 --- /dev/null +++ b/test/e2e/erc20/decimals/roundingLoss.test.ts @@ -0,0 +1,296 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; +import {createResourceID} from "../../../helpers"; + +describe("E2E ERC20 - Two EVM Chains both with decimal places != 18 with rounding loss", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const originDecimalPlaces = 20; + const destinationDecimalPlaces = 14; + const bridgeDefaultDecimalPlaces = 18; + const initialTokenAmount = parseUnits("100", originDecimalPlaces); + const originDepositAmount = parseUnits("1.00000000000000005683", originDecimalPlaces); + const destinationDepositAmount = parseUnits("1", destinationDecimalPlaces); + const originRelayerConvertedAmount = parseUnits("1.000000000000000056", bridgeDefaultDecimalPlaces); + const destinationRelayerConvertedAmount = parseUnits("1", bridgeDefaultDecimalPlaces); + const roundingLoss = originDepositAmount - parseUnits("1", originDecimalPlaces); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + + let OriginBridgeInstance: ContractTypesMap["Bridge"]; + let OriginERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let OriginDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let OriginERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let originDepositData: Hex; + let originResourceID: Hex;; + + let DestinationBridgeInstance: ContractTypesMap["Bridge"];; + let DestinationERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let DestinationDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let DestinationERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let destinationDepositData: Hex; + let destinationResourceID: Hex; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let originRelayer1: WalletClient; + let destinationRelayer1: WalletClient; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance: OriginDefaultMessageReceiverInstance, + BridgeInstance: OriginBridgeInstance, + ERC20MintableInstance: OriginERC20MintableInstance, + ERC20HandlerInstance: OriginERC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + ({ + DefaultMessageReceiverInstance: DestinationDefaultMessageReceiverInstance, + BridgeInstance: DestinationBridgeInstance, + ERC20MintableInstance: DestinationERC20MintableInstance, + ERC20HandlerInstance: DestinationERC20HandlerInstance, + } = await loadFixture(deployDestinationChainContracts)); + [ + admin, + depositor, + recipient, + originRelayer1, + destinationRelayer1, + ] = await hre.viem.getWalletClients(); + + originResourceID = createResourceID(OriginERC20MintableInstance.address, originDomainID); + destinationResourceID = createResourceID(DestinationERC20MintableInstance.address, originDomainID); + + await OriginERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + + await OriginERC20MintableInstance.write.approve([ + OriginERC20HandlerInstance.address, + originDepositAmount], + {account: depositor.account} + ); + await OriginERC20MintableInstance.write.grantRole([ + await OriginERC20MintableInstance.read.MINTER_ROLE(), + OriginERC20HandlerInstance.address + ]); + await DestinationERC20MintableInstance.write.grantRole([ + await DestinationERC20MintableInstance.read.MINTER_ROLE(), + DestinationERC20HandlerInstance.address + ]); + await OriginBridgeInstance.write.adminSetResource([ + OriginERC20HandlerInstance.address, + originResourceID, + DestinationERC20MintableInstance.address, + // set decimal places for handler and token + toHex(originDecimalPlaces) + ]); + await OriginBridgeInstance.write.adminSetBurnable([ + OriginERC20HandlerInstance.address, + OriginERC20MintableInstance.address + ]); + await DestinationBridgeInstance.write.adminSetResource([ + DestinationERC20HandlerInstance.address, + destinationResourceID, + DestinationERC20MintableInstance.address, + // set decimal places for handler and token + toHex(destinationDecimalPlaces) + ]); + await DestinationBridgeInstance.write.adminSetBurnable([ + DestinationERC20HandlerInstance.address, + DestinationERC20MintableInstance.address + ]); + + originDepositData = createERCDepositData(originDepositAmount, 20, recipient.account!.address); + destinationDepositData = createERCDepositData(destinationDepositAmount, 20, depositor.account!.address); + + // set MPC address to unpause the Bridge + await OriginBridgeInstance.write.endKeygen([mpcAddress]); + await DestinationBridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] check token contract decimals match set decimals on handlers", async () => { + const originTokenContractDecimals = (await OriginERC20MintableInstance.read.decimals()); + const originDecimalsSetOnHandler = ( + await OriginERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + OriginERC20MintableInstance.address + ]))[3] + + const destinationTokenContractDecimals = (await DestinationERC20MintableInstance.read.decimals()); + const destinationDecimalsSetOnHandler = (await DestinationERC20HandlerInstance.read + ._tokenContractAddressToTokenProperties([DestinationERC20MintableInstance.address + ]))[3]; + + assert.strictEqual( + originTokenContractDecimals, + originDecimalsSetOnHandler["externalDecimals"] + ); + assert.strictEqual( + destinationTokenContractDecimals, + destinationDecimalsSetOnHandler["externalDecimals"] + ); + }); + + it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 + owned by recipient and back again`, async () => { + + + let depositorBalance; + let recipientBalance; + + // depositor makes initial deposit of depositAmount + const originDepositTx = await OriginBridgeInstance.write.deposit([ + destinationDomainID, + originResourceID, + originDepositData, + feeData], + {account: depositor.account} + ); + await expect(originDepositTx).not.to.be.reverted; + + + // check that deposited amount converted to 18 decimal places is + // emitted in handlerResponse + await expect(originDepositTx).to.emit(OriginBridgeInstance, "Deposit").withArgs( + destinationDomainID, + originResourceID.toLowerCase(), + expectedDepositNonce, + originDepositData.toLowerCase(), + toHex(originRelayerConvertedAmount, {size: 32}) + ); + // this mocks depositProposal data for executing on + // destination chain which is returned from relayers + const originDepositProposalData = createDepositProposalDataFromHandlerResponse( + originDepositTx, + 20, + recipient + ); + + const originDomainProposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: originDepositProposalData, + resourceID: destinationResourceID + }; + + const originProposalSignedData = await signTypedProposal( + DestinationBridgeInstance.address, + [originDomainProposal] + ); + + // destinationRelayer1 executes the proposal + await expect( + DestinationBridgeInstance.write.executeProposal([ + originDomainProposal, + originProposalSignedData], + {account: destinationRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from depositor + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - originDepositAmount, + "originDepositAmount wasn't transferred from depositor" + ); + + // Assert ERC20 balance was transferred to recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual( + recipientBalance.toString(), + destinationDepositAmount.toString(), + "originDepositAmount wasn't transferred to recipient" + ); + + // At this point a representation of OriginERC20Mintable has been transferred from + // depositor to the recipient using Both Bridges and DestinationERC20Mintable. + // Next we will transfer DestinationERC20Mintable back to the depositor + + await DestinationERC20MintableInstance.write.approve([ + DestinationERC20HandlerInstance.address, + destinationDepositAmount], + {account: recipient.account} + ); + + // recipient makes a deposit of the received depositAmount + const destinationDepositTx = await DestinationBridgeInstance.write.deposit([ + originDomainID, + destinationResourceID, + destinationDepositData, + feeData], + {account: recipient.account} + ); + await expect(destinationDepositTx).not.to.be.reverted; + + // check that deposited amount converted to 18 decimal places is + // emitted in handlerResponse + await expect(destinationDepositTx).to.emit(DestinationBridgeInstance, "Deposit").withArgs( + originDomainID, + destinationResourceID.toLowerCase(), + expectedDepositNonce, + destinationDepositData.toLowerCase(), + toHex(destinationRelayerConvertedAmount, {size: 32}) + ); + + // this mocks depositProposal data for executing on + // destination chain which is returned from relayers + const destinationDepositProposalData = createDepositProposalDataFromHandlerResponse( + destinationDepositTx, + 20, + depositor + ); + + const destinationDomainProposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + data: destinationDepositProposalData, + resourceID: originResourceID + }; + + const destinationProposalSignedData = await signTypedProposal( + OriginBridgeInstance.address, + [destinationDomainProposal] + ); + + // Recipient should have a balance of 0 (deposit amount) + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // destinationRelayer1 executes the proposal + await expect( + OriginBridgeInstance.write.executeProposal([ + destinationDomainProposal, + destinationProposalSignedData], + {account: originRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // Assert ERC20 balance was transferred to recipient minus the roundingLoss + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance, initialTokenAmount - roundingLoss); + }); +}); diff --git a/test/e2e/erc20/differentChainsMock.js b/test/e2e/erc20/differentChainsMock.js deleted file mode 100644 index 78be0398..00000000 --- a/test/e2e/erc20/differentChainsMock.js +++ /dev/null @@ -1,329 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("E2E ERC20 - Two EVM Chains", async (accounts) => { - const adminAddress = accounts[0]; - - const originDomainID = 1; - const originRelayer1Address = accounts[3]; - - const destinationDomainID = 2; - const destinationRelayer1Address = accounts[3]; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let OriginBridgeInstance; - let OriginERC20MintableInstance; - let OriginDefaultMessageReceiverInstance; - let OriginERC20HandlerInstance; - let originDepositData; - let originDepositProposalData; - let originResourceID; - let originBurnableContractAddresses; - - let DestinationBridgeInstance; - let DestinationERC20MintableInstance; - let DestinationDefaultMessageReceiverInstance; - let DestinationERC20HandlerInstance; - let destinationDepositData; - let destinationDepositProposalData; - let destinationResourceID; - let destinationBurnableContractAddresses; - - let originDomainProposal; - let destinationDomainProposal; - - beforeEach(async () => { - await Promise.all([ - (OriginBridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - (DestinationBridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (OriginERC20MintableInstance = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (DestinationERC20MintableInstance = instance) - ), - ]); - - originResourceID = Helpers.createResourceID( - OriginERC20MintableInstance.address, - originDomainID - ); - originInitialResourceIDs = [originResourceID]; - originInitialContractAddresses = [OriginERC20MintableInstance.address]; - originBurnableContractAddresses = [OriginERC20MintableInstance.address]; - - destinationResourceID = Helpers.createResourceID( - DestinationERC20MintableInstance.address, - originDomainID - ); - destinationInitialResourceIDs = [destinationResourceID]; - destinationInitialContractAddresses = [ - DestinationERC20MintableInstance.address, - ]; - destinationBurnableContractAddresses = [ - DestinationERC20MintableInstance.address, - ]; - - OriginDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - DestinationDefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - await Promise.all([ - ERC20HandlerContract.new( - OriginBridgeInstance.address, - OriginDefaultMessageReceiverInstance.address - ).then( - (instance) => (OriginERC20HandlerInstance = instance) - ), - ERC20HandlerContract.new( - DestinationBridgeInstance.address, - DestinationDefaultMessageReceiverInstance.address - ).then( - (instance) => (DestinationERC20HandlerInstance = instance) - ), - ]); - - await OriginERC20MintableInstance.mint( - depositorAddress, - initialTokenAmount - ); - - await OriginERC20MintableInstance.approve( - OriginERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ), - await OriginERC20MintableInstance.grantRole( - await OriginERC20MintableInstance.MINTER_ROLE(), - OriginERC20HandlerInstance.address - ), - await DestinationERC20MintableInstance.grantRole( - await DestinationERC20MintableInstance.MINTER_ROLE(), - DestinationERC20HandlerInstance.address - ), - await OriginBridgeInstance.adminSetResource( - OriginERC20HandlerInstance.address, - originResourceID, - OriginERC20MintableInstance.address, - emptySetResourceData - ), - await OriginBridgeInstance.adminSetBurnable( - OriginERC20HandlerInstance.address, - originBurnableContractAddresses[0] - ), - await DestinationBridgeInstance.adminSetResource( - DestinationERC20HandlerInstance.address, - destinationResourceID, - DestinationERC20MintableInstance.address, - emptySetResourceData - ), - await DestinationBridgeInstance.adminSetBurnable( - DestinationERC20HandlerInstance.address, - destinationBurnableContractAddresses[0] - ); - - originDepositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - originDepositProposalData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - originDepositProposalDataHash = Ethers.utils.keccak256( - DestinationERC20HandlerInstance.address + - originDepositProposalData.substr(2) - ); - - destinationDepositData = Helpers.createERCDepositData( - depositAmount, - 20, - depositorAddress - ); - destinationDepositProposalData = Helpers.createERCDepositData( - depositAmount, - 20, - depositorAddress - ); - destinationDepositProposalDataHash = Ethers.utils.keccak256( - OriginERC20HandlerInstance.address + - destinationDepositProposalData.substr(2) - ); - - originDomainProposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: originDepositProposalData, - resourceID: destinationResourceID, - }; - - destinationDomainProposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - data: destinationDepositProposalData, - resourceID: originResourceID, - }; - - // set MPC address to unpause the Bridge - await OriginBridgeInstance.endKeygen(Helpers.mpcAddress); - await DestinationBridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositorAddress' balance should be equal to initialTokenAmount", async () => { - const depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toNumber(), initialTokenAmount); - }); - - it( - "[sanity] OriginERC20HandlerInstance.address should have an allowance of depositAmount from depositorAddress", - async () => { - const handlerAllowance = await OriginERC20MintableInstance.allowance( - depositorAddress, - OriginERC20HandlerInstance.address - ); - assert.strictEqual(handlerAllowance.toNumber(), depositAmount); - }); - - it( - "[sanity] DestinationERC20HandlerInstance.address should have minterRole for DestinationERC20MintableInstance", - async () => { - const isMinter = await DestinationERC20MintableInstance.hasRole( - await DestinationERC20MintableInstance.MINTER_ROLE(), - DestinationERC20HandlerInstance.address - ); - assert.isTrue(isMinter); - }); - - it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 - owned by recipientAddress and back again`, async () => { - const originProposalSignedData = await Helpers.signTypedProposal( - DestinationBridgeInstance.address, - [originDomainProposal] - ); - const destinationProposalSignedData = await Helpers.signTypedProposal( - OriginBridgeInstance.address, - [destinationDomainProposal] - ); - - let depositorBalance; - let recipientBalance; - - // depositorAddress makes initial deposit of depositAmount - await TruffleAssert.passes( - OriginBridgeInstance.deposit( - destinationDomainID, - originResourceID, - originDepositData, - feeData, - {from: depositorAddress} - ) - ); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - DestinationBridgeInstance.executeProposal( - originDomainProposal, - originProposalSignedData, - {from: destinationRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from depositorAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual( - depositorBalance.toNumber(), - initialTokenAmount - depositAmount, - "depositAmount wasn't transferred from depositorAddress" - ); - - // Assert ERC20 balance was transferred to recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual( - recipientBalance.toNumber(), - depositAmount, - "depositAmount wasn't transferred to recipientAddress" - ); - - // At this point a representation of OriginERC20Mintable has been transferred from - // depositor to the recipient using Both Bridges and DestinationERC20Mintable. - // Next we will transfer DestinationERC20Mintable back to the depositor - - await DestinationERC20MintableInstance.approve( - DestinationERC20HandlerInstance.address, - depositAmount, - {from: recipientAddress} - ); - - // recipientAddress makes a deposit of the received depositAmount - await TruffleAssert.passes( - DestinationBridgeInstance.deposit( - originDomainID, - destinationResourceID, - destinationDepositData, - feeData, - {from: recipientAddress} - ) - ); - - // Recipient should have a balance of 0 (deposit amount - deposit amount) - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), 0); - - // destinationRelayer1 executes the proposal - await TruffleAssert.passes( - OriginBridgeInstance.executeProposal( - destinationDomainProposal, - destinationProposalSignedData, - {from: originRelayer1Address} - ) - ); - - // Assert ERC20 balance was transferred from recipientAddress - recipientBalance = await DestinationERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), 0); - - // Assert ERC20 balance was transferred to recipientAddress - depositorBalance = await OriginERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toNumber(), initialTokenAmount); - }); -}); diff --git a/test/e2e/erc20/differentChainsMock.test.ts b/test/e2e/erc20/differentChainsMock.test.ts new file mode 100644 index 00000000..1f14af0a --- /dev/null +++ b/test/e2e/erc20/differentChainsMock.test.ts @@ -0,0 +1,299 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createResourceID, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; + + +describe("E2E ERC20 - Two EVM Chains", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let OriginBridgeInstance: ContractTypesMap["Bridge"]; + let OriginERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let OriginDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let OriginERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let originDepositProposalData: Hex; + let originDepositData: Hex; + let originResourceID: Hex;; + let originDomainProposal: Proposal; + let originDepositProposalDataHash: Hex; + + let DestinationBridgeInstance: ContractTypesMap["Bridge"];; + let DestinationERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let DestinationDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let DestinationERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let destinationDepositData: Hex; + let destinationDepositProposalData: Hex; + let destinationResourceID: Hex; + let destinationDepositProposalDataHash: Hex; + let destinationDomainProposal: Proposal; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let originRelayer1: WalletClient; + let destinationRelayer1: WalletClient; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance: OriginDefaultMessageReceiverInstance, + BridgeInstance: OriginBridgeInstance, + ERC20MintableInstance: OriginERC20MintableInstance, + ERC20HandlerInstance: OriginERC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + ({ + DefaultMessageReceiverInstance: DestinationDefaultMessageReceiverInstance, + BridgeInstance: DestinationBridgeInstance, + ERC20MintableInstance: DestinationERC20MintableInstance, + ERC20HandlerInstance: DestinationERC20HandlerInstance, + } = await loadFixture(deployDestinationChainContracts)); + [ + admin, + depositor, + recipient, + originRelayer1, + destinationRelayer1, + ] = await hre.viem.getWalletClients(); + + originResourceID = createResourceID( + OriginERC20MintableInstance.address, + originDomainID + ); + destinationResourceID = createResourceID( + DestinationERC20MintableInstance.address, + originDomainID + ); + + await OriginERC20MintableInstance.write.mint([ + depositor.account!.address, + initialTokenAmount + ]); + + await OriginERC20MintableInstance.write.approve([ + OriginERC20HandlerInstance.address, + depositAmount], + {account: depositor.account} + ); + await OriginERC20MintableInstance.write.grantRole([ + await OriginERC20MintableInstance.read.MINTER_ROLE(), + OriginERC20HandlerInstance.address + ]); + await DestinationERC20MintableInstance.write.grantRole([ + await DestinationERC20MintableInstance.read.MINTER_ROLE(), + DestinationERC20HandlerInstance.address + ]); + await OriginBridgeInstance.write.adminSetResource([ + OriginERC20HandlerInstance.address, + originResourceID, + OriginERC20MintableInstance.address, + emptySetResourceData + ]); + await OriginBridgeInstance.write.adminSetBurnable([ + OriginERC20HandlerInstance.address, + OriginERC20MintableInstance.address + ]); + await DestinationBridgeInstance.write.adminSetResource([ + DestinationERC20HandlerInstance.address, + destinationResourceID, + DestinationERC20MintableInstance.address, + emptySetResourceData + ]); + await DestinationBridgeInstance.write.adminSetBurnable([ + DestinationERC20HandlerInstance.address, + DestinationERC20MintableInstance.address + ]); + + originDepositData = createERCDepositData( + depositAmount, + 20, + recipient + ); + originDepositProposalData = createERCDepositData( + depositAmount, + 20, + recipient + ); + originDepositProposalDataHash = keccak256( + concat([ + DestinationERC20HandlerInstance.address, + trimPrefix(originDepositProposalData) + ]) + ); + + destinationDepositData = createERCDepositData( + depositAmount, + 20, + depositor + ); + destinationDepositProposalData = createERCDepositData( + depositAmount, + 20, + depositor + ); + destinationDepositProposalDataHash = keccak256( + concat([ + OriginERC20HandlerInstance.address, + trimPrefix(destinationDepositProposalData) + ]) + ); + + originDomainProposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: originDepositProposalData, + resourceID: destinationResourceID, + }; + + destinationDomainProposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + data: destinationDepositProposalData, + resourceID: originResourceID, + }; + + // set MPC address to unpause the Bridge + await OriginBridgeInstance.write.endKeygen([mpcAddress]); + await DestinationBridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor' balance should be equal to initialTokenAmount", async () => { + const depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); + + it(`[sanity] OriginERC20HandlerInstance.address should + have an allowance of depositAmount from depositor`, async () => { + const handlerAllowance = await OriginERC20MintableInstance.read.allowance([ + depositor.account!.address, + OriginERC20HandlerInstance.address + ]); + assert.strictEqual(handlerAllowance, depositAmount); + }); + + it(`[sanity] DestinationERC20HandlerInstance.address should + have minterRole for DestinationERC20MintableInstance`, async () => { + const isMinter = await DestinationERC20MintableInstance.read.hasRole([ + await DestinationERC20MintableInstance.read.MINTER_ROLE(), + DestinationERC20HandlerInstance.address + ]); + assert.isTrue(isMinter); + }); + + it(`E2E: depositAmount of Origin ERC20 owned by depositAddress to Destination ERC20 + owned by recipient and back again`, async () => { + const originProposalSignedData = await signTypedProposal( + DestinationBridgeInstance.address, + [originDomainProposal] + ); + const destinationProposalSignedData = await signTypedProposal( + OriginBridgeInstance.address, + [destinationDomainProposal] + ); + + let depositorBalance; + let recipientBalance; + + // depositor makes initial deposit of depositAmount + await expect( + OriginBridgeInstance.write.deposit([ + destinationDomainID, + originResourceID, + originDepositData, + feeData], + {account: depositor.account} + ) + ).not.to.be.reverted; + + // destinationRelayer1 executes the proposal + await expect( + DestinationBridgeInstance.write.executeProposal([ + originDomainProposal, + originProposalSignedData], + {account: destinationRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from depositor + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - depositAmount, + "depositAmount wasn't transferred from depositor" + ); + + // Assert ERC20 balance was transferred to recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual( + recipientBalance, + depositAmount, + "depositAmount wasn't transferred to recipient" + ); + + // At this point a representation of OriginERC20Mintable has been transferred from + // depositor to the recipient using Both Bridges and DestinationERC20Mintable. + // Next we will transfer DestinationERC20Mintable back to the depositor + + await DestinationERC20MintableInstance.write.approve([ + DestinationERC20HandlerInstance.address, + depositAmount], + {account: recipient.account} + ); + + // recipient makes a deposit of the received depositAmount + await expect( + DestinationBridgeInstance.write.deposit([ + originDomainID, + destinationResourceID, + destinationDepositData, + feeData], + {account: recipient.account} + ) + ).not.to.be.reverted; + + // Recipient should have a balance of 0 (deposit amount - deposit amount) + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // destinationRelayer1 executes the proposal + await expect( + OriginBridgeInstance.write.executeProposal([ + destinationDomainProposal, + destinationProposalSignedData], + {account: originRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from recipient + recipientBalance = await DestinationERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, BigInt(0)); + + // Assert ERC20 balance was transferred to recipient + depositorBalance = await OriginERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); +}); diff --git a/test/e2e/erc20/sameChain.js b/test/e2e/erc20/sameChain.js deleted file mode 100644 index a5b5cfa3..00000000 --- a/test/e2e/erc20/sameChain.js +++ /dev/null @@ -1,164 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("E2E ERC20 - Same Chain", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const initialTokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let ERC20HandlerInstance; - let DefaultMessageReceiverInstance; - - let resourceID; - let depositData; - let depositProposalData; - - let proposal; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new( - [], - 100000 - ); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await Promise.all([ - ERC20MintableInstance.mint(depositorAddress, initialTokenAmount), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ]); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - depositProposalData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - depositProposalDataHash = Ethers.utils.keccak256( - ERC20HandlerInstance.address + depositProposalData.substr(2) - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: depositProposalData, - resourceID: resourceID, - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositorAddress' balance should be equal to initialTokenAmount", async () => { - const depositorBalance = await ERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toNumber(), initialTokenAmount); - }); - - it( - "[sanity] ERC20HandlerInstance.address should have an allowance of depositAmount from depositorAddress", - async () => { - const handlerAllowance = await ERC20MintableInstance.allowance( - depositorAddress, - ERC20HandlerInstance.address - ); - assert.strictEqual(handlerAllowance.toNumber(), depositAmount); - }); - - it("depositAmount of Destination ERC20 should be transferred to recipientAddress", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }) - ); - - // Handler should have a balance of depositAmount - const handlerBalance = await ERC20MintableInstance.balanceOf( - ERC20HandlerInstance.address - ); - assert.strictEqual(handlerBalance.toNumber(), depositAmount); - - // relayer2 executes the proposal - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // Assert ERC20 balance was transferred from depositorAddress - const depositorBalance = await ERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.strictEqual( - depositorBalance.toNumber(), - initialTokenAmount - depositAmount - ); - - // // Assert ERC20 balance was transferred to recipientAddress - const recipientBalance = await ERC20MintableInstance.balanceOf( - recipientAddress - ); - assert.strictEqual(recipientBalance.toNumber(), depositAmount); - }); -}); diff --git a/test/e2e/erc20/sameChain.test.ts b/test/e2e/erc20/sameChain.test.ts new file mode 100644 index 00000000..646f02c8 --- /dev/null +++ b/test/e2e/erc20/sameChain.test.ts @@ -0,0 +1,157 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createResourceID, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; + +describe("E2E ERC20 - Same Chain", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + let depositProposalData: Hex; + let proposal: Proposal; + let depositProposalDataHash: Hex; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + relayer1, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + await ERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]), + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount], + {account: depositor.account} + ); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient + ); + depositProposalData = createERCDepositData( + depositAmount, + 20, + recipient + ); + depositProposalDataHash = keccak256( + concat([ + ERC20HandlerInstance.address, + trimPrefix(depositProposalData) + ]) + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: depositProposalData, + resourceID: resourceID, + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor' balance should be equal to initialTokenAmount", async () => { + const depositorBalance = await ERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance, initialTokenAmount); + }); + + it(`[sanity] ERC20HandlerInstance.address should have + an allowance of depositAmount from depositor`, async () => { + const handlerAllowance = await ERC20MintableInstance.read.allowance([ + depositor.account!.address, + ERC20HandlerInstance.address + ]); + assert.strictEqual(handlerAllowance, depositAmount); + }); + + it("depositAmount of Destination ERC20 should be transferred to recipient", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([originDomainID, resourceID, depositData, feeData], { + account: depositor.account, + }) + ).not.to.be.reverted; + + // Handler should have a balance of depositAmount + const handlerBalance = await ERC20MintableInstance.read.balanceOf([ + ERC20HandlerInstance.address + ]); + assert.strictEqual(handlerBalance, depositAmount); + + // relayer2 executes the proposal + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }) + ).not.to.be.reverted; + + // Assert ERC20 balance was transferred from depositor + const depositorBalance = await ERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual( + depositorBalance, + initialTokenAmount - depositAmount + ); + + // // Assert ERC20 balance was transferred to recipient + const recipientBalance = await ERC20MintableInstance.read.balanceOf([ + recipient.account!.address + ]); + assert.strictEqual(recipientBalance, depositAmount); + }); +}); diff --git a/test/e2e/erc721/differentChainsMock.js b/test/e2e/erc721/differentChainsMock.js deleted file mode 100644 index f78930bf..00000000 --- a/test/e2e/erc721/differentChainsMock.js +++ /dev/null @@ -1,300 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); - -contract("E2E ERC721 - Two EVM Chains", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const originRelayer1Address = accounts[3]; - const destinationRelayer1Address = accounts[4]; - - const tokenID = 1; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let OriginBridgeInstance; - let OriginERC721MintableInstance; - let OriginERC721HandlerInstance; - let originDepositData; - let originDepositProposalData; - let originResourceID; - - let DestinationBridgeInstance; - let DestinationERC721MintableInstance; - let DestinationERC721HandlerInstance; - let destinationDepositData; - let destinationDepositProposalData; - let destinationResourceID; - let destinationBurnableContractAddresses; - - let originDomainProposal; - let destinationDomainProposal; - - beforeEach(async () => { - await Promise.all([ - (OriginBridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - (DestinationBridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (OriginERC721MintableInstance = instance) - ), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (DestinationERC721MintableInstance = instance) - ), - ]); - - originResourceID = Helpers.createResourceID( - OriginERC721MintableInstance.address, - originDomainID - ); - originInitialResourceIDs = [originResourceID]; - originInitialContractAddresses = [OriginERC721MintableInstance.address]; - originBurnableContractAddresses = []; - - destinationResourceID = Helpers.createResourceID( - DestinationERC721MintableInstance.address, - originDomainID - ); - destinationInitialResourceIDs = [destinationResourceID]; - destinationInitialContractAddresses = [ - DestinationERC721MintableInstance.address, - ]; - destinationBurnableContractAddresses = [ - DestinationERC721MintableInstance.address, - ]; - - await Promise.all([ - ERC721HandlerContract.new(OriginBridgeInstance.address).then( - (instance) => (OriginERC721HandlerInstance = instance) - ), - ERC721HandlerContract.new(DestinationBridgeInstance.address).then( - (instance) => (DestinationERC721HandlerInstance = instance) - ), - ]); - - await OriginERC721MintableInstance.mint(depositorAddress, tokenID, ""); - - await Promise.all([ - OriginERC721MintableInstance.approve( - OriginERC721HandlerInstance.address, - tokenID, - {from: depositorAddress} - ), - DestinationERC721MintableInstance.grantRole( - await DestinationERC721MintableInstance.MINTER_ROLE(), - DestinationERC721HandlerInstance.address - ), - await OriginBridgeInstance.adminSetResource( - OriginERC721HandlerInstance.address, - originResourceID, - OriginERC721MintableInstance.address, - emptySetResourceData - ), - await DestinationBridgeInstance.adminSetResource( - DestinationERC721HandlerInstance.address, - destinationResourceID, - DestinationERC721MintableInstance.address, - emptySetResourceData - ), - DestinationBridgeInstance.adminSetBurnable( - DestinationERC721HandlerInstance.address, - destinationBurnableContractAddresses[0] - ), - ]); - - originDepositData = Helpers.createERCDepositData( - tokenID, - 20, - recipientAddress - ); - originDepositProposalData = Helpers.createERC721DepositProposalData( - tokenID, - 20, - recipientAddress, - 32, - 0 - ); - - destinationDepositData = Helpers.createERCDepositData( - tokenID, - 20, - depositorAddress - ); - destinationDepositProposalData = Helpers.createERC721DepositProposalData( - tokenID, - 20, - depositorAddress, - 32, - 0 - ); - destinationDepositProposalDataHash = Ethers.utils.keccak256( - OriginERC721HandlerInstance.address + - destinationDepositProposalData.substr(2) - ); - - originDomainProposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: originDepositProposalData, - resourceID: destinationResourceID, - }; - - destinationDomainProposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - data: destinationDepositProposalData, - resourceID: originResourceID, - }; - - // set MPC address to unpause the Bridge - await OriginBridgeInstance.endKeygen(Helpers.mpcAddress); - await DestinationBridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositorAddress' should own tokenID", async () => { - const tokenOwner = await OriginERC721MintableInstance.ownerOf(tokenID); - assert.strictEqual(depositorAddress, tokenOwner); - }); - - it("[sanity] ERC721HandlerInstance.address should have an allowance for tokenID from depositorAddress", async () => { - const allowedAddress = await OriginERC721MintableInstance.getApproved( - tokenID - ); - assert.strictEqual(OriginERC721HandlerInstance.address, allowedAddress); - }); - - it( - "[sanity] DestinationERC721HandlerInstance.address should have minterRole for DestinationERC721MintableInstance", - async () => { - const isMinter = await DestinationERC721MintableInstance.hasRole( - await DestinationERC721MintableInstance.MINTER_ROLE(), - DestinationERC721HandlerInstance.address - ); - assert.isTrue(isMinter); - }); - - it(`E2E: tokenID of Origin ERC721 owned by depositAddress to Destination ERC721 - owned by recipientAddress and back again`, async () => { - const originProposalSignedData = await Helpers.signTypedProposal( - DestinationBridgeInstance.address, - [originDomainProposal] - ); - const destinationProposalSignedData = await Helpers.signTypedProposal( - OriginBridgeInstance.address, - [destinationDomainProposal] - ); - - let tokenOwner; - - // depositorAddress makes initial deposit of tokenID - await TruffleAssert.passes( - OriginBridgeInstance.deposit( - destinationDomainID, - originResourceID, - originDepositData, - feeData, - {from: depositorAddress} - ) - ); - - // Handler should own tokenID - tokenOwner = await OriginERC721MintableInstance.ownerOf(tokenID); - assert.strictEqual( - OriginERC721HandlerInstance.address, - tokenOwner, - "OriginERC721HandlerInstance.address does not own tokenID" - ); - - // destinationRelayer2 executes the proposal - await TruffleAssert.passes( - DestinationBridgeInstance.executeProposal( - originDomainProposal, - originProposalSignedData, - {from: destinationRelayer1Address} - ) - ); - - // Handler should still own tokenID of OriginERC721MintableInstance - tokenOwner = await OriginERC721MintableInstance.ownerOf(tokenID); - assert.strictEqual( - OriginERC721HandlerInstance.address, - tokenOwner, - "OriginERC721HandlerInstance.address does not own tokenID" - ); - - // Assert ERC721 balance was transferred from depositorAddress - tokenOwner = await DestinationERC721MintableInstance.ownerOf(tokenID); - assert.strictEqual( - tokenOwner, - recipientAddress, - "tokenID wasn't transferred from depositorAddress to recipientAddress" - ); - - // At this point a representation of OriginERC721Mintable has been transferred from - // depositor to the recipient using Both Bridges and DestinationERC721Mintable. - // Next we will transfer DestinationERC721Mintable back to the depositor - - await DestinationERC721MintableInstance.approve( - DestinationERC721HandlerInstance.address, - tokenID, - {from: recipientAddress} - ); - - // recipientAddress makes a deposit of the received depositAmount - await TruffleAssert.passes( - DestinationBridgeInstance.deposit( - originDomainID, - destinationResourceID, - destinationDepositData, - feeData, - {from: recipientAddress} - ) - ); - - // Token should no longer exist - await Helpers.reverts( - DestinationERC721MintableInstance.ownerOf(tokenID), - "ERC721: owner query for nonexistent token" - ); - - // originRelayer executes the proposal - await TruffleAssert.passes( - OriginBridgeInstance.executeProposal( - destinationDomainProposal, - destinationProposalSignedData, - {from: originRelayer1Address} - ) - ); - - // Assert Destination tokenID no longer exists - await Helpers.reverts( - DestinationERC721MintableInstance.ownerOf(tokenID), - "ERC721: owner query for nonexistent token" - ); - - // Assert DestinationERC721MintableInstance tokenID was transferred to recipientAddress - tokenOwner = await OriginERC721MintableInstance.ownerOf(tokenID); - assert.strictEqual( - depositorAddress, - tokenOwner, - "OriginERC721MintableInstance tokenID was not transferred back to depositorAddress" - ); - }); -}); diff --git a/test/e2e/erc721/differentChainsMock.test.ts b/test/e2e/erc721/differentChainsMock.test.ts new file mode 100644 index 00000000..92f9a0b6 --- /dev/null +++ b/test/e2e/erc721/differentChainsMock.test.ts @@ -0,0 +1,287 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createBtcDepositData, createERC721DepositProposalData, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; +import {createResourceID} from "../../helpers"; + +describe("E2E ERC721 - Two EVM Chains", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const tokenID = BigInt(1); + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let OriginBridgeInstance: ContractTypesMap["Bridge"]; + let OriginDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let OriginERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let OriginERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + + let originDepositProposalData: Hex; + let originDepositData: Hex; + let originResourceID: Hex;; + let originDomainProposal: Proposal; + let originDepositProposalDataHash: Hex; + + let DestinationBridgeInstance: ContractTypesMap["Bridge"];; + let DestinationDefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let DestinationERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let DestinationERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + + let destinationDepositData: Hex; + let destinationDepositProposalData: Hex; + let destinationResourceID: Hex; + let destinationDomainProposal: Proposal; + let destinationDepositProposalDataHash: Hex; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let originRelayer1: WalletClient; + let destinationRelayer1: WalletClient; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance: OriginDefaultMessageReceiverInstance, + BridgeInstance: OriginBridgeInstance, + ERC721MintableInstance: OriginERC721MintableInstance, + ERC721HandlerInstance: OriginERC721HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + ({ + DefaultMessageReceiverInstance: DestinationDefaultMessageReceiverInstance, + BridgeInstance: DestinationBridgeInstance, + ERC721MintableInstance: DestinationERC721MintableInstance, + ERC721HandlerInstance: DestinationERC721HandlerInstance, + } = await loadFixture(deployDestinationChainContracts)); + [ + admin, + depositor, + recipient, + originRelayer1, + destinationRelayer1, + ] = await hre.viem.getWalletClients(); + + originResourceID = createResourceID( + OriginERC721MintableInstance.address, + originDomainID + ); + + destinationResourceID = createResourceID( + DestinationERC721MintableInstance.address, + originDomainID + ); + + await OriginERC721MintableInstance.write.mint([depositor.account!.address, tokenID, ""]); + + await OriginERC721MintableInstance.write.approve([ + OriginERC721HandlerInstance.address, + tokenID], + {account: depositor.account} + ); + await DestinationERC721MintableInstance.write.grantRole([ + await DestinationERC721MintableInstance.read.MINTER_ROLE(), + DestinationERC721HandlerInstance.address + ]); + await OriginBridgeInstance.write.adminSetResource([ + OriginERC721HandlerInstance.address, + originResourceID, + OriginERC721MintableInstance.address, + emptySetResourceData + ]); + await DestinationBridgeInstance.write.adminSetResource([ + DestinationERC721HandlerInstance.address, + destinationResourceID, + DestinationERC721MintableInstance.address, + emptySetResourceData + ]); + await DestinationBridgeInstance.write.adminSetBurnable([ + DestinationERC721HandlerInstance.address, + DestinationERC721MintableInstance.address, + ]), + + originDepositData = createERCDepositData( + tokenID, + 20, + recipient + ); + originDepositProposalData = createERC721DepositProposalData( + tokenID, + 20, + recipient.account!.address, + 32, + toHex(0) + ); + + destinationDepositData = createERCDepositData( + tokenID, + 20, + depositor + ); + destinationDepositProposalData = createERC721DepositProposalData( + tokenID, + 20, + depositor.account!.address, + 32, + toHex(0) + ); + destinationDepositProposalDataHash = keccak256( + concat([ + OriginERC721HandlerInstance.address, + trimPrefix(destinationDepositProposalData) + ]) + ); + + originDomainProposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: originDepositProposalData, + resourceID: destinationResourceID, + }; + + destinationDomainProposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + data: destinationDepositProposalData, + resourceID: originResourceID, + }; + + // set MPC address to unpause the Bridge + await OriginBridgeInstance.write.endKeygen([mpcAddress]); + await DestinationBridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor' should own tokenID", async () => { + const tokenOwner = await OriginERC721MintableInstance.read.ownerOf([tokenID]); + assert.strictEqual(depositor.account!.address, tokenOwner); + }); + + it("[sanity] ERC721HandlerInstance.address should have an allowance for tokenID from depositor", async () => { + const allowedAddress = await OriginERC721MintableInstance.read.getApproved([ + tokenID + ]); + assert.strictEqual(OriginERC721HandlerInstance.address, allowedAddress); + }); + + it(`[sanity] DestinationERC721HandlerInstance.address should have + minterRole for DestinationERC721MintableInstance`, async () => { + const isMinter = await DestinationERC721MintableInstance.read.hasRole([ + await DestinationERC721MintableInstance.read.MINTER_ROLE(), + DestinationERC721HandlerInstance.address + ]); + assert.isTrue(isMinter); + }); + + it(`E2E: tokenID of Origin ERC721 owned by depositAddress to Destination ERC721 + owned by recipient and back again`, async () => { + const originProposalSignedData = await signTypedProposal( + DestinationBridgeInstance.address, + [originDomainProposal] + ); + const destinationProposalSignedData = await signTypedProposal( + OriginBridgeInstance.address, + [destinationDomainProposal] + ); + + let tokenOwner; + + // depositor makes initial deposit of tokenID + await expect( + OriginBridgeInstance.write.deposit([ + destinationDomainID, + originResourceID, + originDepositData, + feeData], + {account: depositor.account} + ) + ).not.to.be.reverted; + + // Handler should own tokenID + tokenOwner = await OriginERC721MintableInstance.read.ownerOf([tokenID]); + assert.strictEqual( + OriginERC721HandlerInstance.address, + tokenOwner, + "OriginERC721HandlerInstance.address does not own tokenID" + ); + + // destinationRelayer2 executes the proposal + await expect( + DestinationBridgeInstance.write.executeProposal([ + originDomainProposal, + originProposalSignedData], + {account: destinationRelayer1.account} + ) + ).not.to.be.reverted; + + // Handler should still own tokenID of OriginERC721MintableInstance + tokenOwner = await OriginERC721MintableInstance.read.ownerOf([tokenID]); + assert.strictEqual( + OriginERC721HandlerInstance.address, + tokenOwner, + "OriginERC721HandlerInstance.address does not own tokenID" + ); + + // Assert ERC721 balance was transferred from depositor + tokenOwner = await DestinationERC721MintableInstance.read.ownerOf([tokenID]); + assert.strictEqual( + tokenOwner, + recipient, + "tokenID wasn't transferred from depositor to recipient" + ); + + // At this point a representation of OriginERC721Mintable has been transferred from + // depositor to the recipient using Both Bridges and DestinationERC721Mintable. + // Next we will transfer DestinationERC721Mintable back to the depositor + + await DestinationERC721MintableInstance.write.approve([ + DestinationERC721HandlerInstance.address, + tokenID], + {account: recipient.account} + ); + + // recipient makes a deposit of the received depositAmount + await expect( + DestinationBridgeInstance.write.deposit([ + originDomainID, + destinationResourceID, + destinationDepositData, + feeData], + {account: recipient.account} + ) + ).not.to.be.reverted; + + // Token should no longer exist + await expect( + DestinationERC721MintableInstance.read.ownerOf([tokenID]), + "ERC721: owner query for nonexistent token" + ).to.be.reverted; + + // originRelayer executes the proposal + await expect( + OriginBridgeInstance.write.executeProposal([ + destinationDomainProposal, + destinationProposalSignedData], + {account: originRelayer1.account} + ) + ).not.to.be.reverted; + + // Assert Destination tokenID no longer exists + await expect( + DestinationERC721MintableInstance.read.ownerOf([tokenID]), + "ERC721: owner query for nonexistent token" + ).to.be.reverted; + + // Assert DestinationERC721MintableInstance tokenID was transferred to recipient + tokenOwner = await OriginERC721MintableInstance.read.ownerOf([tokenID]); + assert.strictEqual( + depositor.account!.address, + tokenOwner, + "OriginERC721MintableInstance tokenID was not transferred back to depositor" + ); + }); +}); diff --git a/test/e2e/erc721/sameChain.js b/test/e2e/erc721/sameChain.js deleted file mode 100644 index 00cf0311..00000000 --- a/test/e2e/erc721/sameChain.js +++ /dev/null @@ -1,139 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); - -contract("E2E ERC721 - Same Chain", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const tokenID = 1; - const depositMetadata = "0xc0ff33"; - const expectedDepositNonce = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC721MintableInstance; - let ERC721HandlerInstance; - - let resourceID; - let depositData; - let proposalData; - - let proposal; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC721MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC721MintableInstance.address]; - burnableContractAddresses = []; - - ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - - await Promise.all([ - ERC721MintableInstance.mint(depositorAddress, tokenID, depositMetadata), - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - resourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - ]); - - await ERC721MintableInstance.approve( - ERC721HandlerInstance.address, - tokenID, - {from: depositorAddress} - ); - - depositData = Helpers.createERCDepositData(tokenID, 20, recipientAddress); - proposalData = Helpers.createERC721DepositProposalData( - tokenID, - 20, - recipientAddress, - depositMetadata.length, - depositMetadata - ); - depositProposalDataHash = Ethers.utils.keccak256( - ERC721HandlerInstance.address + proposalData.substr(2) - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: proposalData, - resourceID: resourceID, - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositorAddress' should own tokenID", async () => { - const tokenOwner = await ERC721MintableInstance.ownerOf(tokenID); - assert.strictEqual(depositorAddress, tokenOwner); - }); - - it("[sanity] ERC721HandlerInstance.address should have an allowance for tokenID from depositorAddress", async () => { - const allowedAddress = await ERC721MintableInstance.getApproved(tokenID); - assert.strictEqual(ERC721HandlerInstance.address, allowedAddress); - }); - - it("depositAmount of Destination ERC721 should be transferred to recipientAddress", async () => { - // depositorAddress makes initial deposit of depositAmount - await TruffleAssert.passes( - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }) - ); - - // Handler should have a balance of depositAmount - const tokenOwner = await ERC721MintableInstance.ownerOf(tokenID); - assert.strictEqual(ERC721HandlerInstance.address, tokenOwner); - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // relayer1 creates the deposit proposal - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // Assert ERC721 balance was transferred from depositorAddress - const tokenOwnerAfterTransfer = await ERC721MintableInstance.ownerOf( - tokenID - ); - assert.strictEqual(recipientAddress, tokenOwnerAfterTransfer); - }); -}); diff --git a/test/e2e/erc721/sameChain.test.ts b/test/e2e/erc721/sameChain.test.ts new file mode 100644 index 00000000..5f25fc8d --- /dev/null +++ b/test/e2e/erc721/sameChain.test.ts @@ -0,0 +1,138 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from "hardhat"; +import {assert, expect} from "chai"; +import {encodeAbiParameters, Hex, keccak256, parseAbiParameters, parseEther, parseUnits, WalletClient, concat, toHex} from "viem"; +import {createERC721DepositProposalData, createResourceID, createERCDepositData, deploySourceChainContracts, deployDestinationChainContracts, getBalance, mpcAddress, signTypedProposal, trimPrefix, createDepositProposalDataFromHandlerResponse} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Proposal} from "../../../types"; + + +describe("E2E ERC721 - Same Chain", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const tokenID = BigInt(1); + const depositMetadata = "0xc0ff33" as unknown as Hex; + const expectedDepositNonce = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let relayer1: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + let depositProposalData: Hex; + let proposalData: Hex; + let proposal: Proposal; + let depositProposalDataHash: Hex; + + beforeEach(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC721MintableInstance, + ERC721HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + relayer1, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC721MintableInstance.address, + originDomainID + ); + + await ERC721MintableInstance.write.mint([depositor.account!.address, tokenID, depositMetadata]); + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + resourceID, + ERC721MintableInstance.address, + emptySetResourceData + ]); + + await ERC721MintableInstance.write.approve([ + ERC721HandlerInstance.address, + tokenID], + {account: depositor.account} + ); + + depositData = createERCDepositData(tokenID, 20, recipient); + proposalData = createERC721DepositProposalData( + tokenID, + 20, + recipient.account!.address, + depositMetadata.length, + depositMetadata + ); + depositProposalDataHash = keccak256( + concat([ + ERC721HandlerInstance.address, + trimPrefix(proposalData) + ]) + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: proposalData, + resourceID: resourceID, + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor' should own tokenID", async () => { + const tokenOwner = await ERC721MintableInstance.read.ownerOf([tokenID]); + assert.strictEqual(depositor.account!.address, tokenOwner); + }); + + it("[sanity] ERC721HandlerInstance.address should have an allowance for tokenID from depositor", async () => { + const allowedAddress = await ERC721MintableInstance.read.getApproved([tokenID]); + assert.strictEqual(ERC721HandlerInstance.address, allowedAddress); + }); + + it("depositAmount of Destination ERC721 should be transferred to recipient", async () => { + // depositor makes initial deposit of depositAmount + await expect( + BridgeInstance.write.deposit([originDomainID, resourceID, depositData, feeData], { + account: depositor.account, + }) + ).not.to.be.reverted; + + // Handler should have a balance of depositAmount + const tokenOwner = await ERC721MintableInstance.read.ownerOf([tokenID]); + assert.strictEqual(ERC721HandlerInstance.address, tokenOwner); + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // relayer1 creates the deposit proposal + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }) + ).not.to.be.reverted; + + // Assert ERC721 balance was transferred from depositor + const tokenOwnerAfterTransfer = await ERC721MintableInstance.read.ownerOf([ + tokenID + ]); + assert.strictEqual(recipient.account!.address, tokenOwnerAfterTransfer); + }); +}); diff --git a/test/forwarder/forwarder.js b/test/forwarder/forwarder.js deleted file mode 100644 index 6e54b8f8..00000000 --- a/test/forwarder/forwarder.js +++ /dev/null @@ -1,414 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Helpers = require("../helpers"); -const Ethers = require("ethers"); -const Wallet = require("ethereumjs-wallet").default; -const ethSigUtil = require("eth-sig-util"); -const ForwarderContract = artifacts.require("Forwarder"); -const TestTargetContract = artifacts.require("TestTarget"); - -contract("Forwarder", async () => { - const relayer1 = Wallet.generate(); - const relayer2 = Wallet.generate(); - const relayer3 = Wallet.generate(); - const relayer1Address = relayer1.getAddressString(); - const relayer2Address = relayer2.getAddressString(); - const relayer3Address = relayer3.getAddressString(); - - const provider = new Ethers.providers.JsonRpcProvider(); - - const name = "Forwarder"; - const version = "0.0.1"; - - const EIP712Domain = [ - {name: "name", type: "string"}, - {name: "version", type: "string"}, - {name: "chainId", type: "uint256"}, - {name: "verifyingContract", type: "address"}, - ]; - - let domain; - const types = { - EIP712Domain, - ForwardRequest: [ - {name: "from", type: "address"}, - {name: "to", type: "address"}, - {name: "value", type: "uint256"}, - {name: "gas", type: "uint256"}, - {name: "nonce", type: "uint256"}, - {name: "data", type: "bytes"}, - ], - }; - - let ForwarderInstance; - let TestTargetInstance; - - let sign; - let request; - - beforeEach(async () => { - ForwarderInstance = await ForwarderContract.new(); - TestTargetInstance = await TestTargetContract.new(); - - const signer = provider.getSigner(); - - await signer.sendTransaction({ - to: relayer1Address, - value: Ethers.utils.parseEther("0.1"), - }); - await signer.sendTransaction({ - to: relayer2Address, - value: Ethers.utils.parseEther("0.1"), - }); - await signer.sendTransaction({ - to: relayer3Address, - value: Ethers.utils.parseEther("0.1"), - }); - - domain = { - name, - version, - chainId: 1, - verifyingContract: ForwarderInstance.address, - }; - - request = { - from: relayer1Address, - to: TestTargetInstance.address, - value: "0", - gas: "300000", - nonce: 0, - data: "0x", - }; - - sign = ethSigUtil.signTypedMessage(relayer1.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: request, - }, - }); - }); - - it(`In case of invalid request(from), - it should not be verified and should be reverted in executing of the forwarder contract`, async () => { - const request_other = { - from: relayer2Address, - to: TestTargetInstance.address, - value: "0", - gas: "300000", - nonce: 0, - data: "0x", - }; - - assert.equal(await ForwarderInstance.verify(request_other, sign), false); - return Helpers.reverts( - ForwarderInstance.execute(request_other, sign), - "MinimalForwarder: signature does not match request" - ); - }); - - it(`In case of invalid request(to), - it should not be verified and should be reverted in executing of the forwarder contract`, async () => { - const request_other = { - from: relayer1Address, - to: relayer2Address, - value: "0", - gas: "300000", - nonce: 0, - data: "0x", - }; - - assert.equal(await ForwarderInstance.verify(request_other, sign), false); - return Helpers.reverts( - ForwarderInstance.execute(request_other, sign), - "MinimalForwarder: signature does not match request" - ); - }); - - it(`In case of invalid request(value), - it should not be verified and should be reverted in executing of the forwarder contract`, async () => { - const request_other = { - from: relayer1Address, - to: TestTargetInstance.address, - value: "1", - gas: "300000", - nonce: 0, - data: "0x", - }; - - assert.equal(await ForwarderInstance.verify(request_other, sign), false); - return Helpers.reverts( - ForwarderInstance.execute(request_other, sign), - "MinimalForwarder: signature does not match request" - ); - }); - - it(`In case of invalid request(gas), - it should not be verified and should be reverted in executing of the forwarder contract`, async () => { - const request_other = { - from: relayer1Address, - to: TestTargetInstance.address, - value: "0", - gas: "50000", - nonce: 0, - data: "0x", - }; - - assert.equal(await ForwarderInstance.verify(request_other, sign), false); - return Helpers.reverts( - ForwarderInstance.execute(request_other, sign), - "MinimalForwarder: signature does not match request" - ); - }); - - it(`In case of invalid request(nonce), - it should not be verified and should be reverted in executing of the forwarder contract`, async () => { - const request_other = { - from: relayer1Address, - to: TestTargetInstance.address, - value: "0", - gas: "300000", - nonce: 1, - data: "0x", - }; - - assert.equal(await ForwarderInstance.verify(request_other, sign), false); - return Helpers.reverts( - ForwarderInstance.execute(request_other, sign), - "MinimalForwarder: signature does not match request" - ); - }); - - it(`In case of invalid request(data), - it should not be verified and should be reverted in executing of the forwarder contract`, async () => { - const request_other = { - from: relayer1Address, - to: TestTargetInstance.address, - value: "0", - gas: "300000", - nonce: 0, - data: "0x1234", - }; - - assert.equal(await ForwarderInstance.verify(request_other, sign), false); - return Helpers.reverts( - ForwarderInstance.execute(request_other, sign), - "MinimalForwarder: signature does not match request" - ); - }); - - it("If signature is valid, but req.from != signer, it should be reverted and should not be verified", async () => { - const sign_other = ethSigUtil.signTypedMessage(relayer2.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: request, - }, - }); - - assert.equal(await ForwarderInstance.verify(request, sign_other), false); - return Helpers.reverts( - ForwarderInstance.execute(request, sign_other), - "MinimalForwarder: signature does not match request" - ); - }); - - it(`If signature is valid, - but req.nonce != nonce[signer], it should be reverted and should not be verified`, async () => { - const request_other = { - from: relayer1Address, - to: TestTargetInstance.address, - value: "0", - gas: "300000", - nonce: 10, - data: "0x", - }; - - const sign_other = ethSigUtil.signTypedMessage(relayer1.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: request_other, - }, - }); - - assert.equal( - await ForwarderInstance.verify(request_other, sign_other), - false - ); - return Helpers.reverts( - ForwarderInstance.execute(request_other, sign_other), - "MinimalForwarder: signature does not match request" - ); - }); - - it("Execute should succeed even if the call to the target failed", async () => { - const new_request = { - from: relayer1Address, - to: ForwarderInstance.address, - value: "0", - gas: "300000", - nonce: 0, - data: "0x", - }; - - const new_sign = ethSigUtil.signTypedMessage(relayer1.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: new_request, - }, - }); - - const result = await ForwarderInstance.execute.call(new_request, new_sign); - assert.equal(result[0], false); - }); - - it("Should be failed in case of execute is called with less gas than req.gas", async () => { - const new_request = { - from: relayer3Address, - to: TestTargetInstance.address, - value: "0", - gas: "300000", - nonce: 0, - data: "0x", - }; - - const new_sign = ethSigUtil.signTypedMessage(relayer3.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: new_request, - }, - }); - - await TestTargetInstance.setBurnAllGas(); - await TruffleAssert.fails( - ForwarderInstance.execute(new_request, new_sign, {gas: 100000}) - ); - }); - - it("req.gas should be passed to the target contract", async () => { - const requestGas = 100000; - const new_request = { - from: relayer3Address, - to: TestTargetInstance.address, - value: "0", - gas: requestGas.toString(), - nonce: 0, - data: "0x", - }; - - const new_sign = ethSigUtil.signTypedMessage(relayer3.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: new_request, - }, - }); - - await ForwarderInstance.execute(new_request, new_sign, {gas: 200000}); - const availableGas = await TestTargetInstance.gasLeft(); - assert(availableGas > 96000); - assert(availableGas < requestGas); - }); - - it("req.data should be passed to the target contract along with the req.from at the end", async () => { - const requestData = "0x1234"; - const new_request = { - from: relayer3Address, - to: TestTargetInstance.address, - value: "0", - gas: "300000", - nonce: 0, - data: requestData, - }; - - const new_sign = ethSigUtil.signTypedMessage(relayer3.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: new_request, - }, - }); - await ForwarderInstance.execute(new_request, new_sign); - const callData = await TestTargetInstance.data(); - const expectedData = requestData + relayer3Address.substr(2); - assert.equal(callData, expectedData); - }); - - it("req.value should be passed to the target contract", async () => { - const request_value = Ethers.utils.parseEther("0.1"); - const new_request = { - from: relayer3Address, - to: TestTargetInstance.address, - value: request_value.toString(), - gas: "300000", - nonce: 0, - data: "0x", - }; - - const new_sign = ethSigUtil.signTypedMessage(relayer3.getPrivateKey(), { - data: { - types: types, - domain: domain, - primaryType: "ForwardRequest", - message: new_request, - }, - }); - await ForwarderInstance.execute(new_request, new_sign, { - value: Ethers.utils.parseEther("0.3"), - }); - const targetContract_balance = provider.getBalance( - TestTargetInstance.address - ); - assert.equal( - (await targetContract_balance).toString(), - request_value.toString() - ); - }); - - it("The successful execute can not be replayed again", async () => { - await ForwarderInstance.execute(request, sign); - return Helpers.reverts( - ForwarderInstance.execute(request, sign), - "MinimalForwarder: signature does not match request" - ); - }); - - it("Only a single call to the target is performed during the execution", async () => { - await ForwarderInstance.execute(request, sign); - const calls = await TestTargetInstance.calls(); - assert.equal(calls.toNumber(), 1); - }); - - it("In case of request is matched with signature, it should be verified", async () => { - assert.equal(await ForwarderInstance.verify(request, sign), true); - }); - - it( - "In case of request is matched with signature, it should not be reverted and nonce should be increased", - async () => { - const nonce_before_execute = await ForwarderInstance.getNonce( - relayer1Address - ); - await ForwarderInstance.execute(request, sign); - const nonce_after_execute = await ForwarderInstance.getNonce( - relayer1Address - ); - assert.equal( - nonce_after_execute.toNumber(), - nonce_before_execute.toNumber() + 1 - ); - }); -}); diff --git a/test/forwarder/forwarder.test.ts b/test/forwarder/forwarder.test.ts new file mode 100644 index 00000000..6ec1b7dd --- /dev/null +++ b/test/forwarder/forwarder.test.ts @@ -0,0 +1,447 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import 'viem/window'; +import {createPublicClient, createTestClient, createWalletClient, custom, getAddress, Hex, http, parseEther, publicActions, TestClient, walletActions, WalletClient} from "viem"; +import { hardhat, localhost } from 'viem/chains' +import {generatePrivateKey, toAccount, privateKeyToAccount} from 'viem/accounts'; +import {assert, expect} from 'chai'; +import {deploySourceChainContracts, getBalance, trimPrefix} from '../helpers'; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {signTypedData, SignTypedDataVersion} from '@metamask/eth-sig-util'; + + +describe("Forwarder", () => { + const relayer1PrivKey = generatePrivateKey(); + const relayer2PrivKey = generatePrivateKey(); + const relayer3PrivKey = generatePrivateKey(); + + const relayer1Account = privateKeyToAccount(relayer1PrivKey); + const relayer2Account = privateKeyToAccount(relayer2PrivKey); + const relayer3Account = privateKeyToAccount(relayer3PrivKey); + + const relayer1Address = relayer1Account.address; + const relayer2Address = relayer2Account.address; + const relayer3Address = relayer3Account.address; + + const expectedNonce = BigInt(0); + + const client = createPublicClient({ + chain: hardhat, + transport: http(), + }).extend(walletActions) + + const name = "Forwarder" as string; + const primaryType = "ForwardRequest"; + + const EIP712Domain = [ + {name: "name", type: "string"}, + {name: "version", type: "string"}, + {name: "chainId", type: "uint256"}, + {name: "verifyingContract", type: "address"}, + ]; + + let domain: { + name: string, + chainId: number, + verifyingContract: Hex, + }; + + const types = { + EIP712Domain: EIP712Domain, + ForwardRequest: [ + {name: "from", type: "address"}, + {name: "to", type: "address"}, + {name: "value", type: "uint256"}, + {name: "gas", type: "uint256"}, + {name: "nonce", type: "uint256"}, + {name: "data", type: "bytes"}, + ], + }; + + let ForwarderInstance: ContractTypesMap["Forwarder"]; + let TestTargetInstance: ContractTypesMap["TestTarget"]; + + let signature: Hex; + let request: { + from: Hex, + to: Hex, + value: bigint, + gas: bigint, + nonce: bigint, + data: Hex, + }; + + before(async () => { + ({ + ForwarderInstance, + TestTargetInstance, + } = await loadFixture(deploySourceChainContracts)); + const [account] = await client.getAddresses(); + + await client.sendTransaction({ + account, + to: relayer2Address, + value: parseEther("0.1"), + }); + await client.sendTransaction({ + account, + to: relayer2Address, + value: parseEther("0.1"), + }); + await client.sendTransaction({ + account, + to: relayer3Address, + value: parseEther("0.1"), + }); + + domain = { + name, + chainId: 1, + verifyingContract: ForwarderInstance.address + }; + + request = { + from: relayer1Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + signature = signTypedData({ + privateKey: Buffer.from(relayer1PrivKey), + data: { + types: types, + domain: domain, + primaryType: primaryType, + message: request, + }, + version: SignTypedDataVersion.V3, + }) as Hex + }); + + it(`In case of invalid request(from), + it should not be verified and should be reverted in executing of the forwarder contract`, async () => { + const request_other = { + from: relayer2Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + assert.equal(await ForwarderInstance.read.verify([request_other, signature]), false); + await expect(ForwarderInstance.write.execute([request_other, signature])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it(`In case of invalid request(to), + it should not be verified and should be reverted in executing of the forwarder contract`, async () => { + const request_other = { + from: relayer1Address, + to: relayer2Address, + value: BigInt(0), + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + assert.equal(await ForwarderInstance.read.verify([request_other, signature]), false); + await expect(ForwarderInstance.write.execute([request_other, signature])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it(`In case of invalid request(value), + it should not be verified and should be reverted in executing of the forwarder contract`, async () => { + const request_other = { + from: relayer1Address, + to: TestTargetInstance.address, + value: BigInt(1), + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + assert.equal(await ForwarderInstance.read.verify([request_other, signature]), false); + await expect(ForwarderInstance.write.execute([request_other, signature])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it(`In case of invalid request(gas), + it should not be verified and should be reverted in executing of the forwarder contract`, async () => { + const request_other = { + from: relayer1Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(50000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + assert.equal(await ForwarderInstance.read.verify([request_other, signature]), false); + await expect(ForwarderInstance.write.execute([request_other, signature])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it(`In case of invalid request(nonce), + it should not be verified and should be reverted in executing of the forwarder contract`, async () => { + const request_other = { + from: relayer1Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: BigInt(1), + data: "0x" as unknown as Hex, + }; + + assert.equal(await ForwarderInstance.read.verify([request_other, signature]), false); + await expect(ForwarderInstance.write.execute([request_other, signature])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it(`In case of invalid request(data), + it should not be verified and should be reverted in executing of the forwarder contract`, async () => { + const request_other = { + from: relayer1Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x1234" as unknown as Hex, + }; + + assert.equal(await ForwarderInstance.read.verify([request_other, signature]), false); + await expect(ForwarderInstance.write.execute([request_other, signature])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it("If signature is valid, but req.from != client, it should be reverted and should not be verified", async () => { + const sign_other = signTypedData({ + privateKey: Buffer.from(relayer1PrivKey), + data: { + types: types, + domain: domain, + primaryType: primaryType, + message: request, + }, + version: SignTypedDataVersion.V3, + }) as Hex; + + assert.equal(await ForwarderInstance.read.verify([request, sign_other]), false); + await expect(ForwarderInstance.write.execute([request, sign_other])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it(`If signature is valid, + but req.nonce != nonce[client], it should be reverted and should not be verified`, async () => { + const request_other = { + from: relayer1Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: BigInt(10), + data: "0x" as unknown as Hex, + }; + + const sign_other = signTypedData({ + privateKey: Buffer.from(relayer1PrivKey), + data: { + types: types, + domain: domain, + primaryType: "ForwardRequest", + message: request_other, + }, + version: SignTypedDataVersion.V3, + }) as Hex; + + assert.equal( + await ForwarderInstance.read.verify([request_other, sign_other]), + false + ); + await expect(ForwarderInstance.write.execute([request_other, sign_other])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it("Execute should succeed even if the call to the target failed", async () => { + const new_request = { + from: relayer1Address, + to: ForwarderInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + const new_sign = signTypedData({ + privateKey: Buffer.from(relayer1PrivKey), + data: { + types: types, + domain: domain, + primaryType: "ForwardRequest", + message: new_request, + }, + version: SignTypedDataVersion.V3, + }) as Hex; + + const result = await ForwarderInstance.write.execute([new_request, new_sign]); + assert.equal(Boolean(result[0]), false); + }); + + it("Should be failed in case of execute is called with less gas than req.gas", async () => { + const new_request = { + from: relayer3Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + const new_sign = signTypedData({ + privateKey: Buffer.from(relayer3PrivKey), + data: { + types: types, + domain: domain, + primaryType: "ForwardRequest", + message: new_request, + }, + version: SignTypedDataVersion.V3, + }) as Hex; + + await TestTargetInstance.write.setBurnAllGas(); + await expect( + ForwarderInstance.write.execute([new_request, new_sign], {gas: BigInt(100000)}) + ).to.be.rejected; + }); + + it("req.gas should be passed to the target contract", async () => { + const requestGas = BigInt(100000); + const new_request = { + from: relayer3Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: requestGas, + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + const new_sign = signTypedData({ + privateKey: Buffer.from(relayer3PrivKey), + data: { + types: types, + domain: domain, + primaryType: "ForwardRequest", + message: new_request, + }, + version: SignTypedDataVersion.V3, + }) as Hex; + + await ForwarderInstance.write.execute([new_request, new_sign], {gas: BigInt(200000)}); + const availableGas = await TestTargetInstance.read.gasLeft(); + assert(availableGas > 96000); + assert(availableGas < requestGas); + }); + + it("req.data should be passed to the target contract along with the req.from at the end", async () => { + const requestData = "0x1234" as unknown as Hex; + const new_request = { + from: relayer3Address, + to: TestTargetInstance.address, + value: BigInt(0), + gas: BigInt(300000), + nonce: expectedNonce, + data: requestData, + }; + + const new_sign = signTypedData({ + privateKey: Buffer.from(relayer3PrivKey), + data: { + types: types, + domain: domain, + primaryType: "ForwardRequest", + message: new_request, + }, + version: SignTypedDataVersion.V3, + }) as Hex; + await ForwarderInstance.write.execute([new_request, new_sign]); + const callData = await TestTargetInstance.read.data(); + const expectedData = requestData + trimPrefix(relayer3Address); + assert.equal(callData, expectedData); + }); + + it("req.value should be passed to the target contract", async () => { + const request_value = parseEther("0.1"); + const new_request = { + from: relayer3Address, + to: TestTargetInstance.address, + value: request_value, + gas: BigInt(300000), + nonce: expectedNonce, + data: "0x" as unknown as Hex, + }; + + const new_sign = signTypedData({ + privateKey: Buffer.from(relayer3PrivKey), + data: { + types: types, + domain: domain, + primaryType: "ForwardRequest", + message: new_request, + }, + version: SignTypedDataVersion.V3, + }) as Hex; + await ForwarderInstance.write.execute([new_request, new_sign], { + value: parseEther("0.3"), + }); + const targetContract_balance = getBalance( + TestTargetInstance + ); + assert.equal( + (await targetContract_balance).toString(), + request_value.toString() + ); + }); + + it("The successful execute can not be replayed again", async () => { + await ForwarderInstance.write.execute([request, signature]); + await expect(ForwarderInstance.write.execute([request, signature])).to.be.revertedWith( + "MinimalForwarder: signature does not match request" + ); + }); + + it("Only a single call to the target is performed during the execution", async () => { + await ForwarderInstance.write.execute([request, signature]); + const calls = await TestTargetInstance.read.calls(); + assert.equal(calls, BigInt(1)); + }); + + it("In case of request is matched with signature, it should be verified", async () => { + assert.equal(await ForwarderInstance.read.verify([request, signature]), true); + }); + + it("In case of request is matched with signature, it should not be reverted and nonce should be increased", async () => { + const nonce_before_execute = await ForwarderInstance.read.getNonce([ + relayer1Address + ]); + await ForwarderInstance.write.execute([request, signature]); + const nonce_after_execute = await ForwarderInstance.read.getNonce([ + relayer1Address + ]); + assert.equal( + nonce_after_execute, + nonce_before_execute + BigInt(1) + ); + }); +}); diff --git a/test/frostKeygen/frostKeygen.js b/test/frostKeygen/frostKeygen.js deleted file mode 100644 index 55953a65..00000000 --- a/test/frostKeygen/frostKeygen.js +++ /dev/null @@ -1,41 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Helpers = require("../helpers"); -const FROSTKeygen = artifacts.require("FROSTKeygen") - -contract("FROSTKeygen", (accounts) => { - let FROSTKeygenInstance; - - beforeEach(async () => { - FROSTKeygenInstance = await FROSTKeygen.new(accounts[0]); - }); - - it("should emit StartedFROSTKeygen event when startFROSTKeygen is called by the owner", async () => { - const tx = await FROSTKeygenInstance.startFROSTKeygen({from: accounts[0]}) - - TruffleAssert.eventEmitted(tx, "StartedFROSTKeygen"); - }); - - it("should revert when startFROSTKeygen is not called by the owner", async () => { - await Helpers.reverts( - FROSTKeygenInstance.startFROSTKeygen({from: accounts[1]}), - ) - }); - - it("should revert when keygen ended", async() => { - const tx = await FROSTKeygenInstance.endFROSTKeygen({from: accounts[0]}) - TruffleAssert.eventEmitted(tx, "EndedFROSTKeygen"); - - await Helpers.reverts( - FROSTKeygenInstance.startFROSTKeygen({from: accounts[0]}) - ) - }); - - it("should revert when end keygen not called by owner", async() => { - await Helpers.reverts( - FROSTKeygenInstance.endFROSTKeygen({from: accounts[1]}), - ) - }); -}) diff --git a/test/frostKeygen/frostKeygen.test.ts b/test/frostKeygen/frostKeygen.test.ts new file mode 100644 index 00000000..28fc717d --- /dev/null +++ b/test/frostKeygen/frostKeygen.test.ts @@ -0,0 +1,53 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {deploySourceChainContracts} from "../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {WalletClient} from 'viem'; +import {expect} from 'chai'; + + +describe("FROSTKeygen", () => { + let FROSTKeygenInstance: ContractTypesMap["FROSTKeygen"];; + let admin: WalletClient; + let nonadmin: WalletClient; + + before(async () => { + ({ + FROSTKeygenInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + nonadmin + ] = await hre.viem.getWalletClients(); + }); + + it("should emit StartedFROSTKeygen event when startFROSTKeygen is called by the owner", async () => { + const startKexgenTx = await FROSTKeygenInstance.write.startFROSTKeygen({account: admin.account}) + + await expect(startKexgenTx).to.emit(FROSTKeygenInstance, "StartedFROSTKeygen"); + }); + + it("should revert when startFROSTKeygen is not called by the owner", async () => { + await expect( + FROSTKeygenInstance.write.startFROSTKeygen({account: nonadmin.account}), + ).to.be.reverted + }); + + it("should revert when keygen ended", async() => { + const endKeygenTx = await FROSTKeygenInstance.write.endFROSTKeygen({account: admin.account}) + await expect(endKeygenTx).to.emit(FROSTKeygenInstance, "EndedFROSTKeygen"); + + await expect( + FROSTKeygenInstance.write.startFROSTKeygen({account: admin.account}) + ).to.be.reverted + }); + + it("should revert when end keygen not called by owner", async() => { + await expect( + FROSTKeygenInstance.write.endFROSTKeygen({account: nonadmin.account}), + ).to.be.reverted + }); +}) diff --git a/test/gasBenchmarks/deployments.js b/test/gasBenchmarks/deployments.js deleted file mode 100644 index 24bd17c2..00000000 --- a/test/gasBenchmarks/deployments.js +++ /dev/null @@ -1,68 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../helpers"); - -const BridgeContract = artifacts.require("Bridge"); -const AccessControlSegregatorContract = artifacts.require( - "AccessControlSegregator" -); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const TestStoreContract = artifacts.require("TestStore"); -const ERCHandlerHelpersContract = artifacts.require("ERCHandlerHelpers"); -const ERC20SafeContract = artifacts.require("ERC20Safe"); -const ERC721SafeContract = artifacts.require("ERC721Safe"); -const ERC1155SafeContract = artifacts.require("ERC1155Safe"); - -contract("Gas Benchmark - [contract deployments]", async (accounts) => { - const domainID = 1; - const TestStoreMinCount = 1; - const gasBenchmarks = []; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - - it.skip("Should deploy all contracts and print benchmarks", async () => { - const accessControlInstance = await AccessControlSegregatorContract.new( - Helpers.accessControlFuncSignatures, - Array(13).fill(accounts[0]) - ); - let contractInstances = [accessControlInstance]; - contractInstances = contractInstances.concat( - await Promise.all([ - await BridgeContract.new(domainID, accessControlInstance.address).then( - (instance) => (BridgeInstance = instance) - ), - await DefaultMessageReceiverContract.new([], 100000).then( - (instance) => (DefaultMessageReceiverInstance = instance) - ), - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address), - ERC721HandlerContract.new(BridgeInstance.address), - ERC1155HandlerContract.new(BridgeInstance.address), - GmpHandlerContract.new(BridgeInstance.address), - TestStoreContract.new(TestStoreMinCount), - ERCHandlerHelpersContract.new(BridgeInstance.address), - ERC20SafeContract.new(), - ERC721SafeContract.new(), - ERC1155SafeContract.new(), - ]) - ); - for (const contractInstance of contractInstances) { - const txReceipt = await web3.eth.getTransactionReceipt( - contractInstance.transactionHash - ); - gasBenchmarks.push({ - type: contractInstance.constructor._json.contractName, - gasUsed: txReceipt.gasUsed, - }); - } - - console.table(gasBenchmarks); - }); -}); diff --git a/test/gasBenchmarks/deposits.js b/test/gasBenchmarks/deposits.js deleted file mode 100644 index 4aef8939..00000000 --- a/test/gasBenchmarks/deposits.js +++ /dev/null @@ -1,189 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); - -const Helpers = require("../helpers"); - -contract("Gas Benchmark - [Deposits]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const lenRecipientAddress = 20; - const gasBenchmarks = []; - - const erc20TokenAmount = 100; - const erc721TokenID = 1; - const erc1155TokenID = 1; - const erc1155TokenAmount = 100; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let ERC721MintableInstance; - let ERC721HandlerInstance; - let ERC1155MintableInstance; - let ERC1155HandlerInstance; - - let erc20ResourceID; - let erc721ResourceID; - let erc1155ResourceID; - - before(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance = instance) - ), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance = instance) - ), - ]); - - erc20ResourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - erc721ResourceID = Helpers.createResourceID( - ERC721MintableInstance.address, - originDomainID - ); - erc1155ResourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - originDomainID - ); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - - await Promise.all([ - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address).then( - (instance) => (ERC20HandlerInstance = instance) - ), - ERC20MintableInstance.mint(depositorAddress, erc20TokenAmount), - ERC721HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC721HandlerInstance = instance) - ), - ERC721MintableInstance.mint(depositorAddress, erc721TokenID, ""), - ERC1155HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC1155HandlerInstance = instance) - ), - ERC1155MintableInstance.mintBatch( - depositorAddress, - [erc1155TokenID], - [erc1155TokenAmount], - "0x0" - ), - ]); - - await Promise.all([ - ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - erc20TokenAmount, - {from: depositorAddress} - ), - ERC721MintableInstance.approve( - ERC721HandlerInstance.address, - erc721TokenID, - {from: depositorAddress} - ), - ERC1155MintableInstance.setApprovalForAll( - ERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - erc20ResourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - erc721ResourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - erc1155ResourceID, - ERC1155MintableInstance.address, - emptySetResourceData - ), - ]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("Should make ERC20 deposit", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - erc20ResourceID, - Helpers.createERCDepositData( - erc20TokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - gasBenchmarks.push({ - type: "ERC20", - gasUsed: depositTx.receipt.gasUsed, - }); - }); - - it("Should make ERC721 deposit", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - erc721ResourceID, - Helpers.createERCDepositData( - erc721TokenID, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - gasBenchmarks.push({ - type: "ERC721", - gasUsed: depositTx.receipt.gasUsed, - }); - }); - - it("Should make ERC1155 deposit", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - erc1155ResourceID, - Helpers.createERC1155DepositData([erc1155TokenID], [erc1155TokenAmount]), - feeData, - {from: depositorAddress} - ); - - gasBenchmarks.push({ - type: "ERC1155", - gasUsed: depositTx.receipt.gasUsed, - }); - }); - - it("Should print out benchmarks", () => console.table(gasBenchmarks)); -}); diff --git a/test/gasBenchmarks/executeProposal.js b/test/gasBenchmarks/executeProposal.js deleted file mode 100644 index 10f9b9c9..00000000 --- a/test/gasBenchmarks/executeProposal.js +++ /dev/null @@ -1,230 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const Helpers = require("../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); - -contract("Gas Benchmark - [Execute Proposal]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const lenRecipientAddress = 20; - const gasBenchmarks = []; - - const erc20TokenAmount = 100; - const erc721TokenID = 1; - const erc1155TokenID = 1; - const erc1155TokenAmount = 100; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let ERC721MintableInstance; - let ERC721HandlerInstance; - let ERC1155HandlerInstance; - - let erc20ResourceID; - let erc721ResourceID; - let erc1155ResourceID; - - const deposit = (resourceID, depositData) => - BridgeInstance.deposit(originDomainID, resourceID, depositData, feeData, { - from: depositorAddress, - }); - const execute = async ( - originDomainID, - depositNonce, - depositData, - resourceID - ) => { - const proposal = { - originDomainID: originDomainID, - depositNonce: depositNonce, - data: depositData, - resourceID: resourceID, - }; - - const signature = await Helpers.signTypedProposal(BridgeInstance.address, [ - proposal, - ]); - return BridgeInstance.executeProposal(proposal, signature); - }; - - before(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance = instance) - ), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance = instance) - ), - ]); - - erc20ResourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - erc721ResourceID = Helpers.createResourceID( - ERC721MintableInstance.address, - originDomainID - ); - erc1155ResourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - originDomainID - ); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - - await Promise.all([ - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address).then( - (instance) => (ERC20HandlerInstance = instance) - ), - ERC20MintableInstance.mint(depositorAddress, erc20TokenAmount), - ERC721HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC721HandlerInstance = instance) - ), - ERC721MintableInstance.mint(depositorAddress, erc721TokenID, ""), - ERC1155HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC1155HandlerInstance = instance) - ), - ERC1155MintableInstance.mintBatch( - depositorAddress, - [erc1155TokenID], - [erc1155TokenAmount], - "0x0" - ), - ]); - - await Promise.all([ - ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - erc20TokenAmount, - {from: depositorAddress} - ), - ERC721MintableInstance.approve( - ERC721HandlerInstance.address, - erc721TokenID, - {from: depositorAddress} - ), - ERC1155MintableInstance.setApprovalForAll( - ERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - erc20ResourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - erc721ResourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - erc1155ResourceID, - ERC1155MintableInstance.address, - emptySetResourceData - ), - ]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("Should execute ERC20 deposit proposal", async () => { - const depositNonce = 1; - const depositData = Helpers.createERCDepositData( - erc20TokenAmount, - lenRecipientAddress, - recipientAddress - ); - - await deposit(erc20ResourceID, depositData); - const executeTx = await execute( - originDomainID, - depositNonce, - depositData, - erc20ResourceID - ); - - gasBenchmarks.push({ - type: "ERC20", - gasUsed: executeTx.receipt.gasUsed, - }); - }); - - it("Should execute ERC721 deposit proposal", async () => { - const depositNonce = 2; - const lenMetaData = 0; - const metaData = "0x"; - const depositData = Helpers.createERC721DepositProposalData( - erc721TokenID, - lenRecipientAddress, - recipientAddress, - lenMetaData, - metaData - ); - - await deposit(erc721ResourceID, depositData); - const executeTx = await execute( - originDomainID, - depositNonce, - depositData, - erc721ResourceID - ); - - gasBenchmarks.push({ - type: "ERC721", - gasUsed: executeTx.receipt.gasUsed, - }); - }); - - it("Should execute ERC1155 deposit proposal", async () => { - const depositNonce = 3; - const metaData = "0x"; - const depositData = Helpers.createERC1155DepositProposalData( - [erc1155TokenID], - [erc1155TokenAmount], - recipientAddress, - metaData - ); - - await deposit(erc1155ResourceID, depositData); - const executeTx = await execute( - originDomainID, - depositNonce, - depositData, - erc1155ResourceID - ); - - gasBenchmarks.push({ - type: "ERC1155", - gasUsed: executeTx.receipt.gasUsed, - }); - }); - - it("Should print out benchmarks", () => console.table(gasBenchmarks)); -}); diff --git a/test/gmpTransferAdapter/erc20Transfer/deposit.js b/test/gmpTransferAdapter/erc20Transfer/deposit.js deleted file mode 100644 index a4c13b8b..00000000 --- a/test/gmpTransferAdapter/erc20Transfer/deposit.js +++ /dev/null @@ -1,211 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); -const Helpers = require("../../helpers"); - -const GmpTransferAdapterContract = artifacts.require("GmpTransferAdapter"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const XERC20FactoryContract = artifacts.require("XERC20Factory"); -const XERC20Contract = artifacts.require("XERC20"); -const XERC20LockboxContract = artifacts.require("XERC20Lockbox"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - - -contract("Gmp transfer adapter - [Deposit XERC20 - wrapped ERC20 token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const expectedDepositNonce = 1; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[3]; - - const destinationMaxFee = 950000; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000500"; - const depositAmount = 10; - const fee = Ethers.utils.parseEther("0.1"); - const mintingLimit = 500; - const burningLimit = 500; - - - - let BridgeInstance; - let GmpTransferAdapterInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let depositFunctionSignature; - let GmpHandlerInstance; - let XERC20LockboxInstance; - let XERC20Instance; - let ERC20MintableInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - await ERC20MintableInstance.mint(depositorAddress, depositAmount); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - GmpHandlerInstance = await GmpHandlerContract.new(BridgeInstance.address); - GmpTransferAdapterInstance = await GmpTransferAdapterContract.new( - BridgeInstance.address, - GmpHandlerInstance.address, - resourceID, - ); - - XERC20FactoryInstance = await XERC20FactoryContract.new(); - const XERC20DeployResponse = await XERC20FactoryInstance.deployXERC20( - "sygmaETH", - "sETH", - [mintingLimit], - [burningLimit], - [GmpTransferAdapterInstance.address] - ); - // set XERC20 contract instance address to the address deployed via XERC20Factory - const deployedXERC20Address = XERC20DeployResponse.logs[0].args._xerc20 - XERC20Instance = await XERC20Contract.at(deployedXERC20Address) - const lockboxDeployResponse = await XERC20FactoryInstance.deployLockbox( - XERC20Instance.address, - ERC20MintableInstance.address, - false - ); - // set Lockbox contract instance address to the address deployed via XERC20Factory - const lockboxAddress = lockboxDeployResponse.logs[0].args._lockbox - XERC20LockboxInstance = await XERC20LockboxContract.at(lockboxAddress); - - await ERC20MintableInstance.increaseAllowance( - XERC20LockboxInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - await XERC20LockboxInstance.depositTo( - depositorAddress, - depositAmount, - { - from: depositorAddress - } - ); - await XERC20Instance.increaseAllowance( - GmpTransferAdapterInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - await BasicFeeHandlerInstance.changeFee(originDomainID, resourceID, fee); - - depositFunctionSignature = Helpers.getFunctionSignature( - GmpTransferAdapterInstance, - "executeProposal" - ); - - const GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - GmpHandlerInstance.address, - GmpHandlerSetResourceData - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("deposit can be made successfully and depositor tokens are burnt", async () => { - const depositorXERC20BalanceBefore = await XERC20Instance.balanceOf(depositorAddress); - - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee, - } - ) - ); - const depositorXERC20BalanceAfter = await XERC20Instance.balanceOf(depositorAddress); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).sub(depositorXERC20BalanceBefore.toString()).toString(), - depositorXERC20BalanceAfter.toString() - ); - }); - - it("depositEvent is emitted with expected values", async () => { - const preparedExecutionData = await GmpTransferAdapterInstance.prepareDepositData( - recipientAddress, - XERC20Instance.address, - depositAmount - ); - const depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - GmpTransferAdapterInstance.address, - destinationMaxFee, - GmpTransferAdapterInstance.address, - preparedExecutionData, - false - ); - - const depositTx = await GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee, - } - ); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === originDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === GmpTransferAdapterInstance.address && - event.data === depositData && - event.handlerResponse == null - ); - }); - }); -}); diff --git a/test/gmpTransferAdapter/erc20Transfer/executeProposalDifferentAddresses.js b/test/gmpTransferAdapter/erc20Transfer/executeProposalDifferentAddresses.js deleted file mode 100644 index d48688d3..00000000 --- a/test/gmpTransferAdapter/erc20Transfer/executeProposalDifferentAddresses.js +++ /dev/null @@ -1,406 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const GmpTransferAdapterContract = artifacts.require("GmpTransferAdapter"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const XERC20FactoryContract = artifacts.require("XERC20Factory"); -const XERC20Contract = artifacts.require("XERC20"); -const XERC20LockboxContract = artifacts.require("XERC20Lockbox"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract(`Gmp transfer adapter - - [Execute proposal XERC20 with different addresses- wrapped ERC20 token]`, async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const handlerResponseLength = 64; - const contractCallReturndata = Ethers.constants.HashZero; - const destinationMaxFee = 900000; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const depositAmount = 10; - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = 10; - const mintingLimit = 500; - const burningLimit = 500; - - let BridgeInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let sourceXERC20FactoryInstance; - let sourceXERC20Instance; - let sourceXERC20LockboxInstance; - let destinationXERC20FactoryInstance; - let destinationXERC20Instance; - let proposal; - let dataHash; - let depositFunctionSignature; - let ERC20MintableSourceInstance; - - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC20MintableContract.new("sToken", "sTOK").then( - (instance) => (ERC20MintableSourceInstance = instance) - ), - ERC20MintableContract.new("dToken", "dTOK").then( - (instance) => (ERC20MintableDestinationInstance = instance) - ), - ]); - - await ERC20MintableSourceInstance.mint(depositorAddress, depositAmount); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - - GmpHandlerInstance = await GmpHandlerContract.new(BridgeInstance.address); - GmpTransferAdapterInstance = await GmpTransferAdapterContract.new( - BridgeInstance.address, - GmpHandlerInstance.address, - resourceID, - ); - - // deploy source XERC20 contract instances - sourceXERC20FactoryInstance = await XERC20FactoryContract.new(); - const sourceXERC20DeployResponse = await sourceXERC20FactoryInstance.deployXERC20( - "srcSygmaToken", - "srcSTOK", - [mintingLimit], - [burningLimit], - [GmpTransferAdapterInstance.address] - ); - // set source XERC20 contract instance address to the address deployed via XERC20Factory - const sourceDeployedXERC20Address = sourceXERC20DeployResponse.logs[0].args._xerc20 - sourceXERC20Instance = await XERC20Contract.at(sourceDeployedXERC20Address) - const sourceLockboxDeployResponse = await sourceXERC20FactoryInstance.deployLockbox( - sourceXERC20Instance.address, - ERC20MintableSourceInstance.address, - false - ); - // set source Lockbox contract instance address to the address deployed via XERC20Factory - const sourceLockboxAddress = sourceLockboxDeployResponse.logs[0].args._lockbox - sourceXERC20LockboxInstance = await XERC20LockboxContract.at(sourceLockboxAddress); - - // deploy destination contract instances - destinationXERC20FactoryInstance = await XERC20FactoryContract.new(); - const destinationXERC20DeployResponse = await destinationXERC20FactoryInstance.deployXERC20( - "destSygmaToken", - "destSTOK", - [mintingLimit], - [burningLimit], - [GmpTransferAdapterInstance.address] - ); - // set destination XERC20 contract instance address to the address deployed via XERC20Factory - const destinationDeployedXERC20Address = destinationXERC20DeployResponse.logs[0].args._xerc20 - destinationXERC20Instance = await XERC20Contract.at(destinationDeployedXERC20Address) - const destinationLockboxDeployResponse = await destinationXERC20FactoryInstance.deployLockbox( - destinationXERC20Instance.address, - ERC20MintableDestinationInstance.address, - false - ); - // set destination Lockbox contract instance address to the address deployed via XERC20Factory - const destinationLockboxAddress = destinationLockboxDeployResponse.logs[0].args._lockbox - await XERC20LockboxContract.at(destinationLockboxAddress); - - await ERC20MintableSourceInstance.increaseAllowance( - sourceXERC20LockboxInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - await sourceXERC20LockboxInstance.depositTo( - depositorAddress, - depositAmount, - { - from: depositorAddress - } - ); - await sourceXERC20Instance.increaseAllowance( - GmpTransferAdapterInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - - depositFunctionSignature = Helpers.getFunctionSignature( - GmpTransferAdapterInstance, - "executeProposal" - ); - - const GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - GmpHandlerInstance.address, - GmpHandlerSetResourceData - ); - - const preparedExecutionData = await GmpTransferAdapterInstance.prepareDepositData( - recipientAddress, - destinationXERC20Instance.address, - transferredAmount - ); - depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - GmpTransferAdapterInstance.address, - destinationMaxFee, - GmpTransferAdapterInstance.address, - preparedExecutionData - ); - - await GmpTransferAdapterInstance.setTokenPairAddress( - sourceXERC20Instance.address, - originDomainID, - destinationXERC20Instance.address - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositData, - }; - - dataHash = Ethers.utils.keccak256( - GmpHandlerInstance.address + depositData.substr(2) - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - const depositorSourceXERC20BalanceBefore = await sourceXERC20Instance.balanceOf(depositorAddress); - const recipientSourceXERC20BalanceBefore = await sourceXERC20Instance.balanceOf(recipientAddress); - const depositorDestinationXERC20BalanceBefore = await destinationXERC20Instance.balanceOf(depositorAddress); - const recipientDestinationXERC20BalanceBefore = await destinationXERC20Instance.balanceOf(recipientAddress); - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - sourceXERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }); - - const recipientSourceNativeBalanceBefore = await web3.eth.getBalance(recipientAddress); - const depositorSourceXERC20BalanceAfter = await sourceXERC20Instance.balanceOf(depositorAddress); - const recipientSourceXERC20BalanceAfter = await sourceXERC20Instance.balanceOf(recipientAddress); - const depositorDestinationXERC20BalanceAfter = await destinationXERC20Instance.balanceOf(depositorAddress); - const recipientDestinationXERC20BalanceAfter = await destinationXERC20Instance.balanceOf(recipientAddress); - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that depositor and recipient balances are aligned with expectations - const recipientNativeBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(recipientSourceNativeBalanceBefore, recipientNativeBalanceAfter); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).sub(depositorSourceXERC20BalanceBefore.toString()).toString(), - depositorSourceXERC20BalanceAfter.toString() - ); - assert.strictEqual( - recipientSourceXERC20BalanceBefore.toString(), - recipientSourceXERC20BalanceAfter.toString() - ); - assert.strictEqual( - depositorDestinationXERC20BalanceBefore.toString(), - depositorDestinationXERC20BalanceAfter.toString() - ); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).add(recipientDestinationXERC20BalanceBefore.toString()).toString(), - recipientDestinationXERC20BalanceAfter.toString() - ); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - sourceXERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - sourceXERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - const recipientNativeBalanceBefore = await web3.eth.getBalance(recipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["bool", "uint256", "bytes32"], - [true, handlerResponseLength, contractCallReturndata] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - - // check that recipient native token balance hasn't changed - const recipientNativeBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(recipientNativeBalanceBefore, recipientNativeBalanceAfter); - }); - - it(`should fail to executeProposal if signed Proposal has different - chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - sourceXERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); -}); diff --git a/test/gmpTransferAdapter/erc20Transfer/executeProposalSameAddresses.js b/test/gmpTransferAdapter/erc20Transfer/executeProposalSameAddresses.js deleted file mode 100644 index 7bb4fafa..00000000 --- a/test/gmpTransferAdapter/erc20Transfer/executeProposalSameAddresses.js +++ /dev/null @@ -1,366 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const GmpTransferAdapterContract = artifacts.require("GmpTransferAdapter"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const XERC20FactoryContract = artifacts.require("XERC20Factory"); -const XERC20Contract = artifacts.require("XERC20"); -const XERC20LockboxContract = artifacts.require("XERC20Lockbox"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract(`Gmp transfer adapter - - [Execute proposal XERC20 with same addresses- wrapped ERC20 token]`, async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const handlerResponseLength = 64; - const contractCallReturndata = Ethers.constants.HashZero; - const destinationMaxFee = 900000; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const depositAmount = 10; - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = 10; - const mintingLimit = 500; - const burningLimit = 500; - - let BridgeInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let XERC20Instance; - let XERC20LockboxInstance; - let proposal; - let dataHash; - let depositFunctionSignature; - let ERC20MintableInstance; - - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - await ERC20MintableInstance.mint(depositorAddress, depositAmount); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - - GmpHandlerInstance = await GmpHandlerContract.new(BridgeInstance.address); - GmpTransferAdapterInstance = await GmpTransferAdapterContract.new( - BridgeInstance.address, - GmpHandlerInstance.address, - resourceID, - ); - - XERC20FactoryInstance = await XERC20FactoryContract.new(); - const XERC20DeployResponse = await XERC20FactoryInstance.deployXERC20( - "sygmaToken", - "sTOK", - [mintingLimit], - [burningLimit], - [GmpTransferAdapterInstance.address] - ); - // set XERC20 contract instance address to the address deployed via XERC20Factory - const deployedXERC20Address = XERC20DeployResponse.logs[0].args._xerc20 - XERC20Instance = await XERC20Contract.at(deployedXERC20Address) - const lockboxDeployResponse = await XERC20FactoryInstance.deployLockbox( - XERC20Instance.address, - ERC20MintableInstance.address, - false - ); - // set Lockbox contract instance address to the address deployed via XERC20Factory - const lockboxAddress = lockboxDeployResponse.logs[0].args._lockbox - XERC20LockboxInstance = await XERC20LockboxContract.at(lockboxAddress); - - await ERC20MintableInstance.increaseAllowance( - XERC20LockboxInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - await XERC20LockboxInstance.depositTo( - depositorAddress, - depositAmount, - { - from: depositorAddress - } - ); - await XERC20Instance.increaseAllowance( - GmpTransferAdapterInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - - depositFunctionSignature = Helpers.getFunctionSignature( - GmpTransferAdapterInstance, - "executeProposal" - ); - - const GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - GmpHandlerInstance.address, - GmpHandlerSetResourceData - ); - - const preparedExecutionData = await GmpTransferAdapterInstance.prepareDepositData( - recipientAddress, - XERC20Instance.address, - transferredAmount - ); - depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - GmpTransferAdapterInstance.address, - destinationMaxFee, - GmpTransferAdapterInstance.address, - preparedExecutionData - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositData, - }; - - dataHash = Ethers.utils.keccak256( - GmpHandlerInstance.address + depositData.substr(2) - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - const depositorXERC20BalanceBefore = await XERC20Instance.balanceOf(depositorAddress); - const recipientXERC20BalanceBefore = await XERC20Instance.balanceOf(recipientAddress); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }); - - const recipientNativeBalanceBefore = await web3.eth.getBalance(recipientAddress); - const depositorXERC20BalanceAfter = await XERC20Instance.balanceOf(depositorAddress); - const recipientXERC20BalanceAfter = await XERC20Instance.balanceOf(recipientAddress); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that depositor and recipient balances are aligned with expectations - const recipientNativeBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(recipientNativeBalanceBefore, recipientNativeBalanceAfter); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).sub(depositorXERC20BalanceBefore.toString()).toString(), - depositorXERC20BalanceAfter.toString() - ); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).add(recipientXERC20BalanceBefore.toString()).toString(), - recipientXERC20BalanceAfter.toString() - ); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).add(recipientXERC20BalanceBefore.toString()).toString(), - recipientXERC20BalanceAfter.toString() - ); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - const recipientBalanceBefore = await web3.eth.getBalance(recipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["bool", "uint256", "bytes32"], - [true, handlerResponseLength, contractCallReturndata] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - - // check that recipient native token balance hasn't changed - const recipientBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(recipientBalanceBefore, recipientBalanceAfter); - }); - - it(`should fail to executeProposal if signed Proposal has different - chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); -}); diff --git a/test/gmpTransferAdapter/fees/collectFee.js b/test/gmpTransferAdapter/fees/collectFee.js deleted file mode 100644 index 7b188d3d..00000000 --- a/test/gmpTransferAdapter/fees/collectFee.js +++ /dev/null @@ -1,178 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../../helpers"); -const Ethers = require("ethers"); - -const GmpTransferAdapterContract = artifacts.require("GmpTransferAdapter"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const XERC20FactoryContract = artifacts.require("XERC20Factory"); -const XERC20Contract = artifacts.require("XERC20"); -const XERC20LockboxContract = artifacts.require("XERC20Lockbox"); - - -contract("Gmp transfer adapter - [Collect fee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[3]; - - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000500"; - const depositAmount = 10; - const fee = Ethers.utils.parseEther("0.1"); - const excessFee = Ethers.utils.parseEther("1"); - const transferredAmount = 10 - const mintingLimit = 500; - const burningLimit = 500; - - - - let BridgeInstance; - let GmpTransferAdapterInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let depositFunctionSignature; - let GmpHandlerInstance; - let XERC20LockboxInstance; - let XERC20Instance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )) - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - GmpHandlerInstance = await GmpHandlerContract.new(BridgeInstance.address); - GmpTransferAdapterInstance = await GmpTransferAdapterContract.new( - BridgeInstance.address, - GmpHandlerInstance.address, - resourceID, - ); - - XERC20FactoryInstance = await XERC20FactoryContract.new(); - const XERC20DeployResponse = await XERC20FactoryInstance.deployXERC20( - "sygmaETH", - "sETH", - [mintingLimit], - [burningLimit], - [GmpTransferAdapterInstance.address] - ); - // set XERC20 contract instance address to the address deployed via XERC20Factory - const deployedXERC20Address = XERC20DeployResponse.logs[0].args._xerc20 - XERC20Instance = await XERC20Contract.at(deployedXERC20Address) - const lockboxDeployResponse = await XERC20FactoryInstance.deployLockbox( - XERC20Instance.address, - Ethers.constants.AddressZero, - true - ); - // set Lockbox contract instance address to the address deployed via XERC20Factory - const lockboxAddress = lockboxDeployResponse.logs[0].args._lockbox - XERC20LockboxInstance = await XERC20LockboxContract.at(lockboxAddress); - - await XERC20LockboxInstance.depositNativeTo(depositorAddress, {value: transferredAmount}); - await XERC20Instance.increaseAllowance( - GmpTransferAdapterInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - await BasicFeeHandlerInstance.changeFee(originDomainID, resourceID, fee); - - depositFunctionSignature = Helpers.getFunctionSignature( - GmpTransferAdapterInstance, - "executeProposal" - ); - - const GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - GmpHandlerInstance.address, - GmpHandlerSetResourceData - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should successfully charge fee on deposit", async () => { - const feeHandlerBalanceBefore = await web3.eth.getBalance(BasicFeeHandlerInstance.address); - - await Helpers.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee, - } - ) - ); - const feeHandlerBalanceAfter = await web3.eth.getBalance(BasicFeeHandlerInstance.address); - assert.strictEqual( - Ethers.BigNumber.from(feeHandlerBalanceBefore).add(fee.toString()).toString(), - feeHandlerBalanceAfter.toString() - ); - }); - - it("should refund the depositor if too much ETH is sent as fee", async () => { - const feeHandlerBalanceBefore = await web3.eth.getBalance(BasicFeeHandlerInstance.address); - const depositorNativeBalanceBefore = await web3.eth.getBalance(depositorAddress); - - await Helpers.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: excessFee, - } - ) - ); - const feeHandlerBalanceAfter = await web3.eth.getBalance(BasicFeeHandlerInstance.address); - const depositorNativeBalanceAfter = await web3.eth.getBalance(depositorAddress); - assert.strictEqual( - Ethers.BigNumber.from(feeHandlerBalanceBefore).add(fee.toString()).toString(), - feeHandlerBalanceAfter.toString() - ); - expect( - Number(Ethers.utils.formatEther(new Ethers.BigNumber.from(depositorNativeBalanceBefore).sub(fee))) - ).to.be.within( - Number(Ethers.utils.formatEther(depositorNativeBalanceAfter))*0.99, - Number(Ethers.utils.formatEther(depositorNativeBalanceAfter))*1.01 - ); - }); -}); diff --git a/test/gmpTransferAdapter/nativeTransfer/deposit.js b/test/gmpTransferAdapter/nativeTransfer/deposit.js deleted file mode 100644 index 5cd681e0..00000000 --- a/test/gmpTransferAdapter/nativeTransfer/deposit.js +++ /dev/null @@ -1,195 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); -const Helpers = require("../../helpers"); - -const GmpTransferAdapterContract = artifacts.require("GmpTransferAdapter"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const XERC20FactoryContract = artifacts.require("XERC20Factory"); -const XERC20Contract = artifacts.require("XERC20"); -const XERC20LockboxContract = artifacts.require("XERC20Lockbox"); - - -contract("Gmp transfer adapter - [Deposit XERC20 - wrapped native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const expectedDepositNonce = 1; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[3]; - - const destinationMaxFee = 950000; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000500"; - const depositAmount = 10; - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = 10 - const mintingLimit = 500; - const burningLimit = 500; - - - - let BridgeInstance; - let GmpTransferAdapterInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let depositFunctionSignature; - let GmpHandlerInstance; - let XERC20LockboxInstance; - let XERC20Instance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )) - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - GmpHandlerInstance = await GmpHandlerContract.new(BridgeInstance.address); - GmpTransferAdapterInstance = await GmpTransferAdapterContract.new( - BridgeInstance.address, - GmpHandlerInstance.address, - resourceID, - ); - - XERC20FactoryInstance = await XERC20FactoryContract.new(); - const XERC20DeployResponse = await XERC20FactoryInstance.deployXERC20( - "sygmaETH", - "sETH", - [mintingLimit], - [burningLimit], - [GmpTransferAdapterInstance.address] - ); - // set XERC20 contract instance address to the address deployed via XERC20Factory - const deployedXERC20Address = XERC20DeployResponse.logs[0].args._xerc20 - XERC20Instance = await XERC20Contract.at(deployedXERC20Address) - const lockboxDeployResponse = await XERC20FactoryInstance.deployLockbox( - XERC20Instance.address, - Ethers.constants.AddressZero, - true - ); - // set Lockbox contract instance address to the address deployed via XERC20Factory - const lockboxAddress = lockboxDeployResponse.logs[0].args._lockbox - XERC20LockboxInstance = await XERC20LockboxContract.at(lockboxAddress); - - await XERC20LockboxInstance.depositNativeTo(depositorAddress, {value: transferredAmount}); - await XERC20Instance.increaseAllowance( - GmpTransferAdapterInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - await BasicFeeHandlerInstance.changeFee(originDomainID, resourceID, fee); - - depositFunctionSignature = Helpers.getFunctionSignature( - GmpTransferAdapterInstance, - "executeProposal" - ); - - const GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - GmpHandlerInstance.address, - GmpHandlerSetResourceData - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("deposit can be made successfully and depositor native tokens are deducted", async () => { - const depositorNativeBalanceBefore = await web3.eth.getBalance(depositorAddress); - - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee, - } - ) - ); - const depositorNativeBalanceAfter = await web3.eth.getBalance(depositorAddress); - expect( - Number(Ethers.utils.formatEther(new Ethers.BigNumber.from(depositorNativeBalanceBefore).add(fee))) - ).to.be.within( - Number(Ethers.utils.formatEther(depositorNativeBalanceAfter))*0.99, - Number(Ethers.utils.formatEther(depositorNativeBalanceAfter))*1.01 - ); - }); - - it("depositEvent is emitted with expected values", async () => { - const preparedExecutionData = await GmpTransferAdapterInstance.prepareDepositData( - recipientAddress, - XERC20Instance.address, - depositAmount - ); - const depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - GmpTransferAdapterInstance.address, - destinationMaxFee, - GmpTransferAdapterInstance.address, - preparedExecutionData, - false - ); - - const depositTx = await GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee, - } - ); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === originDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === GmpTransferAdapterInstance.address && - event.data === depositData && - event.handlerResponse === null - ); - }); - }); -}); diff --git a/test/gmpTransferAdapter/nativeTransfer/executeProposal.js b/test/gmpTransferAdapter/nativeTransfer/executeProposal.js deleted file mode 100644 index 3b14b1b0..00000000 --- a/test/gmpTransferAdapter/nativeTransfer/executeProposal.js +++ /dev/null @@ -1,352 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const GmpTransferAdapterContract = artifacts.require("GmpTransferAdapter"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const XERC20FactoryContract = artifacts.require("XERC20Factory"); -const XERC20Contract = artifacts.require("XERC20"); -const XERC20LockboxContract = artifacts.require("XERC20Lockbox"); - -contract("Gmp transfer adapter - [Execute proposal XERC20 - wrapped native token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const handlerResponseLength = 64; - const contractCallReturndata = Ethers.constants.HashZero; - const destinationMaxFee = 900000; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const depositAmount = 10; - const fee = Ethers.utils.parseEther("0.1"); - const transferredAmount = 10 - const mintingLimit = 500; - const burningLimit = 500; - - let BridgeInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - let XERC20Instance; - let XERC20LockboxInstance; - let proposal; - let dataHash; - let depositFunctionSignature; - - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - originDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - - GmpHandlerInstance = await GmpHandlerContract.new(BridgeInstance.address); - GmpTransferAdapterInstance = await GmpTransferAdapterContract.new( - BridgeInstance.address, - GmpHandlerInstance.address, - resourceID, - ); - - XERC20FactoryInstance = await XERC20FactoryContract.new(); - const response = await XERC20FactoryInstance.deployXERC20( - "sygmaETH", - "sETH", - [mintingLimit], - [burningLimit], - [GmpTransferAdapterInstance.address] - ); - // set XERC20 contract instance address to the address deployed via XERC20Factory - const deployedXERC20Address = response.logs[0].args._xerc20 - XERC20Instance = await XERC20Contract.at(deployedXERC20Address) - const lockboxDeployResponse = await XERC20FactoryInstance.deployLockbox( - XERC20Instance.address, - Ethers.constants.AddressZero, - true - ); - // set Lockbox contract instance address to the address deployed via XERC20Factory - const lockboxAddress = lockboxDeployResponse.logs[0].args._lockbox - XERC20LockboxInstance = await XERC20LockboxContract.at(lockboxAddress); - - await XERC20LockboxInstance.depositNativeTo( - depositorAddress, - { - value: depositAmount - } - ); - await XERC20Instance.increaseAllowance( - GmpTransferAdapterInstance.address, - depositAmount, - { - from: depositorAddress - } - ); - - depositFunctionSignature = Helpers.getFunctionSignature( - GmpTransferAdapterInstance, - "executeProposal" - ); - - const GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - GmpHandlerInstance.address, - GmpHandlerSetResourceData - ); - - const preparedExecutionData = await GmpTransferAdapterInstance.prepareDepositData( - recipientAddress, - XERC20Instance.address, - transferredAmount - ); - depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - GmpTransferAdapterInstance.address, - destinationMaxFee, - GmpTransferAdapterInstance.address, - preparedExecutionData - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositData, - }; - - dataHash = Ethers.utils.keccak256( - GmpHandlerInstance.address + depositData.substr(2) - ); - - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - const recipientNativeBalanceBefore = await web3.eth.getBalance(recipientAddress); - const depositorXERC20BalanceBefore = await XERC20Instance.balanceOf(depositorAddress); - const recipientXERC20BalanceBefore = await XERC20Instance.balanceOf(recipientAddress); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }); - - const depositorXERC20BalanceAfter = await XERC20Instance.balanceOf(depositorAddress); - const recipientXERC20BalanceAfter = await XERC20Instance.balanceOf(recipientAddress); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that depositor and recipient balances are aligned with expectations - const recipientNativeBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(recipientNativeBalanceBefore, recipientNativeBalanceAfter); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).sub(depositorXERC20BalanceBefore.toString()).toString(), - depositorXERC20BalanceAfter.toString() - ); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).add(recipientXERC20BalanceBefore.toString()).toString(), - recipientXERC20BalanceAfter.toString() - ); - assert.strictEqual( - Ethers.BigNumber.from(depositAmount).add(recipientXERC20BalanceBefore.toString()).toString(), - recipientXERC20BalanceAfter.toString() - ); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - const recipientBalanceBefore = await web3.eth.getBalance(recipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["bool", "uint256", "bytes32"], - [true, handlerResponseLength, contractCallReturndata] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - - // check that recipient native token balance hasn't changed - const recipientBalanceAfter = await web3.eth.getBalance(recipientAddress); - assert.strictEqual(recipientBalanceBefore, recipientBalanceAfter); - }); - - it(`should fail to executeProposal if signed Proposal has different - chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - GmpTransferAdapterInstance.deposit( - originDomainID, - recipientAddress, - XERC20Instance.address, - depositAmount, - { - from: depositorAddress, - value: fee - } - ) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); -}); diff --git a/test/handlers/erc1155/deposit.js b/test/handlers/erc1155/deposit.js deleted file mode 100644 index ddbc1b11..00000000 --- a/test/handlers/erc1155/deposit.js +++ /dev/null @@ -1,111 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../helpers"); - -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); - -contract("ERC1155Handler - [Deposit ERC1155]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const expectedDepositNonce = 1; - const depositorAddress = accounts[1]; - - const tokenID = 1; - const tokenAmount = 100; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC1155MintableInstance; - let ERC1155HandlerInstance; - - let resourceID; - let depositData; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC1155MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC1155MintableInstance.address]; - burnableContractAddresses = []; - - await Promise.all([ - ERC1155HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC1155HandlerInstance = instance) - ), - ERC1155MintableInstance.mintBatch( - depositorAddress, - [tokenID], - [tokenAmount], - "0x0" - ), - ]); - - await Promise.all([ - ERC1155MintableInstance.setApprovalForAll( - ERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ), - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - resourceID, - ERC1155MintableInstance.address, - emptySetResourceData - ), - ]); - - depositData = Helpers.createERC1155DepositData([tokenID], [tokenAmount]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositor owns tokenAmount of tokenID", async () => { - const depositorBalance = await ERC1155MintableInstance.balanceOf( - depositorAddress, - tokenID - ); - assert.equal(tokenAmount, depositorBalance); - }); - - it("Deposit event is emitted with expected values", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.data === - Helpers.createERC1155DepositData( - [tokenID], - [tokenAmount] - ).toLowerCase() && - event.handlerResponse === null - ); - }); - }); -}); diff --git a/test/handlers/erc1155/deposit.test.ts b/test/handlers/erc1155/deposit.test.ts new file mode 100644 index 00000000..35aaa6e7 --- /dev/null +++ b/test/handlers/erc1155/deposit.test.ts @@ -0,0 +1,105 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createERC1155DepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../helpers"; +import {Hex, WalletClient} from "viem"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + + +describe("ERC1155Handler - [Deposit ERC1155]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const expectedDepositNonce = 1; + + const tokenID = BigInt(1); + const tokenAmount = BigInt(100); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC1155MintableInstance: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + + let admin: WalletClient; + let depositor: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC1155MintableInstance, + ERC1155HandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC1155MintableInstance.address, + originDomainID + ); + + await ERC1155MintableInstance.write.mintBatch([ + depositor.account!.address, + [tokenID], + [tokenAmount], + "0x0" + ]); + + await ERC1155MintableInstance.write.setApprovalForAll([ + ERC1155HandlerInstance.address, + true + ], + { + account: depositor.account + } + ); + await BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + resourceID, + ERC1155MintableInstance.address, + emptySetResourceData + ]); + + depositData = createERC1155DepositData([tokenID], [tokenAmount]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor owns tokenAmount of tokenID", async () => { + const depositorBalance = await ERC1155MintableInstance.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.equal(tokenAmount, depositorBalance); + }); + + it("Deposit event is emitted with expected values", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositData, + null, + ); + }); +}); diff --git a/test/handlers/erc1155/depositBurn.js b/test/handlers/erc1155/depositBurn.js deleted file mode 100644 index 593bc1da..00000000 --- a/test/handlers/erc1155/depositBurn.js +++ /dev/null @@ -1,132 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../../helpers"); - -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); - -contract("ERC1155Handler - [Deposit Burn ERC1155]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - - const tokenID = 1; - const tokenAmount = 100; - - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC1155MintableInstance1; - let ERC1155MintableInstance2; - let ERC1155HandlerInstance; - - let resourceID1; - let resourceID2; - let burnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance1 = instance) - ), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance2 = instance) - ), - ]); - - resourceID1 = Helpers.createResourceID( - ERC1155MintableInstance1.address, - originDomainID - ); - resourceID2 = Helpers.createResourceID( - ERC1155MintableInstance2.address, - originDomainID - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC1155MintableInstance1.address, - ERC1155MintableInstance2.address, - ]; - burnableContractAddresses = [ERC1155MintableInstance1.address]; - - await Promise.all([ - ERC1155HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC1155HandlerInstance = instance) - ), - ERC1155MintableInstance1.mintBatch( - depositorAddress, - [tokenID], - [tokenAmount], - "0x0" - ), - ]); - - await Promise.all([ - ERC1155MintableInstance1.setApprovalForAll( - ERC1155HandlerInstance.address, - true, - {from: depositorAddress} - ), - await BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - resourceID1, - ERC1155MintableInstance1.address, - emptySetResourceData - ), - await BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - resourceID2, - ERC1155MintableInstance2.address, - emptySetResourceData - ), - BridgeInstance.adminSetBurnable( - ERC1155HandlerInstance.address, - ERC1155MintableInstance1.address - ), - ]); - - depositData = Helpers.createERC1155DepositData([tokenID], [tokenAmount]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] burnableContractAddresses should be marked as burnable", async () => { - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await ERC1155HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); - - it("depositAmount of ERC1155MintableInstance1 tokens should have been burned", async () => { - await BridgeInstance.deposit( - destinationDomainID, - resourceID1, - depositData, - feeData, - {from: depositorAddress} - ); - - const handlerBalance = await ERC1155MintableInstance1.balanceOf( - ERC1155HandlerInstance.address, - tokenID - ); - assert.strictEqual(handlerBalance.toNumber(), 0); - - const depositorBalance = await ERC1155MintableInstance1.balanceOf( - depositorAddress, - tokenID - ); - assert.strictEqual(depositorBalance.toNumber(), 0); - }); -}); diff --git a/test/handlers/erc1155/depositBurn.test.ts b/test/handlers/erc1155/depositBurn.test.ts new file mode 100644 index 00000000..35b36cc5 --- /dev/null +++ b/test/handlers/erc1155/depositBurn.test.ts @@ -0,0 +1,129 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {deploySourceChainContracts, mpcAddress} from "../../helpers"; +import {Hex, WalletClient} from "viem"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert} from 'chai'; + + + + +describe("ERC1155Handler - [Deposit Burn ERC1155]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const tokenID = BigInt(1); + const tokenAmount = BigInt(100); + + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC1155MintableInstance1: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155MintableInstance2: ContractTypesMap["ERC1155PresetMinterPauser"]; + let ERC1155HandlerInstance: ContractTypesMap["ERC1155Handler"]; + + let depositor: WalletClient; + let resourceID1: Hex; + let resourceID2: Hex; + let depositData: Hex; + let burnableContractAddresses: Array; + + before(async () => { + ({ + BridgeInstance, + ERC1155HandlerInstance, + ERC1155MintableInstance: ERC1155MintableInstance1, + ERC1155MintableInstance: ERC1155MintableInstance2, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + ERC1155MintableInstance1.address, + originDomainID + ); + resourceID2 = createResourceID( + ERC1155MintableInstance2.address, + originDomainID + ); + burnableContractAddresses = [ERC1155MintableInstance1.address]; + + await ERC1155MintableInstance1.write.mintBatch([ + depositor, + [tokenID], + [tokenAmount], + "0x0" + ]); + + await ERC1155MintableInstance1.write.setApprovalForAll([ + ERC1155HandlerInstance.address, + true + ], + { + account: depositor.account + } + ); + await BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + resourceID1, + ERC1155MintableInstance1.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + resourceID2, + ERC1155MintableInstance2.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetBurnable([ + ERC1155HandlerInstance.address, + ERC1155MintableInstance1.address + ]); + + depositData = createERC1155DepositData([tokenID], [tokenAmount]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] burnableContractAddresses should be marked as burnable", async () => { + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await ERC1155HandlerInstance.read._tokenContractAddressToTokenProperties([ + burnableAddress + ])); + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); + + it("depositAmount of ERC1155MintableInstance1 tokens should have been burned", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const handlerBalance = await ERC1155MintableInstance1.read.balanceOf([ + ERC1155HandlerInstance.address, + tokenID + ]); + assert.strictEqual(handlerBalance, BigInt(0)); + + const depositorBalance = await ERC1155MintableInstance1.read.balanceOf([ + depositor.account!.address, + tokenID + ]); + assert.strictEqual(depositorBalance, BigInt(0)); + }); +}); diff --git a/test/handlers/erc1155/isBurnable.js b/test/handlers/erc1155/isBurnable.js deleted file mode 100644 index f5f492de..00000000 --- a/test/handlers/erc1155/isBurnable.js +++ /dev/null @@ -1,222 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC1155MintableContract = artifacts.require("ERC1155PresetMinterPauser"); -const ERC1155HandlerContract = artifacts.require("ERC1155Handler"); - -contract("ERC1155Handler - [Burn ERC1155]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC1155MintableInstance1; - let ERC1155MintableInstance2; - let resourceID1; - let resourceID2; - let initialResourceIDs; - let initialContractAddresses; - let burnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance1 = instance) - ), - ERC1155MintableContract.new("TOK").then( - (instance) => (ERC1155MintableInstance2 = instance) - ), - ]); - - resourceID1 = Ethers.utils.hexZeroPad( - ERC1155MintableInstance1.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - resourceID2 = Ethers.utils.hexZeroPad( - ERC1155MintableInstance2.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC1155MintableInstance1.address, - ERC1155MintableInstance2.address, - ]; - burnableContractAddresses = [ERC1155MintableInstance1.address]; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes( - ERC1155HandlerContract.new(BridgeInstance.address) - ); - }); - - it("burnableContractAddresses should be marked as burnable", async () => { - const ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC1155HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await ERC1155HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); - - it("ERC1155MintableInstance2.address should not be marked as burnable", async () => { - const ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC1155HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - const isBurnable = (await ERC1155HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC1155MintableInstance2.address - )).isBurnable - - assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); - }); - - it("ERC1155MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { - const ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC1155HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - await BridgeInstance.adminSetBurnable( - ERC1155HandlerInstance.address, - ERC1155MintableInstance2.address - ); - const isBurnable = (await ERC1155HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC1155MintableInstance2.address - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - }); - - it(`ERC1155MintableInstances should not be marked as - burnable after setResource is called on already burnable tokens`, async () => { - const ERC1155HandlerInstance = await ERC1155HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC1155HandlerInstance.address, - initialContractAddresses[i] - ) - ); - } - - // tokens should be marked as burnable - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableBeforeReRegisteringResource = ( - await ERC1155HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); - } - - // re-register resource - sets isBurnable to false for tokens - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC1155HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - // tokens should not be marked as burnable if resource is re-registered - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableAfterReRegisteringResource = ( - await ERC1155HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); - } - }); -}); diff --git a/test/handlers/erc1155/isBurnable.test.ts b/test/handlers/erc1155/isBurnable.test.ts new file mode 100644 index 00000000..f67906ae --- /dev/null +++ b/test/handlers/erc1155/isBurnable.test.ts @@ -0,0 +1,209 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {deploySourceChainContracts} from "../../helpers"; +import {Hex, WalletClient} from "viem"; +import {ContractTypesMap} from "hardhat/types"; +import {assert, expect} from 'chai'; + + + +describe("ERC1155Handler - [Burn ERC1155]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC1155MintableInstance1: ContractTypesMap["ERC1155PresetMinterPauser"];; + let ERC1155MintableInstance2: ContractTypesMap["ERC1155PresetMinterPauser"];; + let resourceID1: Hex; + let resourceID2: Hex; + let initialResourceIDs: Array; + let initialContractAddresses: Array; + let burnableContractAddresses: Array; + let mockBridge: WalletClient; + + before(async () => { + ({ + BridgeInstance, + ERC1155MintableInstance: ERC1155MintableInstance1, + ERC1155MintableInstance: ERC1155MintableInstance2, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + mockBridge + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + ERC1155MintableInstance1.address, + domainID + ); + resourceID2 = createResourceID( + ERC1155MintableInstance2.address, + domainID + ); + initialResourceIDs = [resourceID1, resourceID2]; + initialContractAddresses = [ + ERC1155MintableInstance1.address, + ERC1155MintableInstance2.address, + ]; + burnableContractAddresses = [ERC1155MintableInstance1.address]; + }); + + it("burnableContractAddresses should be marked as burnable", async () => { + const ERC1155HandlerInstance = await hre.viem.deployContract("ERC1155Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC1155HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await ERC1155HandlerInstance.read._tokenContractAddressToTokenProperties([ + burnableAddress + ])); + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); + + it("ERC1155MintableInstance2.address should not be marked as burnable", async () => { + const ERC1155HandlerInstance = await hre.viem.deployContract("ERC1155Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC1155HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + const isBurnable = (await ERC1155HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC1155MintableInstance2.address + ])); + + assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); + }); + + it("ERC1155MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { + const ERC1155HandlerInstance = await hre.viem.deployContract("ERC1155Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC1155HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + await BridgeInstance.write.adminSetBurnable([ + ERC1155HandlerInstance.address, + ERC1155MintableInstance2.address + ]); + const isBurnable = (await ERC1155HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC1155MintableInstance2.address + ])); + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + }); + + it(`ERC1155MintableInstances should not be marked as + burnable after setResource is called on already burnable tokens`, async () => { + const ERC1155HandlerInstance = await hre.viem.deployContract("ERC1155Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC1155HandlerInstance.address, + initialContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + // tokens should be marked as burnable + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableBeforeReRegisteringResource = ( + await ERC1155HandlerInstance.read._tokenContractAddressToTokenProperties([ + initialContractAddresses[i] + ]) + ); + + assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); + } + + // re-register resource - sets isBurnable to false for tokens + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC1155HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + // tokens should not be marked as burnable if resource is re-registered + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableAfterReRegisteringResource = ( + await ERC1155HandlerInstance.read._tokenContractAddressToTokenProperties([ + initialContractAddresses[i] + ]) + ); + + assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); + } + }); +}); diff --git a/test/handlers/erc20/constructor.js b/test/handlers/erc20/constructor.js deleted file mode 100644 index ac80adb6..00000000 --- a/test/handlers/erc20/constructor.js +++ /dev/null @@ -1,128 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("ERC20Handler - [constructor]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let ERC20MintableInstance1; - let ERC20MintableInstance2; - let ERC20MintableInstance3; - let initialResourceIDs; - let initialContractAddresses; - - beforeEach(async () => { - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance3 = instance) - ), - ]); - - initialResourceIDs = []; - burnableContractAddresses = []; - - initialResourceIDs.push( - Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ) - ); - initialResourceIDs.push( - Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ) - ); - initialResourceIDs.push( - Ethers.utils.hexZeroPad( - ERC20MintableInstance3.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ) - ); - - initialContractAddresses = [ - ERC20MintableInstance1.address, - ERC20MintableInstance2.address, - ERC20MintableInstance3.address, - ]; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes( - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address) - ); - }); - - it("[sanity] bridge configured on domain", async () => { - assert.equal(await BridgeInstance._domainID(), domainID); - }); - - it("[sanity] bridge should be initially paused", async () => { - assert.isTrue(await BridgeInstance.paused()); - }); - - it( - "initialResourceIDs should be parsed correctly and corresponding resourceID mappings should have expected values", - async () => { - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (const resourceID of initialResourceIDs) { - const tokenAddress = "0x" + resourceID.substr(24, 40); - - const retrievedTokenAddress = - await ERC20HandlerInstance._resourceIDToTokenContractAddress.call( - resourceID - ); - assert.strictEqual( - Ethers.utils.getAddress(tokenAddress).toLowerCase(), - retrievedTokenAddress.toLowerCase() - ); - - const retrievedResourceID = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - tokenAddress - )).resourceID - - assert.strictEqual( - resourceID.toLowerCase(), - retrievedResourceID.toLowerCase() - ); - } - }); -}); diff --git a/test/handlers/erc20/constructor.test.ts b/test/handlers/erc20/constructor.test.ts new file mode 100644 index 00000000..5f72d443 --- /dev/null +++ b/test/handlers/erc20/constructor.test.ts @@ -0,0 +1,111 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, toHex, WalletClient} from "viem"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + +describe("ERC20Handler - [constructor]", async () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"];; + let ERC20MintableInstance3: ContractTypesMap["ERC20PresetMinterPauser"];; + let initialResourceIDs: Array; + let initialContractAddresses: Array; + let mockBridge: WalletClient; + let mockDefaultMessageReceiver: WalletClient; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance: ERC20MintableInstance1, + ERC20MintableInstance: ERC20MintableInstance2, + ERC20MintableInstance: ERC20MintableInstance3, + } = await loadFixture(deploySourceChainContracts)); + [ + , + mockBridge, + mockDefaultMessageReceiver, + ] = await hre.viem.getWalletClients(); + + initialResourceIDs.push( + createResourceID( + ERC20MintableInstance1.address, + domainID + ) + ); + initialResourceIDs.push( + createResourceID( + ERC20MintableInstance2.address, + domainID + ) + ); + initialResourceIDs.push( + createResourceID( + ERC20MintableInstance3.address, + domainID + ) + ); + + initialContractAddresses = [ + ERC20MintableInstance1.address, + ERC20MintableInstance2.address, + ERC20MintableInstance3.address, + ]; + }); + + it("[sanity] bridge configured on domain", async () => { + assert.equal(await BridgeInstance.read._domainID(), domainID); + }); + + it("[sanity] bridge should be initially paused", async () => { + assert.isTrue(await BridgeInstance.read.paused()); + }); + + it(`initialResourceIDs should be parsed correctly and + corresponding resourceID mappings should have expected values`, async () => { + const ERC20HandlerInstance = await hre.viem.deployContract("ERC20Handler", [BridgeInstance.address, DefaultMessageReceiverInstance.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (const resourceID of initialResourceIDs) { + const tokenAddress = toHex(resourceID.substring(24, 40), {size: 20}); + + const retrievedTokenAddress = + await ERC20HandlerInstance.read._resourceIDToTokenContractAddress([ + resourceID + ]); + assert.strictEqual( + tokenAddress, + retrievedTokenAddress + ); + + const retrievedResourceID = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + tokenAddress + ]))[0]; + + assert.strictEqual( + resourceID.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + } + }); +}); diff --git a/test/handlers/erc20/decimals.js b/test/handlers/erc20/decimals.js deleted file mode 100644 index cc8c79e4..00000000 --- a/test/handlers/erc20/decimals.js +++ /dev/null @@ -1,103 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauserDecimals"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("ERC20Handler - [decimals]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - - const tokenAmount = 100; - const depositAmount = 10; - const expectedDepositNonce = 1; - const setDecimalPlaces = 11; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - - let resourceID; - let depositProposalData; - - beforeEach(async () => { - await Promise.all([ - BridgeInstance = await Helpers.deployBridge(originDomainID, accounts[0]), - ERC20MintableContract.new("token", "TOK", 11).then(instance => ERC20MintableInstance = instance) - ]); - - resourceID = Helpers.createResourceID(ERC20MintableInstance.address, originDomainID); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC20MintableInstance.address]; - - proposal = { - originDomainID: destinationDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - depositProposalData = Helpers.createERCDepositData(depositAmount, 20, recipientAddress) - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - await Promise.all([ - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address) - .then(instance => ERC20HandlerInstance = instance), - ERC20MintableInstance.mint(depositorAddress, tokenAmount) - ]); - - await Promise.all([ - ERC20MintableInstance.approve(ERC20HandlerInstance.address, tokenAmount, {from: depositorAddress}), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - // set decimal places for handler and token - emptySetResourceData - ) - ]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] decimals value is not set if 'adminSetResource' is called with empty args", async () => { - const ERC20MintableInstanceDecimals = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - await ERC20MintableInstance.address - )).decimals; - - assert.strictEqual(ERC20MintableInstanceDecimals.isSet, false) - assert.strictEqual(ERC20MintableInstanceDecimals["externalDecimals"], "0") - }); - - it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - // set decimal places for handler and token - setDecimalPlaces - ); - - const ERC20MintableInstanceDecimals = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance.address - )).decimals; - - assert.strictEqual(ERC20MintableInstanceDecimals.isSet, true); - assert.strictEqual(ERC20MintableInstanceDecimals["externalDecimals"], "11"); - assert.strictEqual( - ERC20MintableInstanceDecimals["externalDecimals"], - (await ERC20MintableInstance.decimals()).toString() - ); - }); -}); diff --git a/test/handlers/erc20/decimals.test.ts b/test/handlers/erc20/decimals.test.ts new file mode 100644 index 00000000..dcb020c4 --- /dev/null +++ b/test/handlers/erc20/decimals.test.ts @@ -0,0 +1,103 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, toHex, WalletClient} from 'viem'; +import {assert} from 'chai'; + + + + +describe("ERC20Handler - [decimals]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const tokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const expectedDepositNonce = 1; + const decimalPlaces = 11; + const hexDecimalPlaces = toHex(decimalPlaces); + + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let depositor: WalletClient; + let recipient: WalletClient; + + let resourceID: Hex; + let depositProposalData: Hex; + let proposal: Proposal; + + before(async () => { + ({ + BridgeInstance, + ERC20HandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID(ERC20MintableInstance.address, originDomainID); + + proposal = { + originDomainID: destinationDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + depositProposalData = createERCDepositData(depositAmount, 20, recipient.account!.address) + + await ERC20MintableInstance.write.mint([depositor.account!.address, tokenAmount]) + await ERC20MintableInstance.write.approve([ERC20HandlerInstance.address, tokenAmount], {account: depositor.account}), + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + // set decimal places for handler and token + emptySetResourceData + ]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] decimals value is not set if 'adminSetResource' is called with empty args", async () => { + const ERC20MintableInstanceDecimals = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance.address + ]))[3]; + + assert.strictEqual(ERC20MintableInstanceDecimals.isSet, false) + assert.strictEqual(ERC20MintableInstanceDecimals["externalDecimals"], 0) + }); + + it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + // set decimal places for handler and token + hexDecimalPlaces + ]); + + const ERC20MintableInstanceDecimals = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance.address + ]))[3]; + + assert.strictEqual(ERC20MintableInstanceDecimals.isSet, true); + assert.strictEqual(ERC20MintableInstanceDecimals["externalDecimals"], 11); + assert.strictEqual( + ERC20MintableInstanceDecimals["externalDecimals"], + (await ERC20MintableInstance.read.decimals()) + ); + }); +}); diff --git a/test/handlers/erc20/deposit.js b/test/handlers/erc20/deposit.js deleted file mode 100644 index d89ac045..00000000 --- a/test/handlers/erc20/deposit.js +++ /dev/null @@ -1,211 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("ERC20Handler - [Deposit ERC20]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const expectedDepositNonce = 1; - const depositorAddress = accounts[1]; - - const tokenAmount = 100; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - - let resourceID; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC20MintableInstance.address]; - burnableContractAddresses = []; - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - await Promise.all([ - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address).then( - (instance) => (ERC20HandlerInstance = instance) - ), - ERC20MintableInstance.mint(depositorAddress, tokenAmount), - ]); - - await Promise.all([ - ERC20MintableInstance.approve(ERC20HandlerInstance.address, tokenAmount, { - from: depositorAddress, - }), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositor owns tokenAmount of ERC20", async () => { - const depositorBalance = await ERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.equal(tokenAmount, depositorBalance); - }); - - it("[sanity] ERC20HandlerInstance.address has an allowance of tokenAmount from depositorAddress", async () => { - const handlerAllowance = await ERC20MintableInstance.allowance( - depositorAddress, - ERC20HandlerInstance.address - ); - assert.equal(tokenAmount, handlerAllowance); - }); - - it("Varied recipient address with length 40", async () => { - const recipientAddress = accounts[0] + accounts[1].substr(2); - const lenRecipientAddress = 40; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ).toLowerCase() && - event.handlerResponse === null - ); - }); - }); - - it("Varied recipient address with length 32", async () => { - const recipientAddress = Ethers.utils.keccak256(accounts[0]); - const lenRecipientAddress = 32; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ).toLowerCase() && - event.handlerResponse === null - ); - }); - }); - - it(`When non-contract addresses are whitelisted in the handler, - deposits which the addresses are set as a token address will be failed`, async () => { - const NonContract_Address = "0x0000000000000000000000000000000000001111"; - const EOA_Address = accounts[1]; - const resourceID_NonContract_Address = Helpers.createResourceID( - NonContract_Address, - originDomainID - ); - const resourceID_EOA_Address = Helpers.createResourceID( - EOA_Address, - originDomainID - ); - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID_NonContract_Address, - NonContract_Address, - emptySetResourceData - ); - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID_EOA_Address, - EOA_Address, - emptySetResourceData - ); - - const recipientAddress = accounts[0] + accounts[1].substr(2); - const lenRecipientAddress = 40; - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID_NonContract_Address, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ), - "ERC20: not a contract" - ); - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID_EOA_Address, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ), - "ERC20: not a contract" - ); - }); -}); diff --git a/test/handlers/erc20/deposit.test.ts b/test/handlers/erc20/deposit.test.ts new file mode 100644 index 00000000..2d19297b --- /dev/null +++ b/test/handlers/erc20/deposit.test.ts @@ -0,0 +1,194 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, Hex, keccak256, WalletClient} from "viem"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress, trimPrefix} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {assert, expect} from 'chai'; + + +describe("ERC20Handler - [Deposit ERC20]", async () => { + const originDomainID = 1; + const destinationDomainID = 2; + const expectedDepositNonce = 1; + + const tokenAmount = BigInt(100); + const feeData = "0x"; + const emptySetResourceData = "0x"; + const lenrecipient = 40; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let EOA_Address: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC20HandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + depositData = createERCDepositData( + tokenAmount, + lenrecipient, + concat([admin.account!.address, trimPrefix(recipient.account!.address)]) + ); + + await ERC20MintableInstance.write.mint([depositor.account!.address, tokenAmount]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + tokenAmount + ], { + account: depositor.account, + } + ); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor owns tokenAmount of ERC20", async () => { + const depositorBalance = await ERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.equal(tokenAmount, depositorBalance); + }); + + it("[sanity] ERC20HandlerInstance.address has an allowance of tokenAmount from depositor", async () => { + const handlerAllowance = await ERC20MintableInstance.read.allowance([ + depositor.account!.address, + ERC20HandlerInstance.address + ]); + assert.equal(tokenAmount, handlerAllowance); + }); + + it("Varied recipient address with length 40", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositData, + null + ); + }); + + it("Varied recipient address with length 32", async () => { + const recipient = keccak256(admin.account!.address); + const lenrecipient = 32; + const depositData = createERCDepositData( + tokenAmount, + lenrecipient, + recipient + ); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositData, + null + ); + }); + + it(`When non-contract addresses are whitelisted in the handler, + deposits which the addresses are set as a token address will be failed`, async () => { + const NonContract_Address = "0x0000000000000000000000000000000000001111"; + const resourceID_NonContract_Address = createResourceID( + NonContract_Address, + originDomainID + ); + const resourceID_EOA_Address = createResourceID( + EOA_Address.account!.address, + originDomainID + ); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID_NonContract_Address, + NonContract_Address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID_EOA_Address, + EOA_Address.account!.address, + emptySetResourceData + ]); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID_NonContract_Address, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).to.be.revertedWith("ERC20: not a contract"); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID_EOA_Address, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).to.be.revertedWith("ERC20: not a contract"); + }); +}); diff --git a/test/handlers/erc20/depositBurn.js b/test/handlers/erc20/depositBurn.js deleted file mode 100644 index f3fc8da3..00000000 --- a/test/handlers/erc20/depositBurn.js +++ /dev/null @@ -1,106 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("ERC20Handler - [Deposit Burn ERC20]", async (accounts) => { - const domainID = 1; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const initialTokenAmount = 100; - const depositAmount = 10; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance1; - let ERC20MintableInstance2; - let ERC20HandlerInstance; - - let resourceID1; - let resourceID2; - let burnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ]); - - resourceID1 = Helpers.createResourceID( - ERC20MintableInstance1.address, - domainID - ); - resourceID2 = Helpers.createResourceID( - ERC20MintableInstance2.address, - domainID - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC20MintableInstance1.address, - ERC20MintableInstance2.address, - ]; - burnableContractAddresses = [ERC20MintableInstance1.address]; - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - await Promise.all([ - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address).then( - (instance) => (ERC20HandlerInstance = instance) - ), - ERC20MintableInstance1.mint(depositorAddress, initialTokenAmount), - ]); - - await Promise.all([ - ERC20MintableInstance1.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ), - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID1, - ERC20MintableInstance1.address, - emptySetResourceData - ), - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID2, - ERC20MintableInstance2.address, - emptySetResourceData - ), - BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - ERC20MintableInstance1.address - ), - ]); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] burnableContractAddresses should be marked as burnable", async () => { - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); -}); diff --git a/test/handlers/erc20/depositBurn.test.ts b/test/handlers/erc20/depositBurn.test.ts new file mode 100644 index 00000000..4aca225d --- /dev/null +++ b/test/handlers/erc20/depositBurn.test.ts @@ -0,0 +1,103 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../helpers"; +import {Hex, WalletClient} from "viem"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert} from 'chai'; + +describe("ERC20Handler - [Deposit Burn ERC20]", () => { + const domainID = 1; + const depositAmount = BigInt(10); + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let recipient: WalletClient; + let depositor: WalletClient; + + let resourceID1: Hex; + let resourceID2: Hex; + let depositData: Hex; + let initialResourceIDs: Array; + let initialContractAddresses: Array; + let burnableContractAddresses: Array; + + before(async () => { + ({ + BridgeInstance, + ERC20HandlerInstance, + ERC20MintableInstance: ERC20MintableInstance1, + ERC20MintableInstance: ERC20MintableInstance2, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + ERC20MintableInstance1.address, + domainID + ); + resourceID2 = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + initialResourceIDs = [resourceID1, resourceID2]; + initialContractAddresses = [ + ERC20MintableInstance1.address, + ERC20MintableInstance2.address, + ]; + burnableContractAddresses = [ERC20MintableInstance1.address]; + + await ERC20MintableInstance1.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ), + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID2, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetBurnable([ + ERC20HandlerInstance.address, + ERC20MintableInstance1.address + ]); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] burnableContractAddresses should be marked as burnable", async () => { + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + burnableAddress + ]))[0] + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); +}); diff --git a/test/handlers/erc20/isBurnable.js b/test/handlers/erc20/isBurnable.js deleted file mode 100644 index 46dc8844..00000000 --- a/test/handlers/erc20/isBurnable.js +++ /dev/null @@ -1,227 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("ERC20Handler - [Burn ERC20]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let ERC20MintableInstance1; - let ERC20MintableInstance2; - let resourceID1; - let resourceID2; - let initialResourceIDs; - let initialContractAddresses; - let burnableContractAddresses; - - beforeEach(async () => { - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ]); - - resourceID1 = Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - resourceID2 = Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC20MintableInstance1.address, - ERC20MintableInstance2.address, - ]; - burnableContractAddresses = [ERC20MintableInstance1.address]; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes( - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address) - ); - }); - - it("burnableContractAddresses should be marked as burnable", async () => { - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); - - it("ERC20MintableInstance2.address should not be marked as burnable", async () => { - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - const isBurnable = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).isBurnable - - assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); - }); - - it("ERC20MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - await BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - ERC20MintableInstance2.address - ); - const isBurnable = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - }); - - it(`ERC20MintableInstances should not be marked as - burnable after setResource is called on already burnable tokens`, async () => { - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - initialContractAddresses[i] - ) - ); - } - - // tokens should be marked as burnable - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableBeforeReRegisteringResource = ( - await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); - } - - // re-register resource - sets isBurnable to false for tokens - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - // tokens should not be marked as burnable if resource is re-registered - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableAfterReRegisteringResource = ( - await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); - } - }); -}); diff --git a/test/handlers/erc20/isBurnable.test.ts b/test/handlers/erc20/isBurnable.test.ts new file mode 100644 index 00000000..3851d7c5 --- /dev/null +++ b/test/handlers/erc20/isBurnable.test.ts @@ -0,0 +1,219 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {Hex} from "viem"; +import {deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + +describe("ERC20Handler - [Burn ERC20]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"]; + let resourceID1: Hex; + let resourceID2: Hex; + let initialResourceIDs: Array; + let initialContractAddresses: Array; + let burnableContractAddresses: Array; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance: ERC20MintableInstance1, + ERC20MintableInstance: ERC20MintableInstance2, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + evmRecipient, + relayer1 + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + ERC20MintableInstance1.address, + domainID + ); + resourceID2 = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + initialResourceIDs = [resourceID1, resourceID2]; + initialContractAddresses = [ + ERC20MintableInstance1.address, + ERC20MintableInstance2.address, + ]; + burnableContractAddresses = [ERC20MintableInstance1.address]; + }); + + it("burnableContractAddresses should be marked as burnable", async () => { + const ERC20HandlerInstance = await ERC20HandlerContract.new( + BridgeInstance.address, + DefaultMessageReceiverInstance.address + ); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC20HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( + burnableAddress + )).isBurnable + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); + + it("ERC20MintableInstance2.address should not be marked as burnable", async () => { + const ERC20HandlerInstance = await ERC20HandlerContract.new( + BridgeInstance.address, + DefaultMessageReceiverInstance.address + ); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC20HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + const isBurnable = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ]))[0]; + + assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); + }); + + it("ERC20MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { + const ERC20HandlerInstance = await ERC20HandlerContract.new( + BridgeInstance.address, + DefaultMessageReceiverInstance.address + ); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC20HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + await BridgeInstance.write.adminSetBurnable([ + ERC20HandlerInstance.address, + ERC20MintableInstance2.address + ]); + const isBurnable = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ]))[0]; + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + }); + + it(`ERC20MintableInstances should not be marked as + burnable after setResource is called on already burnable tokens`, async () => { + const ERC20HandlerInstance = await hre.viem.deployContract("ERC20Handler", [mockBridge.account!.address]); + + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC20HandlerInstance.address, + initialContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + // tokens should be marked as burnable + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableBeforeReRegisteringResource = ( + await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + initialContractAddresses[i] + ]) + ).isBurnable; + + assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); + } + + // re-register resource - sets isBurnable to false for tokens + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + // tokens should not be marked as burnable if resource is re-registered + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableAfterReRegisteringResource = ( + await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + initialContractAddresses[i] + ]) + )[0]; + + assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); + } + }); +}); diff --git a/test/handlers/erc20/isWhitelisted.js b/test/handlers/erc20/isWhitelisted.js deleted file mode 100644 index a83aafa7..00000000 --- a/test/handlers/erc20/isWhitelisted.js +++ /dev/null @@ -1,67 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract("ERC20Handler - [isWhitelisted]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let ERC20MintableInstance1; - let initialResourceIDs; - - beforeEach(async () => { - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ]); - - initialResourceIDs = []; - resourceID1 = Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - initialResourceIDs.push(resourceID1); - initialContractAddresses = [ERC20MintableInstance1.address]; - burnableContractAddresses = []; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes( - ERC20HandlerContract.new(BridgeInstance.address, DefaultMessageReceiverInstance.address) - ); - }); - - it("initialContractAddress should be whitelisted", async () => { - const ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID1, - ERC20MintableInstance1.address, - emptySetResourceData - ); - const isWhitelisted = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance1.address - )).isWhitelisted; - - assert.isTrue(isWhitelisted, "Contract wasn't successfully whitelisted"); - }) -}) diff --git a/test/handlers/erc20/isWhitelisted.test.ts b/test/handlers/erc20/isWhitelisted.test.ts new file mode 100644 index 00000000..a53f7399 --- /dev/null +++ b/test/handlers/erc20/isWhitelisted.test.ts @@ -0,0 +1,48 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; +import {Hex} from 'viem'; + + +describe("ERC20Handler - [isWhitelisted]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let resourceID: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + + resourceID = createResourceID( + ERC20MintableInstance.address, + domainID + ); + }); + + it("initialContractAddress should be whitelisted", async () => { + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + const isWhitelisted = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance.address + ]))[0]; + + assert.isTrue(isWhitelisted, "Contract wasn't successfully whitelisted"); + }) +}) diff --git a/test/handlers/erc20/optionalContracCall/collectFee.js b/test/handlers/erc20/optionalContracCall/collectFee.js deleted file mode 100644 index 45d65e8f..00000000 --- a/test/handlers/erc20/optionalContracCall/collectFee.js +++ /dev/null @@ -1,159 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); - -contract("Bridge - [collect fee - erc20 token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const initialTokenAmount = 100; - const depositAmount = 10; - const fee = 100000; // BPS - const feeAmount = 1; - const executionGasAmount = 30000000; - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const feeData = "0x"; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let PercentageFeeHandlerInstance; - let FeeHandlerRouterInstance; - let ERC721MintableInstance; - let message; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address, - ); - ERC20MintableInstance = await ERC20MintableContract.new( - "token20", - "TOK20" - ); - ERC721MintableInstance = await ERC721MintableContract.new("token721", "TOK721", "") - await ERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ); - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ), - - await DefaultMessageReceiverInstance.grantRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - ERC20HandlerInstance.address - ); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - const mintableERC721Iface = new Ethers.utils.Interface( - ["function mint(address to, uint256 tokenId, string memory _data)"] - ); - const actions = [{ - nativeValue: 0, - callTo: ERC721MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC721Iface.encodeFunctionData("mint", [evmRecipientAddress, "5", ""]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - depositAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("ERC20 token transfer fee should be successfully deducted", async () => { - const depositorBalanceBefore = await ERC20MintableInstance.balanceOf(depositorAddress); - const handlerBalanceBefore = await ERC20MintableInstance.balanceOf(ERC20HandlerInstance.address); - - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - message, - feeData, - { - from: depositorAddress, - } - )); - - // check that correct ERC20 token amount is successfully transferred to the handler - const handlerBalanceAfter = await ERC20MintableInstance.balanceOf(ERC20HandlerInstance.address); - assert.strictEqual( - new Ethers.BigNumber.from(feeAmount).add(Number(handlerBalanceBefore)).toString(), - handlerBalanceAfter.toString() - ); - - // check that depositor before and after balances align - const depositorBalanceAfter = await ERC20MintableInstance.balanceOf(depositorAddress); - assert.strictEqual( - new Ethers.BigNumber.from(Number(depositorBalanceBefore) - ).sub(feeAmount).toString(), depositorBalanceAfter.toString() - ) - }); -}); diff --git a/test/handlers/erc20/optionalContracCall/collectFee.test.ts b/test/handlers/erc20/optionalContracCall/collectFee.test.ts new file mode 100644 index 00000000..1b4efdff --- /dev/null +++ b/test/handlers/erc20/optionalContracCall/collectFee.test.ts @@ -0,0 +1,151 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {getAbiItem, Hex, keccak256, toFunctionSelector, toHex, WalletClient, encodeFunctionData} from "viem"; +import {createGmpDepositData, createResourceID, deploySourceChainContracts, mpcAddress, createMessageCallData, createOptionalContractCallDepositData} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; + + +describe("Bridge - [collect fee - erc20 token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size: 32}); + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const fee = BigInt(100000); // BPS + const feeAmount = BigInt(1); + const executionGasAmount = BigInt(30000000); + const transactionId = toHex(1, {size: 32}); + const feeData = "0x"; + + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"] + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC20BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let ERC721BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + + let depositor: WalletClient; + let evmRecipient: WalletClient; + + let message: Hex; + let depositProposalData: Hex; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + BasicFeeHandlerInstance: ERC20BasicFeeHandlerInstance, + BasicFeeHandlerInstance: ERC721BasicFeeHandlerInstance, + PercentageFeeHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + evmRecipient + ] = await hre.viem.getWalletClients(); + + await ERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + + await DefaultMessageReceiverInstance.write.grantRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + ERC20HandlerInstance.address + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 tokenId, string memory _data)"], + functionName: "mint", + args: [evmRecipient, "5", ""] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC721MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + evmRecipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + depositAmount, + zeroAddress, + executionGasAmount, + message + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("ERC20 token transfer fee should be successfully deducted", async () => { + const depositorBalanceBefore = await ERC20MintableInstance.read.balanceOf([depositor.account!.address]); + const handlerBalanceBefore = await ERC20MintableInstance.read.balanceOf([ERC20HandlerInstance.address]); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + message, + feeData + ], + { + account: depositor.account, + } + )).not.to.be.reverted; + + // check that correct ERC20 token amount is successfully transferred to the handler + const handlerBalanceAfter = await ERC20MintableInstance.read.balanceOf([ERC20HandlerInstance.address]); + assert.strictEqual( + handlerBalanceBefore + feeAmount, + handlerBalanceAfter + ); + + // check that depositor before and after balances align + const depositorBalanceAfter = await ERC20MintableInstance.read.balanceOf([depositor.account!.address]); + assert.strictEqual( + depositorBalanceBefore - feeAmount, + depositorBalanceAfter + ) + }); +}); diff --git a/test/handlers/erc20/optionalContracCall/decimalConversion.js b/test/handlers/erc20/optionalContracCall/decimalConversion.js deleted file mode 100644 index 3a8b05e9..00000000 --- a/test/handlers/erc20/optionalContracCall/decimalConversion.js +++ /dev/null @@ -1,277 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); - - -contract("Bridge - [decimal conversion - erc20 token]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - const returnBytesLength = 128; - - const expectedDepositNonce = 1; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const originDecimalPlaces = 8; - const bridgeDefaultDecimalPlaces = 18; - const initialTokenAmount = Ethers.utils.parseUnits("100", originDecimalPlaces); - const depositAmount = Ethers.utils.parseUnits("10", originDecimalPlaces); - const fee = 100000; // BPS - const feeAmount = Ethers.utils.parseUnits("1", originDecimalPlaces); - const convertedTransferAmount = Ethers.utils.parseUnits("10", bridgeDefaultDecimalPlaces); - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - const amountToMint = 1; - const feeData = "0x"; - - const AbiCoder = new Ethers.utils.AbiCoder(); - const expectedHandlerResponse = AbiCoder.encode( - ["uint256"], - [convertedTransferAmount] - ); - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let PercentageFeeHandlerInstance; - let FeeHandlerRouterInstance; - let depositProposalData; - let ERC20MintableInstance; - let ERC721MintableInstance; - - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address, - ); - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - ERC721MintableInstance = await ERC721MintableContract.new("token721", "TOK721", "") - await ERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - await ERC20MintableInstance.mint(ERC20HandlerInstance.address, initialTokenAmount); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - originDecimalPlaces - ); - await BridgeInstance.adminSetBurnable( - ERC20HandlerInstance.address, - ERC20MintableInstance.address - ); - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ); - - await DefaultMessageReceiverInstance.grantRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - ERC20HandlerInstance.address - ); - - await ERC721MintableInstance.grantRole( - await ERC721MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - ERC20HandlerInstance.address - ); - - await ERC20MintableInstance.approve( - PercentageFeeHandlerInstance.address, - feeAmount, - {from: depositorAddress} - ); - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - const mintableERC721Iface = new Ethers.utils.Interface( - ["function mint(address to, uint256 tokenId, string memory _data)"] - ); - const actions = [{ - nativeValue: 0, - callTo: ERC721MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC721Iface.encodeFunctionData("mint", [evmRecipientAddress, "5", ""]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - depositAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - - it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { - const ERC20Decimals = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance.address - )).decimals; - - assert.strictEqual(ERC20Decimals.isSet, true); - assert.strictEqual(ERC20Decimals["externalDecimals"], "8"); - }); - - it("Deposit converts sent token amount with 8 decimals to 18 decimal places", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ); - - await TruffleAssert.passes(depositTx); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === depositProposalData && - event.handlerResponse === expectedHandlerResponse - ); - }); - }); - - it("Proposal execution converts sent token amount with 18 decimals to 8 decimal places", async () => { - const proposalData = Helpers.createOptionalContractCallDepositData( - convertedTransferAmount, // 18 decimals - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - const dataHash = Ethers.utils.keccak256( - ERC20HandlerInstance.address + proposalData.substr(2) - ); - - const proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: proposalData, - }; - - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - const recipientBalanceBefore = await ERC721MintableInstance.balanceOf(evmRecipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256", "uint16", "uint256"], - [ - ERC20MintableInstance.address, - DefaultMessageReceiverInstance.address, - convertedTransferAmount, - returnBytesLength, - 0 - ] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that ERC721 token is transferred to recipient address - const recipientBalanceAfter = await ERC721MintableInstance.balanceOf(evmRecipientAddress); - assert.strictEqual(new Ethers.BigNumber.from(amountToMint).add( - Number(recipientBalanceBefore)).toString(), - recipientBalanceAfter.toString() - ); - }); -}); diff --git a/test/handlers/erc20/optionalContracCall/decimalConversion.test.ts b/test/handlers/erc20/optionalContracCall/decimalConversion.test.ts new file mode 100644 index 00000000..c803aebc --- /dev/null +++ b/test/handlers/erc20/optionalContracCall/decimalConversion.test.ts @@ -0,0 +1,277 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, mpcAddress, signTypedProposal, trimPrefix} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Wallet} from 'ethers'; +import {Proposal} from '../../../../types'; + + +describe("Bridge - [decimal conversion - erc20 token]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const returnBytesLength = 128; + + const expectedDepositNonce = BigInt(1); + const resourceID = toHex(650, {size:32}); + const originDecimalPlaces = 8; + const bridgeDefaultDecimalPlaces = 18; + const initialTokenAmount = parseUnits("100", originDecimalPlaces); + const depositAmount = parseUnits("10", originDecimalPlaces); + const fee = BigInt(100000); // BPS + const feeAmount = parseUnits("1", originDecimalPlaces); + const convertedTransferAmount = parseUnits("10", bridgeDefaultDecimalPlaces); + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + const amountToMint = BigInt(1); + const feeData = "0x"; + + const expectedHandlerResponse = + encodeAbiParameters( + parseAbiParameters( + ["uint256"] + ), + [convertedTransferAmount] + ); + + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"] + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC20BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let ERC721BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + + let depositor: WalletClient; + let evmRecipient: WalletClient; + let relayer1: WalletClient; + + let depositProposalData: Hex; + let message: Hex; + let proposal: Proposal; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + BasicFeeHandlerInstance: ERC20BasicFeeHandlerInstance, + BasicFeeHandlerInstance: ERC721BasicFeeHandlerInstance, + PercentageFeeHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + evmRecipient + ] = await hre.viem.getWalletClients(); + + await ERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + await ERC20MintableInstance.write.mint([ERC20HandlerInstance.address, initialTokenAmount]); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + toHex(originDecimalPlaces) + ]); + await BridgeInstance.write.adminSetBurnable([ + ERC20HandlerInstance.address, + ERC20MintableInstance.address + ]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + + await DefaultMessageReceiverInstance.write.grantRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + ERC20HandlerInstance.address + ]); + + await ERC721MintableInstance.write.grantRole([ + await ERC721MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + ERC20HandlerInstance.address + ]); + + await ERC20MintableInstance.write.approve([ + PercentageFeeHandlerInstance.address, + feeAmount + ], + { + account: depositor.account + } + ); + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 tokenId, string memory _data)"], + functionName: "mint", + args: [evmRecipient, "5", ""] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC721MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }]; + message = createMessageCallData( + transactionId, + actions, + evmRecipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + depositAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + + it("[sanity] decimals value is set if args are provided to 'adminSetResource'", async () => { + const ERC20Decimals = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance.address + ]))[3]; + + assert.strictEqual(ERC20Decimals.isSet, true); + assert.strictEqual(ERC20Decimals["externalDecimals"], 8); + }); + + it("Deposit converts sent token amount with 8 decimals to 18 decimal places", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositProposalData, + expectedHandlerResponse + ); + }); + + it("Proposal execution converts sent token amount with 18 decimals to 8 decimal places", async () => { + const proposalData = createOptionalContractCallDepositData( + convertedTransferAmount, // 18 decimals + zeroAddress, + executionGasAmount, + message + ); + + const dataHash = keccak256( + concat([ + ERC20HandlerInstance.address, + trimPrefix(proposalData) + ]) + ); + + const proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: proposalData, + }; + + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + const recipientBalanceBefore = await ERC721MintableInstance.read.balanceOf([evmRecipient.account!.address]); + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + const expectedHandlerResponse = encodeAbiParameters( + parseAbiParameters( + ["address", "address", "uint256", "uint16", "uint256"] + ), + [ + ERC20MintableInstance.address, + DefaultMessageReceiverInstance.address, + convertedTransferAmount, + returnBytesLength, + BigInt(0) + ] + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + expectedHandlerResponse + ); + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that ERC721 token is transferred to recipient address + const recipientBalanceAfter = await ERC721MintableInstance.read.balanceOf([evmRecipient.account!.address]); + assert.strictEqual(recipientBalanceBefore + amountToMint, + recipientBalanceAfter + ); + }); +}); diff --git a/test/handlers/erc20/optionalContracCall/deposit.js b/test/handlers/erc20/optionalContracCall/deposit.js deleted file mode 100644 index ed73ba35..00000000 --- a/test/handlers/erc20/optionalContracCall/deposit.js +++ /dev/null @@ -1,211 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); - - -contract("Bridge - [deposit - erc20 token with contract call]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const initialTokenAmount = 100; - const depositAmount = 10; - const fee = 1; - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - const feeData = "0x"; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let PercentageFeeHandlerInstance; - let FeeHandlerRouterInstance; - let ERC20MintableInstance; - let ERC721MintableInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address, - ); - - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - ERC721MintableInstance = await ERC721MintableContract.new("token721", "TOK721", "") - await ERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ), - - await ERC20MintableInstance.grantRole( - await ERC20MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - const mintableERC721Iface = new Ethers.utils.Interface( - ["function mint(address to, uint256 tokenId, string memory _data)"] - ); - const actions = [{ - nativeValue: 0, - callTo: ERC721MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC721Iface.encodeFunctionData("mint", [evmRecipientAddress, "5", ""]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - - depositProposalData = Helpers.createOptionalContractCallDepositData( - depositAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("Native token deposit to EVM with message can be made", async () => { - await TruffleAssert.passes( - await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ) - ); - }); - - it("_depositCounts should be increments from 0 to 1", async () => { - await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ); - - const depositCount = await BridgeInstance._depositCounts.call( - destinationDomainID - ); - assert.strictEqual(depositCount.toNumber(), expectedDepositNonce); - }); - - it("Deposit event is fired with expected value", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ); - - const internalTx = await TruffleAssert.createTransactionResult( - BridgeInstance, - depositTx.tx - ); - - - TruffleAssert.eventEmitted(internalTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === depositProposalData.toLowerCase() && - event.handlerResponse === null - ); - }); - }); - - it("Should revert if destination domain is current bridge domain", async () => { - await Helpers.reverts( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositProposalData, - feeData, { - from: depositorAddress, - } - ) - ); - }); -}); diff --git a/test/handlers/erc20/optionalContracCall/deposit.test.ts b/test/handlers/erc20/optionalContracCall/deposit.test.ts new file mode 100644 index 00000000..0c25e6a1 --- /dev/null +++ b/test/handlers/erc20/optionalContracCall/deposit.test.ts @@ -0,0 +1,208 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Wallet} from 'ethers'; +import {Proposal} from '../../../../types'; + +describe("Bridge - [deposit - erc20 token with contract call]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const fee = BigInt(1); + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + const feeData = "0x"; + + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"] + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC20BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let ERC721BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + + let depositor: WalletClient; + let recipient: WalletClient; + + let message: Hex; + let depositProposalData: Hex; + let proposal: Proposal; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + BasicFeeHandlerInstance: ERC20BasicFeeHandlerInstance, + BasicFeeHandlerInstance: ERC721BasicFeeHandlerInstance, + PercentageFeeHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient + ] = await hre.viem.getWalletClients(); + + await ERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + + await ERC20MintableInstance.write.grantRole([ + await ERC20MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 tokenId, string memory _data)"], + functionName: "mint", + args: [recipient, "5", ""] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC721MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + + + depositProposalData = createOptionalContractCallDepositData( + depositAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("Native token deposit to EVM with message can be made", async () => { + await expect( + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + }); + + it("_depositCounts should be increments from 0 to 1", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account, + } + ); + + const depositCount = await BridgeInstance.read._depositCounts([ + destinationDomainID + ]); + assert.strictEqual(depositCount, expectedDepositNonce); + }); + + it("Deposit event is fired with expected value", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData], + { + account: depositor.account, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositProposalData.toLowerCase(), + null + ); + }); + + it("Should revert if destination domain is current bridge domain", async () => { + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account, + } + ) + ).to.be.reverted; + }); +}); diff --git a/test/handlers/erc20/optionalContracCall/distributeFee.js b/test/handlers/erc20/optionalContracCall/distributeFee.js deleted file mode 100644 index 53596f26..00000000 --- a/test/handlers/erc20/optionalContracCall/distributeFee.js +++ /dev/null @@ -1,279 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); -const Ethers = require("ethers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); - -contract("PercentageFeeHandler - [distributeFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - - const expectedDepositNonce = 1; - const depositAmount = 100000; - const feeData = "0x"; - const emptySetResourceData = "0x"; - const feeAmount = 30; - const feeBps = 30000; // 3 BPS - const payout = Ethers.BigNumber.from("10"); - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let PercentageFeeHandlerInstance; - let FeeHandlerRouterInstance; - let ERC721MintableInstance; - - let resourceID; - let depositProposalData; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: accounts[1]}), - "sender doesn't have admin role" - ); - }; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ), - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ) - ]); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - ERC721MintableInstance = await ERC721MintableContract.new("token721", "TOK721", "") - - await Promise.all([ - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ERC20MintableInstance.mint(depositorAddress, depositAmount + feeAmount), - ERC20MintableInstance.approve(ERC20HandlerInstance.address, depositAmount, { - from: depositorAddress, - }), - ERC20MintableInstance.approve( - PercentageFeeHandlerInstance.address, - depositAmount, - {from: depositorAddress} - ), - BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ), - PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, feeBps) - ]); - - await DefaultMessageReceiverInstance.grantRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - ERC20HandlerInstance.address - ); - - const mintableERC721Iface = new Ethers.utils.Interface( - ["function mint(address to, uint256 tokenId, string memory _data)"] - ); - const actions = [{ - nativeValue: 0, - callTo: ERC721MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC721Iface.encodeFunctionData("mint", [evmRecipientAddress, "5", ""]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - depositProposalData = Helpers.createOptionalContractCallDepositData( - depositAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should distribute fees", async () => { - // check the balance is 0 - const b1Before = ( - await ERC20MintableInstance.balanceOf(accounts[3]) - ).toString(); - const b2Before = ( - await ERC20MintableInstance.balanceOf(accounts[4]) - ).toString(); - - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - // Transfer the funds - const tx = await PercentageFeeHandlerInstance.transferERC20Fee( - resourceID, - [accounts[3], accounts[4]], - [payout, payout] - ); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === ERC20MintableInstance.address && - event.recipient === accounts[3] && - event.amount.toString() === payout.toString() - ); - }); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === ERC20MintableInstance.address && - event.recipient === accounts[4] && - event.amount.toString() === payout.toString() - ); - }); - b1 = await ERC20MintableInstance.balanceOf(accounts[3]); - b2 = await ERC20MintableInstance.balanceOf(accounts[4]); - assert.equal(b1.toString(), payout.add(b1Before).toString()); - assert.equal(b2.toString(), payout.add(b2Before).toString()); - }); - - it("should not distribute fees with other resourceID", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - const incorrectResourceID = Helpers.createResourceID( - PercentageFeeHandlerInstance.address, - originDomainID - ); - - // Transfer the funds: fails - await Helpers.reverts( - PercentageFeeHandlerInstance.transferERC20Fee( - incorrectResourceID, - [accounts[3], accounts[4]], - [payout, payout] - ) - ); - }); - - it("should require admin role to distribute fee", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - await assertOnlyAdmin( - PercentageFeeHandlerInstance.transferERC20Fee, - resourceID, - [accounts[3], accounts[4]], - [payout.toNumber(), payout.toNumber()] - ); - }); - - it("should revert if addrs and amounts arrays have different length", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - await Helpers.reverts( - PercentageFeeHandlerInstance.transferERC20Fee( - resourceID, - [accounts[3], accounts[4]], - [payout, payout, payout] - ), - "addrs[], amounts[]: diff length" - ); - }); -}); diff --git a/test/handlers/erc20/optionalContracCall/distributeFee.test.ts b/test/handlers/erc20/optionalContracCall/distributeFee.test.ts new file mode 100644 index 00000000..f77ef59a --- /dev/null +++ b/test/handlers/erc20/optionalContracCall/distributeFee.test.ts @@ -0,0 +1,278 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {encodeFunctionData, Hex, keccak256, parseAbiParameters, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Proposal} from '../../../../types'; + +describe("PercentageFeeHandler - [distributeFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const depositAmount = BigInt(100000); + const feeData = "0x"; + const emptySetResourceData = "0x"; + const feeAmount = BigInt(30); + const feeBps = BigInt(30000); // 3 BPS + const payout = BigInt(10); + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"] + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC20BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let ERC721BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + + let nonAdmin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let firstEOA: WalletClient; + let secondEOA: WalletClient; + + let message: Hex; + let depositProposalData: Hex; + let proposal: Proposal; + let resourceID: Hex; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + BasicFeeHandlerInstance: ERC20BasicFeeHandlerInstance, + BasicFeeHandlerInstance: ERC721BasicFeeHandlerInstance, + PercentageFeeHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + nonAdmin, + depositor, + recipient, + firstEOA, + secondEOA + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await ERC20MintableInstance.write.mint([depositor.account!.address, depositAmount + feeAmount]), + await ERC20MintableInstance.write.approve([ERC20HandlerInstance.address, depositAmount], { + account: depositor.account, + }); + await ERC20MintableInstance.write.approve([ + PercentageFeeHandlerInstance.address, + depositAmount + ], + {account: depositor.account} + ), + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, feeBps]); + + await DefaultMessageReceiverInstance.write.grantRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + ERC20HandlerInstance.address + ]); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 tokenId, string memory _data)"], + functionName: "mint", + args: [recipient, "5", ""] + }); + + const actions = [{ + nativeValue: BigInt(0), + callTo: ERC721MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + recipient.account!.address + ); + + depositProposalData = createOptionalContractCallDepositData( + depositAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should distribute fees", async () => { + // check the balance is 0 + const firstEOABalanceBefore = ( + await ERC20MintableInstance.read.balanceOf([firstEOA.account!.address]) + ); + const secondEOABalanceBefore = ( + await ERC20MintableInstance.read.balanceOf([secondEOA.account!.address]) + ); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + const percentageFeeHandlerBalance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(percentageFeeHandlerBalance, feeAmount); + + // Transfer the funds + const transferFeeTx = await PercentageFeeHandlerInstance.write.transferERC20Fee([ + resourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ]); + + await expect(transferFeeTx).to.emit(PercentageFeeHandlerInstance, "FeeDistributed").withArgs( + ERC20MintableInstance.address, + firstEOA.account!.address, + payout + ); + await expect(transferFeeTx).to.emit(PercentageFeeHandlerInstance, "FeeDistributed").withArgs( + ERC20MintableInstance.address, + secondEOA.account!.address, + payout + ); + + const firstEOABalanceAfter = await ERC20MintableInstance.read.balanceOf([firstEOA.account!.address]); + const secondEOABalanceAfter = await ERC20MintableInstance.read.balanceOf([secondEOA.account!.address]); + assert.equal(firstEOABalanceAfter, firstEOABalanceBefore + payout); + assert.equal(secondEOABalanceAfter, secondEOABalanceBefore + payout); + }); + + it("should not distribute fees with other resourceID", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account, + } + ) + ); + const percentageFeeHandlerBalance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(percentageFeeHandlerBalance, feeAmount); + + const incorrectResourceID = createResourceID( + PercentageFeeHandlerInstance.address, + originDomainID + ); + + // Transfer the funds: fails + await expect( + PercentageFeeHandlerInstance.write.transferERC20Fee([ + incorrectResourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ]) + ).to.be.reverted; + }); + + it("should require admin role to distribute fee", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + + const percentageFeeHandlerBalance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(percentageFeeHandlerBalance, feeAmount); + + await expect( + PercentageFeeHandlerInstance.write.transferERC20Fee([ + resourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ],{ + account: nonAdmin.account + } + )).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should revert if addrs and amounts arrays have different length", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + + const percentageFeeHandlerBalance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(percentageFeeHandlerBalance, feeAmount); + + await expect( + PercentageFeeHandlerInstance.write.transferERC20Fee([ + resourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout, payout] + ]), + ).to.be.revertedWith("addrs[], amounts[]: diff length"); + }); +}); diff --git a/test/handlers/erc20/optionalContracCall/executeProposal.js b/test/handlers/erc20/optionalContracCall/executeProposal.js deleted file mode 100644 index dd61a6e9..00000000 --- a/test/handlers/erc20/optionalContracCall/executeProposal.js +++ /dev/null @@ -1,346 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); - -contract("Bridge - [execute proposal - erc20 token with contract call]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const adminAddress = accounts[0]; - const depositorAddress = accounts[1]; - const evmRecipientAddress = accounts[2]; - const relayer1Address = accounts[3]; - - const expectedDepositNonce = 1; - const emptySetResourceData = "0x"; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650"; - const initialTokenAmount = 100; - const depositAmount = 10; - const fee = 1000000; // BPS - const transferredAmount = 9; - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const executionGasAmount = 30000000; - const feeData = "0x"; - const amountToMint = 1; - const returnBytesLength = 128; - - let BridgeInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let PercentageFeeHandlerInstance; - let FeeHandlerRouterInstance; - let ERC20MintableInstance; - let ERC721MintableInstance; - let dataHash; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - adminAddress - )), - ]); - - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address, - ); - - ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ); - ERC721MintableInstance = await ERC721MintableContract.new("token721", "TOK721", "") - await ERC20MintableInstance.mint(depositorAddress, initialTokenAmount); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - // await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 2, 10) - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ), - await DefaultMessageReceiverInstance.grantRole( - await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(), - ERC20HandlerInstance.address - ); - await ERC721MintableInstance.grantRole( - await ERC721MintableInstance.MINTER_ROLE(), - DefaultMessageReceiverInstance.address - ); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - const mintableERC721Iface = new Ethers.utils.Interface( - ["function mint(address to, uint256 tokenId, string memory _data)"] - ); - const actions = [{ - nativeValue: 0, - callTo: ERC721MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC721Iface.encodeFunctionData("mint", [evmRecipientAddress, "5", ""]), - }] - message = Helpers.createMessageCallData( - transactionId, - actions, - evmRecipientAddress - ); - - - depositProposalData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - executionGasAmount, - message - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - resourceID: resourceID, - data: depositProposalData - }; - - dataHash = Ethers.utils.keccak256( - ERC20HandlerInstance.address + depositProposalData.substr(2) - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("isProposalExecuted returns false if depositNonce is not used", async () => { - const destinationDomainID = await BridgeInstance._domainID(); - - assert.isFalse( - await BridgeInstance.isProposalExecuted( - destinationDomainID, - expectedDepositNonce - ) - ); - }); - - it("should create and execute executeProposal with contract call successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress - }) - ); - - const recipientNativeBalanceBefore = await web3.eth.getBalance(evmRecipientAddress); - const recipientERC721BalanceBefore = await ERC721MintableInstance.balanceOf(evmRecipientAddress); - const defaultReceiverBalanceBefore = await web3.eth.getBalance(DefaultMessageReceiverInstance.address); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - gas: executionGasAmount - }) - ); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that tokens are transferred to recipient address - const recipientNativeBalanceAfter = await web3.eth.getBalance(evmRecipientAddress); - const recipientERC721BalanceAfter = await ERC721MintableInstance.balanceOf(evmRecipientAddress); - const defaultReceiverBalanceAfter = await web3.eth.getBalance(DefaultMessageReceiverInstance.address); - - assert.strictEqual( - recipientNativeBalanceBefore, - recipientNativeBalanceAfter - ); - assert.strictEqual(new Ethers.BigNumber.from(amountToMint).add( - recipientERC721BalanceBefore.toString()).toString(), recipientERC721BalanceAfter.toString() - ); - assert.strictEqual(defaultReceiverBalanceBefore.toString(), defaultReceiverBalanceAfter.toString()); - }); - - it("should skip executing proposal if deposit nonce is already used", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress - }) - ); - - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - gas: executionGasAmount - }) - ); - - const skipExecuteTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - // check that no ProposalExecution events are emitted - assert.equal(skipExecuteTx.logs.length, 0); - }); - - it("executeProposal event should be emitted with expected values", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress - }) - ); - - const recipientBalanceBefore = await ERC20MintableInstance.balanceOf(evmRecipientAddress); - - const proposalTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - { - from: relayer1Address, - gas: executionGasAmount - } - ); - - TruffleAssert.eventEmitted(proposalTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === dataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["address", "address", "uint256", "uint16", "uint256"], - [ - ERC20MintableInstance.address, - DefaultMessageReceiverInstance.address, - transferredAmount, - returnBytesLength, - 0 - ] - ) - ); - }); - - // check that deposit nonce has been marked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // check that ERC20 tokens are transferred to recipient address - const recipientBalanceAfter = await ERC20MintableInstance.balanceOf(evmRecipientAddress); - assert.strictEqual(new Ethers.BigNumber.from(transferredAmount).add( - Number(recipientBalanceBefore)).toString(), - recipientBalanceAfter.toString() - ); - }); - - it(`should fail to executeProposal if signed Proposal has different - chainID than the one on which it should be executed`, async () => { - const proposalSignedData = - await Helpers.mockSignTypedProposalWithInvalidChainID( - BridgeInstance.address, - [proposal] - ); - - // depositorAddress makes initial deposit of depositAmount - assert.isFalse(await BridgeInstance.paused()); - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositProposalData, - feeData, - { - from: depositorAddress - }) - ); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }), - "InvalidProposalSigner()" - ); - }); -}); diff --git a/test/handlers/erc20/optionalContracCall/executeProposal.test.ts b/test/handlers/erc20/optionalContracCall/executeProposal.test.ts new file mode 100644 index 00000000..fbaf487a --- /dev/null +++ b/test/handlers/erc20/optionalContracCall/executeProposal.test.ts @@ -0,0 +1,352 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, encodeFunctionData, Hex, keccak256, parseAbiParameters, parseUnits, toFunctionSelector, toHex, WalletClient, zeroAddress} from "viem"; +import {createGmpDepositData, createMessageCallData, createOptionalContractCallDepositData, createResourceID, deploySourceChainContracts, getBalance, mockSignTypedProposalWithInvalidChainID, mpcAddress, signTypedProposal, trimPrefix} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Wallet} from 'ethers'; +import {Proposal} from '../../../../types'; + +describe("Bridge - [execute proposal - erc20 token with contract call]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = BigInt(1); + const emptySetResourceData = "0x"; + const resourceID = toHex(650, {size:32}); + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const fee = BigInt(1000000); // BPS + const transferredAmount = BigInt(9); + const transactionId = toHex(1, {size:32}); + const executionGasAmount = BigInt(30000000); + const feeData = "0x"; + const amountToMint = BigInt(1); + const returnBytesLength = 128; + + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"] + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + + let depositor: WalletClient; + let evmRecipient: WalletClient; + let relayer1: WalletClient; + + let dataHash: Hex; + let message: Hex; + let depositProposalData: Hex; + let proposal: Proposal; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + PercentageFeeHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + evmRecipient, + relayer1, + ] = await hre.viem.getWalletClients(); + + await ERC20MintableInstance.write.mint([depositor.account!.address, initialTokenAmount]); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(2), BigInt(10)]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + await DefaultMessageReceiverInstance.write.grantRole([ + await DefaultMessageReceiverInstance.read.SYGMA_HANDLER_ROLE(), + ERC20HandlerInstance.address + ]); + await ERC721MintableInstance.write.grantRole([ + await ERC721MintableInstance.read.MINTER_ROLE(), + DefaultMessageReceiverInstance.address + ]); + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + const actionData = encodeFunctionData({ + abi: ["function mint(address to, uint256 tokenId, string memory _data)"], + functionName: "mint", + args: [evmRecipient, "5", ""] + }); + const actions = [{ + nativeValue: 0, + callTo: ERC721MintableInstance.address, + approveTo: zeroAddress, + tokenSend: zeroAddress, + tokenReceive: zeroAddress, + data: actionData, + }] + message = createMessageCallData( + transactionId, + actions, + evmRecipient + ); + + depositProposalData = createOptionalContractCallDepositData( + transferredAmount, + zeroAddress, + executionGasAmount, + message + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + resourceID: resourceID, + data: depositProposalData + }; + + dataHash = keccak256( + concat([ + ERC20HandlerInstance.address, + trimPrefix(depositProposalData) + ]) + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("isProposalExecuted returns false if depositNonce is not used", async () => { + const destinationDomainID = await BridgeInstance.read._domainID(); + + assert.isFalse( + await BridgeInstance.read.isProposalExecuted([ + destinationDomainID, + expectedDepositNonce + ]) + ); + }); + + it("should create and execute executeProposal with contract call successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account + }) + ).not.to.be.reverted; + + const recipientNativeBalanceBefore = await getBalance(evmRecipient); + const recipientERC721BalanceBefore = await ERC721MintableInstance.read.balanceOf([evmRecipient.account!.address]); + const defaultReceiverBalanceBefore = await getBalance(DefaultMessageReceiverInstance); + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + gas: executionGasAmount + }) + ).not.to.be.reverted; + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that tokens are transferred to recipient address + const recipientNativeBalanceAfter = await getBalance(evmRecipient); + const recipientERC721BalanceAfter = await ERC721MintableInstance.read.balanceOf([evmRecipient.account!.address]); + const defaultReceiverBalanceAfter = await getBalance(DefaultMessageReceiverInstance); + + assert.strictEqual( + recipientNativeBalanceBefore, + recipientNativeBalanceAfter + ); + assert.strictEqual(recipientERC721BalanceBefore + amountToMint, recipientERC721BalanceAfter); + assert.strictEqual(defaultReceiverBalanceBefore, defaultReceiverBalanceAfter); + }); + + it("should skip executing proposal if deposit nonce is already used", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account + }) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + gas: executionGasAmount + }) + ).not.to.be.reverted; + + const skipExecuteTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + // check that no ProposalExecution events are emitted + await expect(skipExecuteTx).not.to.emit(BridgeInstance, "ProposalExecution"); + + }); + + it("executeProposal event should be emitted with expected values", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account + }) + ).not.to.be.reverted; + + const recipientBalanceBefore = await ERC20MintableInstance.read.balanceOf([evmRecipient.account!.address]); + + const proposalTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account, + gas: executionGasAmount + } + ); + + + const expectedHandlerResponse = encodeAbiParameters( + parseAbiParameters( + ["address", "address", "uint256", "uint16", "uint256"] + ), + [ + ERC20MintableInstance.address, + DefaultMessageReceiverInstance.address, + transferredAmount, + returnBytesLength, + BigInt(0) + ] + ); + + await expect(proposalTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + dataHash, + expectedHandlerResponse + ); + + // check that deposit nonce has been marked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // check that ERC20 tokens are transferred to recipient address + const recipientBalanceAfter = await ERC20MintableInstance.read.balanceOf([evmRecipient.account!.address]); + assert.strictEqual(recipientBalanceBefore + transferredAmount, + recipientBalanceAfter + ); + }); + + it(`should fail to executeProposal if signed Proposal has different + chainID than the one on which it should be executed`, async () => { + const proposalSignedData = + await mockSignTypedProposalWithInvalidChainID( + BridgeInstance.address, + [proposal] + ); + + // depositor makes initial deposit of depositAmount + assert.isFalse(await BridgeInstance.read.paused()); + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositProposalData, + feeData + ], + { + account: depositor.account + }) + ).not.to.be.reverted; + + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }), + ).to.be.revertedWithCustomError(BridgeInstance, "InvalidProposalSigner()"); + }); +}); diff --git a/test/handlers/erc20/setResourceIDAndContractAddress.js b/test/handlers/erc20/setResourceIDAndContractAddress.js deleted file mode 100644 index a15f87f3..00000000 --- a/test/handlers/erc20/setResourceIDAndContractAddress.js +++ /dev/null @@ -1,226 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); - -contract( - "ERC20Handler - [setResourceIDAndContractAddress]", - async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance1; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let initialResourceIDs; - let initialContractAddresses; - - beforeEach(async () => { - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - (ERC20MintableInstance1 = await ERC20MintableContract.new( - "token", - "TOK" - )); - - initialResourceIDs = [ - Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ), - ]; - initialContractAddresses = [ERC20MintableInstance1.address]; - burnableContractAddresses = []; - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[0], - initialContractAddresses[0], - emptySetResourceData - ); - }); - - it("[sanity] ERC20MintableInstance1's resourceID and contract address should be set correctly", async () => { - const retrievedTokenAddress = - await ERC20HandlerInstance._resourceIDToTokenContractAddress.call( - initialResourceIDs[0] - ); - assert.strictEqual( - Ethers.utils.getAddress(ERC20MintableInstance1.address), - retrievedTokenAddress - ); - - const retrievedResourceID = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance1.address - )).resourceID - - assert.strictEqual( - initialResourceIDs[0].toLowerCase(), - retrievedResourceID.toLowerCase() - ); - }); - - it("new resourceID and corresponding contract address should be set correctly", async () => { - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - const secondERC20ResourceID = Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - secondERC20ResourceID, - ERC20MintableInstance2.address, - emptySetResourceData - ); - - const retrievedTokenAddress = - await ERC20HandlerInstance._resourceIDToTokenContractAddress.call( - secondERC20ResourceID - ); - assert.strictEqual( - Ethers.utils.getAddress(ERC20MintableInstance2.address).toLowerCase(), - retrievedTokenAddress.toLowerCase() - ); - - const retrievedResourceID = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).resourceID - - assert.strictEqual( - secondERC20ResourceID.toLowerCase(), - retrievedResourceID.toLowerCase() - ); - }); - - it("existing resourceID should be updated correctly with new token contract address", async () => { - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance2.address, - emptySetResourceData - ); - - const retrievedTokenAddress = - await ERC20HandlerInstance._resourceIDToTokenContractAddress.call( - initialResourceIDs[0] - ); - assert.strictEqual(ERC20MintableInstance2.address, retrievedTokenAddress); - - const retrievedResourceID = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).resourceID - - assert.strictEqual( - initialResourceIDs[0].toLowerCase(), - retrievedResourceID.toLowerCase() - ); - }); - - it("existing resourceID should be updated correctly with new handler address", async () => { - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - ERC20HandlerInstance2 = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance2.address, - initialResourceIDs[0], - ERC20MintableInstance2.address, - emptySetResourceData - ); - - const bridgeHandlerAddress = - await BridgeInstance._resourceIDToHandlerAddress.call( - initialResourceIDs[0] - ); - assert.strictEqual( - bridgeHandlerAddress.toLowerCase(), - ERC20HandlerInstance2.address.toLowerCase() - ); - }); - - it("existing resourceID should be replaced by new resourceID in handler", async () => { - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - const secondERC20ResourceID = Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - secondERC20ResourceID, - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const retrievedResourceID = (await ERC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance1.address - )).resourceID - - assert.strictEqual( - secondERC20ResourceID.toLowerCase(), - retrievedResourceID.toLowerCase() - ); - - const retrievedContractAddress = - await ERC20HandlerInstance._resourceIDToTokenContractAddress.call( - secondERC20ResourceID - ); - - assert.strictEqual( - retrievedContractAddress.toLowerCase(), - ERC20MintableInstance1.address.toLowerCase() - ); - }); - } -); diff --git a/test/handlers/erc20/setResourceIDAndContractAddress.test.ts b/test/handlers/erc20/setResourceIDAndContractAddress.test.ts new file mode 100644 index 00000000..9952f1d9 --- /dev/null +++ b/test/handlers/erc20/setResourceIDAndContractAddress.test.ts @@ -0,0 +1,209 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex, WalletClient} from 'viem'; +import {assert} from 'chai'; + + + +describe("ERC20Handler - [setResourceIDAndContractAddress]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let mockBridge: WalletClient; + + let resourceID1: Hex; + + before(async () => { + ({ + DefaultMessageReceiverInstance, + BridgeInstance, + ERC20HandlerInstance, + ERC20MintableInstance: ERC20MintableInstance1, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + mockBridge, + relayer1 + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + ERC20MintableInstance1.address, + domainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + }); + + it("[sanity] ERC20MintableInstance1's resourceID and contract address should be set correctly", async () => { + const retrievedTokenAddress = + await ERC20HandlerInstance.read._resourceIDToTokenContractAddress([ + resourceID1 + ]); + assert.strictEqual( + ERC20MintableInstance1.address, + retrievedTokenAddress + ); + + const retrievedResourceID = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance1.address + ]))[0] + + assert.strictEqual( + resourceID1.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + }); + + it("new resourceID and corresponding contract address should be set correctly", async () => { + const ERC20MintableInstance2 = await hre.viem.deployContract("ERC20PresetMinterPauser", ["Token", "TOK"]); + + const resourceID2 = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID2, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + + const retrievedTokenAddress = + await ERC20HandlerInstance.read._resourceIDToTokenContractAddress([ + resourceID2 + ]); + assert.strictEqual( + ERC20MintableInstance2.address, + retrievedTokenAddress + ); + + const retrievedResourceID = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ]))[0] + + assert.strictEqual( + resourceID2.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + }); + + it("existing resourceID should be updated correctly with new token contract address", async () => { + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + const ERC20MintableInstance2 = await hre.viem.deployContract("ERC20PresetMinterPauser", ["Token", "TOK"]); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + + const retrievedTokenAddress = + await ERC20HandlerInstance.read._resourceIDToTokenContractAddress([ + resourceID1 + ]); + assert.strictEqual(ERC20MintableInstance2.address, retrievedTokenAddress); + + const retrievedResourceID = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ]))[0] + + assert.strictEqual( + resourceID1.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + }); + + it("existing resourceID should be updated correctly with new handler address", async () => { + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + const ERC20MintableInstance2 = await hre.viem.deployContract("ERC20PresetMinterPauser", ["Token", "TOK"]); + const ERC20HandlerInstance2 = await hre.viem.deployContract("ERC20Handler", [mockBridge.account!.address, DefaultMessageReceiverInstance.address]); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance2.address, + resourceID1, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + + const bridgeHandlerAddress = + await BridgeInstance.read._resourceIDToHandlerAddress([ + resourceID1 + ]); + assert.strictEqual( + bridgeHandlerAddress.toLowerCase(), + ERC20HandlerInstance2.address.toLowerCase() + ); + }); + + it("existing resourceID should be replaced by new resourceID in handler", async () => { + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + const ERC20MintableInstance2 = await hre.viem.deployContract("ERC20PresetMinterPauser", ["Token", "TOK"]); + + const resourceID2 = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID2, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + const retrievedResourceID = (await ERC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance1.address + ]))[0]; + + assert.strictEqual( + resourceID2.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + + const retrievedContractAddress = + await ERC20HandlerInstance.read._resourceIDToTokenContractAddress([ + resourceID2 + ]); + + assert.strictEqual( + retrievedContractAddress.toLowerCase(), + ERC20MintableInstance1.address.toLowerCase() + ); + }); + } +); diff --git a/test/handlers/erc721/deposit.js b/test/handlers/erc721/deposit.js deleted file mode 100644 index ae43be12..00000000 --- a/test/handlers/erc721/deposit.js +++ /dev/null @@ -1,145 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); - -contract("ERC721Handler - [Deposit ERC721]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const expectedDepositNonce = 1; - const depositorAddress = accounts[1]; - - const tokenID = 1; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC721MintableInstance; - let ERC721HandlerInstance; - - let resourceID; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC721MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC721MintableInstance.address]; - burnableContractAddresses = []; - - await Promise.all([ - ERC721HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC721HandlerInstance = instance) - ), - ERC721MintableInstance.mint(depositorAddress, tokenID, ""), - ]); - - await Promise.all([ - ERC721MintableInstance.approve(ERC721HandlerInstance.address, tokenID, { - from: depositorAddress, - }), - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - resourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - ]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositor owns ERC721 with tokenID", async () => { - const tokenOwner = await ERC721MintableInstance.ownerOf(tokenID); - assert.equal(depositorAddress, tokenOwner); - }); - - it("[sanity] ERC721HandlerInstance.address has an allowance for tokenID", async () => { - const tokenAllowee = await ERC721MintableInstance.getApproved(tokenID); - assert.equal(ERC721HandlerInstance.address, tokenAllowee); - }); - - it("Varied recipient address with length 40", async () => { - const recipientAddress = accounts[0] + accounts[1].substr(2); - const lenRecipientAddress = 40; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - Helpers.createERCDepositData( - tokenID, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === - Helpers.createERCDepositData( - tokenID, - lenRecipientAddress, - recipientAddress - ).toLowerCase() && - event.handlerResponse === null - ); - }); - }); - - it("Varied recipient address with length 32", async () => { - const recipientAddress = Ethers.utils.keccak256(accounts[0]); - const lenRecipientAddress = 32; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - Helpers.createERCDepositData( - tokenID, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === - Helpers.createERCDepositData( - tokenID, - lenRecipientAddress, - recipientAddress - ).toLowerCase() && - event.handlerResponse === null - ); - }); - }); -}); diff --git a/test/handlers/erc721/deposit.test.ts b/test/handlers/erc721/deposit.test.ts new file mode 100644 index 00000000..cde41514 --- /dev/null +++ b/test/handlers/erc721/deposit.test.ts @@ -0,0 +1,139 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, Hex, keccak256, WalletClient} from "viem"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress, trimPrefix} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + + +describe("ERC721Handler - [Deposit ERC721]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const expectedDepositNonce = 1; + + const lenRecipient = 40; + const tokenID = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let recipient32ByteAddress: Hex; + let resourceID: Hex; + let proposalData: Hex; + + + before(async () => { + ({ + BridgeInstance, + ERC721HandlerInstance, + ERC721MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC721MintableInstance.address, + originDomainID + ); + recipient32ByteAddress = concat([admin.account!.address, trimPrefix(recipient.account!.address)]); + proposalData = createERCDepositData( + tokenID, + lenRecipient, + recipient.account!.address + ) + + + await ERC721MintableInstance.write.mint([depositor.account!.address, tokenID, ""]), + + await ERC721MintableInstance.write.approve([ERC721HandlerInstance.address, tokenID + ], + { + account: depositor.account, + } + ); + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + resourceID, + ERC721MintableInstance.address, + emptySetResourceData + ]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor owns ERC721 with tokenID", async () => { + const tokenOwner = await ERC721MintableInstance.read.ownerOf([tokenID]); + assert.equal(depositor.account!.address, tokenOwner); + }); + + it("[sanity] ERC721HandlerInstance.address has an allowance for tokenID", async () => { + const tokenAllowance = await ERC721MintableInstance.read.getApproved([tokenID]); + assert.equal(ERC721HandlerInstance.address, tokenAllowance); + }); + + it("Varied recipient address with length 40", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + proposalData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + proposalData, + null + ); + }); + + it("Varied recipient address with length 32", async () => { + const recipient = keccak256(admin.account!.address); + const lenRecipient = 32; + const proposalData = createERCDepositData( + tokenID, + lenRecipient, + recipient32ByteAddress + ); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + proposalData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + proposalData, + null + ); + }); +}); diff --git a/test/handlers/erc721/depositBurn.js b/test/handlers/erc721/depositBurn.js deleted file mode 100644 index b91dc0ad..00000000 --- a/test/handlers/erc721/depositBurn.js +++ /dev/null @@ -1,146 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../../helpers"); - -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); - -contract("ERC721Handler - [Deposit Burn ERC721]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const tokenID = 1; - - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC721MintableInstance1; - let ERC721MintableInstance2; - let ERC721HandlerInstance; - - let resourceID1; - let resourceID2; - let burnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance1 = instance) - ), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance2 = instance) - ), - ]); - - resourceID1 = Helpers.createResourceID( - ERC721MintableInstance1.address, - originDomainID - ); - resourceID2 = Helpers.createResourceID( - ERC721MintableInstance2.address, - originDomainID - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC721MintableInstance1.address, - ERC721MintableInstance2.address, - ]; - burnableContractAddresses = [ERC721MintableInstance1.address]; - - await Promise.all([ - ERC721HandlerContract.new(BridgeInstance.address).then( - (instance) => (ERC721HandlerInstance = instance) - ), - ERC721MintableInstance1.mint(depositorAddress, tokenID, ""), - ]); - - await Promise.all([ - ERC721MintableInstance1.approve(ERC721HandlerInstance.address, tokenID, { - from: depositorAddress, - }), - await BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - resourceID1, - ERC721MintableInstance1.address, - emptySetResourceData - ), - await BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - resourceID2, - ERC721MintableInstance2.address, - emptySetResourceData - ), - BridgeInstance.adminSetBurnable( - ERC721HandlerInstance.address, - ERC721MintableInstance1.address - ), - ]); - - depositData = Helpers.createERCDepositData(tokenID, 20, recipientAddress); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] burnableContractAddresses should be marked as burnable", async () => { - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await ERC721HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); - - it("[sanity] ERC721MintableInstance1 tokenID has been minted for depositorAddress", async () => { - const tokenOwner = await ERC721MintableInstance1.ownerOf(tokenID); - assert.strictEqual(tokenOwner, depositorAddress); - }); - - it("depositAmount of ERC721MintableInstance1 tokens should have been burned", async () => { - await BridgeInstance.deposit( - destinationDomainID, - resourceID1, - depositData, - feeData, - {from: depositorAddress} - ); - - const handlerBalance = await ERC721MintableInstance1.balanceOf( - ERC721HandlerInstance.address - ); - assert.strictEqual(handlerBalance.toNumber(), 0); - - const depositorBalance = await ERC721MintableInstance1.balanceOf( - depositorAddress - ); - assert.strictEqual(depositorBalance.toNumber(), 0); - - await Helpers.reverts( - ERC721MintableInstance1.ownerOf(tokenID), - "ERC721: owner query for nonexistent token" - ); - }); - - it("depositAmount of ERC721MintableInstance1 tokens should NOT burn from NOT token owner", async () => { - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID1, - depositData, - feeData, - {from: accounts[3]} - ), - "Burn not from owner" - ); - }); -}); diff --git a/test/handlers/erc721/depositBurn.test.ts b/test/handlers/erc721/depositBurn.test.ts new file mode 100644 index 00000000..9c0e47d1 --- /dev/null +++ b/test/handlers/erc721/depositBurn.test.ts @@ -0,0 +1,150 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex, WalletClient} from 'viem'; +import {assert, expect} from 'chai'; + + + +describe("ERC721Handler - [Deposit Burn ERC721]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const tokenID = BigInt(1); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC721MintableInstance1: ContractTypesMap["ERC721MinterBurnerPauser"];; + let ERC721MintableInstance2: ContractTypesMap["ERC721MinterBurnerPauser"];; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + + let resourceID1: Hex; + let resourceID2: Hex; + let burnableContractAddresses: Array; + let depositData: Hex; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let nonTokenOwner: WalletClient; + + before(async () => { + ({ + BridgeInstance, + ERC721HandlerInstance, + ERC721MintableInstance: ERC721MintableInstance1, + ERC721MintableInstance: ERC721MintableInstance2, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + nonTokenOwner + ] = await hre.viem.getWalletClients(); + + + resourceID1 = createResourceID( + ERC721MintableInstance1.address, + originDomainID + ); + resourceID2 = createResourceID( + ERC721MintableInstance2.address, + originDomainID + ); + burnableContractAddresses = [ERC721MintableInstance1.address]; + + + await ERC721MintableInstance1.write.mint([depositor.account!.address, tokenID, ""]), + + await ERC721MintableInstance1.write.approve([ERC721HandlerInstance.address, tokenID], + { + account: depositor.account, + } + ); + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + resourceID1, + ERC721MintableInstance1.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + resourceID2, + ERC721MintableInstance2.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetBurnable([ + ERC721HandlerInstance.address, + ERC721MintableInstance1.address + ]); + + depositData = createERCDepositData(tokenID, 20, recipient.account!.address); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] burnableContractAddresses should be marked as burnable", async () => { + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await ERC721HandlerInstance.read._tokenContractAddressToTokenProperties([ + burnableAddress + ]))[0]; + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); + + it("[sanity] ERC721MintableInstance1 tokenID has been minted for depositor", async () => { + const tokenOwner = await ERC721MintableInstance1.read.ownerOf([tokenID]); + assert.strictEqual(tokenOwner, depositor.account!.address); + }); + + it("depositAmount of ERC721MintableInstance1 tokens should have been burned", async () => { + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + const handlerBalance = await ERC721MintableInstance1.read.balanceOf([ + ERC721HandlerInstance.address + ]); + assert.strictEqual(handlerBalance, BigInt(0)); + + const depositorBalance = await ERC721MintableInstance1.read.balanceOf([ + depositor.account!.address + ]); + assert.strictEqual(depositorBalance, BigInt(0)); + + await expect( + ERC721MintableInstance1.read.ownerOf([tokenID]), + "ERC721: owner query for nonexistent token" + ).to.be.reverted; + }); + + it("depositAmount of ERC721MintableInstance1 tokens should NOT burn from NOT token owner", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID1, + depositData, + feeData + ], + { + account: nonTokenOwner.account + } + ), + "Burn not from owner" + ); + }); +}); diff --git a/test/handlers/erc721/isBurnable.js b/test/handlers/erc721/isBurnable.js deleted file mode 100644 index 407e2097..00000000 --- a/test/handlers/erc721/isBurnable.js +++ /dev/null @@ -1,219 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../helpers"); - -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); - -contract("ERC721Handler - [Burn ERC721]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC721MintableInstance1; - let ERC721MintableInstance2; - let resourceID1; - let resourceID2; - let initialResourceIDs; - let initialContractAddresses; - let burnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance1 = instance) - ), - ERC721MintableContract.new("token", "TOK", "").then( - (instance) => (ERC721MintableInstance2 = instance) - ), - ]); - - resourceID1 = Helpers.createResourceID( - ERC721MintableInstance1.address, - domainID - ); - resourceID2 = Helpers.createResourceID( - ERC721MintableInstance2.address, - domainID - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC721MintableInstance1.address, - ERC721MintableInstance2.address, - ]; - burnableContractAddresses = [ERC721MintableInstance1.address]; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes( - ERC721HandlerContract.new(BridgeInstance.address) - ); - }); - - it("burnableContractAddresses should be marked as burnable", async () => { - const ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC721HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await ERC721HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); - - it("ERC721MintableInstance2.address should not be marked as burnable", async () => { - const ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC721HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - const isBurnable = (await ERC721HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC721MintableInstance2.address - )).isBurnable; - - assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); - }); - - it("ERC721MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { - const ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC721HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - await BridgeInstance.adminSetBurnable( - ERC721HandlerInstance.address, - ERC721MintableInstance2.address - ); - const isBurnable = (await ERC721HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC721MintableInstance2.address - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - }); - - it(`ERC721MintableInstances should not be marked as - burnable after setResource is called on already burnable tokens`, async () => { - const ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - ERC721HandlerInstance.address, - initialContractAddresses[i] - ) - ); - } - - // tokens should be marked as burnable - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableBeforeReRegisteringResource = ( - await ERC721HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); - } - - // re-register resource - sets isBurnable to false for tokens - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - // tokens should not be marked as burnable if resource is re-registered - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableAfterReRegisteringResource = ( - await ERC721HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); - } - }); -}); diff --git a/test/handlers/erc721/isBurnable.test.ts b/test/handlers/erc721/isBurnable.test.ts new file mode 100644 index 00000000..4bd65c8f --- /dev/null +++ b/test/handlers/erc721/isBurnable.test.ts @@ -0,0 +1,210 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, WalletClient} from "viem"; +import {deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + + + +describe("ERC721Handler - [Burn ERC721]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC721MintableInstance1: ContractTypesMap["ERC721MinterBurnerPauser"];; + let ERC721MintableInstance2: ContractTypesMap["ERC721MinterBurnerPauser"];; + let resourceID1: Hex; + let resourceID2: Hex; + let initialResourceIDs: Array; + let initialContractAddresses: Array; + let burnableContractAddresses: Array; + let mockBridge: WalletClient; + + before(async () => { + ({ + BridgeInstance, + ERC721MintableInstance: ERC721MintableInstance1, + ERC721MintableInstance: ERC721MintableInstance2, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + mockBridge + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + ERC721MintableInstance1.address, + domainID + ); + resourceID2 = createResourceID( + ERC721MintableInstance2.address, + domainID + ); + initialResourceIDs = [resourceID1, resourceID2]; + initialContractAddresses = [ + ERC721MintableInstance1.address, + ERC721MintableInstance2.address, + ]; + burnableContractAddresses = [ERC721MintableInstance1.address]; + }); + + it("burnableContractAddresses should be marked as burnable", async () => { + const ERC721HandlerInstance = await hre.viem.deployContract("ERC721Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC721HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await ERC721HandlerInstance.read._tokenContractAddressToTokenProperties([ + burnableAddress + ])) + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); + + it("ERC721MintableInstance2.address should not be marked as burnable", async () => { + const ERC721HandlerInstance = await hre.viem.deployContract("ERC721Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC721HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + const isBurnable = (await ERC721HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC721MintableInstance2.address + ])); + + assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); + }); + + it("ERC721MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { + const ERC721HandlerInstance = await hre.viem.deployContract("ERC721Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC721HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + await BridgeInstance.write.adminSetBurnable([ + ERC721HandlerInstance.address, + ERC721MintableInstance2.address + ]); + const isBurnable = (await ERC721HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC721MintableInstance2.address + ])); + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + }); + + it(`ERC721MintableInstances should not be marked as + burnable after setResource is called on already burnable tokens`, async () => { + const ERC721HandlerInstance = await hre.viem.deployContract("ERC721Handler", [mockBridge.account!.address]); + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + ERC721HandlerInstance.address, + initialContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + // tokens should be marked as burnable + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableBeforeReRegisteringResource = ( + await ERC721HandlerInstance.read._tokenContractAddressToTokenProperties([ + initialContractAddresses[i] + ]) + ); + + assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); + } + + // re-register resource - sets isBurnable to false for tokens + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + // tokens should not be marked as burnable if resource is re-registered + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableAfterReRegisteringResource = ( + await ERC721HandlerInstance.read._tokenContractAddressToTokenProperties([ + initialContractAddresses[i] + ]) + ); + + assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); + } + }); +}); diff --git a/test/handlers/fee/basic/admin.js b/test/handlers/fee/basic/admin.js deleted file mode 100644 index fdbede01..00000000 --- a/test/handlers/fee/basic/admin.js +++ /dev/null @@ -1,96 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); - -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("BasicFeeHandler - [admin]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const initialRelayers = accounts.slice(0, 3); - const currentFeeHandlerAdmin = accounts[0]; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: initialRelayers[1]}), - "sender doesn't have admin role" - ); - }; - - let BridgeInstance; - let BasicFeeHandlerInstance; - let OriginERC20MintableInstance; - let ADMIN_ROLE; - let resourceID; - - beforeEach(async () => { - BridgeInstance = awaitBridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - ); - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - OriginERC20MintableInstance = await ERC20MintableContract.new("token", "TOK") - - ADMIN_ROLE = await BasicFeeHandlerInstance.DEFAULT_ADMIN_ROLE(); - resourceID = Helpers.createResourceID( - OriginERC20MintableInstance.address, - originDomainID - ) - }); - - it("[sanity] should return fee handler type from fee handler", async () => { - assert.equal(await BasicFeeHandlerInstance.feeHandlerType.call(), "basic"); - }); - - it("[sanity] should return fee handler from fee handler router", async () => { - const feeRouterInstance = await FeeHandlerRouterContract.at(BasicFeeHandlerInstance.address) - assert.equal(await feeRouterInstance.feeHandlerType.call(), "basic"); - }); - - it("should set fee property", async () => { - const fee = 3; - assert.equal(await BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, resourceID), "0"); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - assert.equal(await BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, resourceID), fee); - }); - - it("should require admin role to change fee property", async () => { - const fee = 3; - await assertOnlyAdmin(BasicFeeHandlerInstance.changeFee, destinationDomainID, resourceID, fee); - }); - - it("BasicFeeHandler admin should be changed to expectedBasicFeeHandlerAdmin", async () => { - const expectedBasicFeeHandlerAdmin = accounts[1]; - - // check current admin - assert.isTrue( - await BasicFeeHandlerInstance.hasRole(ADMIN_ROLE, currentFeeHandlerAdmin) - ); - - await TruffleAssert.passes( - BasicFeeHandlerInstance.renounceAdmin(expectedBasicFeeHandlerAdmin) - ); - assert.isTrue( - await BasicFeeHandlerInstance.hasRole( - ADMIN_ROLE, - expectedBasicFeeHandlerAdmin - ) - ); - - // check that former admin is no longer admin - assert.isFalse( - await BasicFeeHandlerInstance.hasRole(ADMIN_ROLE, currentFeeHandlerAdmin) - ); - }); -}); diff --git a/test/handlers/fee/basic/admin.test.ts b/test/handlers/fee/basic/admin.test.ts new file mode 100644 index 00000000..c1a86d77 --- /dev/null +++ b/test/handlers/fee/basic/admin.test.ts @@ -0,0 +1,89 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, WalletClient} from "viem"; +import {deploySourceChainContracts} from "../../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from "chai"; + +const Helpers = require("../../../helpers"); + +describe("BasicFeeHandler - [admin]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const fee = BigInt(3); + + let relayer1: WalletClient; + let feeHandlerAdmin: WalletClient; + let newFeeHandlerAdmin: WalletClient; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ADMIN_ROLE: Hex; + let resourceID: Hex; + + before(async () => { + ({ + BridgeInstance, + BasicFeeHandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + feeHandlerAdmin, + newFeeHandlerAdmin, + relayer1, + ] = await hre.viem.getWalletClients(); + + ADMIN_ROLE = await BasicFeeHandlerInstance.read.DEFAULT_ADMIN_ROLE(); + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ) + }); + + it("[sanity] should return fee handler type from fee handler", async () => { + assert.equal(await BasicFeeHandlerInstance.read.feeHandlerType(), "basic"); + }); + + it("[sanity] should return type from fee handler router", async () => { + assert.equal(await FeeHandlerRouterInstance.read.feeHandlerType(), "router"); + }); + + it("should set fee property", async () => { + assert.equal(await BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, resourceID]), BigInt(0)); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + assert.equal(await BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, resourceID]), fee); + }); + + it("should require admin role to change fee property", async () => { + await expect( + BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]) + ).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("BasicFeeHandler admin should be changed to expectedBasicFeeHandlerAdmin", async () => { + // check current admin + assert.isTrue( + await BasicFeeHandlerInstance.read.hasRole([ADMIN_ROLE, feeHandlerAdmin.account!.address]) + ); + + await expect( + BasicFeeHandlerInstance.write.renounceAdmin([newFeeHandlerAdmin.account!.address]) + ); + await expect( + await BasicFeeHandlerInstance.read.hasRole([ + ADMIN_ROLE, + newFeeHandlerAdmin.account!.address + ]) + ).not.to.be.reverted; + + // check that former admin is no longer admin + assert.isFalse( + await BasicFeeHandlerInstance.read.hasRole([ADMIN_ROLE, feeHandlerAdmin.account!.address]) + ); + }); +}); diff --git a/test/handlers/fee/basic/calculateFee.js b/test/handlers/fee/basic/calculateFee.js deleted file mode 100644 index 1118772b..00000000 --- a/test/handlers/fee/basic/calculateFee.js +++ /dev/null @@ -1,105 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("BasicFeeHandler - [calculateFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const relayer = accounts[0]; - const recipientAddress = accounts[1]; - const feeData = "0x0"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let BasicFeeHandlerInstance; - let resourceID; - let depositData; - let DefaultMessageReceiverInstance; - let ERC20MintableInstance; - let FeeHandlerRouterInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC20MintableInstance.address]; - - burnableContractAddresses = []; - - depositData = Helpers.createERCDepositData(100, 20, recipientAddress); - - await Promise.all([ - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ), - ]); - }); - - it("should return amount of fee", async () => { - // current fee is set to 0 - let res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - - assert.equal(web3.utils.fromWei(res[0], "ether"), "0"); - // Change fee to 0.5 ether - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, Ethers.utils.parseEther("0.5")); - res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(web3.utils.fromWei(res[0], "ether"), "0.5"); - }); -}); diff --git a/test/handlers/fee/basic/calculateFee.test.ts b/test/handlers/fee/basic/calculateFee.test.ts new file mode 100644 index 00000000..e605d88a --- /dev/null +++ b/test/handlers/fee/basic/calculateFee.test.ts @@ -0,0 +1,90 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, parseEther, WalletClient} from "viem"; +import {deploySourceChainContracts} from "../../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert} from 'chai'; + +const Helpers = require("../../../helpers"); + +describe("BasicFeeHandler - [calculateFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + + let recipient: WalletClient; + let relayer1: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + BasicFeeHandlerInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + recipient, + relayer1, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + depositData = createERCDepositData(100, 20, recipient.account!.address); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + }); + + it("should return amount of fee", async () => { + // current fee is set to 0 + let res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer1.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + + assert.equal(web3.utils.fromWei(res[0], "ether"), "0"); + // Change fee to 0.5 ether + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, parseEther("0.5")]); + res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer1.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(web3.utils.fromWei(res[0], "ether"), "0.5"); + }); +}); diff --git a/test/handlers/fee/basic/changeFee.js b/test/handlers/fee/basic/changeFee.js deleted file mode 100644 index dc3149a2..00000000 --- a/test/handlers/fee/basic/changeFee.js +++ /dev/null @@ -1,86 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("BasicFeeHandler - [changeFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const nonAdmin = accounts[1]; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: nonAdmin}), - "sender doesn't have admin role" - ); - }; - - let BridgeInstance; - let OriginERC20MintableInstance; - let resourceID; - - - beforeEach(async () => { - BridgeInstance = await Helpers.deployBridge(originDomainID, accounts[0]); - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - - OriginERC20MintableInstance = await ERC20MintableContract.new("token", "TOK") - resourceID = Helpers.createResourceID( - OriginERC20MintableInstance.address, - originDomainID - ) - }); - - it("[sanity] contract should be deployed successfully", async () => { - TruffleAssert.passes( - await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ) - ); - }); - - it("should set fee", async () => { - const BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - const fee = Ethers.utils.parseEther("0.05"); - const tx = await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - TruffleAssert.eventEmitted( - tx, - "FeeChanged", - (event) => web3.utils.fromWei(event.newFee, "ether") === "0.05" - ); - const newFee = await BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, resourceID); - assert.equal(web3.utils.fromWei(newFee, "ether"), "0.05"); - }); - - it("should not set the same fee", async () => { - const BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await Helpers.reverts( - BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 0), - "Current fee is equal to new fee" - ); - }); - - it("should require admin role to change fee", async () => { - const BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await assertOnlyAdmin(BasicFeeHandlerInstance.changeFee, destinationDomainID, resourceID, 1); - }); -}); diff --git a/test/handlers/fee/basic/changeFee.test.ts b/test/handlers/fee/basic/changeFee.test.ts new file mode 100644 index 00000000..6e2293dc --- /dev/null +++ b/test/handlers/fee/basic/changeFee.test.ts @@ -0,0 +1,64 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, parseEther, WalletClient} from "viem"; +import {deploySourceChainContracts} from "../../../helpers"; +import {assert, expect} from "chai"; + +const Helpers = require("../../../helpers"); + +describe("BasicFeeHandler - [changeFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const fee = parseEther("0.05"); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + + let nonAdmin: WalletClient; + + let resourceID: Hex; + + + before(async () => { + ({ + BridgeInstance, + BasicFeeHandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + nonAdmin, + ] = await hre.viem.getWalletClients(); + }); + + it("should set fee", async () => { + const changeFeeTx = await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + await expect(changeFeeTx).to.emit(BasicFeeHandlerInstance, "FeeChanged").withArgs( + parseEther("0.05") + ); + + const newFee = await BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, resourceID]); + assert.equal(newFee, parseEther("0.05")); + }); + + it("should not set the same fee", async () => { + await expect( + BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee])).to.be.revertedWith( + "Current fee is equal to new fee" + ); + }); + + it("should require admin role to change fee", async () => { + await expect(BasicFeeHandlerInstance.write.changeFee([ + destinationDomainID, resourceID, BigInt(1) + ], + { + account: nonAdmin.account!.address + } + )); + }); +}); diff --git a/test/handlers/fee/basic/collectFee.js b/test/handlers/fee/basic/collectFee.js deleted file mode 100644 index 5b3e6173..00000000 --- a/test/handlers/fee/basic/collectFee.js +++ /dev/null @@ -1,522 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const ERC721MintableContract = artifacts.require("ERC721MinterBurnerPauser"); -const ERC721HandlerContract = artifacts.require("ERC721Handler"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("BasicFeeHandler - [collectFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const depositAmount = 10; - const feeData = "0x0"; - const tokenID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let ERC721HandlerInstance; - let ERC721MintableInstance; - let ERC20BasicFeeHandlerInstance; - let ERC721BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - - let erc20ResourceID; - let erc721ResourceID; - let erc20depositData; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - (ERC20MintableInstance = ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - )), - (ERC721MintableInstance = ERC721MintableContract.new( - "ERC721Token", - "ERC721TOK", - "" - ).then((instance) => (ERC721MintableInstance = instance))), - ]); - - erc20ResourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - erc721ResourceID = Helpers.createResourceID( - ERC721MintableInstance.address, - originDomainID - ); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - ERC721HandlerInstance = await ERC721HandlerContract.new( - BridgeInstance.address - ); - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - ERC20BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - ERC721BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - await Promise.all([ - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - erc20ResourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - await BridgeInstance.adminSetResource( - ERC721HandlerInstance.address, - erc721ResourceID, - ERC721MintableInstance.address, - emptySetResourceData - ), - await ERC20MintableInstance.mint(depositorAddress, depositAmount), - ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ), - await ERC721MintableInstance.mint(depositorAddress, tokenID, ""), - ERC721MintableInstance.approve(ERC721HandlerInstance.address, tokenID, { - from: depositorAddress, - }), - BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - erc20ResourceID, - ERC20BasicFeeHandlerInstance.address - ), - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - erc721ResourceID, - ERC721BasicFeeHandlerInstance.address - ), - ]); - - erc20depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - erc721depositData = Helpers.createERCDepositData( - tokenID, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] Generic deposit can be made", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - {from: depositorAddress} - ) - ); - }); - - it("deposit should revert if invalid fee amount supplied", async () => { - // current fee is set to 0 - assert.equal(await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), 0); - const incorrectFee = Ethers.utils.parseEther("1.0"); - - const errorValues = await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit( - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - { - from: depositorAddress, - value: incorrectFee, - } - ), - "IncorrectFeeSupplied(uint256)" - ); - - assert.equal(errorValues[0].toString(), incorrectFee.toString()); - }); - - it("deposit should pass if valid fee amount supplied for ERC20 deposit", async () => { - const fee = Ethers.utils.parseEther("0.5"); - // current fee is set to 0 - assert.equal(await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), 0); - // Change fee to 0.5 ether - await ERC20BasicFeeHandlerInstance.changeFee(destinationDomainID, erc20ResourceID, fee); - assert.equal( - web3.utils.fromWei( - await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), - "ether" - ), - "0.5" - ); - - const balanceBefore = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - { - from: depositorAddress, - value: fee, - } - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc20ResourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - ERC20BasicFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc20ResourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === "0x0000000000000000000000000000000000000000" - ); - }); - const balanceAfter = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, fee.add(balanceBefore)); - }); - - it("deposit should pass if valid fee amount supplied for ERC721 deposit", async () => { - const fee = Ethers.utils.parseEther("0.4"); - // current fee is set to 0 - assert.equal(await ERC721BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc721ResourceID), 0); - // Change fee to 0.4 ether - await ERC721BasicFeeHandlerInstance.changeFee(destinationDomainID, erc721ResourceID, fee); - assert.equal( - web3.utils.fromWei( - await ERC721BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc721ResourceID), - "ether" - ), - "0.4" - ); - - const balanceBefore = await web3.eth.getBalance( - ERC721BasicFeeHandlerInstance.address - ); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - erc721ResourceID, - erc721depositData, - feeData, - { - from: depositorAddress, - value: fee, - } - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc721ResourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - ERC721BasicFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc721ResourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === "0x0000000000000000000000000000000000000000" - ); - }); - const balanceAfter = await web3.eth.getBalance( - ERC721BasicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, fee.add(balanceBefore)); - }); - - it("deposit should revert if fee handler not set and fee supplied", async () => { - await BridgeInstance.adminChangeFeeHandler( - "0x0000000000000000000000000000000000000000" - ); - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - { - from: depositorAddress, - value: Ethers.utils.parseEther("1.0"), - } - ), - "no FeeHandler, msg.value != 0" - ); - }); - - it("deposit should pass if fee handler not set and fee not supplied", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - {from: depositorAddress} - ) - ); - }); - - it("deposit should revert if not called by router on BasicFeeHandler contract", async () => { - const fee = Ethers.utils.parseEther("0.5"); - await BridgeInstance.adminChangeFeeHandler( - ERC20BasicFeeHandlerInstance.address - ); - // current fee is set to 0 - assert.equal(await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), 0); - // Change fee to 0.5 ether - await ERC20BasicFeeHandlerInstance.changeFee(destinationDomainID, erc20ResourceID, fee); - assert.equal( - web3.utils.fromWei( - await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), - "ether" - ), - "0.5" - ); - - const balanceBefore = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - - await Helpers.reverts( - ERC20BasicFeeHandlerInstance.collectFee( - depositorAddress, - originDomainID, - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - { - from: depositorAddress, - value: Ethers.utils.parseEther("0.5").toString(), - } - ), - "sender must be bridge or fee router contract" - ); - - const balanceAfter = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, balanceBefore); - }); - - it("deposit should revert if not called by bridge on FeeHandlerRouter contract", async () => { - const fee = Ethers.utils.parseEther("0.5"); - await BridgeInstance.adminChangeFeeHandler( - ERC20BasicFeeHandlerInstance.address - ); - // current fee is set to 0 - assert.equal(await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), 0); - // Change fee to 0.5 ether - await ERC20BasicFeeHandlerInstance.changeFee(destinationDomainID, erc20ResourceID, fee); - assert.equal( - web3.utils.fromWei( - await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), - "ether" - ), - "0.5" - ); - - const balanceBefore = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - - await Helpers.reverts( - FeeHandlerRouterInstance.collectFee( - depositorAddress, - originDomainID, - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - { - from: depositorAddress, - value: Ethers.utils.parseEther("0.5").toString(), - } - ), - "sender must be bridge contract" - ); - - const balanceAfter = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, balanceBefore); - }); - - it( - "should successfully change fee handler from FeeRouter to ERC20BasicFeeHandlerInstance and collect fee", - async () => { - await BridgeInstance.adminChangeFeeHandler( - ERC20BasicFeeHandlerInstance.address - ); - - const fee = Ethers.utils.parseEther("0.5"); - // current fee is set to 0 - assert.equal(await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), 0); - // Change fee to 0.5 ether - await ERC20BasicFeeHandlerInstance.changeFee(destinationDomainID, erc20ResourceID, fee); - assert.equal( - web3.utils.fromWei( - await ERC20BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc20ResourceID), - "ether" - ), - "0.5" - ); - - const balanceBefore = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - erc20ResourceID, - erc20depositData, - feeData, - { - from: depositorAddress, - value: fee, - } - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc20ResourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - ERC20BasicFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc20ResourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === "0x0000000000000000000000000000000000000000" - ); - }); - const balanceAfter = await web3.eth.getBalance( - ERC20BasicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, fee.add(balanceBefore)); - }); - - it( - "should successfully change fee handler from FeeRouter to ERC721BasicFeeHandlerInstance and collect fee", - async () => { - await BridgeInstance.adminChangeFeeHandler( - ERC721BasicFeeHandlerInstance.address - ); - - const fee = Ethers.utils.parseEther("0.4"); - // current fee is set to 0 - assert.equal(await ERC721BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc721ResourceID), 0); - // Change fee to 0.4 ether - await ERC721BasicFeeHandlerInstance.changeFee(destinationDomainID, erc721ResourceID, fee); - assert.equal( - web3.utils.fromWei( - await ERC721BasicFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, erc721ResourceID), - "ether" - ), - "0.4" - ); - - const balanceBefore = await web3.eth.getBalance( - ERC721BasicFeeHandlerInstance.address - ); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - erc721ResourceID, - erc721depositData, - feeData, - { - from: depositorAddress, - value: fee, - } - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc721ResourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - ERC721BasicFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === erc721ResourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === "0x0000000000000000000000000000000000000000" - ); - }); - const balanceAfter = await web3.eth.getBalance( - ERC721BasicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, fee.add(balanceBefore)); - }); -}); diff --git a/test/handlers/fee/basic/collectFee.test.ts b/test/handlers/fee/basic/collectFee.test.ts new file mode 100644 index 00000000..bb60020b --- /dev/null +++ b/test/handlers/fee/basic/collectFee.test.ts @@ -0,0 +1,469 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {Hex, parseEther, WalletClient, zeroAddress} from "viem"; +import {createResourceID, deploySourceChainContracts, mpcAddress} from "../../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; + +const Helpers = require("../../../helpers"); + +import {ContractTypesMap} from "hardhat/types"; +import {assert, expect} from 'chai'; + +describe("BasicFeeHandler - [collectFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const depositAmount = BigInt(10); + const feeData = "0x"; + const tokenID = BigInt(1); + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC721HandlerInstance: ContractTypesMap["ERC721Handler"]; + let ERC721MintableInstance: ContractTypesMap["ERC721MinterBurnerPauser"]; + let ERC20BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let ERC721BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + + let depositor: WalletClient; + let recipient: WalletClient; + + let erc20ResourceID: Hex; + let erc721ResourceID: Hex; + let erc20depositData: Hex; + let erc721depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC721MintableInstance, + ERC721HandlerInstance, + BasicFeeHandlerInstance: ERC20BasicFeeHandlerInstance, + BasicFeeHandlerInstance: ERC721BasicFeeHandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient + ] = await hre.viem.getWalletClients(); + + erc20ResourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + erc721ResourceID = createResourceID( + ERC721MintableInstance.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + erc20ResourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + ERC721HandlerInstance.address, + erc721ResourceID, + ERC721MintableInstance.address, + emptySetResourceData + ]); + await ERC20MintableInstance.write.mint([depositor.account!.address, depositAmount]); + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ), + await ERC721MintableInstance.write.mint([depositor.account!.address, tokenID, ""]); + await ERC721MintableInstance.write.approve([ERC721HandlerInstance.address, tokenID + ], + { + account: depositor.account, + } + ); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + erc20ResourceID, + ERC20BasicFeeHandlerInstance.address + ]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + erc721ResourceID, + ERC721BasicFeeHandlerInstance.address + ]); + + erc20depositData = createERCDepositData( + depositAmount, + 20, + recipient + ); + erc721depositData = createERCDepositData( + tokenID, + 20, + recipient + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] Generic deposit can be made", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + }); + + it("deposit should revert if invalid fee amount supplied", async () => { + // current fee is set to 0 + assert.equal(await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), BigInt(0)); + const incorrectFee = parseEther("1.0"); + + await expect(BridgeInstance.write.deposit([ + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account, + value: incorrectFee, + } + ) + ).to.be.revertedWithCustomError(ERC20BasicFeeHandlerInstance, "IncorrectFeeSupplied(uint256)").withArgs( + incorrectFee + ); + }); + + it("deposit should pass if valid fee amount supplied for ERC20 deposit", async () => { + const fee = parseEther("0.5"); + // current fee is set to 0 + assert.equal(await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), BigInt(0)); + // Change fee to 0.5 ether + await ERC20BasicFeeHandlerInstance.write.changeFee([destinationDomainID, erc20ResourceID, fee]); + assert.equal( + await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), + parseEther("0.5") + ); + + const balanceBefore = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account, + value: fee, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + erc20ResourceID.toLowerCase() + ); + + await expect(depositTx).to.emit(ERC20BasicFeeHandlerInstance, "FeeCollected").withArgs( + depositor, + originDomainID, + destinationDomainID, + erc20ResourceID.toLowerCase(), + fee.toString(), + zeroAddress, + ); + + const balanceAfter = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + assert.equal(balanceAfter, balanceBefore + fee); + }); + + it("deposit should pass if valid fee amount supplied for ERC721 deposit", async () => { + const fee = parseEther("0.4"); + // current fee is set to 0 + assert.equal(await ERC721BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc721ResourceID]), BigInt(0)); + // Change fee to 0.4 ether + await ERC721BasicFeeHandlerInstance.write.changeFee([destinationDomainID, erc721ResourceID, fee]); + assert.equal( + await ERC721BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc721ResourceID]), + parseEther("0.4") + ); + + const balanceBefore = await getBalance( + ERC721BasicFeeHandlerInstance.address + ); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + erc721ResourceID, + erc721depositData, + feeData + ], + { + account: depositor.account, + value: fee, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + erc721ResourceID.toLowerCase(), + ); + + await expect(depositTx).to.emit(ERC721BasicFeeHandlerInstance, "FeeCollected").withArgs( + depositor, + originDomainID, + destinationDomainID, + erc721ResourceID.toLowerCase(), + fee.toString(), + zeroAddress, + ); + + const balanceAfter = await getBalance( + ERC721BasicFeeHandlerInstance.address + ); + assert.equal(balanceAfter, fee.add(balanceBefore)); + }); + + it("deposit should revert if fee handler not set and fee supplied", async () => { + await BridgeInstance.write.adminChangeFeeHandler([ + zeroAddress + ]); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("1.0"), + } + ) + ).to.be.revertedWith("no FeeHandler, msg.value != 0"); + }); + + it("deposit should pass if fee handler not set and fee not supplied", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + }); + + it("deposit should revert if not called by router on BasicFeeHandler contract", async () => { + const fee = parseEther("0.5"); + await BridgeInstance.write.adminChangeFeeHandler([ + ERC20BasicFeeHandlerInstance.address + ]); + // current fee is set to 0 + assert.equal(await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), BigInt(0)); + // Change fee to 0.5 ether + await ERC20BasicFeeHandlerInstance.write.changeFee([destinationDomainID, erc20ResourceID, fee]); + assert.equal( + await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), + parseEther("0.5") + ); + + const balanceBefore = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + + await expect( + ERC20BasicFeeHandlerInstance.write.collectFee([ + depositor.account!.address, + originDomainID, + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("0.5"), + } + ) + ).to.be.revertedWith("sender must be bridge or fee router contract"); + + const balanceAfter = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + assert.equal(balanceAfter, balanceBefore); + }); + + it("deposit should revert if not called by bridge on FeeHandlerRouter contract", async () => { + const fee = parseEther("0.5"); + await BridgeInstance.write.adminChangeFeeHandler([ + ERC20BasicFeeHandlerInstance.address + ]); + // current fee is set to 0 + assert.equal(await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), BigInt(0)); + // Change fee to 0.5 ether + await ERC20BasicFeeHandlerInstance.write.changeFee([destinationDomainID, erc20ResourceID, fee]); + assert.equal( + await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), + parseEther("0.5") + ); + + const balanceBefore = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + + await expect( + FeeHandlerRouterInstance.write.collectFee([ + depositor, + originDomainID, + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("0.5"), + } + ) + ).to.be.revertedWith("sender must be bridge contract"); + + const balanceAfter = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + assert.equal(balanceAfter, balanceBefore); + }); + + it( + "should successfully change fee handler from FeeRouter to ERC20BasicFeeHandlerInstance and collect fee", + async () => { + await BridgeInstance.write.adminChangeFeeHandler([ + ERC20BasicFeeHandlerInstance.address + ]); + + const fee = parseEther("0.5"); + // current fee is set to 0 + assert.equal(await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), BigInt(0)); + // Change fee to 0.5 ether + await ERC20BasicFeeHandlerInstance.write.changeFee([destinationDomainID, erc20ResourceID, fee]); + assert.equal( + await ERC20BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc20ResourceID]), + parseEther("0.5") + ); + + const balanceBefore = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + erc20ResourceID, + erc20depositData, + feeData + ], + { + account: depositor.account, + value: fee, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + erc20ResourceID.toLowerCase + ); + + await expect(depositTx).to.emit(ERC20BasicFeeHandlerInstance, "FeeCollected").withArgs( + depositor, + originDomainID, + destinationDomainID, + erc20ResourceID.toLowerCase(), + fee.toString(), + zeroAddress + ); + + const balanceAfter = await getBalance( + ERC20BasicFeeHandlerInstance.address + ); + assert.equal(balanceAfter, balanceBefore + fee); + }); + + it( + "should successfully change fee handler from FeeRouter to ERC721BasicFeeHandlerInstance and collect fee", + async () => { + await BridgeInstance.write.adminChangeFeeHandler([ + ERC721BasicFeeHandlerInstance.address + ]); + + const fee = parseEther("0.4"); + // current fee is set to 0 + assert.equal(await ERC721BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc721ResourceID]), BigInt(0)); + // Change fee to 0.4 ether + await ERC721BasicFeeHandlerInstance.write.changeFee([destinationDomainID, erc721ResourceID, fee]); + assert.equal( + await ERC721BasicFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, erc721ResourceID]), + parseEther("0.4") + ); + + const balanceBefore = await getBalance( + ERC721BasicFeeHandlerInstance.address + ); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + erc721ResourceID, + erc721depositData, + feeData + ], + { + account: depositor.account, + value: fee, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + erc721ResourceID.toLowerCase() + ); + await expect(depositTx).to.emit(ERC721BasicFeeHandlerInstance, "FeeCollected").withArgs( + depositor, + originDomainID, + destinationDomainID, + erc721ResourceID.toLowerCase(), + fee.toString(), + zeroAddress, + ); + + const balanceAfter = await getBalance( + ERC721BasicFeeHandlerInstance.address + ); + assert.equal(balanceAfter, balanceBefore + fee); + }); +}); diff --git a/test/handlers/fee/basic/distributeFee.js b/test/handlers/fee/basic/distributeFee.js deleted file mode 100644 index 069ee784..00000000 --- a/test/handlers/fee/basic/distributeFee.js +++ /dev/null @@ -1,226 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("BasicFeeHandler - [distributeFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const depositAmount = 10; - const feeData = "0x0"; - const emptySetResourceData = "0x"; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: accounts[1]}), - "sender doesn't have admin role" - ); - }; - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let BasicFeeHandlerInstance; - let FeeHandlerRouterInstance; - - let resourceID; - let depositData; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await Promise.all([ - ERC20MintableInstance.mint(depositorAddress, depositAmount), - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ]); - - await ERC20MintableInstance.approve( - ERC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should distribute fees", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, Ethers.utils.parseEther("1")); - assert.equal( - web3.utils.fromWei(await BasicFeeHandlerInstance._domainResourceIDToFee( - destinationDomainID, - resourceID - ), "ether"), - "1" - ); - - // check the balance is 0 - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BridgeInstance.address), - "ether" - ), - "0" - ); - await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress, value: Ethers.utils.parseEther("1")} - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BridgeInstance.address), - "ether" - ), - "0" - ); - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BasicFeeHandlerInstance.address), - "ether" - ), - "1" - ); - - const b1Before = await web3.eth.getBalance(accounts[1]); - const b2Before = await web3.eth.getBalance(accounts[2]); - - const payout = Ethers.utils.parseEther("0.5"); - // Transfer the funds - const tx = await BasicFeeHandlerInstance.transferFee( - [accounts[1], accounts[2]], - [payout, payout] - ); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === "0x0000000000000000000000000000000000000000" && - event.recipient === accounts[1] && - event.amount.toString() === payout.toString() - ); - }); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === "0x0000000000000000000000000000000000000000" && - event.recipient === accounts[2] && - event.amount.toString() === payout.toString() - ); - }); - b1 = await web3.eth.getBalance(accounts[1]); - b2 = await web3.eth.getBalance(accounts[2]); - assert.equal(b1, Ethers.BigNumber.from(b1Before).add(payout)); - assert.equal(b2, Ethers.BigNumber.from(b2Before).add(payout)); - }); - - it("should require admin role to distribute fee", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, Ethers.utils.parseEther("1")); - - await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress, value: Ethers.utils.parseEther("1")} - ); - - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BasicFeeHandlerInstance.address), - "ether" - ), - "1" - ); - - const payout = Ethers.utils.parseEther("0.5"); - await assertOnlyAdmin( - BasicFeeHandlerInstance.transferFee, - [accounts[3], accounts[4]], - [payout, payout] - ); - }); - - it("should revert if addrs and amounts arrays have different length", async () => { - await BridgeInstance.adminChangeFeeHandler(BasicFeeHandlerInstance.address); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, Ethers.utils.parseEther("1")); - - await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress, value: Ethers.utils.parseEther("1")} - ); - - assert.equal( - web3.utils.fromWei( - await web3.eth.getBalance(BasicFeeHandlerInstance.address), - "ether" - ), - "1" - ); - - const payout = Ethers.utils.parseEther("0.5"); - await Helpers.reverts( - BasicFeeHandlerInstance.transferFee( - [accounts[3], accounts[4]], - [payout, payout, payout] - ), - "addrs[], amounts[]: diff length" - ); - }); -}); diff --git a/test/handlers/fee/basic/distributeFee.test.ts b/test/handlers/fee/basic/distributeFee.test.ts new file mode 100644 index 00000000..a1fcfa22 --- /dev/null +++ b/test/handlers/fee/basic/distributeFee.test.ts @@ -0,0 +1,200 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {parseEther, Hex, WalletClient, zeroAddress} from "viem"; +import {createERCDepositData, deploySourceChainContracts, mpcAddress} from "../../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + +const Helpers = require("../../../helpers"); + +describe("BasicFeeHandler - [distributeFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const depositAmount = BigInt(10); + const feeData = "0x"; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + + let resourceID: Hex; + let depositData: Hex; + + let depositor: WalletClient; + let recipient: WalletClient; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + BasicFeeHandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + await ERC20MintableInstance.write.mint([depositor.account!.address, depositAmount]); + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient.account!.address + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should distribute fees", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, parseEther("1")]); + assert.equal( + await BasicFeeHandlerInstance.read._domainResourceIDToFee([ + destinationDomainID, + resourceID + ]), + parseEther("1"), + ); + + // check the balance is 0 + assert.equal( + await getBalance(BridgeInstance.address), + parseEther("0") + ); + + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("1") + } + ); + assert.equal( + await getBalance(BridgeInstance.address), + parseEther("0") + ); + assert.equal( + await getBalance(BasicFeeHandlerInstance.address), + parseEther("1") + ); + + const depositorBalanceBefore = await getBalance(depositor); + const recipientBalanceBefore = await getBalance(recipient); + + const payout = parseEther("0.5"); + // Transfer the funds + const transferFeeTx = await BasicFeeHandlerInstance.write.transferFee([ + [depositor.account!.address, recipient.account!.address], + [payout, payout] + ]); + + await expect(transferFeeTx).to.emit(BasicFeeHandlerInstance, "FeeDistributed").withArgs( + zeroAddress, + depositor.account!.address, + payout.toString() + ); + + await expect(transferFeeTx).to.emit(BasicFeeHandlerInstance, "FeeDistributed").withArgs( + zeroAddress, + recipient.account!.address, + payout.toString() + ); + + const depositorBalanceAfter = await getBalance(depositor.account!.address); + const recipientBalanceAfter = await getBalance(recipient.account!.address); + assert.equal(depositorBalanceAfter, depositorBalanceBefore + payout); + assert.equal(recipientBalanceAfter, recipientBalanceBefore + payout); + }); + + it("should require admin role to distribute fee", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, parseEther("1")]); + + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("1")} + ); + + assert.equal( + await getBalance(BasicFeeHandlerInstance.address), + parseEther("1") + ); + + const payout = parseEther("0.5"); + await expect(BasicFeeHandlerInstance.write.transferFee([ + [depositor.account!.address, recipient.account!.address], + [payout, payout] + ])).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should revert if addrs and amounts arrays have different length", async () => { + await BridgeInstance.write.adminChangeFeeHandler([BasicFeeHandlerInstance.address]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, parseEther("1")]); + + await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("1") + } + ); + + assert.equal( + await getBalance(BasicFeeHandlerInstance.address), + parseEther("1") + ); + + const payout = parseEther("0.5"); + await expect( + BasicFeeHandlerInstance.write.transferFee([ + [depositor.account!.address, recipient.account!.address], + [payout, payout, payout] + ]) + ).to.be.revertedWith("addrs[], amounts[]: diff length"); + }); +}); diff --git a/test/handlers/fee/handlerRouter.js b/test/handlers/fee/handlerRouter.js deleted file mode 100644 index 0fcdf6f4..00000000 --- a/test/handlers/fee/handlerRouter.js +++ /dev/null @@ -1,232 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../helpers"); - -const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - -contract("FeeHandlerRouter", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const feeData = "0x0"; - const nonAdmin = accounts[1]; - const whitelistAddress = accounts[2]; - const nonWhitelistAddress = accounts[3]; - const recipientAddress = accounts[3]; - const bridgeAddress = accounts[4]; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: nonAdmin}), - "sender doesn't have admin role" - ); - }; - - let FeeHandlerRouterInstance; - let BasicFeeHandlerInstance; - let ERC20MintableInstance; - let resourceID; - - beforeEach(async () => { - await Promise.all([ - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - bridgeAddress - ); - BasicFeeHandlerInstance = await BasicFeeHandlerContract.new( - bridgeAddress, - FeeHandlerRouterInstance.address - ); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - }); - - it("[sanity] should return fee handler router type", async () => { - assert.equal(await FeeHandlerRouterInstance.feeHandlerType.call(), "router"); - }); - - it("should successfully set handler to resourceID", async () => { - const feeHandlerAddress = accounts[1]; - assert.equal( - await FeeHandlerRouterInstance._domainResourceIDToFeeHandlerAddress.call( - destinationDomainID, - resourceID - ), - "0x0000000000000000000000000000000000000000" - ); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - feeHandlerAddress - ); - const newFeeHandler = - await FeeHandlerRouterInstance._domainResourceIDToFeeHandlerAddress( - destinationDomainID, - resourceID - ); - assert.equal(newFeeHandler, feeHandlerAddress); - }); - - it("should require admin role to set handler for resourceID", async () => { - const feeHandlerAddress = accounts[1]; - await assertOnlyAdmin( - FeeHandlerRouterInstance.adminSetResourceHandler, - destinationDomainID, - resourceID, - feeHandlerAddress - ); - }); - - it("should successfully set whitelist on an address", async () => { - assert.equal( - await FeeHandlerRouterInstance._whitelist.call( - whitelistAddress - ), - false - ); - - const whitelistTx = await FeeHandlerRouterInstance.adminSetWhitelist( - whitelistAddress, - true - ); - assert.equal( - await FeeHandlerRouterInstance._whitelist.call( - whitelistAddress - ), - true - ); - TruffleAssert.eventEmitted(whitelistTx, "WhitelistChanged", (event) => { - return ( - event.whitelistAddress === whitelistAddress && - event.isWhitelisted === true - ); - }); - }); - - it("should require admin role to set whitelist address", async () => { - await assertOnlyAdmin( - FeeHandlerRouterInstance.adminSetWhitelist, - whitelistAddress, - true - ); - }); - - it("should return fee 0 if address whitelisted", async () => { - await FeeHandlerRouterInstance.adminSetWhitelist( - whitelistAddress, - true - ); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, Ethers.utils.parseEther("0.5")); - - const depositData = Helpers.createERCDepositData(100, 20, recipientAddress); - let res = await FeeHandlerRouterInstance.calculateFee.call( - whitelistAddress, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(web3.utils.fromWei(res[0], "ether"), "0") - res = await FeeHandlerRouterInstance.calculateFee.call( - nonWhitelistAddress, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(web3.utils.fromWei(res[0], "ether"), "0.5") - }); - - it("should revert if whitelisted address provides fee", async () => { - await FeeHandlerRouterInstance.adminSetWhitelist( - whitelistAddress, - true - ); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, Ethers.utils.parseEther("0.5")); - - const depositData = Helpers.createERCDepositData(100, 20, recipientAddress); - await Helpers.expectToRevertWithCustomError( - FeeHandlerRouterInstance.collectFee.call( - whitelistAddress, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: bridgeAddress, - value: Ethers.utils.parseEther("0.5").toString() - } - ), - "IncorrectFeeSupplied(uint256)" - ); - await Helpers.passes( - FeeHandlerRouterInstance.collectFee( - nonWhitelistAddress, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: bridgeAddress, - value: Ethers.utils.parseEther("0.5").toString() - } - ), - ); - }); - - it("should not collect fee from whitelisted address", async () => { - await FeeHandlerRouterInstance.adminSetWhitelist( - whitelistAddress, - true - ); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - BasicFeeHandlerInstance.address - ); - await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, Ethers.utils.parseEther("0.5")); - - const depositData = Helpers.createERCDepositData(100, 20, recipientAddress); - await TruffleAssert.passes( - FeeHandlerRouterInstance.collectFee( - whitelistAddress, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: bridgeAddress, - value: "0" - } - ), - ); - }); -}); diff --git a/test/handlers/fee/handlerRouter.test.ts b/test/handlers/fee/handlerRouter.test.ts new file mode 100644 index 00000000..2daddaef --- /dev/null +++ b/test/handlers/fee/handlerRouter.test.ts @@ -0,0 +1,226 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {Hex, parseEther, WalletClient, zeroAddress} from "viem"; +import {createERCDepositData, createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + +describe("FeeHandlerRouter", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const feeData = "0x"; + const depositAmount = BigInt(100); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let BasicFeeHandlerInstance: ContractTypesMap["BasicFeeHandler"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + + let recipient: WalletClient; + let nonAdmin: WalletClient; + let whitelistAddress: WalletClient + let nonWhitelistAddress: WalletClient; + let feeHandlerMock: WalletClient; + let bridgeMock: WalletClient + + let resourceID: Hex + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + FeeHandlerRouterInstance, + BasicFeeHandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + recipient, + whitelistAddress, + nonWhitelistAddress, + nonAdmin, + feeHandlerMock + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + }); + + it("[sanity] should return fee handler router type", async () => { + assert.equal(await FeeHandlerRouterInstance.read.feeHandlerType(), "router"); + }); + + it("should successfully set handler to resourceID", async () => { + assert.equal( + await FeeHandlerRouterInstance.read._domainResourceIDToFeeHandlerAddress([ + destinationDomainID, + resourceID + ]), + zeroAddress + ); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + feeHandlerMock.account!.address + ]); + const newFeeHandler = + await FeeHandlerRouterInstance.read._domainResourceIDToFeeHandlerAddress([ + destinationDomainID, + resourceID + ]); + assert.equal(newFeeHandler, feeHandlerMock.account!.address); + }); + + it("should require admin role to set handler for resourceID", async () => { + await expect( + FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + feeHandlerMock.account!.address + ])).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should successfully set whitelist on an address", async () => { + assert.equal( + await FeeHandlerRouterInstance.read._whitelist([ + whitelistAddress.account!.address + ]), + false + ); + + const whitelistTx = await FeeHandlerRouterInstance.write.adminSetWhitelist([ + whitelistAddress.account!.address, + true + ]); + assert.equal( + await FeeHandlerRouterInstance.read._whitelist([ + whitelistAddress.account!.address + ]), + true + ); + + await expect(whitelistTx).to.emit(FeeHandlerRouterInstance, "WhitelistChanged").withArgs( + whitelistAddress.account?.address.toLowerCase(), + true + ); + }); + + it("should require admin role to set whitelist address", async () => { + await expect( + FeeHandlerRouterInstance.write.adminSetWhitelist([ + whitelistAddress.account!.address, + true], + {account: nonAdmin.account!.address} + )).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should return fee 0 if address whitelisted", async () => { + await FeeHandlerRouterInstance.write.adminSetWhitelist([ + whitelistAddress.account!.address, + true + ]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, parseEther("0.5")]); + + const depositData = createERCDepositData(depositAmount, 20, recipient.account!.address); + let res = await FeeHandlerRouterInstance.read.calculateFee([ + whitelistAddress.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(web3.utils.fromWei(res[0], "ether"), "0") + res = await FeeHandlerRouterInstance.read.calculateFee([ + nonWhitelistAddress.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(web3.utils.fromWei(res[0], "ether"), "0.5") + }); + + it("should revert if whitelisted address provides fee", async () => { + await FeeHandlerRouterInstance.write.adminSetWhitelist([ + whitelistAddress.account!.address, + true + ]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, parseEther("0.5")]); + + const depositData = createERCDepositData(depositAmount, 20, recipient.account!.address); + await expect( + FeeHandlerRouterInstance.write.collectFee([ + whitelistAddress.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData], + { + account: bridgeMock.account, + value: parseEther("0.5") + } + ), + ).to.be.revertedWithCustomError(FeeHandlerRouterInstance, "IncorrectFeeSupplied(uint256)"); + await expect( + FeeHandlerRouterInstance.write.collectFee([ + nonWhitelistAddress.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData], + { + account: bridgeMock.account, + value: parseEther("0.5") + } + ) + ).not.to.be.reverted; + }); + + it("should not collect fee from whitelisted address", async () => { + await FeeHandlerRouterInstance.write.adminSetWhitelist([ + whitelistAddress.account!.address, + true + ]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + BasicFeeHandlerInstance.address + ]); + await BasicFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, parseEther("0.5")]); + + const depositData = createERCDepositData(depositAmount, 20, recipient.account!.address); + await expect( + FeeHandlerRouterInstance.write.collectFee([ + whitelistAddress.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData], + { + account: bridgeMock.account, + value: BigInt(0) + } + ), + ).not.to.be.reverted; + }); +}); diff --git a/test/handlers/fee/percentage/admin.js b/test/handlers/fee/percentage/admin.js deleted file mode 100644 index 0778858a..00000000 --- a/test/handlers/fee/percentage/admin.js +++ /dev/null @@ -1,122 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); - -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - - -contract("PercentageFeeHandler - [admin]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const initialRelayers = accounts.slice(0, 3); - const currentFeeHandlerAdmin = accounts[0]; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: initialRelayers[1]}), - "sender doesn't have admin role" - ); - }; - - let BridgeInstance; - let PercentageFeeHandlerInstance; - let ERC20MintableInstance; - let ADMIN_ROLE; - let resourceID; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - ADMIN_ROLE = await PercentageFeeHandlerInstance.DEFAULT_ADMIN_ROLE(); - - resourceID = Helpers.createResourceID(ERC20MintableInstance.address, originDomainID); - }); - - it("[sanity] should return fee handler type from fee handler", async () => { - assert.equal(await PercentageFeeHandlerInstance.feeHandlerType.call(), "percentage"); - }); - - it("[sanity] should return fee handler from fee handler router", async () => { - const feeRouterInstance = await FeeHandlerRouterContract.at(PercentageFeeHandlerInstance.address) - assert.equal(await feeRouterInstance.feeHandlerType.call(), "percentage"); - }); - - it("should set fee property", async () => { - const fee = 60000; - assert.equal(await PercentageFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, resourceID), "0"); - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - assert.equal(await PercentageFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, resourceID), fee); - }); - - it("should require admin role to change fee property", async () => { - const fee = 600; - await assertOnlyAdmin(PercentageFeeHandlerInstance.changeFee, destinationDomainID, resourceID, fee); - }); - - it("should set fee bounds", async () => { - const newLowerBound = "100"; - const newUpperBound = "300"; - assert.equal((await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).lowerBound, "0"); - assert.equal((await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).upperBound, "0"); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, newLowerBound, newUpperBound); - assert.equal( - (await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).lowerBound.toString(), - newLowerBound - ); - assert.equal( - (await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).upperBound.toString(), - newUpperBound - ); - }); - - it("should require admin role to change fee bounds", async () => { - const lowerBound = 100; - const upperBound = 300; - await assertOnlyAdmin(PercentageFeeHandlerInstance.changeFeeBounds, resourceID, lowerBound, upperBound); - }); - - it("PercentageFeeHandler admin should be changed to expectedPercentageFeeHandlerAdmin", async () => { - const expectedPercentageFeeHandlerAdmin = accounts[1]; - - // check current admin - assert.isTrue( - await PercentageFeeHandlerInstance.hasRole(ADMIN_ROLE, currentFeeHandlerAdmin) - ); - - await TruffleAssert.passes( - PercentageFeeHandlerInstance.renounceAdmin(expectedPercentageFeeHandlerAdmin) - ); - assert.isTrue( - await PercentageFeeHandlerInstance.hasRole( - ADMIN_ROLE, - expectedPercentageFeeHandlerAdmin - ) - ); - - // check that former admin is no longer admin - assert.isFalse( - await PercentageFeeHandlerInstance.hasRole(ADMIN_ROLE, currentFeeHandlerAdmin) - ); - }); -}); diff --git a/test/handlers/fee/percentage/admin.test.ts b/test/handlers/fee/percentage/admin.test.ts new file mode 100644 index 00000000..231a6ef4 --- /dev/null +++ b/test/handlers/fee/percentage/admin.test.ts @@ -0,0 +1,112 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {deploySourceChainContracts} from "../../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex, WalletClient} from "viem"; +import {assert, expect} from 'chai'; + +const Helpers = require("../../../helpers"); + + +describe("PercentageFeeHandler - [admin]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const fee = BigInt(60000); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let ADMIN_ROLE: Hex; + let resourceID: Hex; + + let feeHandlerAdmin: WalletClient; + let newFeeHandlerAdmin: WalletClient; + + before(async () => { + ({ + BridgeInstance, + PercentageFeeHandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + feeHandlerAdmin, + newFeeHandlerAdmin, + ] = await hre.viem.getWalletClients(); + + ADMIN_ROLE = await PercentageFeeHandlerInstance.read.DEFAULT_ADMIN_ROLE(); + + resourceID = createResourceID(ERC20MintableInstance.address, originDomainID); + }); + + it("[sanity] should return fee handler type from fee handler", async () => { + assert.equal(await PercentageFeeHandlerInstance.read.feeHandlerType(), "percentage"); + }); + + it("[sanity] should return type from fee handler router", async () => { + assert.equal(await FeeHandlerRouterInstance.read.feeHandlerType(), "router"); + }); + + it("should set fee property", async () => { + assert.equal(await PercentageFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, resourceID]), BigInt(0)); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + assert.equal(await PercentageFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, resourceID]), fee); + }); + + it("should require admin role to change fee property", async () => { + await expect( + PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]) + ).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should set fee bounds", async () => { + const newLowerBound = BigInt(100); + const newUpperBound = BigInt(300); + assert.equal((await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[0], BigInt(0)); + assert.equal((await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[1], BigInt(0)); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, newLowerBound, newUpperBound]); + assert.equal( + (await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[0], + newLowerBound + ); + assert.equal( + (await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[1], + newUpperBound + ); + }); + + it("should require admin role to change fee bounds", async () => { + const lowerBound = BigInt(100); + const upperBound = BigInt(300); + await expect( + PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, lowerBound, upperBound]) + ).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("PercentageFeeHandler admin should be changed to newFeeHandlerAdmin", async () => { + + // check current admin + assert.isTrue( + await PercentageFeeHandlerInstance.read.hasRole([ADMIN_ROLE, feeHandlerAdmin.account!.address]) + ); + + await expect( + PercentageFeeHandlerInstance.write.renounceAdmin([newFeeHandlerAdmin.account!.address]) + ).not.to.be.reverted; + + assert.isTrue( + await PercentageFeeHandlerInstance.read.hasRole([ + ADMIN_ROLE, + newFeeHandlerAdmin.account!.address + ]) + ); + + // check that former admin is no longer admin + assert.isFalse( + await PercentageFeeHandlerInstance.read.hasRole([ADMIN_ROLE, feeHandlerAdmin.account!.address]) + ); + }); +}); diff --git a/test/handlers/fee/percentage/calculateFee.js b/test/handlers/fee/percentage/calculateFee.js deleted file mode 100644 index 1233f4be..00000000 --- a/test/handlers/fee/percentage/calculateFee.js +++ /dev/null @@ -1,196 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("PercentageFeeHandler - [calculateFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const relayer = accounts[0]; - const recipientAddress = accounts[1]; - const feeData = "0x0"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let PercentageFeeHandlerInstance; - let resourceID; - let ERC20MintableInstance; - let FeeHandlerRouterInstance; - let DefaultMessageReceiverInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC20MintableInstance.address]; - - burnableContractAddresses = []; - - await Promise.all([ - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ), - ]); - }); - - it(`should return percentage of token amount for fee if bounds - are set [lowerBound > 0, upperBound > 0]`, async () => { - const depositData = Helpers.createERCDepositData(100000000, 20, recipientAddress); - - // current fee is set to 0 - let res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - - assert.equal(res[0].toString(), "0"); - // Change fee to 1 BPS () - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 10000); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 100, 300000); - res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(res[0].toString(), "10000"); - }); - - it(`should return percentage of token amount for fee if bounds - are not set [lowerBound = 0, upperBound = 0]`, async () => { - const depositData = Helpers.createERCDepositData(100000000, 20, recipientAddress); - - // current fee is set to 0 - let res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - - assert.equal(res[0].toString(), "0"); - // Change fee to 1 BPS () - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 10000); - res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(res[0].toString(), "10000"); - }); - - it("should return lower bound token amount for fee [lowerBound > 0, upperBound > 0]", async () => { - const depositData = Helpers.createERCDepositData(10000, 20, recipientAddress); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 100, 300); - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 10000); - - res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(res[0].toString(), "100"); - }); - - it("should return lower bound token amount for fee [lowerBound > 0, upperBound = 0]", async () => { - const depositData = Helpers.createERCDepositData(10000, 20, recipientAddress); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 100, 0); - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 10000); - - res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(res[0].toString(), "100"); - }); - - it("should return upper bound token amount for fee [lowerBound = 0, upperBound > 0]", async () => { - const depositData = Helpers.createERCDepositData(100000000, 20, recipientAddress); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 0, 300); - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 10000); - - res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(res[0].toString(), "300"); - }); - - it("should return percentage of token amount for fee [lowerBound = 0, upperBound > 0]", async () => { - const depositData = Helpers.createERCDepositData(100000, 20, recipientAddress); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 0, 300); - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 10000); - - res = await FeeHandlerRouterInstance.calculateFee.call( - relayer, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData - ); - assert.equal(res[0].toString(), "10"); - }); -}); diff --git a/test/handlers/fee/percentage/calculateFee.test.ts b/test/handlers/fee/percentage/calculateFee.test.ts new file mode 100644 index 00000000..83f790ef --- /dev/null +++ b/test/handlers/fee/percentage/calculateFee.test.ts @@ -0,0 +1,182 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {deploySourceChainContracts} from "../../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {Hex, WalletClient} from 'viem'; +import {assert} from 'chai'; + +const Helpers = require("../../../helpers"); + +describe("PercentageFeeHandler - [calculateFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const feeData = "0x"; + const emptySetResourceData = "0x"; + const fee = BigInt(10000); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + + let resourceID: Hex; + let relayer: WalletClient; + let recipient: WalletClient; + + before(async () => { + ({ + BridgeInstance, + PercentageFeeHandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + relayer, + recipient, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]), + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + }); + + it(`should return percentage of token amount for fee if bounds + are set [lowerBound > 0, upperBound > 0]`, async () => { + const depositData = createERCDepositData(100000000, 20, recipient); + + // current fee is set to 0 + let res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + + assert.equal(res[0], BigInt(0)); + // Change fee to 1 BPS () + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(100), BigInt(300000)]); + res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(res[0], fee); + }); + + it(`should return percentage of token amount for fee if bounds + are not set [lowerBound = 0, upperBound = 0]`, async () => { + const depositData = createERCDepositData(100000000, 20, recipient); + + // current fee is set to 0 + let res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + + assert.equal(res[0], BigInt(0)); + // Change fee to 1 BPS () + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(res[0], fee); + }); + + it("should return lower bound token amount for fee [lowerBound > 0, upperBound > 0]", async () => { + const depositData = createERCDepositData(fee, 20, recipient); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(100), BigInt(300)]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + const res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(res[0], BigInt(100)); + }); + + it("should return lower bound token amount for fee [lowerBound > 0, upperBound = 0]", async () => { + const depositData = createERCDepositData(fee, 20, recipient); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(100), BigInt(0)]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + const res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(res[0], BigInt(100)); + }); + + it("should return upper bound token amount for fee [lowerBound = 0, upperBound > 0]", async () => { + const depositData = createERCDepositData(100000000, 20, recipient); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(0), BigInt(300)]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + const res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(res[0], BigInt(300)); + }); + + it("should return percentage of token amount for fee [lowerBound = 0, upperBound > 0]", async () => { + const depositData = createERCDepositData(100000, 20, recipient); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(0), BigInt(300)]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + const res = await FeeHandlerRouterInstance.read.calculateFee([ + relayer.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ]); + assert.equal(res[0], BigInt(10)); + }); +}); diff --git a/test/handlers/fee/percentage/changeFee.js b/test/handlers/fee/percentage/changeFee.js deleted file mode 100644 index 55baea41..00000000 --- a/test/handlers/fee/percentage/changeFee.js +++ /dev/null @@ -1,171 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); - - -contract("PercentageFeeHandler - [change fee and bounds]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const nonAdmin = accounts[1]; - - let resourceID; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: nonAdmin}), - "sender doesn't have admin role" - ); - }; - - let BridgeInstance; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - }); - - it("[sanity] contract should be deployed successfully", async () => { - TruffleAssert.passes( - await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ) - ); - }); - - it("should set fee", async () => { - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - const fee = Ethers.utils.parseUnits("25"); - const tx = await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee); - TruffleAssert.eventEmitted( - tx, - "FeeChanged", - (event) => { - return Ethers.utils.formatUnits(event.newFee.toString()) === "25.0" - } - ); - const newFee = await PercentageFeeHandlerInstance._domainResourceIDToFee(destinationDomainID, resourceID); - assert.equal(Ethers.utils.formatUnits(newFee.toString()), "25.0"); - }); - - it("should not set the same fee", async () => { - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await Helpers.reverts( - PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, 0), - "Current fee is equal to new fee" - ); - }); - - it("should require admin role to change fee", async () => { - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await assertOnlyAdmin(PercentageFeeHandlerInstance.changeFee, destinationDomainID, resourceID, 1); - }); - - it("should set fee bounds", async () => { - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - const tx = await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 50, 100); - TruffleAssert.eventEmitted( - tx, - "FeeBoundsChanged", - (event) => { - return event.newLowerBound.toString() === "50" && - event.newUpperBound.toString() === "100" - } - ); - const newLowerBound = (await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).lowerBound - const newUpperBound = (await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).upperBound - assert.equal(newLowerBound.toString(), "50"); - assert.equal(newUpperBound.toString(), "100"); - }); - - it("should not set the same fee bounds", async () => { - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 25, 50) - await Helpers.reverts( - PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 25, 50), - "Current bounds are equal to new bounds" - ); - }); - - it("should fail to set lower bound larger than upper bound ", async () => { - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await Helpers.reverts( - PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 50, 25), - "Upper bound must be larger than lower bound or 0" - ); - }); - - it("should set only lower bound", async () => { - const newLowerBound = 30; - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 25, 50); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, newLowerBound, 50); - const currentLowerBound = (await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).lowerBound; - assert.equal(currentLowerBound, newLowerBound); - }); - - it("should set only upper bound", async () => { - const newUpperBound = 100; - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 25, 50); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, 25, newUpperBound); - const currentUpperBound = (await PercentageFeeHandlerInstance._resourceIDToFeeBounds.call(resourceID)).upperBound; - assert.equal(newUpperBound, currentUpperBound); - }); - - it("should require admin role to change fee bunds", async () => { - const PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - await assertOnlyAdmin(PercentageFeeHandlerInstance.changeFeeBounds, resourceID, 50, 100); - }); -}); diff --git a/test/handlers/fee/percentage/changeFee.test.ts b/test/handlers/fee/percentage/changeFee.test.ts new file mode 100644 index 00000000..8f9abb35 --- /dev/null +++ b/test/handlers/fee/percentage/changeFee.test.ts @@ -0,0 +1,132 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {formatUnits, Hex, parseEther, parseUnits, WalletClient} from "viem"; +import {deploySourceChainContracts} from "../../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + +const Helpers = require("../../../helpers"); + +describe("PercentageFeeHandler - [change fee and bounds]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const fee = BigInt(25); + const lowerBound = BigInt(50); + const upperBound = BigInt(100); + + let resourceID: Hex; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + + let admin: WalletClient; + let nonAdmin: WalletClient; + + before(async () => { + ({ + BridgeInstance, + PercentageFeeHandlerInstance, + ERC20MintableInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + nonAdmin, + ] = await hre.viem.getWalletClients(); + + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + }); + + it("should set fee", async () => { + const changeFeeTx = await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]); + + await expect(changeFeeTx).to.emit(PercentageFeeHandlerInstance, "FeeChanged").withArgs( + BigInt(25) + ); + const newFee = await PercentageFeeHandlerInstance.read._domainResourceIDToFee([destinationDomainID, resourceID]); + assert.equal(BigInt(newFee), fee); + }); + + it("should not set the same fee", async () => { + await expect( + PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, fee]) + ).to.be.revertedWithCustomError(PercentageFeeHandlerInstance, "Current fee is equal to new fee"); + }); + + it("should require admin role to change fee", async () => { + await expect( + PercentageFeeHandlerInstance.write.changeFee([ + destinationDomainID, + resourceID, + fee + ], + { + account: nonAdmin.account!.address + } + ) + ).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should set fee bounds", async () => { + const changeFeeBoundsTx = await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, lowerBound, upperBound]); + + await expect(changeFeeBoundsTx).to.emit(PercentageFeeHandlerInstance, "FeeBoundsChanged").withArgs( + lowerBound, + upperBound + ); + + const newLowerBound = (await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[0]; + const newUpperBound = (await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[1]; + assert.equal(newLowerBound, BigInt(50)); + assert.equal(newUpperBound, BigInt(100)); + }); + + it("should not set the same fee bounds", async () => { + await expect( + PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, lowerBound, upperBound]) + ).to.be.revertedWith("Current bounds are equal to new bounds"); + }); + + it("should fail to set lower bound larger than upper bound ", async () => { + await expect( + PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(60), BigInt(25)]) + ).to.be.revertedWith("Upper bound must be larger than lower bound or 0"); + }); + + it("should set only lower bound", async () => { + const newLowerBound = BigInt(60); + + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, newLowerBound, upperBound]); + const currentLowerBound = (await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[0]; + assert.equal(currentLowerBound, newLowerBound); + }); + + it("should set only upper bound", async () => { + const newUpperBound = BigInt(120); + + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, BigInt(60), newUpperBound]); + const currentUpperBound = (await PercentageFeeHandlerInstance.read._resourceIDToFeeBounds([resourceID]))[1]; + assert.equal(newUpperBound, currentUpperBound); + }); + + it("should require admin role to change fee bunds", async () => { + const newLowerBound = BigInt(80); + const newUpperBound = BigInt(200); + await expect(PercentageFeeHandlerInstance.write.changeFeeBounds([ + resourceID, + newLowerBound, + newUpperBound + ], + { + account: nonAdmin.account!.address + } + )); + }); +}); diff --git a/test/handlers/fee/percentage/collectFee.js b/test/handlers/fee/percentage/collectFee.js deleted file mode 100644 index f02c6838..00000000 --- a/test/handlers/fee/percentage/collectFee.js +++ /dev/null @@ -1,295 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("PercentageFeeHandler - [collectFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const recipientAddress = accounts[2]; - const tokenAmount = Ethers.utils.parseEther("200000"); - const depositorAddress = accounts[1]; - - const emptySetResourceData = "0x"; - const feeData = "0x"; - const feeBps = 60000; // BPS - const fee = Ethers.utils.parseEther("120"); - const lowerBound = Ethers.utils.parseEther("100"); - const upperBound = Ethers.utils.parseEther("300"); - - - let BridgeInstance; - let PercentageFeeHandlerInstance; - let resourceID; - let depositData; - - let FeeHandlerRouterInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let ERC20MintableInstance; - - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - (ERC20MintableInstance = ERC20MintableContract.new( - "ERC20Token", - "ERC20TOK" - ).then((instance) => (ERC20MintableInstance = instance))), - ]); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - - await PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, feeBps); - await PercentageFeeHandlerInstance.changeFeeBounds(resourceID, lowerBound, upperBound); - - await Promise.all([ - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ERC20MintableInstance.mint(depositorAddress, tokenAmount + fee), - ERC20MintableInstance.approve(ERC20HandlerInstance.address, tokenAmount, { - from: depositorAddress, - }), - ERC20MintableInstance.approve(PercentageFeeHandlerInstance.address, fee, { - from: depositorAddress, - }), - BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ), - ]); - - depositData = Helpers.createERCDepositData( - tokenAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should collect fee in tokens", async () => { - const balanceBefore = ( - await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ) - ).toString(); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - } - ); - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - PercentageFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === ERC20MintableInstance.address - ); - }); - const balanceAfter = ( - await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ) - ).toString(); - assert.equal(balanceAfter, fee.add(balanceBefore).toString()); - }); - - it("deposit should revert if msg.value != 0", async () => { - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - value: Ethers.utils.parseEther("0.5").toString(), - } - ), - "collectFee: msg.value != 0" - ); - }); - - it("deposit should revert if fee collection fails", async () => { - const depositData = Helpers.createERCDepositData( - tokenAmount, - 20, - recipientAddress - ); - - await ERC20MintableInstance.approve( - PercentageFeeHandlerInstance.address, - 0, - {from: depositorAddress} - ); - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - value: Ethers.utils.parseEther("0.5").toString(), - } - ) - ); - }); - - it("deposit should revert if not called by router on PercentageFeeHandler contract", async () => { - const depositData = Helpers.createERCDepositData( - tokenAmount, - 20, - recipientAddress - ); - await ERC20MintableInstance.approve( - PercentageFeeHandlerInstance.address, - 0, - {from: depositorAddress} - ); - await Helpers.reverts( - PercentageFeeHandlerInstance.collectFee( - depositorAddress, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - value: Ethers.utils.parseEther("0.5").toString(), - } - ), - "sender must be bridge or fee router contract" - ); - }); - - it("deposit should revert if not called by bridge on FeeHandlerRouter contract", async () => { - const depositData = Helpers.createERCDepositData( - tokenAmount, - 20, - recipientAddress - ); - await ERC20MintableInstance.approve( - PercentageFeeHandlerInstance.address, - 0, - {from: depositorAddress} - ); - await Helpers.reverts( - FeeHandlerRouterInstance.collectFee( - depositorAddress, - originDomainID, - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - value: Ethers.utils.parseEther("0.5").toString(), - } - ), - "sender must be bridge contract" - ); - }); - - it("should successfully change fee handler from FeeRouter to PercentageFeeHandler and collect fee", async () => { - await BridgeInstance.adminChangeFeeHandler( - PercentageFeeHandlerInstance.address - ); - - const balanceBefore = ( - await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ) - ).toString(); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - } - ); - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - PercentageFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === ERC20MintableInstance.address - ); - }); - const balanceAfter = ( - await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ) - ).toString(); - assert.equal(balanceAfter, fee.add(balanceBefore).toString()); - }); -}); diff --git a/test/handlers/fee/percentage/collectFee.test.ts b/test/handlers/fee/percentage/collectFee.test.ts new file mode 100644 index 00000000..cdca418f --- /dev/null +++ b/test/handlers/fee/percentage/collectFee.test.ts @@ -0,0 +1,276 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {Hex, parseEther, WalletClient} from "viem"; +import {createERCDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + + +describe("PercentageFeeHandler - [collectFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const tokenAmount = parseEther("200000"); + + const emptySetResourceData = "0x"; + const feeData = "0x"; + const feeBps = 60000; // BPS + const fee = parseEther("120"); + const lowerBound = parseEther("100"); + const upperBound = parseEther("300"); + + + let BridgeInstance: ContractTypesMap["Bridge"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + + let depositor: WalletClient; + let recipient: WalletClient; + + let depositData: Hex; + let resourceID: Hex; + + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + PercentageFeeHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, feeBps]); + await PercentageFeeHandlerInstance.write.changeFeeBounds([resourceID, lowerBound, upperBound]); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await ERC20MintableInstance.write.mint([depositor.account!.address, tokenAmount + fee]), + await ERC20MintableInstance.write.approve([ERC20HandlerInstance.address, tokenAmount], { + account: depositor.account, + }); + await ERC20MintableInstance.write.approve([PercentageFeeHandlerInstance.address, fee], { + account: depositor.account, + }); + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + + depositData = createERCDepositData( + tokenAmount, + 20, + recipient.account!.address + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should collect fee in tokens", async () => { + const balanceBefore = + await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase() + ); + + await expect(depositTx).to.emit(PercentageFeeHandlerInstance, "FeeCollected").withArgs( + depositor, + originDomainID, + destinationDomainID, + resourceID.toLowerCase(), + fee.toString(), + ERC20MintableInstance.address + ); + + const balanceAfter = + await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + + assert.equal(balanceAfter, balanceBefore + fee); + }); + + it("deposit should revert if msg.value != 0", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("0.5"), + } + ), + ).to.be.revertedWith("collectFee: msg.value != 0") + }); + + it("deposit should revert if fee collection fails", async () => { + const depositData = createERCDepositData( + tokenAmount, + 20, + recipient.account!.address + ); + + await ERC20MintableInstance.write.approve([ + PercentageFeeHandlerInstance.address, + 0 + ], + { + account: depositor.account + } + ); + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData], + { + account: depositor.account, + value: parseEther("0.5"), + } + ) + ).to.be.reverted; + }); + + it("deposit should revert if not called by router on PercentageFeeHandler contract", async () => { + const depositData = createERCDepositData( + tokenAmount, + 20, + recipient.account!.address + ); + await ERC20MintableInstance.write.approve([ + PercentageFeeHandlerInstance.address, + BigInt(0) + ], + { + account: depositor.account + } + ); + await expect( + PercentageFeeHandlerInstance.write.collectFee([ + depositor.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("0.5"), + } + ), + ).to.be.revertedWith("sender must be bridge or fee router contract"); + }); + + it("deposit should revert if not called by bridge on FeeHandlerRouter contract", async () => { + const depositData = createERCDepositData( + tokenAmount, + 20, + recipient.account!.address + ); + await ERC20MintableInstance.write.approve([ + PercentageFeeHandlerInstance.address, + BigInt(0) + ], + { + account: depositor.account + } + ); + await expect( + FeeHandlerRouterInstance.write.collectFee([ + depositor.account!.address, + originDomainID, + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + value: parseEther("0.5"), + } + ), + ).to.be.revertedWith("sender must be bridge contract"); + }); + + it("should successfully change fee handler from FeeRouter to PercentageFeeHandler and collect fee", async () => { + await BridgeInstance.write.adminChangeFeeHandler([ + PercentageFeeHandlerInstance.address + ]); + + const balanceBefore = + await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase() + ); + + await expect(depositTx).to.emit(PercentageFeeHandlerInstance, "FeeCollected").withArgs( + depositor, + originDomainID, + destinationDomainID, + resourceID.toLowerCase(), + fee.toString(), + ERC20MintableInstance.address + ); + + const balanceAfter = + await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(balanceAfter, balanceBefore + fee); + }); +}); diff --git a/test/handlers/fee/percentage/distributeFee.js b/test/handlers/fee/percentage/distributeFee.js deleted file mode 100644 index 264d31c5..00000000 --- a/test/handlers/fee/percentage/distributeFee.js +++ /dev/null @@ -1,242 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const TruffleAssert = require("truffle-assertions"); - -const Helpers = require("../../../helpers"); -const Ethers = require("ethers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const PercentageFeeHandlerContract = artifacts.require("PercentageERC20FeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); - -contract("PercentageFeeHandler - [distributeFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const depositAmount = 100000; - const feeData = "0x"; - const emptySetResourceData = "0x"; - const feeAmount = 30; - const feeBps = 30000; // 3 BPS - const payout = Ethers.BigNumber.from("10"); - - let BridgeInstance; - let ERC20MintableInstance; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let PercentageFeeHandlerInstance; - let FeeHandlerRouterInstance; - - let resourceID; - let depositData; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: accounts[1]}), - "sender doesn't have admin role" - ); - }; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ), - PercentageFeeHandlerInstance = await PercentageFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ) - ]); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - - await Promise.all([ - BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ERC20MintableInstance.mint(depositorAddress, depositAmount + feeAmount), - ERC20MintableInstance.approve(ERC20HandlerInstance.address, depositAmount, { - from: depositorAddress, - }), - ERC20MintableInstance.approve( - PercentageFeeHandlerInstance.address, - depositAmount, - {from: depositorAddress} - ), - BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address), - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - PercentageFeeHandlerInstance.address - ), - PercentageFeeHandlerInstance.changeFee(destinationDomainID, resourceID, feeBps) - ]); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should distribute fees", async () => { - // check the balance is 0 - const b1Before = ( - await ERC20MintableInstance.balanceOf(accounts[3]) - ).toString(); - const b2Before = ( - await ERC20MintableInstance.balanceOf(accounts[4]) - ).toString(); - - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - // Transfer the funds - const tx = await PercentageFeeHandlerInstance.transferERC20Fee( - resourceID, - [accounts[3], accounts[4]], - [payout, payout] - ); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === ERC20MintableInstance.address && - event.recipient === accounts[3] && - event.amount.toString() === payout.toString() - ); - }); - TruffleAssert.eventEmitted(tx, "FeeDistributed", (event) => { - return ( - event.tokenAddress === ERC20MintableInstance.address && - event.recipient === accounts[4] && - event.amount.toString() === payout.toString() - ); - }); - b1 = await ERC20MintableInstance.balanceOf(accounts[3]); - b2 = await ERC20MintableInstance.balanceOf(accounts[4]); - assert.equal(b1.toString(), payout.add(b1Before).toString()); - assert.equal(b2.toString(), payout.add(b2Before).toString()); - }); - - it("should not distribute fees with other resourceID", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - const incorrectResourceID = Helpers.createResourceID( - PercentageFeeHandlerInstance.address, - originDomainID - ); - - // Transfer the funds: fails - await Helpers.reverts( - PercentageFeeHandlerInstance.transferERC20Fee( - incorrectResourceID, - [accounts[3], accounts[4]], - [payout, payout] - ) - ); - }); - - it("should require admin role to distribute fee", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - await assertOnlyAdmin( - PercentageFeeHandlerInstance.transferERC20Fee, - resourceID, - [accounts[3], accounts[4]], - [payout.toNumber(), payout.toNumber()] - ); - }); - - it("should revert if addrs and amounts arrays have different length", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - } - ) - ); - const balance = await ERC20MintableInstance.balanceOf( - PercentageFeeHandlerInstance.address - ); - assert.equal(balance, feeAmount); - - await Helpers.reverts( - PercentageFeeHandlerInstance.transferERC20Fee( - resourceID, - [accounts[3], accounts[4]], - [payout, payout, payout] - ), - "addrs[], amounts[]: diff length" - ); - }); -}); diff --git a/test/handlers/fee/percentage/distributeFee.test.ts b/test/handlers/fee/percentage/distributeFee.test.ts new file mode 100644 index 00000000..ad00ac08 --- /dev/null +++ b/test/handlers/fee/percentage/distributeFee.test.ts @@ -0,0 +1,235 @@ +// The Licensed Work is (c) 2022 Sygma + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts, mpcAddress} from "../../../helpers"; +import {Hex, WalletClient} from "viem"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {assert, expect} from 'chai'; + +// SPDX-License-Identifier: LGPL-3.0-only + + +describe("PercentageFeeHandler - [distributeFee]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + + const depositAmount = BigInt(100000); + const feeData = "0x"; + const emptySetResourceData = "0x"; + const feeAmount = BigInt(30); + const feeBps = 30000; // 3 BPS + const payout = BigInt(10); + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let DefaultMessageReceiverInstance: ContractTypesMap["DefaultMessageReceiver"]; + let ERC20HandlerInstance: ContractTypesMap["ERC20Handler"]; + let PercentageFeeHandlerInstance: ContractTypesMap["PercentageERC20FeeHandler"]; + let FeeHandlerRouterInstance: ContractTypesMap["FeeHandlerRouter"]; + + let depositor: WalletClient; + let recipient: WalletClient; + let firstEOA: WalletClient; + let secondEOA: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + PercentageFeeHandlerInstance + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient, + firstEOA, + secondEOA + ] = await hre.viem.getWalletClients(); + + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + ERC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + await ERC20MintableInstance.write.mint([depositor.account!.address, depositAmount + feeAmount]); + await ERC20MintableInstance.write.approve([ + ERC20HandlerInstance.address, + depositAmount + ], { + account: depositor.account, + } + ); + await ERC20MintableInstance.write.approve([ + PercentageFeeHandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ), + await BridgeInstance.write.adminChangeFeeHandler([FeeHandlerRouterInstance.address]); + await FeeHandlerRouterInstance.write.adminSetResourceHandler([ + destinationDomainID, + resourceID, + PercentageFeeHandlerInstance.address + ]); + await PercentageFeeHandlerInstance.write.changeFee([destinationDomainID, resourceID, feeBps]) + + depositData = createERCDepositData( + depositAmount, + 20, + recipient + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("should distribute fees", async () => { + // check the balance is 0 + const firstBalanceBefore = ( + await ERC20MintableInstance.read.balanceOf([firstEOA.account!.address]) + ); + const secondBalanceBefore = ( + await ERC20MintableInstance.read.balanceOf([secondEOA.account!.address]) + ); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + const handlerBalance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(handlerBalance, feeAmount); + + // Transfer the funds + const transferFeeTx = await PercentageFeeHandlerInstance.write.transferERC20Fee([ + resourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ]); + + await expect(transferFeeTx).to.emit(PercentageFeeHandlerInstance, "FeeDistributed").withArgs( + ERC20MintableInstance.address, + firstEOA.account!.address, + payout + ); + await expect(transferFeeTx).to.emit(PercentageFeeHandlerInstance, "FeeDistributed").withArgs( + ERC20MintableInstance.address, + secondEOA.account!.address, + payout + ); + + const firstBalanceAfter = await ERC20MintableInstance.read.balanceOf([firstEOA.account!.address]); + const secondBalanceAfter = await ERC20MintableInstance.read.balanceOf([secondEOA.account!.address]); + assert.equal(firstBalanceBefore, firstBalanceAfter + payout); + assert.equal(secondBalanceBefore, secondBalanceAfter + payout); + }); + + it("should not distribute fees with other resourceID", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + const balance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(balance, feeAmount); + + const incorrectResourceID = createResourceID( + PercentageFeeHandlerInstance.address, + originDomainID + ); + + // Transfer the funds: fails + await expect( + PercentageFeeHandlerInstance.write.transferERC20Fee([ + incorrectResourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ]) + ).to.be.reverted; + }); + + it("should require admin role to distribute fee", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + const balance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(balance, feeAmount); + + await expect( + PercentageFeeHandlerInstance.write.transferERC20Fee([ + resourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout] + ])).to.be.revertedWith("sender doesn't have admin role"); + }); + + it("should revert if addrs and amounts arrays have different length", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account, + } + ) + ).not.to.be.reverted; + const balance = await ERC20MintableInstance.read.balanceOf([ + PercentageFeeHandlerInstance.address + ]); + assert.equal(balance, feeAmount); + + await expect( + PercentageFeeHandlerInstance.write.transferERC20Fee([ + resourceID, + [firstEOA.account!.address, secondEOA.account!.address], + [payout, payout, payout] + ]), + ).to.be.revertedWith("addrs[], amounts[]: diff length"); + }); +}); diff --git a/test/handlers/generic/permissionlessDeposit.js b/test/handlers/generic/permissionlessDeposit.js deleted file mode 100644 index 9b9f9ef5..00000000 --- a/test/handlers/generic/permissionlessDeposit.js +++ /dev/null @@ -1,178 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); -const Helpers = require("../../helpers"); - -const TestStoreContract = artifacts.require("TestStore"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); -const WithDepositorContract = artifacts.require("WithDepositor"); -const ReturnDataContract = artifacts.require("ReturnData"); - -contract("GmpHandler - [deposit]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const expectedDepositNonce = 1; - - const depositorAddress = accounts[1]; - - const feeData = "0x"; - const destinationMaxFee = 900000; - const hashOfTestStore = Ethers.utils.keccak256("0xc0ffee"); - const emptySetResourceData = "0x"; - - let BridgeInstance; - let TestStoreInstance; - - let resourceID; - let depositFunctionSignature; - let GmpHandlerInstance; - let depositData; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - TestStoreContract.new().then( - (instance) => (TestStoreInstance = instance) - ), - WithDepositorContract.new().then( - (instance) => (WithDepositorInstance = instance) - ), - ReturnDataContract.new().then( - (instance) => (ReturnDataInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - TestStoreInstance.address, - originDomainID - ); - - GmpHandlerInstance = - await GmpHandlerContract.new(BridgeInstance.address); - - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - TestStoreInstance.address, - emptySetResourceData - ); - - depositFunctionSignature = Helpers.getFunctionSignature( - TestStoreInstance, - "storeWithDepositor" - ); - - depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestStoreInstance.address, - destinationMaxFee, - depositorAddress, - hashOfTestStore - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("deposit can be made successfully", async () => { - await TruffleAssert.passes( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - }); - - it("depositEvent is emitted with expected values", async () => { - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === depositData && - event.handlerResponse === null - ); - }); - }); - - it("deposit data should be of required length", async () => { - // Min length is 76 bytes - const invalidDepositData = "0x" + "aa".repeat(75); - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - invalidDepositData, - feeData, - {from: depositorAddress} - ), - "Incorrect data length" - ); - }); - - it("should revert if metadata encoded depositor does not match deposit depositor", async () => { - const invalidDepositorAddress = accounts[2]; - - const invalidDepositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestStoreInstance.address, - destinationMaxFee, - invalidDepositorAddress, - hashOfTestStore - ); - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - invalidDepositData, - feeData, - {from: depositorAddress} - ), - "incorrect depositor in deposit data" - ); - }); - - - it("should revert if max fee exceeds 1000000", async () => { - const invalidMaxFee = 1000001; - const invalidDepositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestStoreInstance.address, - invalidMaxFee , - depositorAddress, - hashOfTestStore - ); - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - invalidDepositData, - feeData, - {from: depositorAddress} - ), - "requested fee too large" - ); - }); -}); diff --git a/test/handlers/generic/permissionlessDeposit.test.ts b/test/handlers/generic/permissionlessDeposit.test.ts new file mode 100644 index 00000000..df4dc3cc --- /dev/null +++ b/test/handlers/generic/permissionlessDeposit.test.ts @@ -0,0 +1,174 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {Hex, keccak256, toFunctionSelector, WalletClient} from "viem"; +import {createGmpDepositData, createResourceID, deploySourceChainContracts, mpcAddress} from "../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {expect} from 'chai'; + + +describe("GmpHandler - [deposit]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const expectedDepositNonce = 1; + + let depositor: WalletClient; + let invaliddepositor: WalletClient; + + const feeData = "0x"; + const destinationMaxFee = BigInt(900000); + const hashOfTestStore = keccak256("0xc0ffee"); + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let TestStoreInstance: ContractTypesMap["TestStore"]; + let GmpHandlerInstance: ContractTypesMap["GmpHandler"]; + + let resourceID: Hex; + let depositFunctionSignature: Hex; + let depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + TestStoreInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + depositor, + invaliddepositor, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + TestStoreInstance.address, + originDomainID + ); + + await BridgeInstance.write.adminSetResource([ + GmpHandlerInstance.address, + resourceID, + TestStoreInstance.address, + emptySetResourceData + ]); + + depositFunctionSignature = toFunctionSelector( + TestStoreInstance.write.storeWithDepositor.toString() + ); + + depositData = createGmpDepositData( + depositFunctionSignature, + TestStoreInstance.address, + destinationMaxFee, + depositor.account!.address, + hashOfTestStore + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("deposit can be made successfully", async () => { + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + + account: depositor.account + } + ) + ).not.to.be.reverted; + }); + + it("depositEvent is emitted with expected values", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositData, + null + ); + }); + + it("deposit data should be of required length", async () => { + // Min length is 76 bytes + const invalidDepositData= "0x" + "aa".repeat(75) as unknown as Hex; + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + invalidDepositData, + feeData + ], + { + account: depositor.account + } + ), + ).to.be.revertedWith("Incorrect data length"); + }); + + it("should revert if metadata encoded depositor does not match deposit depositor", async () => { + const invalidDepositData = createGmpDepositData( + depositFunctionSignature, + TestStoreInstance.address, + destinationMaxFee, + invaliddepositor.account!.address, + hashOfTestStore + ); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + invalidDepositData, + feeData + ], + { + account: depositor.account + } + ), + ).to.be.revertedWith("incorrect depositor in deposit data"); + }); + + + it("should revert if max fee exceeds 1000000", async () => { + const invalidMaxFee = BigInt(1000001); + const invalidDepositData = createGmpDepositData( + depositFunctionSignature, + TestStoreInstance.address, + invalidMaxFee , + depositor.account!.address, + hashOfTestStore + ); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + invalidDepositData, + feeData + ], + { + account: depositor.account + } + ), + ).to.be.revertedWith("requested fee too large"); + }); +}); diff --git a/test/handlers/generic/permissionlessExecuteProposal.js b/test/handlers/generic/permissionlessExecuteProposal.js deleted file mode 100644 index 528eee5d..00000000 --- a/test/handlers/generic/permissionlessExecuteProposal.js +++ /dev/null @@ -1,435 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); -const Helpers = require("../../helpers"); - -const TestStoreContract = artifacts.require("TestStore"); -const TestDepositContract = artifacts.require("TestDeposit"); -const GmpHandlerContract = artifacts.require( - "GmpHandler" -); - -contract( - "GmpHandler - [Execute Proposal]", - async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const expectedDepositNonce = 1; - - const depositorAddress = accounts[1]; - const relayer1Address = accounts[2]; - const relayer2Address = accounts[3]; - const invalidExecutionContractAddress = accounts[4]; - - const feeData = "0x"; - const destinationMaxFee = 900000; - const hashOfTestStore = Ethers.utils.keccak256("0xc0ffee"); - const handlerResponseLength = 64; - const contractCallReturndata = Ethers.constants.HashZero; - - - let BridgeInstance; - let TestStoreInstance; - let TestDepositInstance; - - let resourceID; - let depositFunctionSignature; - let GmpHandlerInstance; - let depositData; - let proposal; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )), - TestStoreContract.new().then( - (instance) => (TestStoreInstance = instance) - ), - TestDepositContract.new().then( - (instance) => (TestDepositInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - TestStoreInstance.address, - originDomainID - ); - - GmpHandlerInstance = - await GmpHandlerContract.new(BridgeInstance.address); - - depositFunctionSignature = Helpers.getFunctionSignature( - TestStoreInstance, - "storeWithDepositor" - ); - - const GmpHandlerSetResourceData = - Helpers.constructGenericHandlerSetResourceData( - depositFunctionSignature, - Helpers.blankFunctionDepositorOffset, - Helpers.blankFunctionSig - ); - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - TestStoreInstance.address, - GmpHandlerSetResourceData - ); - - depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestStoreInstance.address, - destinationMaxFee, - depositorAddress, - hashOfTestStore - ); - - proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: depositData, - resourceID: resourceID, - }; - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("deposit can be executed successfully", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - // relayer1 executes the proposal - await TruffleAssert.passes( - BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }) - ); - - // Verifying asset was marked as stored in TestStoreInstance - assert.isTrue( - await TestStoreInstance._assetsStored.call(hashOfTestStore) - ); - }); - - it("AssetStored event should be emitted", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - // relayer1 executes the proposal - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer2Address} - ); - - const internalTx = await TruffleAssert.createTransactionResult( - TestStoreInstance, - executeTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "AssetStored", (event) => { - return event.asset === hashOfTestStore; - }); - - assert.isTrue( - await TestStoreInstance._assetsStored.call(hashOfTestStore), - "TestStore asset was not successfully stored" - ); - }); - - it("ProposalExecution should be emitted even if handler execution fails", async () => { - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - // execution contract address - const invalidDepositData = Helpers.createGmpDepositData( - depositFunctionSignature, - invalidExecutionContractAddress, - destinationMaxFee, - depositorAddress, - hashOfTestStore - ); - - const depositDataHash = Ethers.utils.keccak256( - GmpHandlerInstance.address + depositData.substr(2) - ); - - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - invalidDepositData, - feeData, - {from: depositorAddress} - ) - ); - - // relayer1 executes the proposal - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - - // check that ProposalExecution event is emitted - TruffleAssert.eventEmitted(executeTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce && - event.dataHash === depositDataHash && - event.handlerResponse === Ethers.utils.defaultAbiCoder.encode( - ["bool", "uint256", "bytes32"], - [true, handlerResponseLength, contractCallReturndata] - ) - ); - }); - - // check that deposit nonce isn't unmarked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - // Check that asset isn't marked as stored in TestStoreInstance - assert.isTrue( - await TestStoreInstance._assetsStored.call(hashOfTestStore) - ); - }); - - it("ProposalExecution should be emitted even if gas specified too small", async () => { - const num = 6; - const addresses = [BridgeInstance.address, TestStoreInstance.address]; - const message = Ethers.utils.hexlify(Ethers.utils.toUtf8Bytes("message")); - const executionData = Helpers.abiEncode(["uint", "address[]", "bytes"], [num, addresses, message]); - - // If the target function accepts (address depositor, bytes executionData) - // then this helper can be used - const preparedExecutionData = await TestDepositInstance.prepareDepositData(executionData); - const depositFunctionSignature = Helpers.getFunctionSignature( - TestDepositInstance, - "executePacked" - ); - const tooSmallGas = 500; - const depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestDepositInstance.address, - tooSmallGas, - depositorAddress, - preparedExecutionData - ); - const proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: depositData, - resourceID: resourceID, - }; - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - - // relayer1 executes the proposal - const executeTx = await BridgeInstance.executeProposal( - proposal, - proposalSignedData, - {from: relayer1Address} - ); - // check that ProposalExecution event is emitted - TruffleAssert.eventEmitted(executeTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce - ); - }); - - // check that deposit nonce isn't unmarked as used in bitmap - assert.isTrue( - await BridgeInstance.isProposalExecuted( - originDomainID, - expectedDepositNonce - ) - ); - - const internalTx = await TruffleAssert.createTransactionResult( - TestDepositInstance, - executeTx.tx - ); - TruffleAssert.eventNotEmitted(internalTx, "TestExecute", (event) => { - return ( - event.depositor === depositorAddress && - event.num.toNumber() === num && - event.addr === TestStoreInstance.address && - event.message === message - ); - }); - }); - - it("call with packed depositData should be successful", async () => { - const num = 5; - const addresses = [BridgeInstance.address, TestStoreInstance.address]; - const message = Ethers.utils.hexlify(Ethers.utils.toUtf8Bytes("message")); - const executionData = Helpers.abiEncode(["uint", "address[]", "bytes"], [num, addresses, message]); - - // If the target function accepts (address depositor, bytes executionData) - // then this helper can be used - const preparedExecutionData = await TestDepositInstance.prepareDepositData(executionData); - const depositFunctionSignature = Helpers.getFunctionSignature( - TestDepositInstance, - "executePacked" - ); - const depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestDepositInstance.address, - destinationMaxFee, - depositorAddress, - preparedExecutionData - ); - - const proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: depositData, - resourceID: resourceID, - }; - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - // relayer1 executes the proposal - const executeTx = await BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }); - - const internalTx = await TruffleAssert.createTransactionResult( - TestDepositInstance, - executeTx.tx - ); - - // check that ProposalExecution event is emitted - TruffleAssert.eventEmitted(executeTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce - ); - }); - - TruffleAssert.eventEmitted(internalTx, "TestExecute", (event) => { - return ( - event.depositor === depositorAddress && - event.num.toNumber() === num && - event.addr === TestStoreInstance.address && - event.message === message - ); - }); - }); - - it("call with unpacked depositData should be successful", async () => { - const num = 5; - const addresses = [BridgeInstance.address, TestStoreInstance.address]; - const message = Ethers.utils.hexlify(Ethers.utils.toUtf8Bytes("message")); - - const executionData = Helpers.createGmpExecutionData( - ["uint", "address[]", "bytes"], [num, addresses, message] - ); - - const depositFunctionSignature = Helpers.getFunctionSignature( - TestDepositInstance, - "executeUnpacked" - ); - const depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestDepositInstance.address, - destinationMaxFee, - depositorAddress, - executionData - ); - - const proposal = { - originDomainID: originDomainID, - depositNonce: expectedDepositNonce, - data: depositData, - resourceID: resourceID, - }; - const proposalSignedData = await Helpers.signTypedProposal( - BridgeInstance.address, - [proposal] - ); - await TruffleAssert.passes( - BridgeInstance.deposit( - originDomainID, - resourceID, - depositData, - feeData, - {from: depositorAddress} - ) - ); - - // relayer1 executes the proposal - const executeTx = await BridgeInstance.executeProposal(proposal, proposalSignedData, { - from: relayer1Address, - }); - - const internalTx = await TruffleAssert.createTransactionResult( - TestDepositInstance, - executeTx.tx - ); - - // check that ProposalExecution event is emitted - TruffleAssert.eventEmitted(executeTx, "ProposalExecution", (event) => { - return ( - event.originDomainID.toNumber() === originDomainID && - event.depositNonce.toNumber() === expectedDepositNonce - ); - }); - - TruffleAssert.eventEmitted(internalTx, "TestExecute", (event) => { - return ( - event.depositor === depositorAddress && - event.num.toNumber() === num && - event.addr === TestStoreInstance.address && - event.message === message - ); - }); - }); - } -); diff --git a/test/handlers/generic/permissionlessExecuteProposal.test.ts b/test/handlers/generic/permissionlessExecuteProposal.test.ts new file mode 100644 index 00000000..b7888f87 --- /dev/null +++ b/test/handlers/generic/permissionlessExecuteProposal.test.ts @@ -0,0 +1,423 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {concat, encodeAbiParameters, fromBytes, Hex, keccak256, parseAbiParameters, toBytes, toFunctionSelector, WalletClient, zeroHash} from "viem"; +import {mpcAddress,createResourceID, deploySourceChainContracts, createGmpDepositData, trimPrefix, constructGenericHandlerSetResourceData, blankFunctionDepositorOffset, blankFunctionSig, signTypedProposal, createGmpExecutionData} from "../../helpers"; +import {ContractTypesMap} from 'hardhat/types'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; +import {assert, expect} from 'chai'; +import {Proposal} from '../../../types'; + +describe("GmpHandler - [Execute Proposal]", () => { + const originDomainID = 1; + const expectedDepositNonce = BigInt(1); + + const feeData = "0x"; + const destinationMaxFee = BigInt(900000); + const hashOfTestStore = keccak256("0xc0ffee"); + const handlerResponseLength = BigInt(64); + const contractCallReturnData = zeroHash; + + + let BridgeInstance: ContractTypesMap["Bridge"]; + let TestStoreInstance: ContractTypesMap["TestStore"]; + let TestDepositInstance: ContractTypesMap["TestDeposit"];; + let GmpHandlerInstance: ContractTypesMap["GmpHandler"]; + + let depositor: WalletClient; + let relayer1: WalletClient; + let relayer2Address: WalletClient; + let invalidExecutionContractAddress: WalletClient; + + let resourceID: Hex; + let depositFunctionSignature: Hex; + let depositData: Hex; + let proposal: Proposal; + + before(async () => { + ({ + BridgeInstance, + TestStoreInstance, + TestDepositInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + relayer1, + relayer2Address, + invalidExecutionContractAddress + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + TestStoreInstance.address, + originDomainID + ); + + depositFunctionSignature = toFunctionSelector( + TestStoreInstance.write.storeWithDepositor.toString() + ); + + const GmpHandlerSetResourceData = + constructGenericHandlerSetResourceData( + depositFunctionSignature, + blankFunctionDepositorOffset, + blankFunctionSig + ); + await BridgeInstance.write.adminSetResource([ + GmpHandlerInstance.address, + resourceID, + TestStoreInstance.address, + GmpHandlerSetResourceData + ]); + + depositData = createGmpDepositData( + depositFunctionSignature, + TestStoreInstance.address, + destinationMaxFee, + depositor.account!.address, + hashOfTestStore + ); + + proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: depositData, + resourceID: resourceID, + }; + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("deposit can be executed successfully", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + // relayer1 executes the proposal + await expect( + BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }) + ).not.to.be.reverted; + + // Verifying asset was marked as stored in TestStoreInstance + assert.isTrue( + await TestStoreInstance.read._assetsStored([hashOfTestStore]) + ); + }); + + it("AssetStored event should be emitted", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + // relayer1 executes the proposal + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer2Address.account + } + ); + + await expect(executeTx).to.emit(TestStoreInstance, "AssetStored").withArgs( + hashOfTestStore + ); + + assert.isTrue( + await TestStoreInstance.read._assetsStored([hashOfTestStore]), + "TestStore asset was not successfully stored" + ); + }); + + it("ProposalExecution should be emitted even if handler execution fails", async () => { + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + // execution contract address + const invalidDepositData = createGmpDepositData( + depositFunctionSignature, + invalidExecutionContractAddress.account!.address, + destinationMaxFee, + depositor.account!.address, + hashOfTestStore + ); + + const depositDataHash = keccak256( + concat([ + GmpHandlerInstance.address, + trimPrefix(depositData) + ]) + ); + + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + invalidDepositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + // relayer1 executes the proposal + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce, + depositDataHash, + encodeAbiParameters( + parseAbiParameters(["bool", "uint256", "bytes32"]), + [true, handlerResponseLength, contractCallReturnData] + ) + ); + + // check that deposit nonce isn't unmarked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + // Check that asset isn't marked as stored in TestStoreInstance + assert.isTrue( + await TestStoreInstance.read._assetsStored([hashOfTestStore]) + ); + }); + + it("ProposalExecution should be emitted even if gas specified too small", async () => { + const num = BigInt(6); + const addresses = [BridgeInstance.address, TestStoreInstance.address]; + const message = fromBytes(toBytes("message"), "hex"); + const executionData = encodeAbiParameters( + parseAbiParameters(["uint", "address[]", "bytes"]), + [num, addresses, message] + ); + + // If the target function accepts (address depositor, bytes executionData) + // then this helper can be used + const preparedExecutionData = await TestDepositInstance.read.prepareDepositData([executionData]); + const depositFunctionSignature = toFunctionSelector( + TestDepositInstance.write.executePacked.toString() + ); + const tooSmallGas = BigInt(500); + const depositData = createGmpDepositData( + depositFunctionSignature, + TestDepositInstance.address, + tooSmallGas, + depositor.account!.address, + preparedExecutionData + ); + const proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: depositData, + resourceID: resourceID, + }; + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + + // relayer1 executes the proposal + const executeTx = await BridgeInstance.write.executeProposal([ + proposal, + proposalSignedData + ], + { + account: relayer1.account + } + ); + + // check that ProposalExecution event is emitted + await expect (executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce + ); + + // check that deposit nonce isn't unmarked as used in bitmap + assert.isTrue( + await BridgeInstance.read.isProposalExecuted([ + originDomainID, + expectedDepositNonce + ]) + ); + + await expect(executeTx).to.emit(TestDepositInstance, "TestExecute").withArgs( + depositor, + num, + TestStoreInstance.address, + message + ); + }); + + it("call with packed depositData should be successful", async () => { + const num = BigInt(5); + const addresses = [BridgeInstance.address, TestStoreInstance.address]; + const message = fromBytes(toBytes("message"), "hex"); + const executionData = encodeAbiParameters( + parseAbiParameters(["uint", "address[]", "bytes"]), + [num, addresses, message] + ); + + // If the target function accepts (address depositor, bytes executionData) + // then this helper can be used + const preparedExecutionData = await TestDepositInstance.read.prepareDepositData([executionData]); + const depositFunctionSignature = toFunctionSelector( + TestDepositInstance.write.executePacked.toString() + ); + const depositData = createGmpDepositData( + depositFunctionSignature, + TestDepositInstance.address, + destinationMaxFee, + depositor.account!.address, + preparedExecutionData + ); + + const proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: depositData, + resourceID: resourceID, + }; + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + // relayer1 executes the proposal + const executeTx = await BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }); + + + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce + ); + + await expect(executeTx).to.emit(TestStoreInstance, "TestExecute").withArgs( + depositor, + num, + TestStoreInstance.address, + message + ); + }); + + it("call with unpacked depositData should be successful", async () => { + const num = 5; + const addresses = [BridgeInstance.address, TestStoreInstance.address]; + const message = fromBytes(toBytes("message"), "hex"); + + const executionData = createGmpExecutionData( + ["uint", "address[]", "bytes"], [num, addresses, message] + ); + + const depositFunctionSignature = toFunctionSelector( + TestDepositInstance.write.executeUnpacked.toString() + ); + const depositData = createGmpDepositData( + depositFunctionSignature, + TestDepositInstance.address, + destinationMaxFee, + depositor.account!.address, + executionData + ); + + const proposal = { + originDomainID: originDomainID, + depositNonce: expectedDepositNonce, + data: depositData, + resourceID: resourceID, + }; + const proposalSignedData = await signTypedProposal( + BridgeInstance.address, + [proposal] + ); + await expect( + BridgeInstance.write.deposit([ + originDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).not.to.be.reverted; + + // relayer1 executes the proposal + const executeTx = await BridgeInstance.write.executeProposal([proposal, proposalSignedData], { + account: relayer1.account, + }); + + await expect(executeTx).to.emit(BridgeInstance, "ProposalExecution").withArgs( + originDomainID, + expectedDepositNonce + ); + + await expect(executeTx).to.emit(TestStoreInstance, "TestExecute").withArgs( + depositor, + num, + TestStoreInstance.address, + message + ); + }); + } +); diff --git a/test/handlers/xc20/constructor.js b/test/handlers/xc20/constructor.js deleted file mode 100644 index c0883141..00000000 --- a/test/handlers/xc20/constructor.js +++ /dev/null @@ -1,121 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const XC20HandlerContract = artifacts.require("XC20Handler"); - -contract("XC20Handler - [constructor]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance1; - let ERC20MintableInstance2; - let ERC20MintableInstance3; - let initialResourceIDs; - let initialContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance3 = instance) - ), - ]); - - initialResourceIDs = []; - burnableContractAddresses = []; - - initialResourceIDs.push( - Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ) - ); - initialResourceIDs.push( - Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ) - ); - initialResourceIDs.push( - Ethers.utils.hexZeroPad( - ERC20MintableInstance3.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ) - ); - - initialContractAddresses = [ - ERC20MintableInstance1.address, - ERC20MintableInstance2.address, - ERC20MintableInstance3.address, - ]; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes(XC20HandlerContract.new(BridgeInstance.address)); - }); - - it("[sanity] bridge configured on domain", async () => { - assert.equal(await BridgeInstance._domainID(), domainID); - }); - - it("[sanity] bridge should be initially paused", async () => { - assert.isTrue(await BridgeInstance.paused()); - }); - - it( - "initialResourceIDs should be parsed correctly and corresponding resourceID mappings should have expected values", - async () => { - const XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (const resourceID of initialResourceIDs) { - const tokenAddress = "0x" + resourceID.substr(24, 40); - - const retrievedTokenAddress = - await XC20HandlerInstance._resourceIDToTokenContractAddress.call( - resourceID - ); - assert.strictEqual( - Ethers.utils.getAddress(tokenAddress).toLowerCase(), - retrievedTokenAddress.toLowerCase() - ); - - const retrievedResourceID = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - tokenAddress - )).resourceID - - assert.strictEqual( - resourceID.toLowerCase(), - retrievedResourceID.toLowerCase() - ); - } - }); -}); diff --git a/test/handlers/xc20/constructor.test.ts b/test/handlers/xc20/constructor.test.ts new file mode 100644 index 00000000..cb75e456 --- /dev/null +++ b/test/handlers/xc20/constructor.test.ts @@ -0,0 +1,105 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex, toHex} from 'viem'; +import {assert, expect} from 'chai'; + + +describe("XC20Handler - [constructor]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance3: ContractTypesMap["ERC20PresetMinterPauser"]; + let XC20HandlerInstance: ContractTypesMap["XC20Handler"]; + let initialResourceIDs: Array; + let initialContractAddresses: Array; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance: ERC20MintableInstance1, + ERC20MintableInstance: ERC20MintableInstance2, + ERC20MintableInstance: ERC20MintableInstance3, + XC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + + initialResourceIDs = []; + + initialResourceIDs.push( + createResourceID( + ERC20MintableInstance1.address, + + domainID + ) + ); + initialResourceIDs.push( + createResourceID( + ERC20MintableInstance2.address, + domainID + ) + ); + initialResourceIDs.push( + createResourceID( + ERC20MintableInstance3.address, + domainID + ) + ); + + initialContractAddresses = [ + ERC20MintableInstance1.address, + ERC20MintableInstance2.address, + ERC20MintableInstance3.address, + ]; + }); + + it("[sanity] bridge configured on domain", async () => { + assert.equal(await BridgeInstance.read._domainID(), domainID); + }); + + it("[sanity] bridge should be initially paused", async () => { + assert.isTrue(await BridgeInstance.read.paused()); + }); + + it(`initialResourceIDs should be parsed correctly and + corresponding resourceID mappings should have expected values`, async () => { + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (const resourceID of initialResourceIDs) { + const tokenAddress = toHex(resourceID.substring(24, 40), {size: 20}); + + const retrievedTokenAddress = + await XC20HandlerInstance.read._resourceIDToTokenContractAddress([ + resourceID + ]); + assert.strictEqual( + tokenAddress, + retrievedTokenAddress + ); + + const retrievedResourceID = (await XC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + tokenAddress + ]))[0]; + + assert.strictEqual( + resourceID.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + } + }); +}); diff --git a/test/handlers/xc20/deposit.js b/test/handlers/xc20/deposit.js deleted file mode 100644 index cac61c88..00000000 --- a/test/handlers/xc20/deposit.js +++ /dev/null @@ -1,208 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const XC20HandlerContract = artifacts.require("XC20Handler"); - -contract("XC20Handler - [Deposit ERC20]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 2; - const expectedDepositNonce = 1; - const depositorAddress = accounts[1]; - - const tokenAmount = 100; - const feeData = "0x"; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance; - let XC20HandlerInstance; - - let resourceID; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance = instance) - ), - ]); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - initialResourceIDs = [resourceID]; - initialContractAddresses = [ERC20MintableInstance.address]; - burnableContractAddresses = []; - - await Promise.all([ - XC20HandlerContract.new(BridgeInstance.address).then( - (instance) => (XC20HandlerInstance = instance) - ), - ERC20MintableInstance.mint(depositorAddress, tokenAmount), - ]); - - await Promise.all([ - ERC20MintableInstance.approve(XC20HandlerInstance.address, tokenAmount, { - from: depositorAddress, - }), - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ), - ]); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] depositor owns tokenAmount of ERC20", async () => { - const depositorBalance = await ERC20MintableInstance.balanceOf( - depositorAddress - ); - assert.equal(tokenAmount, depositorBalance); - }); - - it("[sanity] XC20HandlerInstance.address has an allowance of tokenAmount from depositorAddress", async () => { - const handlerAllowance = await ERC20MintableInstance.allowance( - depositorAddress, - XC20HandlerInstance.address - ); - assert.equal(tokenAmount, handlerAllowance); - }); - - it("Varied recipient address with length 40", async () => { - const recipientAddress = accounts[0] + accounts[1].substr(2); - const lenRecipientAddress = 40; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ).toLowerCase() && - event.handlerResponse === null - ); - }); - }); - - it("Varied recipient address with length 32", async () => { - const recipientAddress = Ethers.utils.keccak256(accounts[0]); - const lenRecipientAddress = 32; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.depositNonce.toNumber() === expectedDepositNonce && - event.user === depositorAddress && - event.data === - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ).toLowerCase() && - event.handlerResponse === null - ); - }); - }); - - it(`When non-contract addresses are whitelisted in the handler, - deposits which the addresses are set as a token address will be failed`, async () => { - const NonContract_Address = "0x0000000000000000000000000000000000001111"; - const EOA_Address = accounts[1]; - const resourceID_NonContract_Address = Helpers.createResourceID( - NonContract_Address, - originDomainID - ); - const resourceID_EOA_Address = Helpers.createResourceID( - EOA_Address, - originDomainID - ); - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - resourceID_NonContract_Address, - NonContract_Address, - emptySetResourceData - ); - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - resourceID_EOA_Address, - EOA_Address, - emptySetResourceData - ); - - const recipientAddress = accounts[0] + accounts[1].substr(2); - const lenRecipientAddress = 40; - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID_NonContract_Address, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ), - "ERC20: not a contract" - ); - - await Helpers.reverts( - BridgeInstance.deposit( - destinationDomainID, - resourceID_EOA_Address, - Helpers.createERCDepositData( - tokenAmount, - lenRecipientAddress, - recipientAddress - ), - feeData, - {from: depositorAddress} - ), - "ERC20: not a contract" - ); - }); -}); diff --git a/test/handlers/xc20/deposit.test.ts b/test/handlers/xc20/deposit.test.ts new file mode 100644 index 00000000..75967d42 --- /dev/null +++ b/test/handlers/xc20/deposit.test.ts @@ -0,0 +1,202 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {concat, keccak256, WalletClient} from "viem"; +import {mpcAddress, trimPrefix} from "../../helpers"; +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex} from "viem"; +import {assert, expect} from "chai"; + + +describe("XC20Handler - [Deposit ERC20]", () => { + const originDomainID = 1; + const destinationDomainID = 2; + const expectedDepositNonce = 1; + + const tokenAmount = BigInt(100); + const feeData = "0x"; + const emptySetResourceData = "0x"; + const lenrecipient = 40; + + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance: ContractTypesMap["ERC20PresetMinterPauser"]; + let XC20HandlerInstance: ContractTypesMap["XC20Handler"]; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let EOA_Address: WalletClient; + + let resourceID: Hex; + let depositData: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance, + XC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + EOA_Address, + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance.address, + originDomainID + ); + + depositData = createERCDepositData( + tokenAmount, + lenrecipient, + concat([admin.account!.address, trimPrefix(recipient.account!.address)]) + ); + + await ERC20MintableInstance.write.mint([ + depositor.account!.address, + tokenAmount + ]), + + await ERC20MintableInstance.write.approve([ + XC20HandlerInstance.address, + tokenAmount + ], + { + account: depositor.account!.address, + } + ); + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID, + ERC20MintableInstance.address, + emptySetResourceData + ]); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] depositor owns tokenAmount of ERC20", async () => { + const depositorBalance = await ERC20MintableInstance.read.balanceOf([ + depositor.account!.address + ]); + assert.equal(tokenAmount, depositorBalance); + }); + + it("[sanity] XC20HandlerInstance.address has an allowance of tokenAmount from depositor", async () => { + const handlerAllowance = await ERC20MintableInstance.read.allowance([ + depositor.account!.address, + XC20HandlerInstance.address + ]); + assert.equal(tokenAmount, handlerAllowance); + }); + + it("Varied recipient address with length 40", async () => { + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData, + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositData, + null + ); + }); + + it("Varied recipient address with length 32", async () => { + const recipient = keccak256(admin.account!.address); + const lenrecipient = 32; + const depositData = createERCDepositData( + tokenAmount, + lenrecipient, + recipient + ); + + const depositTx = await BridgeInstance.write.deposit([ + destinationDomainID, + resourceID, + depositData, + feeData + ], + { + account: depositor.account + } + ); + + await expect(depositTx).to.emit(BridgeInstance, "Deposit").withArgs( + destinationDomainID, + resourceID.toLowerCase(), + expectedDepositNonce, + depositor, + depositData, + null + ); + }); + + it(`When non-contract addresses are whitelisted in the handler, + deposits which the addresses are set as a token address will be failed`, async () => { + const NonContract_Address = "0x0000000000000000000000000000000000001111"; + const resourceID_NonContract_Address = createResourceID( + NonContract_Address, + originDomainID + ); + const resourceID_EOA_Address = createResourceID( + EOA_Address.account!.address, + originDomainID + ); + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID_NonContract_Address, + NonContract_Address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID_EOA_Address, + EOA_Address.account!.address, + emptySetResourceData + ]); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID_NonContract_Address, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).to.be.revertedWith("ERC20: not a contract"); + + await expect( + BridgeInstance.write.deposit([ + destinationDomainID, + resourceID_EOA_Address, + depositData, + feeData + ], + { + account: depositor.account + } + ) + ).to.be.revertedWith("ERC20: not a contract"); + }); +}); diff --git a/test/handlers/xc20/depositBurn.js b/test/handlers/xc20/depositBurn.js deleted file mode 100644 index 14e01298..00000000 --- a/test/handlers/xc20/depositBurn.js +++ /dev/null @@ -1,104 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const XC20HandlerContract = artifacts.require("XC20Handler"); - -contract("XC20Handler - [Deposit Burn XC20]", async (accounts) => { - const domainID = 1; - - const depositorAddress = accounts[1]; - const recipientAddress = accounts[2]; - - const initialTokenAmount = 100; - const depositAmount = 10; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance1; - let ERC20MintableInstance2; - let XC20HandlerInstance; - - let resourceID1; - let resourceID2; - let burnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ]); - - resourceID1 = Helpers.createResourceID( - ERC20MintableInstance1.address, - domainID - ); - resourceID2 = Helpers.createResourceID( - ERC20MintableInstance2.address, - domainID - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC20MintableInstance1.address, - ERC20MintableInstance2.address, - ]; - burnableContractAddresses = [ERC20MintableInstance1.address]; - - await Promise.all([ - XC20HandlerContract.new(BridgeInstance.address).then( - (instance) => (XC20HandlerInstance = instance) - ), - ERC20MintableInstance1.mint(depositorAddress, initialTokenAmount), - ]); - - await Promise.all([ - ERC20MintableInstance1.approve( - XC20HandlerInstance.address, - depositAmount, - {from: depositorAddress} - ), - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - resourceID1, - ERC20MintableInstance1.address, - emptySetResourceData - ), - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - resourceID2, - ERC20MintableInstance2.address, - emptySetResourceData - ), - BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - ERC20MintableInstance1.address - ), - ]); - - depositData = Helpers.createERCDepositData( - depositAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("[sanity] burnableContractAddresses should be marked as burnable", async () => { - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); -}); diff --git a/test/handlers/xc20/depositBurn.test.ts b/test/handlers/xc20/depositBurn.test.ts new file mode 100644 index 00000000..806185ed --- /dev/null +++ b/test/handlers/xc20/depositBurn.test.ts @@ -0,0 +1,105 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {WalletClient} from "viem"; +import {mpcAddress} from "../../helpers"; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex} from "viem"; +import {assert} from "chai"; + +describe("XC20Handler - [Deposit Burn XC20]", () => { + const domainID = 1; + + const initialTokenAmount = BigInt(100); + const depositAmount = BigInt(10); + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"]; + let XC20HandlerInstance: ContractTypesMap["XC20Handler"]; + + let admin: WalletClient; + let depositor: WalletClient; + let recipient: WalletClient; + let EOA_Address: WalletClient; + + let resourceID1: Hex; + let resourceID2: Hex; + let depositData: Hex; + let burnableContractAddresses: Array; + + before(async () => { + ({ + BridgeInstance, + XC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + depositor, + recipient, + EOA_Address, + ] = await hre.viem.getWalletClients(); + + + resourceID1 = createResourceID( + ERC20MintableInstance1.address, + domainID + ); + resourceID2 = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + + burnableContractAddresses = [ERC20MintableInstance1.address]; + + await ERC20MintableInstance1.write.mint([depositor.account!.address, initialTokenAmount]); + + await ERC20MintableInstance1.write.approve([ + XC20HandlerInstance.address, + depositAmount + ], + { + account: depositor.account + } + ); + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID1, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID2, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + await BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + ERC20MintableInstance1.address + ]); + + depositData = createERCDepositData( + depositAmount, + 20, + recipient + ); + + // set MPC address to unpause the Bridge + await BridgeInstance.write.endKeygen([mpcAddress]); + }); + + it("[sanity] burnableContractAddresses should be marked as burnable", async () => { + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await XC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + burnableAddress + ])); + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); +}); diff --git a/test/handlers/xc20/isBurnable.js b/test/handlers/xc20/isBurnable.js deleted file mode 100644 index 334db6eb..00000000 --- a/test/handlers/xc20/isBurnable.js +++ /dev/null @@ -1,218 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const XC20HandlerContract = artifacts.require("XC20Handler"); - -contract("XC20Handler - [Burn XC20]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance1; - let ERC20MintableInstance2; - let resourceID1; - let resourceID2; - let initialResourceIDs; - let initialContractAddresses; - let burnableContractAddresses; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ]); - - resourceID1 = Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - resourceID2 = Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - initialResourceIDs = [resourceID1, resourceID2]; - initialContractAddresses = [ - ERC20MintableInstance1.address, - ERC20MintableInstance2.address, - ]; - burnableContractAddresses = [ERC20MintableInstance1.address]; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes(XC20HandlerContract.new(BridgeInstance.address)); - }); - - it("burnableContractAddresses should be marked as burnable", async () => { - const XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - for (const burnableAddress of burnableContractAddresses) { - const isBurnable = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - burnableAddress - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - } - }); - - it("ERC20MintableInstance2.address should not be marked as burnable", async () => { - const XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - const isBurnable = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).isBurnable; - - assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); - }); - - it("ERC20MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { - const XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < burnableContractAddresses.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - burnableContractAddresses[i] - ) - ); - } - - await BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - ERC20MintableInstance2.address - ); - const isBurnable = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).isBurnable; - - assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); - }); - - it(`XC20MintableInstances should not be marked as - burnable after setResource is called on already burnable tokens`, async () => { - const XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetBurnable( - XC20HandlerInstance.address, - initialContractAddresses[i] - ) - ); - } - - // tokens should be marked as burnable - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableBeforeReRegisteringResource = ( - await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); - } - - // re-register resource - sets isBurnable to false for tokens - for (i = 0; i < initialResourceIDs.length; i++) { - await TruffleAssert.passes( - BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[i], - initialContractAddresses[i], - emptySetResourceData - ) - ); - } - - // tokens should not be marked as burnable if resource is re-registered - for (i = 0; i < initialResourceIDs.length; i++) { - const isBurnableAfterReRegisteringResource = ( - await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - initialContractAddresses[i] - ) - ).isBurnable; - - assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); - } - }); -}); diff --git a/test/handlers/xc20/isBurnable.test.ts b/test/handlers/xc20/isBurnable.test.ts new file mode 100644 index 00000000..7fcfea8d --- /dev/null +++ b/test/handlers/xc20/isBurnable.test.ts @@ -0,0 +1,203 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {WalletClient} from "viem"; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex} from "viem"; +import {assert, expect} from "chai"; + +describe("XC20Handler - [Burn XC20]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"]; + let XC20HandlerInstance: ContractTypesMap["XC20Handler"]; + let resourceID1: Hex; + let resourceID2: Hex; + let initialResourceIDs: Array; + let initialContractAddresses: Array; + let burnableContractAddresses: Array; + + let mockBridge: WalletClient; + + before(async () => { + ({ + BridgeInstance, + XC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + mockBridge, + ] = await hre.viem.getWalletClients(); + + resourceID1 = createResourceID( + ERC20MintableInstance1.address, + domainID + ); + resourceID2 = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + initialResourceIDs = [resourceID1, resourceID2]; + initialContractAddresses = [ + ERC20MintableInstance1.address, + ERC20MintableInstance2.address, + ]; + burnableContractAddresses = [ERC20MintableInstance1.address]; + }); + + it("burnableContractAddresses should be marked as burnable", async () => { + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + for (const burnableAddress of burnableContractAddresses) { + const isBurnable = (await XC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + burnableAddress + ])); + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + } + }); + + it("ERC20MintableInstance2.address should not be marked as burnable", async () => { + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + const isBurnable = (await XC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ])); + + assert.isFalse(isBurnable, "Contract shouldn't be marked burnable"); + }); + + it("ERC20MintableInstance2.address should be marked as burnable after setBurnable is called", async () => { + const XC20HandlerInstance = await hre.viem.deployContract("XC20Handler", [mockBridge.account!.address]); + + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < burnableContractAddresses.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + burnableContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + await BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + ERC20MintableInstance2.address + ]); + const isBurnable = (await XC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ])); + + assert.isTrue(isBurnable, "Contract wasn't successfully marked burnable"); + }); + + it(`XC20MintableInstances should not be marked as + burnable after setResource is called on already burnable tokens`, async () => { + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetBurnable([ + XC20HandlerInstance.address, + initialContractAddresses[i] + ]) + ).not.to.be.reverted; + } + + // tokens should be marked as burnable + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableBeforeReRegisteringResource = ( + await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( + initialContractAddresses[i] + ) + ).isBurnable; + + assert.isTrue(isBurnableBeforeReRegisteringResource, "Contract wasn't successfully marked burnable"); + } + + // re-register resource - sets isBurnable to false for tokens + for (let i = 0; i < initialResourceIDs.length; i++) { + await expect( + BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + initialResourceIDs[i], + initialContractAddresses[i], + emptySetResourceData + ]) + ).not.to.be.reverted; + } + + // tokens should not be marked as burnable if resource is re-registered + for (let i = 0; i < initialResourceIDs.length; i++) { + const isBurnableAfterReRegisteringResource = ( + await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( + initialContractAddresses[i] + ) + ).isBurnable; + + assert.isFalse(isBurnableAfterReRegisteringResource, "Contract shouldn't be marked burnable"); + } + }); +}); diff --git a/test/handlers/xc20/isWhitelisted.js b/test/handlers/xc20/isWhitelisted.js deleted file mode 100644 index 9ea6db2a..00000000 --- a/test/handlers/xc20/isWhitelisted.js +++ /dev/null @@ -1,61 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const XC20HandlerContract = artifacts.require("XC20Handler"); - -contract("XC20Handler - [isWhitelisted]", async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance1; - let initialResourceIDs; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance1 = instance) - ), - ERC20MintableContract.new("token", "TOK").then( - (instance) => (ERC20MintableInstance2 = instance) - ), - ]); - - initialResourceIDs = []; - resourceID1 = Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - initialResourceIDs.push(resourceID1); - initialContractAddresses = [ERC20MintableInstance1.address]; - burnableContractAddresses = []; - }); - - it("[sanity] contract should be deployed successfully", async () => { - await TruffleAssert.passes(XC20HandlerContract.new(BridgeInstance.address)); - }); - - it("initialContractAddress should be whitelisted", async () => { - const XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - resourceID1, - ERC20MintableInstance1.address, - emptySetResourceData - ); - const isWhitelisted = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance1.address - )).isWhitelisted; - - assert.isTrue(isWhitelisted, "Contract wasn't successfully whitelisted"); - }); -}); diff --git a/test/handlers/xc20/isWhitelisted.test.ts b/test/handlers/xc20/isWhitelisted.test.ts new file mode 100644 index 00000000..0b4b4b65 --- /dev/null +++ b/test/handlers/xc20/isWhitelisted.test.ts @@ -0,0 +1,54 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex} from "viem"; +import {assert} from "chai"; + + +describe("XC20Handler - [isWhitelisted]", async () => { + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"]; + let XC20HandlerInstance: ContractTypesMap["XC20Handler"]; + + let resourceID: Hex; + + before(async () => { + ({ + BridgeInstance, + ERC20MintableInstance: ERC20MintableInstance1, + ERC20MintableInstance: ERC20MintableInstance2, + XC20HandlerInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + , + depositor, + recipient + ] = await hre.viem.getWalletClients(); + + resourceID = createResourceID( + ERC20MintableInstance1.address, + domainID + ); + }); + + it("initialContractAddress should be whitelisted", async () => { + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance.address, + resourceID, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + const isWhitelisted = (await XC20HandlerInstance.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance1.address + ]))[0]; + + assert.isTrue(isWhitelisted, "Contract wasn't successfully whitelisted"); + }); +}); diff --git a/test/handlers/xc20/setResourceIDAndContractAddress.js b/test/handlers/xc20/setResourceIDAndContractAddress.js deleted file mode 100644 index bfeda7bb..00000000 --- a/test/handlers/xc20/setResourceIDAndContractAddress.js +++ /dev/null @@ -1,220 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Ethers = require("ethers"); - -const Helpers = require("../../helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const XC20HandlerContract = artifacts.require("XC20Handler"); - -contract( - "XC20Handler - [setResourceIDAndContractAddress]", - async (accounts) => { - const domainID = 1; - const emptySetResourceData = "0x"; - - let BridgeInstance; - let ERC20MintableInstance1; - let XC20HandlerInstance; - let initialResourceIDs; - let initialContractAddresses; - - beforeEach(async () => { - (BridgeInstance = await Helpers.deployBridge(domainID, accounts[0])), - (ERC20MintableInstance1 = await ERC20MintableContract.new( - "token", - "TOK" - )); - - initialResourceIDs = [ - Ethers.utils.hexZeroPad( - ERC20MintableInstance1.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ), - ]; - initialContractAddresses = [ERC20MintableInstance1.address]; - burnableContractAddresses = []; - - XC20HandlerInstance = await XC20HandlerContract.new( - BridgeInstance.address - ); - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[0], - initialContractAddresses[0], - emptySetResourceData - ); - }); - - it("[sanity] ERC20MintableInstance1's resourceID and contract address should be set correctly", async () => { - const retrievedTokenAddress = - await XC20HandlerInstance._resourceIDToTokenContractAddress.call( - initialResourceIDs[0] - ); - assert.strictEqual( - Ethers.utils.getAddress(ERC20MintableInstance1.address), - retrievedTokenAddress - ); - - const retrievedResourceID = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance1.address - )).resourceID - - assert.strictEqual( - initialResourceIDs[0].toLowerCase(), - retrievedResourceID.toLowerCase() - ); - }); - - it("new resourceID and corresponding contract address should be set correctly", async () => { - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - const secondERC20ResourceID = Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - secondERC20ResourceID, - ERC20MintableInstance2.address, - emptySetResourceData - ); - - const retrievedTokenAddress = - await XC20HandlerInstance._resourceIDToTokenContractAddress.call( - secondERC20ResourceID - ); - assert.strictEqual( - Ethers.utils.getAddress(ERC20MintableInstance2.address).toLowerCase(), - retrievedTokenAddress.toLowerCase() - ); - - const retrievedResourceID = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).resourceID - - assert.strictEqual( - secondERC20ResourceID.toLowerCase(), - retrievedResourceID.toLowerCase() - ); - }); - - it("existing resourceID should be updated correctly with new token contract address", async () => { - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance2.address, - emptySetResourceData - ); - - const retrievedTokenAddress = - await XC20HandlerInstance._resourceIDToTokenContractAddress.call( - initialResourceIDs[0] - ); - assert.strictEqual(ERC20MintableInstance2.address, retrievedTokenAddress); - - const retrievedResourceID = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance2.address - )).resourceID - - assert.strictEqual( - initialResourceIDs[0].toLowerCase(), - retrievedResourceID.toLowerCase() - ); - }); - - it("existing resourceID should be updated correctly with new handler address", async () => { - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - XC20HandlerInstance2 = await XC20HandlerContract.new( - BridgeInstance.address - ); - - await BridgeInstance.adminSetResource( - XC20HandlerInstance2.address, - initialResourceIDs[0], - ERC20MintableInstance2.address, - emptySetResourceData - ); - - const bridgeHandlerAddress = - await BridgeInstance._resourceIDToHandlerAddress.call( - initialResourceIDs[0] - ); - assert.strictEqual( - bridgeHandlerAddress.toLowerCase(), - XC20HandlerInstance2.address.toLowerCase() - ); - }); - - it("existing resourceID should be replaced by new resourceID in handler", async () => { - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - initialResourceIDs[0], - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const ERC20MintableInstance2 = await ERC20MintableContract.new( - "token", - "TOK" - ); - const secondERC20ResourceID = Ethers.utils.hexZeroPad( - ERC20MintableInstance2.address + - Ethers.utils.hexlify(domainID).substr(2), - 32 - ); - - await BridgeInstance.adminSetResource( - XC20HandlerInstance.address, - secondERC20ResourceID, - ERC20MintableInstance1.address, - emptySetResourceData - ); - - const retrievedResourceID = (await XC20HandlerInstance._tokenContractAddressToTokenProperties.call( - ERC20MintableInstance1.address - )).resourceID - - assert.strictEqual( - secondERC20ResourceID.toLowerCase(), - retrievedResourceID.toLowerCase() - ); - - const retrievedContractAddress = - await XC20HandlerInstance._resourceIDToTokenContractAddress.call( - secondERC20ResourceID - ); - assert.strictEqual( - retrievedContractAddress.toLowerCase(), - ERC20MintableInstance1.address.toLowerCase() - ); - }); - } -); diff --git a/test/handlers/xc20/setResourceIDAndContractAddress.test.ts b/test/handlers/xc20/setResourceIDAndContractAddress.test.ts new file mode 100644 index 00000000..89c392e4 --- /dev/null +++ b/test/handlers/xc20/setResourceIDAndContractAddress.test.ts @@ -0,0 +1,192 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + + +import hre from 'hardhat'; +import {WalletClient} from "viem"; +import {ContractTypesMap} from "hardhat/types"; +import {createResourceID, deploySourceChainContracts} from "../../helpers"; +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {Hex} from "viem"; +import {assert, expect} from "chai"; + +describe("XC20Handler - [setResourceIDAndContractAddress]", () => { + const domainID = 1; + const emptySetResourceData = "0x"; + + let BridgeInstance: ContractTypesMap["Bridge"]; + let ERC20MintableInstance1: ContractTypesMap["ERC20PresetMinterPauser"]; + let ERC20MintableInstance2: ContractTypesMap["ERC20PresetMinterPauser"]; + let XC20HandlerInstance1: ContractTypesMap["XC20Handler"]; + let XC20HandlerInstance2: ContractTypesMap["XC20Handler"]; + + let resourceID: Hex; + + before(async () => { + ({ + BridgeInstance, + XC20HandlerInstance: XC20HandlerInstance1, + XC20HandlerInstance: XC20HandlerInstance2, + } = await loadFixture(deploySourceChainContracts)); + + resourceID = createResourceID( + ERC20MintableInstance1.address, + domainID + ); + + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance1.address, + resourceID, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + }); + + it("[sanity] ERC20MintableInstance1's resourceID and contract address should be set correctly", async () => { + const retrievedTokenAddress = + await XC20HandlerInstance1.read._resourceIDToTokenContractAddress([ + resourceID + ]); + assert.strictEqual( + ERC20MintableInstance1.address, + retrievedTokenAddress + ); + + const retrievedResourceID = (await XC20HandlerInstance1.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance1.address + ]))[0] + + assert.strictEqual( + resourceID.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + }); + + it("new resourceID and corresponding contract address should be set correctly", async () => { + const secondERC20ResourceID = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance1.address, + secondERC20ResourceID, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + + const retrievedTokenAddress = + await XC20HandlerInstance1.read._resourceIDToTokenContractAddress([ + secondERC20ResourceID + ]); + assert.strictEqual( + ERC20MintableInstance2.address, + retrievedTokenAddress + ); + + const retrievedResourceID = (await XC20HandlerInstance1.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ]))[0]; + + assert.strictEqual( + secondERC20ResourceID.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + }); + + it("existing resourceID should be updated correctly with new token contract address", async () => { + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance1.address, + resourceID, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance1.address, + resourceID, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + + const retrievedTokenAddress = + await XC20HandlerInstance1.read._resourceIDToTokenContractAddress([ + resourceID + ]); + assert.strictEqual(ERC20MintableInstance2.address, retrievedTokenAddress); + + const retrievedResourceID = (await XC20HandlerInstance1.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance2.address + ]))[0]; + + assert.strictEqual( + resourceID.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + }); + + it("existing resourceID should be updated correctly with new handler address", async () => { + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance1.address, + resourceID, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance2.address, + resourceID, + ERC20MintableInstance2.address, + emptySetResourceData + ]); + + const bridgeHandlerAddress = + await BridgeInstance.read._resourceIDToHandlerAddress([ + resourceID + ]); + assert.strictEqual( + bridgeHandlerAddress.toLowerCase(), + XC20HandlerInstance2.address.toLowerCase() + ); + }); + + it("existing resourceID should be replaced by new resourceID in handler", async () => { + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance1.address, + resourceID, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + const secondERC20ResourceID = createResourceID( + ERC20MintableInstance2.address, + domainID + ); + + await BridgeInstance.write.adminSetResource([ + XC20HandlerInstance1.address, + secondERC20ResourceID, + ERC20MintableInstance1.address, + emptySetResourceData + ]); + + const retrievedResourceID = (await XC20HandlerInstance1.read._tokenContractAddressToTokenProperties([ + ERC20MintableInstance1.address + ]))[0]; + + assert.strictEqual( + secondERC20ResourceID.toLowerCase(), + retrievedResourceID.toLowerCase() + ); + + const retrievedContractAddress = + await XC20HandlerInstance1.read._resourceIDToTokenContractAddress([ + secondERC20ResourceID + ]); + assert.strictEqual( + retrievedContractAddress.toLowerCase(), + ERC20MintableInstance1.address.toLowerCase() + ); + }); + } +); diff --git a/test/helpers.js b/test/helpers.js deleted file mode 100644 index 8857923b..00000000 --- a/test/helpers.js +++ /dev/null @@ -1,493 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - - const Ethers = require("ethers"); - const ethSigUtil = require("eth-sig-util"); - const Utils = require("../scripts/generateFuncSignatures"); - -const AccessControlSegregatorContract = artifacts.require( - "AccessControlSegregator" -); -const BridgeContract = artifacts.require("Bridge"); - -const blankFunctionSig = "0x00000000"; -const blankFunctionDepositorOffset = "0x0000"; -const AbiCoder = new Ethers.utils.AbiCoder(); -const mpcAddress = "0x1Ad4b1efE3Bc6FEE085e995FCF48219430e615C3"; -const mpcPrivateKey = - "0x497b6ae580cb1b0238f8b6b543fada697bc6f8768a983281e5e52a1a5bca4d58"; -const toHex = (covertThis, padding) => { - return Ethers.utils.hexZeroPad(Ethers.utils.hexlify(covertThis), padding); -}; - -const abiEncode = (valueTypes, values) => { - return AbiCoder.encode(valueTypes, values); -}; - -const getFunctionSignature = (contractInstance, functionName) => { - return contractInstance.abi.filter( - (abiProperty) => abiProperty.name === functionName - )[0].signature; -}; - -const createCallData = (contractInstance, functionName, valueTypes, values) => { - const signature = getFunctionSignature(contractInstance, functionName); - const encodedABI = abiEncode(valueTypes, values); - return signature + encodedABI.substr(2); -}; - -const createERCDepositData = ( - tokenAmountOrID, - lenRecipientAddress, - recipientAddress -) => { - return ( - "0x" + - toHex(tokenAmountOrID, 32).substr(2) + // Token amount or ID to deposit (32 bytes) - toHex(lenRecipientAddress, 32).substr(2) + // len(recipientAddress) (32 bytes) - recipientAddress.substr(2) - ); // recipientAddress (?? bytes) -}; - -const createERCWithdrawData = ( - tokenAddress, - recipientAddress, - tokenAmountOrID -) => { - return ( - "0x" + - toHex(tokenAddress, 32).substr(2) + - toHex(recipientAddress, 32).substr(2) + - toHex(tokenAmountOrID, 32).substr(2) - ); -}; - -const createERC1155DepositData = (tokenIDs, amounts) => { - return abiEncode(["uint[]", "uint[]"], [tokenIDs, amounts]); -}; - -const createERC1155DepositProposalData = ( - tokenIDs, - amounts, - recipient, - transferData -) => { - return abiEncode( - ["uint[]", "uint[]", "bytes", "bytes"], - [tokenIDs, amounts, recipient, transferData] - ); -}; - -const createERC1155WithdrawData = ( - tokenAddress, - recipient, - tokenIDs, - amounts, - transferData -) => { - return abiEncode( - ["address", "address", "uint[]", "uint[]", "bytes"], - [tokenAddress, recipient, tokenIDs, amounts, transferData] - ); -}; - -const createERC721DepositProposalData = ( - tokenAmountOrID, - lenRecipientAddress, - recipientAddress, - lenMetaData, - metaData -) => { - return ( - "0x" + - toHex(tokenAmountOrID, 32).substr(2) + // Token amount or ID to deposit (32 bytes) - toHex(lenRecipientAddress, 32).substr(2) + // len(recipientAddress) (32 bytes) - recipientAddress.substr(2) + // recipientAddress (?? bytes) - toHex(lenMetaData, 32).substr(2) + // len(metaData) (32 bytes) - toHex(metaData, lenMetaData).substr(2) - ); // metaData (?? bytes) -}; - -const createBtcDepositData = ( - transferAmount, - btcRecipientAddress -) => { - return Ethers.utils.solidityPack( - ["uint256", "uint256", "string"], - [transferAmount, btcRecipientAddress.length, btcRecipientAddress] - ) -} - -const advanceBlock = () => { - const provider = new Ethers.providers.JsonRpcProvider(); - const time = Math.floor(Date.now() / 1000); - return provider.send("evm_mine", [time]); -}; - -const advanceTime = (seconds) => { - const provider = new Ethers.providers.JsonRpcProvider(); - const time = Math.floor(Date.now() / 1000) + seconds; - return provider.send("evm_mine", [time]); -}; - -const createGmpDepositData = ( - executeFunctionSignature, - executeContractAddress, - maxFee, - depositor, - executionData, - depositorCheck = true -) => { - if (depositorCheck) { - // if "depositorCheck" is true -> append depositor address for destination chain check - executionData = executionData.concat(toHex(depositor, 32).substr(2)); - } - - return ( - "0x" + - toHex(maxFee, 32).substr(2) + // uint256 - toHex(executeFunctionSignature.substr(2).length / 2, 2).substr(2) + // uint16 - executeFunctionSignature.substr(2) + // bytes - toHex(executeContractAddress.substr(2).length / 2, 1).substr(2) + // uint8 - executeContractAddress.substr(2) + // bytes - toHex(depositor.substr(2).length / 2, 1).substr(2) + // uint8 - depositor.substr(2) + // bytes - executionData.substr(2) - ) // bytes - .toLowerCase(); -}; - -const constructGenericHandlerSetResourceData = (...args) => { - return args.reduce((accumulator, currentArg) => { - if (typeof currentArg === "number") { - currentArg = toHex(currentArg, 2); - } - return accumulator + currentArg.substr(2); - }); -}; - -const createResourceID = (contractAddress, domainID) => { - return toHex(contractAddress + toHex(domainID, 1).substr(2), 32); -}; - -const assertObjectsMatch = (expectedObj, actualObj) => { - for (const expectedProperty of Object.keys(expectedObj)) { - assert.property( - actualObj, - expectedProperty, - `actualObj does not have property: ${expectedProperty}` - ); - - let expectedValue = expectedObj[expectedProperty]; - let actualValue = actualObj[expectedProperty]; - - // If expectedValue is not null, we can expected actualValue to not be null as well - if (expectedValue !== null) { - // Handling mixed case ETH addresses - // If expectedValue is a string, we can expected actualValue to be a string as well - if (expectedValue.toLowerCase !== undefined) { - expectedValue = expectedValue.toLowerCase(); - actualValue = actualValue.toLowerCase(); - } - - // Handling BigNumber.js instances - if (actualValue.toNumber !== undefined) { - actualValue = actualValue.toNumber(); - } - - // Truffle seems to return uint/ints as strings - // Also handles when Truffle returns hex number when expecting uint/int - if ( - (typeof expectedValue === "number" && - typeof actualValue === "string") || - (Ethers.utils.isHexString(actualValue) && - typeof expectedValue === "number") - ) { - actualValue = parseInt(actualValue); - } - } - - assert.deepEqual( - expectedValue, - actualValue, - `expectedValue: ${expectedValue} does not match actualValue: ${actualValue}` - ); - } -}; -//uint72 nonceAndID = (uint72(depositNonce) << 8) | uint72(domainID); -const nonceAndId = (nonce, id) => { - return ( - Ethers.utils.hexZeroPad(Ethers.utils.hexlify(nonce), 8) + - Ethers.utils.hexZeroPad(Ethers.utils.hexlify(id), 1).substr(2) - ); -}; - -const createOracleFeeData = (oracleResponse, privateKey, amount) => { - /* - feeData structure: - ber*10^18: uint256 - ter*10^18: uint256 - dstGasPrice: uint256 - timestamp: uint256 - fromDomainID: uint8 encoded as uint256 - toDomainID: uint8 encoded as uint256 - resourceID: bytes32 - msgGasLimit: uint256 - sig: bytes(65 bytes) - - total in bytes: - message: - 32 * 8 = 256 - message + sig: - 256 + 65 = 321 - - amount: uint256 - total feeData length: 353 - */ - - const oracleMessage = Ethers.utils.solidityPack( - [ - "uint256", - "uint256", - "uint256", - "uint256", - "uint256", - "uint256", - "bytes32", - "uint256", - ], - [ - oracleResponse.ber, - oracleResponse.ter, - oracleResponse.dstGasPrice, - oracleResponse.expiresAt, - oracleResponse.fromDomainID, - oracleResponse.toDomainID, - oracleResponse.resourceID, - oracleResponse.msgGasLimit, - ] - ); - const messageHash = Ethers.utils.keccak256(oracleMessage); - const signingKey = new Ethers.utils.SigningKey(privateKey); - const messageHashBytes = Ethers.utils.arrayify(messageHash); - const signature = signingKey.signDigest(messageHashBytes); - const rawSignature = Ethers.utils.joinSignature(signature); - return oracleMessage + rawSignature.substr(2) + toHex(amount, 32).substr(2); -}; - -const decimalToPaddedBinary = (decimal) => { - return decimal.toString(2).padStart(64, "0"); -}; - -// filter out only func signatures -const accessControlFuncSignatures = Utils.generateAccessControlFuncSignatures().map(e => e.hash); - -const deployBridge = async (domainID, admin) => { - const accessControlInstance = await AccessControlSegregatorContract.new( - accessControlFuncSignatures, - Array(13).fill(admin) - ); - return await BridgeContract.new(domainID, accessControlInstance.address); -}; - -const signTypedProposal = (bridgeAddress, proposals, chainId = 1) => { - const name = "Bridge"; - const version = "3.1.0"; - - const EIP712Domain = [ - {name: "name", type: "string"}, - {name: "version", type: "string"}, - {name: "chainId", type: "uint256"}, - {name: "verifyingContract", type: "address"}, - ]; - - const types = { - EIP712Domain: EIP712Domain, - Proposal: [ - {name: "originDomainID", type: "uint8"}, - {name: "depositNonce", type: "uint64"}, - {name: "resourceID", type: "bytes32"}, - {name: "data", type: "bytes"}, - ], - Proposals: [{name: "proposals", type: "Proposal[]"}], - }; - - return ethSigUtil.signTypedMessage(Ethers.utils.arrayify(mpcPrivateKey), { - data: { - types: types, - domain: { - name, - version, - chainId, - verifyingContract: bridgeAddress, - }, - primaryType: "Proposals", - message: { - proposals: proposals, - }, - }, - }); -}; - -const mockSignTypedProposalWithInvalidChainID = (bridgeAddress, proposals) => { - return signTypedProposal(bridgeAddress, proposals, 3); -}; - -const createDepositProposalDataFromHandlerResponse = ( - depositTx, - lenRecipientAddress, - recipientAddress -) => { - const amountFromHandlerResponse = Ethers.BigNumber.from(depositTx.logs[0].args.handlerResponse); - return createERCDepositData(amountFromHandlerResponse, lenRecipientAddress, recipientAddress); -}; - - -// This helper can be used to prepare execution data for GmpHandler -// The execution data will be packed together with depositorAddress before execution. -// If the target function parameters include reference types then the offsets should be kept consistent. -// This function packs the parameters together with a fake address and removes the address. -// After repacking the data in the handler together with depositorAddress, the offsets will be correct. -// Usage: use this function to prepare execution data, -// then pack the result together with executeFunctionSignature, maxFee etc -// (using the createGmpDepositData() helper) -// and then pass the data to Bridge.deposit(). -const createGmpExecutionData = ( - types, - values -) => { - types.unshift("address"); - values.unshift(Ethers.constants.AddressZero); - return "0x" + abiEncode(types, values).substr(66); -}; - -// truffle doesn't support decoding custom errors, this is adapted from -// https://github.com/trufflesuite/truffle/issues/4123 -const expectToRevertWithCustomError = async function(promise, expectedErrorSignature) { - try { - await promise; - } catch (error) { - if (!error.data) { - throw error; - } - const encoded = web3.eth.abi.encodeFunctionSignature(expectedErrorSignature); - const returnValue = error.data.result || error.data; - // expect event error and provided error signatures to match - assert.equal(returnValue.slice(0, 10), encoded); - - let inputParams; - // match everything between () in function signature - const regex = RegExp(/\(([^)]+)\)/); - if(regex.exec(expectedErrorSignature)) { - const types = regex.exec(expectedErrorSignature)[1].split(","); - inputParams = Ethers.utils.defaultAbiCoder.decode( - types, - Ethers.utils.hexDataSlice(returnValue, 4) - ); - } - return inputParams; - } - assert.fail("Expected a custom error but none was received"); -} - -const reverts = async function(promise, expectedErrorMessage) { - try { - await promise; - } catch (error) { - if (expectedErrorMessage) { - const message = error.reason || error.hijackedStack.split("revert ")[1].split("\n")[0]; - assert.equal(message, expectedErrorMessage); - } - return true; - } - assert.fail("Expected an error message but none was received"); -} - -const passes = async function(promise) { - try { - await promise; - } catch (error) { - assert.fail("Revert reason: " + error.data.result); - } -} - -const ACTIONS_ARRAY_ABI = -"tuple(uint256 nativeValue, address callTo, address approveTo, address tokenSend, address tokenReceive, bytes data)[]"; - -const createMessageCallData = function(transactionId, actions, receiver) { - return abiEncode( - ["bytes32", ACTIONS_ARRAY_ABI, "address"], - [ - transactionId, - actions.map(action => [ - action.nativeValue, - action.callTo, - action.approveTo, - action.tokenSend, - action.tokenReceive, - action.data, - ]), - receiver - ] - ) -} - -const createOptionalContractCallDepositData = function(amount, recipient, executionGasAmount, message) { - return ( - "0x" + - toHex(amount, 32).substr(2) + // uint256 - toHex(recipient.substr(2).length / 2, 32).substr(2) + // uint256 - recipient.substr(2) + // bytes - toHex(executionGasAmount, 32).substr(2) + // uint256 - toHex(message.substr(2).length / 2, 32).substr(2) + // uint256 - message.substr(2) // bytes - ) -} - -const getBalance = async (address) => { - return BigInt(await web3.eth.getBalance(address)); -}; - -const getTokenBalance = async (token, address) => { - return BigInt(await token.balanceOf(address)); -}; - -module.exports = { - advanceBlock, - advanceTime, - blankFunctionSig, - blankFunctionDepositorOffset, - mpcAddress, - mpcPrivateKey, - accessControlFuncSignatures, - toHex, - abiEncode, - getFunctionSignature, - createCallData, - createERCDepositData, - createERCWithdrawData, - createERC1155DepositData, - createERC1155DepositProposalData, - createERC1155WithdrawData, - createGmpDepositData, - createBtcDepositData, - constructGenericHandlerSetResourceData, - createERC721DepositProposalData, - createResourceID, - assertObjectsMatch, - nonceAndId, - createOracleFeeData, - decimalToPaddedBinary, - deployBridge, - signTypedProposal, - mockSignTypedProposalWithInvalidChainID, - createDepositProposalDataFromHandlerResponse, - createGmpExecutionData, - expectToRevertWithCustomError, - reverts, - passes, - createMessageCallData, - createOptionalContractCallDepositData, - getBalance, - getTokenBalance, -}; diff --git a/test/helpers.ts b/test/helpers.ts new file mode 100644 index 00000000..d2bf35f5 --- /dev/null +++ b/test/helpers.ts @@ -0,0 +1,464 @@ +import hre from 'hardhat'; +import {ContractTypesMap, HardhatRuntimeEnvironment} from 'hardhat/types'; +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only +import { AbiParameter, Account, Address, concat, createPublicClient, encodeAbiParameters, encodePacked, getAddress, GetBalanceParameters, GetContractReturnType, Hex, http, pad, parseAbiItem, parseAbiParameters, size, toBytes, toFunctionSelector, toHex, WalletClient, zeroAddress } from 'viem'; +import {generateAccessControlFuncSignatures} from '../scripts/generateFuncSignatures'; +import {signTypedData, SignTypedDataVersion} from '@metamask/eth-sig-util'; +import {hardhat} from 'viem/chains'; +import {Proposal} from '../types'; + +const publicClient = createPublicClient({ + chain: hardhat, + transport: http(), +}); + +const UNISWAP_V3_FACTORY_ADDRESS = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; +const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; + +export const blankFunctionSig = "0x00000000" as unknown as Hex; +export const blankFunctionDepositorOffset = "0x0000" as unknown as Hex; +export const mpcAddress = "0x1Ad4b1efE3Bc6FEE085e995FCF48219430e615C3" as unknown as Hex; +export const mpcPrivateKey = + "0x497b6ae580cb1b0238f8b6b543fada697bc6f8768a983281e5e52a1a5bca4d58" as unknown as Hex; + +const accessControlFuncSignatures = generateAccessControlFuncSignatures(); + + +export async function deploySourceChainContracts() { + const [authorizedAddress] = await hre.viem.getWalletClients(); + const recoverGas = BigInt(100000); + const gasUsed = 100000; + const domainID = 1 + const resourceID = toHex(650, {size:32}); + + const AccessControlSegregatorInstance = await hre.viem.deployContract("AccessControlSegregator", [ + accessControlFuncSignatures, + Array(13).fill(authorizedAddress.account.address) + ]); + const DefaultMessageReceiverInstance = await hre.viem.deployContract("DefaultMessageReceiver", [[], recoverGas]); + const BridgeInstance = await hre.viem.deployContract("Bridge", [domainID, AccessControlSegregatorInstance.address]); + const NativeTokenAdapterInstance = await hre.viem.deployContract("NativeTokenTransferGateway", [BridgeInstance.address, resourceID]); + const ERC20MintableInstance = await hre.viem.deployContract("ERC20PresetMinterPauser", ["Token", "TOK"]); + const ERC20HandlerInstance = await hre.viem.deployContract("ERC20Handler", [BridgeInstance.address, DefaultMessageReceiverInstance.address]); + const ERC1155MintableInstance = await hre.viem.deployContract("ERC1155PresetMinterPauser", ["TOK"]); + const ERC1155HandlerInstance = await hre.viem.deployContract("ERC1155Handler", [BridgeInstance.address]); + const ERC721MintableInstance = await hre.viem.deployContract("ERC721MinterBurnerPauser", ["Token", "TOK", ""]); + const ERC721HandlerInstance = await hre.viem.deployContract("ERC721Handler", [BridgeInstance.address]); + const FeeHandlerRouterInstance = await hre.viem.deployContract("FeeHandlerRouter", [BridgeInstance.address]); + const BasicFeeHandlerInstance = await hre.viem.deployContract("BasicFeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address]); + const PercentageFeeHandlerInstance = await hre.viem.deployContract("PercentageERC20FeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address]); + const TwapNativeTokenFeeHandlerInstance = await hre.viem.deployContract("TwapNativeTokenFeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address, gasUsed]); + const TwapOracleInstance = await hre.viem.deployContract("TwapOracle", [UNISWAP_V3_FACTORY_ADDRESS, WETH_ADDRESS]); + const TwapGenericFeeHandlerInstance = await hre.viem.deployContract("TwapGenericFeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address]); + const GmpHandlerInstance = await hre.viem.deployContract("GmpHandler", [BridgeInstance.address]); + const NativeTokenHandlerInstance = await hre.viem.deployContract("NativeTokenHandler", [BridgeInstance.address, NativeTokenAdapterInstance.address, DefaultMessageReceiverInstance.address]); + const TestStoreInstance = await hre.viem.deployContract("TestStore"); + const TestDepositInstance = await hre.viem.deployContract("TestDeposit"); + const XC20TestInstance = await hre.viem.deployContract("XC20Test"); + const XC20HandlerInstance = await hre.viem.deployContract("XC20Handler", [BridgeInstance.address]); + const HandlerRevert = await hre.viem.deployContract("HandlerRevert", [BridgeInstance.address]); + const FROSTKeygenInstance = await hre.viem.deployContract("FROSTKeygen"); + const RetryInstance = await hre.viem.deployContract("Retry"); + const WithDepositorInstance = await hre.viem.deployContract("WithDepositor"); + const ReturnDataInstance = await hre.viem.deployContract("ReturnData"); + const ForwarderInstance = await hre.viem.deployContract("Forwarder"); + const TestTargetInstance = await hre.viem.deployContract("TestTarget"); + + + return { + DefaultMessageReceiverInstance, + BridgeInstance, + NativeTokenAdapterInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC1155MintableInstance, + ERC1155HandlerInstance, + ERC721MintableInstance, + ERC721HandlerInstance, + FeeHandlerRouterInstance, + BasicFeeHandlerInstance, + PercentageFeeHandlerInstance, + TwapNativeTokenFeeHandlerInstance, + TwapOracleInstance, + TwapGenericFeeHandlerInstance, + NativeTokenHandlerInstance, + GmpHandlerInstance, + TestStoreInstance, + TestDepositInstance, + XC20TestInstance, + XC20HandlerInstance, + HandlerRevert, + FROSTKeygenInstance, + RetryInstance, + WithDepositorInstance, + ReturnDataInstance, + ForwarderInstance, + TestTargetInstance + }; +} + +export async function deployDestinationChainContracts(hre: HardhatRuntimeEnvironment) { + const [authorizedAddress] = await hre.viem.getWalletClients(); + const recoverGas = BigInt(100000); + const gasUsed = 100000; + const domainID = 2 + const resourceID = toHex(650, {size:32}); + + const AccessControlSegregatorInstance = await hre.viem.deployContract("AccessControlSegregator", [ + accessControlFuncSignatures, + Array(13).fill(authorizedAddress.account.address) + ]); + const DefaultMessageReceiverInstance = await hre.viem.deployContract("DefaultMessageReceiver", [[], recoverGas]); + const BridgeInstance = await hre.viem.deployContract("Bridge", [domainID, AccessControlSegregatorInstance.address]); + const NativeTokenAdapterInstance = await hre.viem.deployContract("NativeTokenTransferGateway", [BridgeInstance.address, resourceID]); + const ERC20MintableInstance = await hre.viem.deployContract("ERC20PresetMinterPauser", ["Token", "TOK"]); + const ERC20HandlerInstance = await hre.viem.deployContract("ERC20Handler", [BridgeInstance.address, DefaultMessageReceiverInstance.address]); + const ERC1155MintableInstance = await hre.viem.deployContract("ERC1155PresetMinterPauser", ["TOK"]); + const ERC1155HandlerInstance = await hre.viem.deployContract("ERC1155Handler", [BridgeInstance.address]); + const ERC721MintableInstance = await hre.viem.deployContract("ERC721MinterBurnerPauser", ["Token", "TOK", ""]); + const ERC721HandlerInstance = await hre.viem.deployContract("ERC721Handler", [BridgeInstance.address]); + const FeeHandlerRouterInstance = await hre.viem.deployContract("FeeHandlerRouter", [BridgeInstance.address]); + const BasicFeeHandlerInstance = await hre.viem.deployContract("BasicFeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address]); + const PercentageFeeHandlerInstance = await hre.viem.deployContract("PercentageERC20FeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address]); + const TwapNativeTokenFeeHandlerInstance = await hre.viem.deployContract("TwapNativeTokenFeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address, gasUsed]); + const TwapOracleInstance = await hre.viem.deployContract("TwapOracle", [UNISWAP_V3_FACTORY_ADDRESS, WETH_ADDRESS]); + const TwapGenericFeeHandlerInstance = await hre.viem.deployContract("TwapGenericFeeHandler", [BridgeInstance.address, FeeHandlerRouterInstance.address]); + const GmpHandlerInstance = await hre.viem.deployContract("GmpHandler", [BridgeInstance.address]); + const NativeTokenHandlerInstance = await hre.viem.deployContract("NativeTokenHandler", [BridgeInstance.address, NativeTokenAdapterInstance.address, DefaultMessageReceiverInstance.address]); + const TestStoreInstance = await hre.viem.deployContract("TestStore"); + const TestDepositInstance = await hre.viem.deployContract("TestDeposit"); + const XC20TestInstance = await hre.viem.deployContract("XC20Test"); + const XC20HandlerInstance = await hre.viem.deployContract("XC20Handler", [BridgeInstance.address]); + const HandlerRevert = await hre.viem.deployContract("HandlerRevert", [BridgeInstance.address]); + const FROSTKeygenInstance = await hre.viem.deployContract("FROSTKeygen"); + const RetryInstance = await hre.viem.deployContract("Retry"); + const WithDepositorInstance = await hre.viem.deployContract("WithDepositor"); + const ReturnDataInstance = await hre.viem.deployContract("ReturnData"); + const ForwarderInstance = await hre.viem.deployContract("Forwarder"); + const TestTargetInstance = await hre.viem.deployContract("TestTarget"); + + + return { + DefaultMessageReceiverInstance, + BridgeInstance, + NativeTokenAdapterInstance, + ERC20MintableInstance, + ERC20HandlerInstance, + ERC1155MintableInstance, + ERC1155HandlerInstance, + ERC721MintableInstance, + ERC721HandlerInstance, + FeeHandlerRouterInstance, + BasicFeeHandlerInstance, + PercentageFeeHandlerInstance, + TwapNativeTokenFeeHandlerInstance, + TwapOracleInstance, + TwapGenericFeeHandlerInstance, + NativeTokenHandlerInstance, + GmpHandlerInstance, + TestStoreInstance, + TestDepositInstance, + XC20TestInstance, + XC20HandlerInstance, + HandlerRevert, + FROSTKeygenInstance, + RetryInstance, + WithDepositorInstance, + ReturnDataInstance, + ForwarderInstance, + TestTargetInstance + }; +} + +export function createERCDepositData( + tokenAmountOrID: bigint, + lenRecipientAddress: number, + recipientAddress: Hex +): Hex { + return concat( + [ + trimPrefix(toHex(tokenAmountOrID, {size:32})), // Token amount or ID to deposit (32 bytes) + trimPrefix(toHex(lenRecipientAddress, {size: 32})), // len(recipientAddress) (32 bytes) + trimPrefix(recipientAddress) // recipientAddress (20 bytes) + ] + ); +}; + +export function trimPrefix(string: string | Hex):Hex { + return string.substring(2) as unknown as Hex +} + +export function createERCWithdrawData( + tokenAddress: Hex, + recipientAddress: Hex, + tokenAmountOrID: bigint +): Hex { + return concat( + [ + trimPrefix(pad(tokenAddress, {size: 32})), + trimPrefix(pad(recipientAddress, {size: 32})), + trimPrefix(toHex(tokenAmountOrID, {size: 32})) + ] + ) +}; + +export function createERC1155DepositData( + tokenIDs: Array, + amounts: Array +): Hex { + return encodeAbiParameters( + parseAbiParameters( + [ + "uint256[]", "uint256[]" + ] + ), + [tokenIDs, amounts] + ); +}; + +export function createERC1155DepositProposalData( + tokenIDs: Array, + amounts: Array, + recipient: Hex, + transferData: Hex +):Hex { + return encodeAbiParameters( + parseAbiParameters( + ["uint[]", "uint[]", "bytes", "bytes"] + ), + [tokenIDs, amounts, recipient, transferData] + ); +}; + +export function createERC1155WithdrawData( + tokenAddress: Hex, + recipient: Hex, + tokenIDs: Array, + amounts: Array, + transferData: Hex +):Hex { + return encodeAbiParameters( + parseAbiParameters( + ["address", "address", "uint256[]", "uint256[]", "bytes"], + ), + [tokenAddress, recipient, tokenIDs, amounts, transferData] + ); +}; + +export function createERC721DepositProposalData( + tokenAmountOrID: bigint, + lenRecipientAddress: number, + recipientAddress: Hex, + lenMetaData: number, + metaData: Hex +): Hex { + return concat([ + toHex(tokenAmountOrID, {size: 32}), // Token amount or ID to deposit (32 bytes) + trimPrefix(toHex(lenRecipientAddress, {size: 32})), // len(recipientAddress) (32 bytes) + trimPrefix(recipientAddress), // recipientAddress (bytes) + trimPrefix(toHex(lenMetaData, {size: 32})), // len(metaData) (32 bytes) + trimPrefix(toHex(metaData, {size: lenMetaData})) // metaData (bytes) + ]); +}; + +export function createBtcDepositData( + transferAmount: bigint, + btcRecipientAddress: string +): Hex{ + return encodePacked( + ["uint256", "uint256", "string"], + [transferAmount, BigInt(btcRecipientAddress.length), btcRecipientAddress] + ) +} + +export function createGmpDepositData( + executeFunctionSignature: Hex, + executeContractAddress: Hex, + maxFee: bigint, + depositor: Hex, + executionData: Hex, + depositorCheck = true +): Hex { + if (depositorCheck) { + // if "depositorCheck" is true -> append depositor address for destination chain check + executionData = concat([ + executionData, + trimPrefix(pad(depositor, {size: 32})) + ]) + } + + return concat([ + toHex(maxFee, {size:32}), // uint256 + trimPrefix(toHex(trimPrefix(executeFunctionSignature).length / 2, {size:2})), // uint16 + trimPrefix(executeFunctionSignature), // bytes + trimPrefix(toHex(trimPrefix(executeContractAddress).length / 2, {size:1})), // uint8 + trimPrefix(executeContractAddress), // bytes + trimPrefix(toHex(trimPrefix(depositor).length / 2, {size:1})), // uint8 + trimPrefix(depositor), // bytes + trimPrefix(executionData) // bytes + ]) +}; + +export function constructGenericHandlerSetResourceData(...args: Array) { + return args.reduce((accumulator, currentArg) => { + if (typeof currentArg === "number") { + currentArg = toHex(currentArg, {size:2}); + } + return accumulator + currentArg.substring(2) as unknown as Hex; + }); +}; + +export function createResourceID(contractAddress: Hex, domainID: number) { + return pad( + concat([ + contractAddress, + toHex(domainID, {size: 1}), + ]), {size: 32}); +}; + +export function decimalToPaddedBinary(decimal: number): Hex { + return decimal.toString(2).padStart(64, "0") as unknown as Hex; +}; + +export function signTypedProposal(bridgeAddress: Hex, proposals: Array, chainId = 1) :Hex { + const name = "Bridge"; + + const EIP712Domain = [ + {name: "name", type: "string"}, + {name: "version", type: "string"}, + {name: "chainId", type: "uint256"}, + {name: "verifyingContract", type: "address"}, + ]; + + const types = { + EIP712Domain: EIP712Domain, + Proposal: [ + {name: "originDomainID", type: "uint8"}, + {name: "depositNonce", type: "uint64"}, + {name: "resourceID", type: "bytes32"}, + {name: "data", type: "bytes"}, + ], + Proposals: [{name: "proposals", type: "Proposal[]"}], + }; + + return signTypedData({ + privateKey: Buffer.from(mpcPrivateKey), + data: { + types: types, + domain: { + name, + chainId, + verifyingContract: bridgeAddress, + }, + primaryType: "Proposals", + message: { + proposals: proposals, + }, + }, + version: SignTypedDataVersion.V3, + }) as Hex; +}; + +export function mockSignTypedProposalWithInvalidChainID (bridgeAddress: Hex, proposals:Array): Hex { + return signTypedProposal(bridgeAddress, proposals, 3) as Hex; +}; + +export async function createDepositProposalDataFromHandlerResponse( + contractAddress: Address, + depositTx: Hex, + lenRecipientAddress: number, + recipientAddress: Hex +):Promise { + const logs = await publicClient.getLogs({ + address: contractAddress, + event: parseAbiItem('emit Deposit(destinationDomainID, resourceID, depositNonce, sender, depositData, handlerResponse)'), + strict: true + }); + const amountFromHandlerResponse = BigInt(logs[0].args.handlerResponse); + return createERCDepositData(amountFromHandlerResponse, lenRecipientAddress, recipientAddress); +}; + + +// This helper can be used to prepare execution data for GmpHandler +// The execution data will be packed together with depositorAddress before execution. +// If the target function parameters include reference types then the offsets should be kept consistent. +// This function packs the parameters together with a fake address and removes the address. +// After repacking the data in the handler together with depositorAddress, the offsets will be correct. +// Usage: use this function to prepare execution data, +// then pack the result together with executeFunctionSignature, maxFee etc +// (using the createGmpDepositData() helper) +// and then pass the data to Bridge.deposit(). +export function createGmpExecutionData( + types: Array, + values: Array +) { + const array: string[] = []; + types.unshift("address" as unknown as AbiParameter); + values.unshift(zeroAddress); + return encodeAbiParameters( + parseAbiParameters( + types + // ["address", "address", "uint256[]", "uint256[]", "bytes"], + ), + array + ); +}; + + +type Action = { + nativeValue: BigInt, + callTo: Hex, + approveTo: Hex, + tokenSend: Hex, + tokenReceive: Hex, + data: Hex, +} + +const ACTIONS_ARRAY_ABI = +"tuple(uint256 nativeValue)[]"; +// "tuple(uint256 nativeValue, address callTo, address approveTo, address tokenSend, address tokenReceive, bytes data)[]"; + +export function createMessageCallData(transactionId: Hex, actions: Array, receiver: Hex) { + return encodeAbiParameters( + parseAbiParameters(["bytes32", ACTIONS_ARRAY_ABI, "address"]), + [ + transactionId, + actions.map((action: Action) => [ + action.nativeValue, + action.callTo, + action.approveTo, + action.tokenSend, + action.tokenReceive, + action.data, + ]), + receiver + ] + ) +} + +export function createOptionalContractCallDepositData( + amount: bigint, + recipient: Hex, + executionGasAmount: bigint, + message: Hex +): Hex { + return concat([ + trimPrefix(toHex(amount, {size:32})), // uint256 + trimPrefix(toHex(recipient.substring(2).length / 2, {size:32})), // uint256 + trimPrefix(recipient), // bytes + trimPrefix(toHex(executionGasAmount, {size:32})), // uint256 + trimPrefix(toHex(message.substring(2).length / 2, {size:32})), // uint256 + trimPrefix(message) // bytes + ]) +} + +export async function getBalance(args: GetBalanceParameters | WalletClient): Promise{ + console.log("sfasfsaf",typeof args) + if(args.hasOwnProperty("account")){ + const wallet = args as WalletClient; + return await publicClient.getBalance({address: wallet.account!.address }); + } else { + return await publicClient.getBalance(args as GetBalanceParameters); + } +} diff --git a/test/retry/retry.js b/test/retry/retry.js deleted file mode 100644 index 6acded8e..00000000 --- a/test/retry/retry.js +++ /dev/null @@ -1,45 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const Helpers = require("../helpers"); - -const TruffleAssert = require("truffle-assertions"); -const Retry = artifacts.require("Retry") - -contract("Retry", (accounts) => { - let RetryInstance; - - const sourceDomainID = 1; - const destinationDomainID = 2; - const blockHeight = 15; - const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000300"; - - beforeEach(async () => { - RetryInstance = await Retry.new(accounts[0]); - }); - - it("should emit Retry event when retry is called by the owner", async () => { - const tx = await RetryInstance.retry( - sourceDomainID, - destinationDomainID, - blockHeight, - resourceID, - {from: accounts[0]}) - - TruffleAssert.eventEmitted(tx, "Retry", (event) => { - return ( - event.sourceDomainID.toNumber() === sourceDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.blockHeight.toNumber() === blockHeight && - event.resourceID === resourceID - ); - }); - }); - - it("should revert when retry is not called by the owner", async () => { - await Helpers.reverts( - RetryInstance.retry(sourceDomainID, destinationDomainID, blockHeight, resourceID, {from: accounts[1]}), - "Ownable: caller is not the owner" - ) - }); -}) diff --git a/test/retry/retry.test.ts b/test/retry/retry.test.ts new file mode 100644 index 00000000..b1dba3e5 --- /dev/null +++ b/test/retry/retry.test.ts @@ -0,0 +1,67 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import hre from 'hardhat'; +import {expect} from "chai"; +import {ContractTypesMap} from 'hardhat/types'; +import {WalletClient} from 'viem'; +import {deploySourceChainContracts} from '../helpers'; +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; + + +describe("Retry", () => { + let RetryInstance: ContractTypesMap["Retry"]; + + let admin: WalletClient; + let nonadmin: WalletClient; + + const sourceDomainID = 1; + const destinationDomainID = 2; + const blockHeight = BigInt(15); + const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000300"; + + before(async () => { + ({ + RetryInstance, + } = await loadFixture(deploySourceChainContracts)); + [ + admin, + nonadmin + ] = await hre.viem.getWalletClients(); + }); + + it("should emit Retry event when retry is called by the owner", async () => { + const retryTx = await RetryInstance.write.retry([ + sourceDomainID, + destinationDomainID, + blockHeight, + resourceID + ], + { + account: admin.account + } + ); + + await expect(retryTx).to.emit(RetryInstance, "Retry").withArgs( + sourceDomainID, + destinationDomainID, + blockHeight, + resourceID + ); + }); + + it("should revert when retry is not called by the owner", async () => { + await expect( + RetryInstance.write.retry([ + sourceDomainID, + destinationDomainID, + blockHeight, + resourceID + ], + { + account: nonadmin.account + } + ), + ).to.be.revertedWith("Ownable: caller is not the owner") + }); +}) diff --git a/test/utils/accessControlSegregator/constructor.js b/test/utils/accessControlSegregator/constructor.js deleted file mode 100644 index ebae6f52..00000000 --- a/test/utils/accessControlSegregator/constructor.js +++ /dev/null @@ -1,82 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Helpers = require("../../helpers"); - -const AccessControlSegregatorContract = artifacts.require( - "AccessControlSegregator" -); - -contract("AccessControlSegregator - [constructor]", async (accounts) => { - let AccessControlSegregatorInstance; - const initialFunctions = [ - "0x29a71964", - "0x78728c73", - "0x2a64052b", - "0x3a24555a", - ]; - const initialAccessHolders = [ - accounts[1], - accounts[2], - accounts[3], - accounts[4], - ]; - - const grantAccessSig = "0xa973ec93"; - - beforeEach(async () => { - AccessControlSegregatorInstance = await AccessControlSegregatorContract.new( - initialFunctions, - initialAccessHolders - ); - }); - - it("[sanity] should deploy contract successfully", async () => { - await TruffleAssert.passes(AccessControlSegregatorContract.new([], [])); - }); - - it("should revert if length of functions and accounts array is different", async () => { - await Helpers.reverts( - AccessControlSegregatorContract.new( - ["0xa973ec93", "0x78728c73"], - [accounts[0]] - ), - "array length should be equal" - ); - }); - - it("should grant deployer grant access rights", async () => { - assert.isTrue( - await AccessControlSegregatorInstance.hasAccess( - grantAccessSig, - accounts[0] - ) - ); - }); - - it("should grant function access specified in params", async () => { - for (let i = 0; i < initialFunctions.length; i++) { - assert.isTrue( - await AccessControlSegregatorInstance.hasAccess( - initialFunctions[i], - initialAccessHolders[i] - ) - ); - } - }); - - it("should replace grant access of deployer if specified in params", async () => { - const accessControlInstance = await AccessControlSegregatorContract.new( - [grantAccessSig], - [accounts[1]] - ); - - assert.isFalse( - await accessControlInstance.hasAccess(grantAccessSig, accounts[0]) - ); - assert.isTrue( - await accessControlInstance.hasAccess(grantAccessSig, accounts[1]) - ); - }); -}); diff --git a/test/utils/accessControlSegregator/constructor.test.ts b/test/utils/accessControlSegregator/constructor.test.ts new file mode 100644 index 00000000..719db7b1 --- /dev/null +++ b/test/utils/accessControlSegregator/constructor.test.ts @@ -0,0 +1,83 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {assert, expect} from 'chai'; +import hre from 'hardhat'; +import {ContractTypesMap} from 'hardhat/types'; +import {Account, Hex, toHex, WalletClient} from 'viem'; + +describe("AccessControlSegregator - [constructor]", () => { + let AccessControlSegregatorInstance: ContractTypesMap["AccessControlSegregator"]; + + let firstEOA: WalletClient; + let secondEOA: WalletClient; + let thirdEOA: WalletClient; + let fourthEOA: WalletClient; + + const initialFunctions= [ + toHex("29a71964"), + toHex("0x78728c73"), + toHex("0x2a64052b"), + toHex("0x3a24555a"), + ]; + + let initialAccessHolders: Array; + + const grantAccessSig = "0xa973ec93"; + + before(async () => { + AccessControlSegregatorInstance = await hre.viem.deployContract("AccessControlSegregator", [[],[]]); + [ + , + firstEOA, + secondEOA, + thirdEOA, + fourthEOA, + ] = await hre.viem.getWalletClients(); + + initialAccessHolders = [firstEOA, secondEOA, thirdEOA, fourthEOA]; + }); + + it("should revert if length of functions and accounts array is different", async () => { + await expect( + hre.viem.deployContract("AccessControlSegregator", [ + [initialFunctions[0], initialFunctions[1]], + [firstEOA.account!.address] + ]), + ).to.be.revertedWith("array length should be equal"); + }); + + it("should grant deployer grant access rights", async () => { + assert.isTrue( + await AccessControlSegregatorInstance.read.hasAccess([ + grantAccessSig, + initialAccessHolders[0].account!.address + ]) + ); + }); + + it("should grant function access specified in params", async () => { + for (let i = 0; i < initialFunctions.length; i++) { + assert.isTrue( + await AccessControlSegregatorInstance.read.hasAccess([ + initialFunctions[i], + initialAccessHolders[i].account!.address + ]) + ); + } + }); + + it("should replace grant access of deployer if specified in params", async () => { + const AccessControlSegregatorInstance = await hre.viem.deployContract("AccessControlSegregator", [ + [grantAccessSig], + [secondEOA.account!.address] + ]); + + assert.isFalse( + await AccessControlSegregatorInstance.read.hasAccess([grantAccessSig, firstEOA.account!.address]) + ); + assert.isTrue( + await AccessControlSegregatorInstance.read.hasAccess([grantAccessSig, secondEOA.account!.address]) + ); + }); +}); diff --git a/test/utils/accessControlSegregator/grantAccess.js b/test/utils/accessControlSegregator/grantAccess.js deleted file mode 100644 index fbcce18c..00000000 --- a/test/utils/accessControlSegregator/grantAccess.js +++ /dev/null @@ -1,86 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Helpers = require("../../helpers"); - -const AccessControlSegregatorContract = artifacts.require( - "AccessControlSegregator" -); - -contract("AccessControlSegregator - [grant access]", async (accounts) => { - let AccessControlSegregatorInstance; - - const functionSignature = "0x29a71964"; - - beforeEach(async () => { - AccessControlSegregatorInstance = await AccessControlSegregatorContract.new( - [], - [] - ); - }); - - it("hasAccess should return false if access not granted", async () => { - assert.isFalse( - await AccessControlSegregatorInstance.hasAccess( - functionSignature, - accounts[2] - ) - ); - }); - - it("should revert if sender doesn't have grant access rights", async () => { - await Helpers.reverts( - AccessControlSegregatorInstance.grantAccess( - functionSignature, - accounts[2], - {from: accounts[1]} - ), - "sender doesn't have grant access rights" - ); - }); - - it("should successfully grant access to a function", async () => { - await TruffleAssert.passes( - AccessControlSegregatorInstance.grantAccess( - functionSignature, - accounts[2] - ) - ); - - assert.isTrue( - await AccessControlSegregatorInstance.hasAccess( - functionSignature, - accounts[2] - ) - ); - }); - - it("should successfully regrant access", async () => { - await TruffleAssert.passes( - AccessControlSegregatorInstance.grantAccess( - functionSignature, - accounts[2] - ) - ); - assert.isTrue( - await AccessControlSegregatorInstance.hasAccess( - functionSignature, - accounts[2] - ) - ); - - await TruffleAssert.passes( - AccessControlSegregatorInstance.grantAccess( - functionSignature, - accounts[3] - ) - ); - assert.isTrue( - await AccessControlSegregatorInstance.hasAccess( - functionSignature, - accounts[3] - ) - ); - }); -}); diff --git a/test/utils/accessControlSegregator/grantAccess.test.ts b/test/utils/accessControlSegregator/grantAccess.test.ts new file mode 100644 index 00000000..7e1c0394 --- /dev/null +++ b/test/utils/accessControlSegregator/grantAccess.test.ts @@ -0,0 +1,91 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +import {assert, expect} from "chai"; +import hre from 'hardhat'; +import {ContractTypesMap} from "hardhat/types"; +import {WalletClient} from "viem"; + + +describe("AccessControlSegregator - [grant access]", () => { + let AccessControlSegregatorInstance: ContractTypesMap["AccessControlSegregator"]; + + let firstEOA: WalletClient; + let secondEOA: WalletClient; + let thirdEOA: WalletClient; + + const functionSignature = "0x29a71964"; + + before(async () => { + AccessControlSegregatorInstance = await hre.viem.deployContract("AccessControlSegregator", [[],[]]); + [ + , + firstEOA, + secondEOA, + thirdEOA + ] = await hre.viem.getWalletClients(); + }); + + it("hasAccess should return false if access not granted", async () => { + assert.isFalse( + await AccessControlSegregatorInstance.read.hasAccess([ + functionSignature, + firstEOA.account!.address + ]) + ); + }); + + it("should revert if sender doesn't have grant access rights", async () => { + await expect( + AccessControlSegregatorInstance.write.grantAccess([ + functionSignature, + secondEOA.account!.address], + {account: firstEOA.account} + ), + ).to.be.revertedWith("sender doesn't have grant access rights"); + }); + + it("should successfully grant access to a function", async () => { + await expect( + AccessControlSegregatorInstance.write.grantAccess([ + functionSignature, + secondEOA.account!.address + ]) + ).not.to.be.reverted; + + assert.isTrue( + await AccessControlSegregatorInstance.read.hasAccess([ + functionSignature, + secondEOA.account!.address + ]) + ); + }); + + it("should successfully regrant access", async () => { + await expect( + AccessControlSegregatorInstance.write.grantAccess([ + functionSignature, + secondEOA.account!.address + ]) + ).not.to.be.reverted; + assert.isTrue( + await AccessControlSegregatorInstance.read.hasAccess([ + functionSignature, + secondEOA.account!.address + ]) + ); + + await expect( + AccessControlSegregatorInstance.write.grantAccess([ + functionSignature, + thirdEOA.account!.address + ]) + ).not.to.be.reverted; + assert.isTrue( + await AccessControlSegregatorInstance.read.hasAccess([ + functionSignature, + thirdEOA.account!.address + ]) + ); + }); +}); diff --git a/testUnderForked/admin.js b/testUnderForked/admin.js deleted file mode 100644 index a3e05149..00000000 --- a/testUnderForked/admin.js +++ /dev/null @@ -1,222 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const Ethers = require("ethers"); -const TruffleAssert = require("truffle-assertions"); -const Helpers = require("../test/helpers"); -const DynamicFeeHandlerContract = artifacts.require("TwapNativeTokenFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const TwapOracleContract = artifacts.require("TwapOracle"); - -const FACTORY_ABI = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).abi; -const FACTORY_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).bytecode; -const POOL_ABI = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json" -).abi; -const POOL_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json" -).bytecode; -const QUOTER_ABI = require( - "@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json" -).abi; -const QUOTER_BYTECODE = require( - "@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json" -).bytecode; - -contract("TwapFeeHandler - [admin]", async (accounts) => { - const initialRelayers = accounts.slice(0, 3); - const currentFeeHandlerAdmin = accounts[0]; - - const assertOnlyAdmin = (method, ...params) => { - return Helpers.reverts( - method(...params, {from: initialRelayers[1]}), - "sender doesn't have admin role" - ); - }; - - const originDomainID = 1; - const gasUsed = 100000; - const UNISWAP_V3_FACTORY_ADDRESS = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; - const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; - const MATIC_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"; - - let ADMIN_ROLE; - let UniswapFactoryInstance; - let TwapOracleInstance; - let BridgeInstance; - let FeeHandlerRouterInstance; - let pool_500; - let pool_3000; - let pool_10000; - let QuoterInstance; - let DynamicFeeHandlerInstance; - - beforeEach(async () => { - BridgeInstance = await Helpers.deployBridge(originDomainID, accounts[0]); - const provider = new Ethers.providers.JsonRpcProvider(); - const signer = provider.getSigner(); - UniswapFactoryInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(FACTORY_ABI), FACTORY_BYTECODE, signer - ); - UniswapFactoryInstance = await UniswapFactoryInstance.attach(UNISWAP_V3_FACTORY_ADDRESS); - - QuoterInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(QUOTER_ABI), QUOTER_BYTECODE, signer - ); - QuoterInstance = await QuoterInstance.deploy(UniswapFactoryInstance.address, WETH_ADDRESS); - - const poolFactory = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(POOL_ABI), POOL_BYTECODE, signer - ); - pool_500 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 500); - pool_500 = await poolFactory.attach(pool_500); - pool_3000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 3000); - pool_3000 = await poolFactory.attach(pool_3000); - pool_10000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 10000); - pool_10000 = await poolFactory.attach(pool_10000); - - TwapOracleInstance = await TwapOracleContract.new(UniswapFactoryInstance.address, WETH_ADDRESS); - await TwapOracleInstance.setPool(MATIC_ADDRESS, 500, 100); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - DynamicFeeHandlerInstance = await DynamicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address, - 0 - ); - ADMIN_ROLE = await DynamicFeeHandlerInstance.DEFAULT_ADMIN_ROLE(); - }); - - it("should return fee handler type", async () => { - assert.equal(await DynamicFeeHandlerInstance.feeHandlerType.call(), "twap"); - }); - - it("should set fee oracle and emit 'FeeOracleAddressSet' event", async () => { - assert.equal( - await DynamicFeeHandlerInstance.twapOracle.call(), - "0x0000000000000000000000000000000000000000" - ); - const setFeeOracleAddressTx = await DynamicFeeHandlerInstance.setFeeOracle(TwapOracleInstance.address); - const newOracle = await DynamicFeeHandlerInstance.twapOracle.call(); - assert.equal(newOracle, TwapOracleInstance.address); - - TruffleAssert.eventEmitted(setFeeOracleAddressTx, "FeeOracleAddressSet", (event) => { - return ( - event.feeOracleAddress === newOracle - ); - }); - }); - - it("should require admin role to change fee oracle", async () => { - await assertOnlyAdmin( - DynamicFeeHandlerInstance.setFeeOracle, - TwapOracleInstance.address - ); - }); - - it("should set fee properties and emit 'FeePropertySet' event", async () => { - assert.equal(await DynamicFeeHandlerInstance._gasUsed.call(), "0"); - const setFeeOraclePropertiesTx = await DynamicFeeHandlerInstance.setFeeProperties(gasUsed); - assert.equal(await DynamicFeeHandlerInstance._gasUsed.call(), gasUsed); - - TruffleAssert.eventEmitted(setFeeOraclePropertiesTx, "FeePropertySet", (event) => { - return ( - event.gasUsed.toNumber() === gasUsed - ); - }); - }); - - it("should require admin role to change fee properties", async () => { - await assertOnlyAdmin( - DynamicFeeHandlerInstance.setFeeProperties, - gasUsed - ); - }); - - it("should set pool and emit 'PoolSet' event", async () => { - const setPoolTx = await TwapOracleInstance.setPool(MATIC_ADDRESS, 3000, 100); - const pool = await TwapOracleInstance.pools(MATIC_ADDRESS); - assert.equal(pool.poolAddress, pool_3000.address); - assert.equal(pool.timeWindow, 100); - - TruffleAssert.eventEmitted(setPoolTx, "PoolSet", (event) => { - return ( - event.token === MATIC_ADDRESS, - event.feeTier.toNumber() === 3000, - event.timeWindow === 100, - event.pool === pool.poolAddress - ); - }); - }); - - it("should require admin role to set pool", async () => { - await assertOnlyAdmin( - TwapOracleInstance.setPool, - MATIC_ADDRESS, - 3000, - 100 - ); - }); - - it("should set price manually and emit 'PriceSet' event", async () => { - const new_price = Ethers.utils.parseEther("0.018"); - const setPriceTx = await TwapOracleInstance.setPrice(MATIC_ADDRESS, new_price); - const priceOnOracle = await TwapOracleInstance.prices(MATIC_ADDRESS); - const pool = await TwapOracleInstance.pools(MATIC_ADDRESS); - assert.equal(pool.poolAddress, Ethers.constants.AddressZero); - assert.equal(pool.timeWindow, 0); - assert.equal(priceOnOracle.toString(), new_price.toString()); - TruffleAssert.eventEmitted(setPriceTx, "PriceSet", (event) => { - return ( - event.token === MATIC_ADDRESS, - event.price.toString() === new_price.toString() - ); - }); - }); - - it("should require admin role to set price", async () => { - const new_price = Ethers.utils.parseEther("0.018"); - await assertOnlyAdmin( - TwapOracleInstance.setPrice, - MATIC_ADDRESS, - new_price - ); - }); - - it("DynamicFeeHandler admin should be changed to expectedDynamicFeeHandlerAdmin", async () => { - const expectedDynamicFeeHandlerAdmin = accounts[1]; - - // check current admin - assert.isTrue( - await DynamicFeeHandlerInstance.hasRole( - ADMIN_ROLE, - currentFeeHandlerAdmin - ) - ); - - await Helpers.passes( - DynamicFeeHandlerInstance.renounceAdmin( - expectedDynamicFeeHandlerAdmin - ) - ); - assert.isTrue( - await DynamicFeeHandlerInstance.hasRole( - ADMIN_ROLE, - expectedDynamicFeeHandlerAdmin - ) - ); - - // check that former admin is no longer admin - assert.isFalse( - await DynamicFeeHandlerInstance.hasRole( - ADMIN_ROLE, - currentFeeHandlerAdmin - ) - ); - }); -}); diff --git a/testUnderForked/calculateFeeERC20EVM.js b/testUnderForked/calculateFeeERC20EVM.js deleted file mode 100644 index 42628b69..00000000 --- a/testUnderForked/calculateFeeERC20EVM.js +++ /dev/null @@ -1,186 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const Ethers = require("ethers"); -const Helpers = require("../test/helpers"); -const DynamicFeeHandlerContract = artifacts.require("TwapNativeTokenFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const TwapOracleContract = artifacts.require("TwapOracle"); - -const FACTORY_ABI = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).abi; -const FACTORY_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).bytecode; -const POOL_ABI = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json" -).abi; -const POOL_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json" -).bytecode; -const QUOTER_ABI = require( - "@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json" -).abi; -const QUOTER_BYTECODE = require( - "@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json" -).bytecode; - -contract("TwapFeeHandler - [calculateFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 3; - const gasUsed = 100000; - const gasPrice = 200000000000; - const ProtocolFeeType = { - None: "0", - Fixed: "1", - Percentage: "2" - } - const fixedProtocolFee = Ethers.utils.parseEther("0.001"); - const feePercentage = 1000; // 10% - const sender = accounts[0]; - const UNISWAP_V3_FACTORY_ADDRESS = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; - const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; - const MATIC_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"; - const BNB_ADDRESS = "0xB8c77482e45F1F44dE1745F52C74426C631bDD52"; - - let UniswapFactoryInstance; - let TwapOracleInstance; - let BridgeInstance; - let FeeHandlerRouterInstance; - let pool_500; - let pool_3000; - let pool_10000; - let QuoterInstance; - let DynamicFeeHandlerInstance; - let resourceID; - let depositData; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )), - (ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ).then((instance) => (ERC20MintableInstance = instance))), - ]); - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - const provider = new Ethers.providers.JsonRpcProvider(); - const signer = provider.getSigner(); - UniswapFactoryInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(FACTORY_ABI), FACTORY_BYTECODE, signer - ); - UniswapFactoryInstance = await UniswapFactoryInstance.attach(UNISWAP_V3_FACTORY_ADDRESS); - - QuoterInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(QUOTER_ABI), QUOTER_BYTECODE, signer - ); - QuoterInstance = await QuoterInstance.deploy(UniswapFactoryInstance.address, WETH_ADDRESS); - - const poolFactory = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(POOL_ABI), POOL_BYTECODE, signer - ); - pool_500 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 500); - pool_500 = await poolFactory.attach(pool_500); - pool_3000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 3000); - pool_3000 = await poolFactory.attach(pool_3000); - pool_10000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 10000); - pool_10000 = await poolFactory.attach(pool_10000); - - TwapOracleInstance = await TwapOracleContract.new(UniswapFactoryInstance.address, WETH_ADDRESS); - await TwapOracleInstance.setPool(MATIC_ADDRESS, 500, 100); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - DynamicFeeHandlerInstance = await DynamicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address, - 0 - ); - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - DynamicFeeHandlerInstance.address - ), - await DynamicFeeHandlerInstance.setFeeOracle(TwapOracleInstance.address); - await DynamicFeeHandlerInstance.setGasPrice( - destinationDomainID, - gasPrice, // Polygon gas price is 200 Gwei - ProtocolFeeType.Fixed, - fixedProtocolFee - ); - await DynamicFeeHandlerInstance.setWrapTokenAddress(destinationDomainID, MATIC_ADDRESS); - await DynamicFeeHandlerInstance.setFeeProperties(gasUsed); - - depositData = Helpers.createERCDepositData( - 100, - 20, - sender, - ); - }); - - it("[fixed protocol fee] should get the correct values", async () => { - const feeInDestinationToken = gasPrice * gasUsed; - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - - const input = new Ethers.ethers.BigNumber.from(feeInDestinationToken.toString()); - const out = await QuoterInstance.callStatic.quoteExactInputSingle(MATIC_ADDRESS, WETH_ADDRESS, 500, input, 0); - expect( - (await DynamicFeeHandlerInstance.destinationFee(destinationDomainID)).feeType.toString() - ).to.be.equal(ProtocolFeeType.Fixed); - expect(res.fee.toNumber()).to.be.within( - out*0.99 + Number(fixedProtocolFee), - out*1.01 + Number(fixedProtocolFee) - ); - }); - - it("should get the correct price for the tokens with no available pool", async () => { - const bnb_price = Ethers.utils.parseEther("0.18"); - await TwapOracleInstance.setPrice(BNB_ADDRESS, bnb_price); - const priceOnOracle = await TwapOracleInstance.getPrice(BNB_ADDRESS); - assert.equal(priceOnOracle.toString(), bnb_price.toString()); - }); - - it("[percentage protocol fee] should get the correct values", async () => { - await DynamicFeeHandlerInstance.setGasPrice( - destinationDomainID, - gasPrice, // Polygon gas price is 200 Gwei - ProtocolFeeType.Percentage, - feePercentage - ); - - const feeInDestinationToken = gasPrice * gasUsed; - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - - const input = new Ethers.ethers.BigNumber.from(feeInDestinationToken.toString()); - const out = await QuoterInstance.callStatic.quoteExactInputSingle(MATIC_ADDRESS, WETH_ADDRESS, 500, input, 0); - expect( - (await DynamicFeeHandlerInstance.destinationFee(destinationDomainID)).feeType.toString() - ).to.be.equal(ProtocolFeeType.Percentage); - expect(res.fee.toNumber()).to.be.within( - out*1.09, - out*1.11 - ); - }); -}); diff --git a/testUnderForked/collectFeeERC20EVM.js b/testUnderForked/collectFeeERC20EVM.js deleted file mode 100644 index 35e971b5..00000000 --- a/testUnderForked/collectFeeERC20EVM.js +++ /dev/null @@ -1,338 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); - -const Helpers = require("../test/helpers"); - -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver"); -const ERC20HandlerContract = artifacts.require("ERC20Handler"); -const DynamicFeeHandlerContract = artifacts.require("TwapNativeTokenFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const TwapOracleContract = artifacts.require("TwapOracle"); - -const FACTORY_ABI = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json").abi; -const FACTORY_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).bytecode; -const POOL_ABI = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json").abi; -const POOL_BYTECODE = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json").bytecode; -const QUOTER_ABI = require("@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json").abi; -const QUOTER_BYTECODE = require("@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json").bytecode; - -contract("TwapNativeTokenFeeHandler - [collectFee]", async (accounts) => { - const recipientAddress = accounts[2]; - const tokenAmount = Ethers.utils.parseEther("1"); - // const fee = Ethers.utils.parseEther("0.05"); - const depositorAddress = accounts[1]; - const emptySetResourceData = "0x"; - const originDomainID = 1; - const destinationDomainID = 3; - const gasUsed = 100000; - const gasPrice = 200000000000; - const ProtocolFeeType = { - None: "0", - Fixed: "1", - Percentage: "2" - } - const fixedProtocolFee = Ethers.utils.parseEther("0.001"); - const sender = accounts[0]; - const UNISWAP_V3_FACTORY_ADDRESS = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; - const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; - const MATIC_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"; - - let UniswapFactoryInstance; - let TwapOracleInstance; - let BridgeInstance; - let FeeHandlerRouterInstance; - let pool_500; - let pool_3000; - let pool_10000; - let QuoterInstance; - let DynamicFeeHandlerInstance; - let resourceID; - let DefaultMessageReceiverInstance; - let ERC20HandlerInstance; - let ERC20MintableInstance; - let depositData; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )), - (ERC20MintableInstance = ERC20MintableContract.new( - "ERC20Token", - "ERC20TOK" - ).then((instance) => (ERC20MintableInstance = instance))), - ]); - - DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000); - ERC20HandlerInstance = await ERC20HandlerContract.new( - BridgeInstance.address, - DefaultMessageReceiverInstance.address - ); - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - DynamicFeeHandlerInstance = await DynamicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address, - 0 - ); - - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - - const provider = new Ethers.providers.JsonRpcProvider(); - const signer = provider.getSigner(); - UniswapFactoryInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(FACTORY_ABI), FACTORY_BYTECODE, signer - ); - UniswapFactoryInstance = await UniswapFactoryInstance.attach(UNISWAP_V3_FACTORY_ADDRESS); - - QuoterInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(QUOTER_ABI), QUOTER_BYTECODE, signer - ); - QuoterInstance = await QuoterInstance.deploy(UniswapFactoryInstance.address, WETH_ADDRESS); - - const poolFactory = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(POOL_ABI), POOL_BYTECODE, signer - ); - pool_500 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 500); - pool_500 = await poolFactory.attach(pool_500); - pool_3000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 3000); - pool_3000 = await poolFactory.attach(pool_3000); - pool_10000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 10000); - pool_10000 = await poolFactory.attach(pool_10000); - - TwapOracleInstance = await TwapOracleContract.new(UniswapFactoryInstance.address, WETH_ADDRESS); - await TwapOracleInstance.setPool(MATIC_ADDRESS, 500, 100); - - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - DynamicFeeHandlerInstance.address - ); - await DynamicFeeHandlerInstance.setFeeOracle(TwapOracleInstance.address); - await DynamicFeeHandlerInstance.setGasPrice( - destinationDomainID, - gasPrice, // Polygon gas price is 200 Gwei - ProtocolFeeType.Fixed, - fixedProtocolFee - ); - await DynamicFeeHandlerInstance.setWrapTokenAddress(destinationDomainID, MATIC_ADDRESS); - await DynamicFeeHandlerInstance.setFeeProperties(gasUsed); - - await BridgeInstance.adminSetResource( - ERC20HandlerInstance.address, - resourceID, - ERC20MintableInstance.address, - emptySetResourceData - ); - await ERC20MintableInstance.mint(depositorAddress, tokenAmount); - await ERC20MintableInstance.approve(ERC20HandlerInstance.address, tokenAmount, { - from: depositorAddress, - }); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - DynamicFeeHandlerInstance.address - ); - - depositData = Helpers.createERCDepositData( - tokenAmount, - 20, - recipientAddress - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should collect fee in native coins", async () => { - const feeData = "0x00"; - const balanceBefore = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - - const fee = res.fee; - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - value: fee, - } - ); - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - DynamicFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === Ethers.constants.AddressZero - ); - }); - const balanceAfter = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, Ethers.BigNumber.from(fee.toString()).add(balanceBefore)); - }); - - it("deposit should revert if invalid fee (msg.value) amount supplied", async () => { - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - - const expectedFee = res.fee; - const fee = Ethers.BigNumber.from(expectedFee.toString()).div(2); - - const errorValues = await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: fee, - } - ), - "IncorrectFeeSupplied(uint256)" - ); - - assert.equal(errorValues[0].toString(), fee.toString()); - }); - - it("deposit should revert if the destination coin's price is 0", async () => { - const fee = Ethers.utils.parseEther("1.0"); - await TwapOracleInstance.setPrice(MATIC_ADDRESS, 0); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: fee, - } - ), - "IncorrectPrice()" - ); - }); - - it("deposit should not revert if exceed fee (msg.value) amount supplied", async () => { - const exceedFee = Ethers.utils.parseEther("1.0"); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: exceedFee, - } - ); - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - }); - - it("should successfully change fee handler from FeeRouter to DynamicFeeHandler and collect fee", async () => { - await BridgeInstance.adminChangeFeeHandler( - DynamicFeeHandlerInstance.address - ); - - const balanceBefore = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - const fee = res.fee; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: fee, - } - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - - const internalTx = await TruffleAssert.createTransactionResult( - DynamicFeeHandlerInstance, - depositTx.tx - ); - - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === Ethers.constants.AddressZero - ); - }); - const balanceAfter = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - - assert.equal(balanceAfter, Ethers.BigNumber.from(fee.toString()).add(balanceBefore)); - }); -}); diff --git a/testUnderForked/collectFeeGenericEVM.js b/testUnderForked/collectFeeGenericEVM.js deleted file mode 100644 index 65046eb7..00000000 --- a/testUnderForked/collectFeeGenericEVM.js +++ /dev/null @@ -1,334 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -const TruffleAssert = require("truffle-assertions"); -const Ethers = require("ethers"); -const Helpers = require("../test/helpers"); - -const DynamicFeeHandlerContract = artifacts.require("TwapGenericFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const TwapOracleContract = artifacts.require("TwapOracle"); -const GmpHandlerContract = artifacts.require("GmpHandler"); -const TestStoreContract = artifacts.require("TestStore"); - -const FACTORY_ABI = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json").abi; -const FACTORY_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).bytecode; -const POOL_ABI = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json").abi; -const POOL_BYTECODE = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json").bytecode; -const QUOTER_ABI = require("@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json").abi; -const QUOTER_BYTECODE = require("@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json").bytecode; - -contract("TwapGenericFeeHandler - [collectFee]", async (accounts) => { - // const fee = Ethers.utils.parseEther("0.05"); - const depositorAddress = accounts[1]; - const emptySetResourceData = "0x"; - const destinationMaxFee = 900000; - const hashOfTestStore = Ethers.utils.keccak256("0xc0ffee"); - const originDomainID = 1; - const destinationDomainID = 3; - const gasPrice = 200000000000; - const ProtocolFeeType = { - None: "0", - Fixed: "1", - Percentage: "2" - } - const fixedProtocolFee = Ethers.utils.parseEther("0.001"); - const sender = accounts[0]; - const UNISWAP_V3_FACTORY_ADDRESS = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; - const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; - const MATIC_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"; - - let UniswapFactoryInstance; - let TwapOracleInstance; - let BridgeInstance; - let FeeHandlerRouterInstance; - let GmpHandlerInstance; - let TestStoreInstance; - let pool_500; - let pool_3000; - let pool_10000; - let QuoterInstance; - let DynamicFeeHandlerInstance; - let resourceID; - let depositData; - let depositFunctionSignature; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - originDomainID, - accounts[0] - )) - ]); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - - DynamicFeeHandlerInstance = await DynamicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address - ); - - GmpHandlerInstance = await GmpHandlerContract.new( - BridgeInstance.address - ); - - TestStoreInstance = await TestStoreContract.new(); - - resourceID = Helpers.createResourceID( - TestStoreInstance.address, - originDomainID - ); - - depositFunctionSignature = Helpers.getFunctionSignature( - TestStoreInstance, - "storeWithDepositor" - ); - - const provider = new Ethers.providers.JsonRpcProvider(); - const signer = provider.getSigner(); - UniswapFactoryInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(FACTORY_ABI), FACTORY_BYTECODE, signer - ); - UniswapFactoryInstance = await UniswapFactoryInstance.attach(UNISWAP_V3_FACTORY_ADDRESS); - - QuoterInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(QUOTER_ABI), QUOTER_BYTECODE, signer - ); - QuoterInstance = await QuoterInstance.deploy(UniswapFactoryInstance.address, WETH_ADDRESS); - - const poolFactory = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(POOL_ABI), POOL_BYTECODE, signer - ); - pool_500 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 500); - pool_500 = await poolFactory.attach(pool_500); - pool_3000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 3000); - pool_3000 = await poolFactory.attach(pool_3000); - pool_10000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 10000); - pool_10000 = await poolFactory.attach(pool_10000); - - TwapOracleInstance = await TwapOracleContract.new(UniswapFactoryInstance.address, WETH_ADDRESS); - await TwapOracleInstance.setPool(MATIC_ADDRESS, 500, 100); - - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - DynamicFeeHandlerInstance.address - ); - await DynamicFeeHandlerInstance.setFeeOracle(TwapOracleInstance.address); - await DynamicFeeHandlerInstance.setGasPrice( - destinationDomainID, - gasPrice, // Polygon gas price is 200 Gwei - ProtocolFeeType.Fixed, - fixedProtocolFee - ); - await DynamicFeeHandlerInstance.setWrapTokenAddress(destinationDomainID, MATIC_ADDRESS); - - await BridgeInstance.adminSetResource( - GmpHandlerInstance.address, - resourceID, - TestStoreInstance.address, - emptySetResourceData - ); - await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address); - await FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - DynamicFeeHandlerInstance.address - ); - - depositData = Helpers.createGmpDepositData( - depositFunctionSignature, - TestStoreInstance.address, - destinationMaxFee, - depositorAddress, - hashOfTestStore - ); - - // set MPC address to unpause the Bridge - await BridgeInstance.endKeygen(Helpers.mpcAddress); - }); - - it("should collect fee in native coins", async () => { - const feeData = "0x00"; - const balanceBefore = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - - const fee = res.fee; - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - feeData, - { - from: depositorAddress, - value: fee, - } - ); - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - const internalTx = await TruffleAssert.createTransactionResult( - DynamicFeeHandlerInstance, - depositTx.tx - ); - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === Ethers.constants.AddressZero - ); - }); - const balanceAfter = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - assert.equal(balanceAfter, Ethers.BigNumber.from(fee.toString()).add(balanceBefore)); - }); - - it("deposit should revert if invalid fee (msg.value) amount supplied", async () => { - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - - const expectedFee = res.fee; - const fee = Ethers.BigNumber.from(expectedFee.toString()).div(2); - - const errorValues = await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: fee, - } - ), - "IncorrectFeeSupplied(uint256)" - ); - - assert.equal(errorValues[0].toString(), fee.toString()); - }); - - it("deposit should revert if the destination coin's price is 0", async () => { - const fee = Ethers.utils.parseEther("1.0"); - await TwapOracleInstance.setPrice(MATIC_ADDRESS, 0); - - await Helpers.expectToRevertWithCustomError( - BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: fee, - } - ), - "IncorrectPrice()" - ); - }); - - it("deposit should not revert if exceed fee (msg.value) amount supplied", async () => { - const exceedFee = Ethers.utils.parseEther("1.0"); - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: exceedFee, - } - ); - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - }); - - it("should successfully change fee handler from FeeRouter to DynamicFeeHandler and collect fee", async () => { - await BridgeInstance.adminChangeFeeHandler( - DynamicFeeHandlerInstance.address - ); - - const balanceBefore = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - - const res = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - depositData, - "0x00" - ); - const fee = res.fee; - - const depositTx = await BridgeInstance.deposit( - destinationDomainID, - resourceID, - depositData, - "0x00", - { - from: depositorAddress, - value: fee, - } - ); - - TruffleAssert.eventEmitted(depositTx, "Deposit", (event) => { - return ( - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() - ); - }); - - const internalTx = await TruffleAssert.createTransactionResult( - DynamicFeeHandlerInstance, - depositTx.tx - ); - - TruffleAssert.eventEmitted(internalTx, "FeeCollected", (event) => { - return ( - event.sender === depositorAddress && - event.fromDomainID.toNumber() === originDomainID && - event.destinationDomainID.toNumber() === destinationDomainID && - event.resourceID === resourceID.toLowerCase() && - event.fee.toString() === fee.toString() && - event.tokenAddress === Ethers.constants.AddressZero - ); - }); - const balanceAfter = await web3.eth.getBalance( - DynamicFeeHandlerInstance.address - ); - - assert.equal(balanceAfter, Ethers.BigNumber.from(fee.toString()).add(balanceBefore)); - }); -}); diff --git a/testUnderForked/optionalContractCall/calculateFeeERC20EVM.js b/testUnderForked/optionalContractCall/calculateFeeERC20EVM.js deleted file mode 100644 index 55e1648f..00000000 --- a/testUnderForked/optionalContractCall/calculateFeeERC20EVM.js +++ /dev/null @@ -1,178 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only -const Ethers = require("ethers"); -const Helpers = require("../../test/helpers"); -const DynamicFeeHandlerContract = artifacts.require("TwapNativeTokenFeeHandler"); -const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter"); -const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser"); -const TwapOracleContract = artifacts.require("TwapOracle"); - -const FACTORY_ABI = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).abi; -const FACTORY_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json" -).bytecode; -const POOL_ABI = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json" -).abi; -const POOL_BYTECODE = require( - "@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json" -).bytecode; -const QUOTER_ABI = require( - "@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json" -).abi; -const QUOTER_BYTECODE = require( - "@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json" -).bytecode; - -contract("TwapFeeHandler - [calculateFee]", async (accounts) => { - const originDomainID = 1; - const destinationDomainID = 3; - const gasUsed = 100000; - const gasPrice = 200000000000; - const ProtocolFeeType = { - None: "0", - Fixed: "1", - Percentage: "2" - } - const recipientAddress = accounts[2]; - - const depositAmount = Ethers.utils.parseEther("1"); - const fixedProtocolFee = Ethers.utils.parseEther("0.001"); - const transferredAmount = depositAmount.sub(fixedProtocolFee); - const sender = accounts[0]; - const UNISWAP_V3_FACTORY_ADDRESS = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; - const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; - const MATIC_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"; - const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const higherExecutionGasAmount = 30000000; - const lowerExecutionGasAmount = 3000000; - const feeData = "0x"; - - let UniswapFactoryInstance; - let TwapOracleInstance; - let BridgeInstance; - let FeeHandlerRouterInstance; - let pool_500; - let pool_3000; - let pool_10000; - let QuoterInstance; - let DynamicFeeHandlerInstance; - let resourceID; - - beforeEach(async () => { - await Promise.all([ - (BridgeInstance = await Helpers.deployBridge( - destinationDomainID, - accounts[0] - )), - (ERC20MintableInstance = await ERC20MintableContract.new( - "token", - "TOK" - ).then((instance) => (ERC20MintableInstance = instance))), - ]); - resourceID = Helpers.createResourceID( - ERC20MintableInstance.address, - originDomainID - ); - const provider = new Ethers.providers.JsonRpcProvider(); - const signer = provider.getSigner(); - UniswapFactoryInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(FACTORY_ABI), FACTORY_BYTECODE, signer - ); - UniswapFactoryInstance = await UniswapFactoryInstance.attach(UNISWAP_V3_FACTORY_ADDRESS); - - QuoterInstance = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(QUOTER_ABI), QUOTER_BYTECODE, signer - ); - QuoterInstance = await QuoterInstance.deploy(UniswapFactoryInstance.address, WETH_ADDRESS); - - const poolFactory = new Ethers.ethers.ContractFactory( - new Ethers.ethers.utils.Interface(POOL_ABI), POOL_BYTECODE, signer - ); - pool_500 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 500); - pool_500 = await poolFactory.attach(pool_500); - pool_3000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 3000); - pool_3000 = await poolFactory.attach(pool_3000); - pool_10000 = await UniswapFactoryInstance.getPool(WETH_ADDRESS, MATIC_ADDRESS, 10000); - pool_10000 = await poolFactory.attach(pool_10000); - - TwapOracleInstance = await TwapOracleContract.new(UniswapFactoryInstance.address, WETH_ADDRESS); - await TwapOracleInstance.setPool(MATIC_ADDRESS, 500, 100); - - FeeHandlerRouterInstance = await FeeHandlerRouterContract.new( - BridgeInstance.address - ); - DynamicFeeHandlerInstance = await DynamicFeeHandlerContract.new( - BridgeInstance.address, - FeeHandlerRouterInstance.address, - 0 - ); - FeeHandlerRouterInstance.adminSetResourceHandler( - destinationDomainID, - resourceID, - DynamicFeeHandlerInstance.address - ), - await DynamicFeeHandlerInstance.setFeeOracle(TwapOracleInstance.address); - await DynamicFeeHandlerInstance.setGasPrice( - destinationDomainID, - gasPrice, // Polygon gas price is 200 Gwei - ProtocolFeeType.Fixed, - fixedProtocolFee - ); - await DynamicFeeHandlerInstance.setWrapTokenAddress(destinationDomainID, MATIC_ADDRESS); - await DynamicFeeHandlerInstance.setFeeProperties(gasUsed); - }); - - it("should return higher fee for higher execution amount", async () => { - const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]); - const actions = [{ - nativeValue: 0, - callTo: ERC20MintableInstance.address, - approveTo: Ethers.constants.AddressZero, - tokenSend: Ethers.constants.AddressZero, - tokenReceive: Ethers.constants.AddressZero, - data: mintableERC20Iface.encodeFunctionData("mint", [recipientAddress, "20"]), - }] - const message = Helpers.createMessageCallData( - transactionId, - actions, - recipientAddress - ); - - const higherGasDepositData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - higherExecutionGasAmount, - message - ); - - const higherExecutionGasAmountRes = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - higherGasDepositData, - feeData - ); - - const lowerGasDepositData = Helpers.createOptionalContractCallDepositData( - transferredAmount, - Ethers.constants.AddressZero, - lowerExecutionGasAmount, - message - ); - - const lowerExecutionGasAmountRes = await FeeHandlerRouterInstance.calculateFee.call( - sender, - originDomainID, - destinationDomainID, - resourceID, - lowerGasDepositData, - feeData - ); - - expect(higherExecutionGasAmountRes.fee.toNumber()).to.be.gt(lowerExecutionGasAmountRes.fee.toNumber()) - }); -}); diff --git a/truffle-config.js b/truffle-config.js deleted file mode 100644 index 79c8a9c5..00000000 --- a/truffle-config.js +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright 2020 ChainSafe Systems - * SPDX-License-Identifier: LGPL-3.0-only - */ -require("dotenv").config(); - -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -const HDWalletProvider = require("@truffle/hdwallet-provider"); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - plugins: ["solidity-coverage", "truffle-plugin-verify"], - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - networkCheckTimeout: 10000, - geth: { - host: "127.0.0.1", // Localhost (default: none) - port: 8545, // Standard Ethereum port (default: none) - network_id: "5", // Any network (default: none) - }, - test: { - host: "127.0.0.1", // Localhost (default: none) - port: 8545, // Standard Ethereum port (default: none) - network_id: "*", // Any network (default: none) - disableConfirmationListener: true, - }, - test2: { - host: "127.0.0.1", // Localhost (default: none) - port: 8547, // Standard Ethereum port (default: none) - network_id: "*", // Any network (default: none) - disableConfirmationListener: true, - }, - goerli: { - provider: () => { - return new HDWalletProvider({ - mnemonic: process.env.GOERLI_MNEMONIC, - providerOrUrl: process.env.GOERLI_PROVIDER_URL - }) - }, - networkCheckTimeout: 10000, - timeoutBlocks: 200, - network_id: "5", - gasPrice: 30000000000, // 30 gwei - }, - mumbai: { - provider: () => { - return new HDWalletProvider({ - mnemonic: process.env.MUMBAI_MNEMONIC, - providerOrUrl: process.env.MUMBAI_PROVIDER_URL - }) - }, - networkCheckTimeout: 10000, - timeoutBlocks: 200, - network_id: "80001", - gasPrice: 30000000000, // 30 gwei - }, - moonbase: { - provider: () => { - return new HDWalletProvider({ - mnemonic: process.env.MOONBASE_MNEMONIC, - providerOrUrl: process.env.MOONBASE_PROVIDER_URL - }) - }, - networkCheckTimeout: 10000, - timeoutBlocks: 200, - network_id: "1287", - gasPrice: 30000000000, // 30 gwei - }, - gnosis: { - provider: () => { - return new HDWalletProvider({ - mnemonic: process.env.GNOSIS_MNEMONIC, - providerOrUrl: process.env.GNOSIS_PROVIDER_URL - }) - }, - networkCheckTimeout: 10000, - timeoutBlocks: 200, - network_id: "100", - gasPrice: 2000000000, // 2 gwei - }, - base:{ - provider: () => { - return new HDWalletProvider({ - mnemonic: process.env.BASE_MNEMONIC, - providerOrUrl: process.env.BASE_PROVIDER_URL - }) - }, - networkCheckTimeout: 100000, - timeoutBlocks: 200, - network_id: "84531", - gasPrice: 150000000, // 0.15 gwei - }, - cronos: { - provider: () => { - return new HDWalletProvider({ - mnemonic: process.env.CRONOS_MNEMONIC, - providerOrUrl: process.env.CRONOS_PROVIDER - }) - }, - networkCheckTimeout: 10000, - timeoutBlocks: 200, - network_id: "338", - gasPrice: 2000000000000, // 2000 gwei - }, - mainnet: { - provider: () => { - return new HDWalletProvider({ - mnemonic: process.env.MAINNET_MNEMONIC, - providerOrUrl: process.env.MAINNET_PROVIDER - }) - }, - networkCheckTimeout: 100000, - timeoutBlocks: 200, - network_id: "1", - gasPrice: 17000000000, // 17 gwei - } - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - // Explorer api keys for verifying contracts - api_keys: { - etherscan: process.env.ETHERSCAN_API_KEY, - moonscan: process.env.MOONSCAN_API_KEY, - polygonscan: process.env.POLYGONSCAN_API_KEY, - gnosisscan: process.env.GNOSISSCAN_API_KEY, - cronoscan: process.env.CRONOSSCAN_API_KEY - }, - // Configure your compilers - compilers: { - solc: { - version: "0.8.11", // Fetch exact version from solc-bin (default: truffle's version) - // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) - settings: { // See the solidity docs for advice about optimization and evmVersion - optimizer: { - enabled: true, - runs: 200 - }, - evmVersion: "london" - } - } - } -} diff --git a/tsconfig.json b/tsconfig.json index 789e810a..a3546380 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,24 +1,16 @@ { "compilerOptions": { - "outDir": "dist", - "module": "esnext", - "target": "es5", - "lib": ["es6", "dom", "es2016", "es2017"], - "sourceMap": true, - "allowJs": false, - "jsx": "react", - "strict": true, - "declaration": true, + "target": "ES6", + "module": "commonjs", + "esModuleInterop": true, "moduleResolution": "node", "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true, "noImplicitReturns": true, "noImplicitThis": true, "noImplicitAny": true, "strictNullChecks": true, - "suppressImplicitAnyIndexErrors": true, - "noUnusedLocals": true, - "noUnusedParameters": true - }, - "include": ["src"], - "exclude": ["node_modules/"] + } } diff --git a/types/index.ts b/types/index.ts new file mode 100644 index 00000000..73276da9 --- /dev/null +++ b/types/index.ts @@ -0,0 +1,18 @@ +import {bigint} from "hardhat/internal/core/params/argumentTypes"; +import {Hex} from "viem"; + +export type Proposal { + originDomainID: number; + depositNonce: bigint; + resourceID: Hex; + data: Hex; +} + +export type Action { + nativeValue: bigint; + callTo: Hex; + approveTo: Hex; + tokenSend: Hex; + tokenReceive: Hex; + data: Hex; +} diff --git a/yarn.lock b/yarn.lock index 3508eb79..1a1aa54e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,354 +2,67 @@ # yarn lockfile v1 -"@ampproject/remapping@^2.1.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" - integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== - dependencies: - "@jridgewell/trace-mapping" "^0.3.0" +"@adraffy/ens-normalize@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" + integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== -"@apollo/protobufjs@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.2.tgz#4bd92cd7701ccaef6d517cdb75af2755f049f87c" - integrity sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.0" - "@types/node" "^10.1.0" - long "^4.0.0" - -"@apollographql/apollo-tools@^0.5.1": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.5.2.tgz#01750a655731a198c3634ee819c463254a7c7767" - integrity sha512-KxZiw0Us3k1d0YkJDhOpVH5rJ+mBfjXcgoRoCcslbgirjgLotKMzOcx4PZ7YTEvvEROmvG7X3Aon41GvMmyGsw== - -"@apollographql/graphql-playground-html@1.6.29": - version "1.6.29" - resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.29.tgz#a7a646614a255f62e10dcf64a7f68ead41dec453" - integrity sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA== - dependencies: - xss "^1.0.8" +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== -"@babel/code-frame@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== - dependencies: - "@babel/highlight" "^7.18.6" - -"@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/compat-data@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" - integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== - -"@babel/core@^7.17.4": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.7.tgz#f7c28228c83cdf2dbd1b9baa06eaf9df07f0c2f9" - integrity sha512-djHlEfFHnSnTAcPb7dATbiM5HxGOP98+3JLBZtjRb5I7RXrw7kFRoG2dXM8cm3H+o11A8IFH/uprmJpwFynRNQ== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.7" - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helpers" "^7.17.7" - "@babel/parser" "^7.17.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" +"@adraffy/ens-normalize@^1.10.1": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" + integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== -"@babel/generator@^7.17.3", "@babel/generator@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" - integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== +"@babel/code-frame@^7.0.0": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== dependencies: - "@babel/types" "^7.17.0" - jsesc "^2.5.1" - source-map "^0.5.0" + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" -"@babel/helper-compilation-targets@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" - integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== - dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.17.5" - semver "^6.3.0" +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== -"@babel/helper-define-polyfill-provider@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" - integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== - dependencies: - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" - integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== - dependencies: - "@babel/helper-get-function-arity" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/helper-get-function-arity@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" - integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-module-transforms@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" - integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - -"@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf" - integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== - -"@babel/helper-simple-access@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" - integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== - dependencies: - "@babel/types" "^7.17.0" - -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-string-parser@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" - integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/helper-validator-identifier@^7.18.6": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== - -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - -"@babel/helpers@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.7.tgz#6fc0a24280fd00026e85424bbfed4650e76d7127" - integrity sha512-TKsj9NkjJfTBxM7Phfy7kv6yYc4ZcOo+AaWGqQOKTPDOmcGkIFb5xNA746eKisQkm4yavUYh4InYM9S+VnO01w== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - -"@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.7.tgz#fc19b645a5456c8d6fdb6cecd3c66c0173902800" - integrity sha512-bm3AQf45vR4gKggRfvJdYJ0gFLoCbsPxiFLSH6hTVYABptNHY6l9NrhnucVjQ/X+SPtLANT9lc0fFhikj+VBRA== - -"@babel/plugin-transform-runtime@^7.5.5": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz#a3df2d7312eea624c7889a2dcd37fd1dfd25b2c6" - integrity sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA== - dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.19.0" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - semver "^6.3.0" + "@jridgewell/trace-mapping" "0.3.9" -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.6.3", "@babel/runtime@^7.9.2": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" - integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.5.5": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" - integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/traverse@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" - integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.3" - "@babel/types" "^7.17.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.16.7", "@babel/types@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" - integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" - -"@babel/types@^7.18.6": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600" - integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA== - dependencies: - "@babel/helper-string-parser" "^7.18.10" - "@babel/helper-validator-identifier" "^7.18.6" - to-fast-properties "^2.0.0" - -"@codechecks/client@^0.1.12": - version "0.1.12" - resolved "https://registry.yarnpkg.com/@codechecks/client/-/client-0.1.12.tgz#519f11be8fcaa581c6ee8d5e8457e35bbbe5d9b1" - integrity sha512-2GHHvhO3kaOyxFXxOaiznlY8ARmz33/p+WQdhc2y6wzWw5eOl2wSwg1eZxx3LsWlAnB963Y4bd1YjZcGIhKRzA== - dependencies: - bluebird "^3.5.3" - chalk "^2.4.2" - commander "^2.19.0" - debug "^4.1.1" - execa "^1.0.0" - glob "^7.1.3" - graceful-fs "^4.1.15" - js-yaml "^3.13.1" - json5 "^2.1.0" - lodash "^4.17.11" - marked "^0.7.0" - marked-terminal "^3.3.0" - mkdirp "^0.5.1" - ms "^2.1.1" - promise "^8.0.2" - request "^2.88.0" - request-promise "^4.2.2" - ts-essentials "^1.0.2" - ts-node "^8.0.2" - url-join "^4.0.0" - -"@consento/sync-randombytes@^1.0.4", "@consento/sync-randombytes@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@consento/sync-randombytes/-/sync-randombytes-1.0.5.tgz#5be6bc58c6a6fa6e09f04cc684d037e29e6c28d5" - integrity sha512-mPJ2XvrTLQGEdhleDuSIkWtVWnvmhREOC1FjorV1nlK49t/52Z9X1d618gTj6nlQghRLiYvcd8oL4vZ2YZuDIQ== +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== dependencies: - buffer "^5.4.3" - seedrandom "^3.0.5" + eslint-visitor-keys "^3.4.3" -"@eslint/eslintrc@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" - integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== +"@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" + espree "^9.6.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -357,458 +70,252 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@ethereumjs/common@^2.3.0", "@ethereumjs/common@^2.4.0", "@ethereumjs/common@^2.6.1": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.2.tgz#eb006c9329c75c80f634f340dc1719a5258244df" - integrity sha512-vDwye5v0SVeuDky4MtKsu+ogkH2oFUV8pBKzH/eNBzT8oI91pKa8WyzDuYuxOQsgNgv5R34LfFDh2aaw3H4HbQ== - dependencies: - crc-32 "^1.2.0" - ethereumjs-util "^7.1.4" +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@ethereumjs/common@^2.6.4": - version "2.6.5" - resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" - integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== +"@ethereumjs/common@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-3.2.0.tgz#b71df25845caf5456449163012074a55f048e0a0" + integrity sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA== dependencies: + "@ethereumjs/util" "^8.1.0" crc-32 "^1.2.0" - ethereumjs-util "^7.1.5" - -"@ethereumjs/tx@^3.2.1": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.0.tgz#783b0aeb08518b9991b23f5155763bbaf930a037" - integrity sha512-/+ZNbnJhQhXC83Xuvy6I9k4jT5sXiV0tMR9C+AzSSpcCV64+NB8dTE1m3x98RYMqb8+TLYWA+HML4F5lfXTlJw== - dependencies: - "@ethereumjs/common" "^2.6.1" - ethereumjs-util "^7.1.4" - -"@ethereumjs/tx@^3.3.0": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" - integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== - dependencies: - "@ethereumjs/common" "^2.6.4" - ethereumjs-util "^7.1.5" - -"@ethersproject/abi@5.0.7": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.7.tgz#79e52452bd3ca2956d0e1c964207a58ad1a0ee7b" - integrity sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw== - dependencies: - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/abi@5.6.0", "@ethersproject/abi@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.0.tgz#ea07cbc1eec2374d32485679c12408005895e9f3" - integrity sha512-AhVByTwdXCc2YQ20v300w6KVHle9g2OFc28ZAFCPnJyEpkv1xKXjZcSTgWOlv1i+0dqlgF8RCF2Rn2KC1t+1Vg== - dependencies: - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@ethersproject/abstract-provider@5.6.0", "@ethersproject/abstract-provider@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz#0c4ac7054650dbd9c476cf5907f588bbb6ef3061" - integrity sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/web" "^5.6.0" - -"@ethersproject/abstract-signer@5.6.0", "@ethersproject/abstract-signer@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz#9cd7ae9211c2b123a3b29bf47aab17d4d016e3e7" - integrity sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ== - dependencies: - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/address@5.6.0", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.0.tgz#13c49836d73e7885fc148ad633afad729da25012" - integrity sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - -"@ethersproject/base64@5.6.0", "@ethersproject/base64@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.0.tgz#a12c4da2a6fb86d88563216b0282308fc15907c9" - integrity sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw== - dependencies: - "@ethersproject/bytes" "^5.6.0" - -"@ethersproject/basex@5.6.0", "@ethersproject/basex@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.0.tgz#9ea7209bf0a1c3ddc2a90f180c3a7f0d7d2e8a69" - integrity sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/bignumber@5.6.0", "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.0.tgz#116c81b075c57fa765a8f3822648cf718a8a0e26" - integrity sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - bn.js "^4.11.9" -"@ethersproject/bytes@5.6.0", "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.0.tgz#81652f2a0e04533575befadce555213c11d8aa20" - integrity sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w== - dependencies: - "@ethersproject/logger" "^5.6.0" +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== -"@ethersproject/constants@5.6.0", "@ethersproject/constants@^5.0.4", "@ethersproject/constants@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.0.tgz#55e3eb0918584d3acc0688e9958b0cedef297088" - integrity sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA== +"@ethereumjs/tx@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-4.2.0.tgz#5988ae15daf5a3b3c815493bc6b495e76009e853" + integrity sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw== dependencies: - "@ethersproject/bignumber" "^5.6.0" - -"@ethersproject/contracts@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.0.tgz#60f2cfc7addd99a865c6c8cfbbcec76297386067" - integrity sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw== - dependencies: - "@ethersproject/abi" "^5.6.0" - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - -"@ethersproject/hash@5.6.0", "@ethersproject/hash@^5.0.4", "@ethersproject/hash@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.0.tgz#d24446a5263e02492f9808baa99b6e2b4c3429a2" - integrity sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA== - dependencies: - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" + "@ethereumjs/common" "^3.2.0" + "@ethereumjs/rlp" "^4.0.1" + "@ethereumjs/util" "^8.1.0" + ethereum-cryptography "^2.0.0" -"@ethersproject/hdnode@5.6.0", "@ethersproject/hdnode@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.0.tgz#9dcbe8d629bbbcf144f2cae476337fe92d320998" - integrity sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw== - dependencies: - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/basex" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - "@ethersproject/signing-key" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/wordlists" "^5.6.0" - -"@ethersproject/json-wallets@5.6.0", "@ethersproject/json-wallets@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz#4c2fc27f17e36c583e7a252fb938bc46f98891e5" - integrity sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ== - dependencies: - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/hdnode" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + +"@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.1.tgz#ab57818d9aefee919c5721d28cd31fd95eff413d" + integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@5.6.0", "@ethersproject/keccak256@^5.0.3", "@ethersproject/keccak256@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.0.tgz#fea4bb47dbf8f131c2e1774a1cecbfeb9d606459" - integrity sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w== - dependencies: - "@ethersproject/bytes" "^5.6.0" + "@ethersproject/rlp" "^5.6.1" + +"@ethersproject/address@^5.0.2", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/bignumber@^5.6.2", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/keccak256@^5.6.1", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" js-sha3 "0.8.0" -"@ethersproject/logger@5.6.0", "@ethersproject/logger@^5.0.5", "@ethersproject/logger@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" - integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== - -"@ethersproject/networks@5.6.0", "@ethersproject/networks@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.0.tgz#486d03fff29b4b6b5414d47a232ded09fe10de5e" - integrity sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/pbkdf2@5.6.0", "@ethersproject/pbkdf2@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz#04fcc2d7c6bff88393f5b4237d906a192426685a" - integrity sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - -"@ethersproject/properties@5.6.0", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" - integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== - dependencies: - "@ethersproject/logger" "^5.6.0" +"@ethersproject/logger@^5.6.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@ethersproject/providers@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.0.tgz#08ec8e2666771e3a347e66c8f664a2af97366534" - integrity sha512-6+5PKXTWAttJWFWF8+xCDTCa2/dtq9BNrdKQHGl0IyIOwj99vM6OeThmIRcsIAzIOb8m0XS6w+1KFZwrf3j9nw== - dependencies: - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/basex" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/web" "^5.6.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@5.6.0", "@ethersproject/random@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.0.tgz#1505d1ab6a250e0ee92f436850fa3314b2cb5ae6" - integrity sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw== +"@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" + "@ethersproject/logger" "^5.7.0" -"@ethersproject/rlp@5.6.0", "@ethersproject/rlp@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.0.tgz#55a7be01c6f5e64d6e6e7edb6061aa120962a717" - integrity sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g== +"@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" + "@ethersproject/logger" "^5.7.0" -"@ethersproject/sha2@5.6.0", "@ethersproject/sha2@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.0.tgz#364c4c11cc753bda36f31f001628706ebadb64d9" - integrity sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA== +"@ethersproject/rlp@^5.6.1", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - hash.js "1.1.7" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" -"@ethersproject/signing-key@5.6.0", "@ethersproject/signing-key@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.0.tgz#4f02e3fb09e22b71e2e1d6dc4bcb5dafa69ce042" - integrity sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA== +"@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - bn.js "^4.11.9" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/solidity@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.6.0.tgz#64657362a596bf7f5630bdc921c07dd78df06dc3" - integrity sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@ethersproject/strings@5.6.0", "@ethersproject/strings@^5.0.4", "@ethersproject/strings@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.0.tgz#9891b26709153d996bf1303d39a7f4bc047878fd" - integrity sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/transactions@5.6.0", "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.0.tgz#4b594d73a868ef6e1529a2f8f94a785e6791ae4e" - integrity sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg== - dependencies: - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - "@ethersproject/signing-key" "^5.6.0" - -"@ethersproject/units@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.0.tgz#e5cbb1906988f5740254a21b9ded6bd51e826d9c" - integrity sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/wallet@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.0.tgz#33d11a806d783864208f348709a5a3badac8e22a" - integrity sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg== - dependencies: - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/hdnode" "^5.6.0" - "@ethersproject/json-wallets" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.0" - "@ethersproject/signing-key" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/wordlists" "^5.6.0" - -"@ethersproject/web@5.6.0", "@ethersproject/web@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.0.tgz#4bf8b3cbc17055027e1a5dd3c357e37474eaaeb8" - integrity sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg== - dependencies: - "@ethersproject/base64" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@ethersproject/wordlists@5.6.0", "@ethersproject/wordlists@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.0.tgz#79e62c5276e091d8575f6930ba01a29218ded032" - integrity sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@graphql-tools/batch-execute@^8.3.2": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-8.3.2.tgz#8b5a731d5343f0147734f12d480aafde2a1b6eba" - integrity sha512-ICWqM+MvEkIPHm18Q0cmkvm134zeQMomBKmTRxyxMNhL/ouz6Nqld52/brSlaHnzA3fczupeRJzZ0YatruGBcQ== - dependencies: - "@graphql-tools/utils" "^8.6.2" - dataloader "2.0.0" - tslib "~2.3.0" - value-or-promise "1.0.11" - -"@graphql-tools/delegate@^8.4.3": - version "8.5.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-8.5.3.tgz#3d870ef531ce60e656d996828e8909f0c45e6f20" - integrity sha512-e65cEmAccodc3tlVskU0JgEbHgJUGB4sbd/dk2v15nOFzjj9izBTsTdvebI1Bm28Mip10vBJj9G0jJcTeOIyhg== - dependencies: - "@graphql-tools/batch-execute" "^8.3.2" - "@graphql-tools/schema" "^8.3.2" - "@graphql-tools/utils" "^8.6.2" - dataloader "2.0.0" - graphql-executor "0.0.18" - tslib "~2.3.0" - value-or-promise "1.0.11" - -"@graphql-tools/merge@^8.2.3": - version "8.2.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.3.tgz#a2861fec230ee7be9dc42d72fed2ac075c31669f" - integrity sha512-XCSmL6/Xg8259OTWNp69B57CPWiVL69kB7pposFrufG/zaAlI9BS68dgzrxmmSqZV5ZHU4r/6Tbf6fwnEJGiSw== - dependencies: - "@graphql-tools/utils" "^8.6.2" - tslib "~2.3.0" - -"@graphql-tools/mock@^8.1.2": - version "8.6.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.6.0.tgz#c74c4fc7b51e007fbbdbc4c29e3e84ce7e259ed1" - integrity sha512-w9w3Kq44Vu8fFIP/T6cYoKWI1lDMt3pT7x18brQgeBN3j4n9KP5AomA4LqRQ3FujPxSjRmX97fhWRDQU7G4tgw== - dependencies: - "@graphql-tools/schema" "^8.3.2" - "@graphql-tools/utils" "^8.6.2" - fast-json-stable-stringify "^2.1.0" - tslib "~2.3.0" - -"@graphql-tools/schema@^8.0.0", "@graphql-tools/schema@^8.3.1", "@graphql-tools/schema@^8.3.2": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.2.tgz#5b949d7a2cc3936f73507d91cc609996f1266d11" - integrity sha512-77feSmIuHdoxMXRbRyxE8rEziKesd/AcqKV6fmxe7Zt+PgIQITxNDew2XJJg7qFTMNM43W77Ia6njUSBxNOkwg== +"@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== dependencies: - "@graphql-tools/merge" "^8.2.3" - "@graphql-tools/utils" "^8.6.2" - tslib "~2.3.0" - value-or-promise "1.0.11" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" -"@graphql-tools/utils@^8.6.2": - version "8.6.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.6.2.tgz#095408135f091aac68fe18a0a21b708e685500da" - integrity sha512-x1DG0cJgpJtImUlNE780B/dfp8pxvVxOD6UeykFH5rHes26S4kGokbgU8F1IgrJ1vAPm/OVBHtd2kicTsPfwdA== - dependencies: - tslib "~2.3.0" +"@fastify/busboy@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" + integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -816,95 +323,50 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@improbable-eng/grpc-web@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@improbable-eng/grpc-web/-/grpc-web-0.12.0.tgz#9b10a7edf2a1d7672f8997e34a60e7b70e49738f" - integrity sha512-uJjgMPngreRTYPBuo6gswMj1gK39Wbqre/RgE0XnSDXJRg6ST7ZhuS53dFE6Vc2CX4jxgl+cO+0B3op8LA4Q0Q== - dependencies: - browser-headers "^0.4.0" - -"@improbable-eng/grpc-web@^0.13.0": - version "0.13.0" - resolved "https://registry.yarnpkg.com/@improbable-eng/grpc-web/-/grpc-web-0.13.0.tgz#289e6fc4dafc00b1af8e2b93b970e6892299014d" - integrity sha512-vaxxT+Qwb7GPqDQrBV4vAAfH0HywgOLw6xGIKXd9Q8hcV63CQhmS3p4+pZ9/wVvt4Ph3ZDK9fdC983b9aGMUFg== - dependencies: - browser-headers "^0.4.0" +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== -"@improbable-eng/grpc-web@^0.14.0", "@improbable-eng/grpc-web@^0.14.1": - version "0.14.1" - resolved "https://registry.yarnpkg.com/@improbable-eng/grpc-web/-/grpc-web-0.14.1.tgz#f4662f64dc89c0f956a94bb8a3b576556c74589c" - integrity sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: - browser-headers "^0.4.1" - -"@josephg/resolvable@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" - integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@jridgewell/resolve-uri@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" - integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.11" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" - integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@^0.3.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" - integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@ledgerhq/devices@^5.51.1": - version "5.51.1" - resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.51.1.tgz#d741a4a5d8f17c2f9d282fd27147e6fe1999edb7" - integrity sha512-4w+P0VkbjzEXC7kv8T1GJ/9AVaP9I6uasMZ/JcdwZBS3qwvKo5A5z9uGhP5c7TvItzcmPb44b5Mw2kT+WjUuAA== - dependencies: - "@ledgerhq/errors" "^5.50.0" - "@ledgerhq/logs" "^5.50.0" - rxjs "6" - semver "^7.3.5" - -"@ledgerhq/errors@^5.50.0": - version "5.50.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.50.0.tgz#e3a6834cb8c19346efca214c1af84ed28e69dad9" - integrity sha512-gu6aJ/BHuRlpU7kgVpy2vcYk6atjB4iauP2ymF7Gk0ez0Y/6VSMVSJvubeEQN+IV60+OBK0JgeIZG7OiHaw8ow== - -"@ledgerhq/hw-transport-webusb@^5.22.0": - version "5.53.1" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-webusb/-/hw-transport-webusb-5.53.1.tgz#3df8c401417571e3bcacc378d8aca587214b05ae" - integrity sha512-A/f+xcrkIAZiJrvPpDvsrjxQX4cI2kbdiunQkwsYmOG3Bp4z89ZnsBiC7YBst4n2/g+QgTg0/KPVtODU5djooQ== - dependencies: - "@ledgerhq/devices" "^5.51.1" - "@ledgerhq/errors" "^5.50.0" - "@ledgerhq/hw-transport" "^5.51.1" - "@ledgerhq/logs" "^5.50.0" - -"@ledgerhq/hw-transport@^5.51.1": - version "5.51.1" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.51.1.tgz#8dd14a8e58cbee4df0c29eaeef983a79f5f22578" - integrity sha512-6wDYdbWrw9VwHIcoDnqWBaDFyviyjZWv6H9vz9Vyhe4Qd7TIFmbTl/eWs6hZvtZBza9K8y7zD8ChHwRI4s9tSw== - dependencies: - "@ledgerhq/devices" "^5.51.1" - "@ledgerhq/errors" "^5.50.0" - events "^3.3.0" - -"@ledgerhq/logs@^5.50.0": - version "5.50.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.50.0.tgz#29c6419e8379d496ab6d0426eadf3c4d100cd186" - integrity sha512-swKHYCOZUGyVt4ge0u8a7AwNcA//h4nx5wIi0sruGye1IJ5Cva0GyK9L2/WdX+kWVTKp92ZiEo1df31lrWGPgA== - -"@metamask/eth-sig-util@4.0.1": +"@metamask/abi-utils@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-2.0.4.tgz#20908c1d910f7a17a89fdf5778a5c59d5cb8b8be" + integrity sha512-StnIgUB75x7a7AgUhiaUZDpCsqGp7VkNnZh2XivXkJ6mPkE83U8ARGQj5MbRis7VJY8BC5V1AbB1fjdh0hupPQ== + dependencies: + "@metamask/superstruct" "^3.1.0" + "@metamask/utils" "^9.0.0" + +"@metamask/eth-sig-util@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== @@ -915,35 +377,93 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" -"@metamask/safe-event-emitter@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c" - integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q== +"@metamask/eth-sig-util@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-8.1.1.tgz#7385cd392798afd557265480d88be23098637858" + integrity sha512-Pfi4DKTBWsfoVg3rbBS7EJq2MYvgbC/1xWzQw2vWxU5eCHUaylUSiuUYpf1e/zYRPJmiLOBx+44e5tOE/MEK3w== + dependencies: + "@ethereumjs/util" "^8.1.0" + "@metamask/abi-utils" "^2.0.4" + "@metamask/utils" "^9.0.0" + "@scure/base" "~1.1.3" + ethereum-cryptography "^2.1.2" + tweetnacl "^1.0.3" -"@multiformats/base-x@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121" - integrity sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw== +"@metamask/superstruct@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@metamask/superstruct/-/superstruct-3.1.0.tgz#148f786a674fba3ac885c1093ab718515bf7f648" + integrity sha512-N08M56HdOgBfRKkrgCMZvQppkZGcArEop3kixNEtVbJKm6P9Cfg0YkI6X0s1g78sNrj2fWUwvJADdZuzJgFttA== + +"@metamask/utils@^9.0.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.3.0.tgz#4726bd7f5d6a43ea8425b6d663ab9207f617c2d1" + integrity sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g== + dependencies: + "@ethereumjs/tx" "^4.2.0" + "@metamask/superstruct" "^3.1.0" + "@noble/hashes" "^1.3.1" + "@scure/base" "^1.1.3" + "@types/debug" "^4.1.7" + debug "^4.3.4" + pony-cause "^2.1.10" + semver "^7.5.4" + uuid "^9.0.1" + +"@noble/curves@1.2.0", "@noble/curves@~1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" -"@noble/hashes@1.1.2", "@noble/hashes@~1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" - integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== +"@noble/curves@1.4.2", "@noble/curves@~1.4.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/curves@1.7.0", "@noble/curves@^1.4.0", "@noble/curves@^1.6.0", "@noble/curves@~1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.7.0.tgz#0512360622439256df892f21d25b388f52505e45" + integrity sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw== + dependencies: + "@noble/hashes" "1.6.0" + +"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" + integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@noble/hashes@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.6.0.tgz#d4bfb516ad6e7b5111c216a5cc7075f4cf19e6c5" + integrity sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ== -"@noble/secp256k1@1.6.3", "@noble/secp256k1@~1.6.0": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.6.3.tgz#7eed12d9f4404b416999d0c87686836c4c5c9b94" - integrity sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ== +"@noble/hashes@1.6.1", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0", "@noble/hashes@^1.5.0", "@noble/hashes@~1.6.0": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.6.1.tgz#df6e5943edcea504bac61395926d6fd67869a0d5" + integrity sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w== -"@nodefactory/filsnap-adapter@^0.2.1": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@nodefactory/filsnap-adapter/-/filsnap-adapter-0.2.2.tgz#0e182150ce3825b6c26b8512ab9355ab7759b498" - integrity sha512-nbaYMwVopOXN2bWOdDY3il6gGL9qMuCmMN4WPuoxzJjSnAMJNqEeSe6MNNJ/fYBLipZcJfAtirNXRrFLFN+Tvw== +"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== -"@nodefactory/filsnap-types@^0.2.1": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@nodefactory/filsnap-types/-/filsnap-types-0.2.2.tgz#f95cbf93ce5815d8d151c60663940086b015cb8f" - integrity sha512-XT1tE2vrYF2D0tSNNekgjqKRpqPQn4W72eKul9dDCul/8ykouhqnVTyjFHYvBhlBWE0PK3nmG7i83QvhgGSiMw== +"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -966,721 +486,451 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@openzeppelin/contracts@3.4.2-solc-0.7": - version "3.4.2-solc-0.7" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" - integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== - -"@openzeppelin/contracts@4.5.0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.5.0.tgz#3fd75d57de172b3743cdfc1206883f56430409cc" - integrity sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA== - -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= +"@nomicfoundation/edr-darwin-arm64@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.5.tgz#37a31565d7ef42bed9028ac44aed82144de30bd1" + integrity sha512-A9zCCbbNxBpLgjS1kEJSpqxIvGGAX4cYbpDYCU2f3jVqOwaZ/NU761y1SvuCRVpOwhoCXqByN9b7HPpHi0L4hw== -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" +"@nomicfoundation/edr-darwin-x64@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.5.tgz#3252f6e86397af460b7a480bfe1b889464d75b89" + integrity sha512-x3zBY/v3R0modR5CzlL6qMfFMdgwd6oHrWpTkuuXnPFOX8SU31qq87/230f4szM+ukGK8Hi+mNq7Ro2VF4Fj+w== -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= +"@nomicfoundation/edr-linux-arm64-gnu@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.5.tgz#e7dc2934920b6cfabeb5ee7a5e26c8fb0d4964ac" + integrity sha512-HGpB8f1h8ogqPHTyUpyPRKZxUk2lu061g97dOQ/W4CxevI0s/qiw5DB3U3smLvSnBHKOzYS1jkxlMeGN01ky7A== -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= +"@nomicfoundation/edr-linux-arm64-musl@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.5.tgz#00459cd53e9fb7bd5b7e32128b508a6e89079d89" + integrity sha512-ESvJM5Y9XC03fZg9KaQg3Hl+mbx7dsSkTIAndoJS7X2SyakpL9KZpOSYrDk135o8s9P9lYJdPOyiq+Sh+XoCbQ== -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= +"@nomicfoundation/edr-linux-x64-gnu@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.5.tgz#5c9e4e2655caba48e0196977cba395bbde6fe97d" + integrity sha512-HCM1usyAR1Ew6RYf5AkMYGvHBy64cPA5NMbaeY72r0mpKaH3txiMyydcHibByOGdQ8iFLWpyUdpl1egotw+Tgg== -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= +"@nomicfoundation/edr-linux-x64-musl@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.5.tgz#9c220751b66452dc43a365f380e1e236a0a8c5a9" + integrity sha512-nB2uFRyczhAvWUH7NjCsIO6rHnQrof3xcCe6Mpmnzfl2PYcGyxN7iO4ZMmRcQS7R1Y670VH6+8ZBiRn8k43m7A== -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= +"@nomicfoundation/edr-win32-x64-msvc@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.5.tgz#90d3ac2a6a8a687522bda5ff2e92dd97e68126ea" + integrity sha512-B9QD/4DSSCFtWicO8A3BrsnitO1FPv7axB62wq5Q+qeJ50yJlTmyeGY3cw62gWItdvy2mh3fRM6L1LpnHiB77A== -"@redux-saga/core@^1.0.0": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@redux-saga/core/-/core-1.1.3.tgz#3085097b57a4ea8db5528d58673f20ce0950f6a4" - integrity sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg== - dependencies: - "@babel/runtime" "^7.6.3" - "@redux-saga/deferred" "^1.1.2" - "@redux-saga/delay-p" "^1.1.2" - "@redux-saga/is" "^1.1.2" - "@redux-saga/symbols" "^1.1.2" - "@redux-saga/types" "^1.1.0" - redux "^4.0.4" - typescript-tuple "^2.2.1" - -"@redux-saga/deferred@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@redux-saga/deferred/-/deferred-1.1.2.tgz#59937a0eba71fff289f1310233bc518117a71888" - integrity sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ== +"@nomicfoundation/edr@^0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.6.5.tgz#b3b1ebcdd0148cfe67cca128e7ebe8092e200359" + integrity sha512-tAqMslLP+/2b2sZP4qe9AuGxG3OkQ5gGgHE4isUuq6dUVjwCRPFhAOhpdFl+OjY5P3yEv3hmq9HjUGRa2VNjng== + dependencies: + "@nomicfoundation/edr-darwin-arm64" "0.6.5" + "@nomicfoundation/edr-darwin-x64" "0.6.5" + "@nomicfoundation/edr-linux-arm64-gnu" "0.6.5" + "@nomicfoundation/edr-linux-arm64-musl" "0.6.5" + "@nomicfoundation/edr-linux-x64-gnu" "0.6.5" + "@nomicfoundation/edr-linux-x64-musl" "0.6.5" + "@nomicfoundation/edr-win32-x64-msvc" "0.6.5" + +"@nomicfoundation/ethereumjs-common@4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz#9901f513af2d4802da87c66d6f255b510bef5acb" + integrity sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg== + dependencies: + "@nomicfoundation/ethereumjs-util" "9.0.4" + +"@nomicfoundation/ethereumjs-rlp@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz#66c95256fc3c909f6fb18f6a586475fc9762fa30" + integrity sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw== + +"@nomicfoundation/ethereumjs-tx@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz#b0ceb58c98cc34367d40a30d255d6315b2f456da" + integrity sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-util@9.0.4": + version "9.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz#84c5274e82018b154244c877b76bc049a4ed7b38" + integrity sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/hardhat-ignition-viem@^0.15.0": + version "0.15.8" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ignition-viem/-/hardhat-ignition-viem-0.15.8.tgz#139bec3d712cb201af992a6d20bec2b36f523e94" + integrity sha512-lbgg9bj56RuEzAy1EwjEl5OMJ27013POsvPOlk2nP9ZckIa8ke99/mkuKQ3CXUQLCfxKnjCv4nZ4Dt0wf8si1A== + +"@nomicfoundation/hardhat-ignition@^0.15.0": + version "0.15.8" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.8.tgz#d1a6bb508740959986ad256a4403570aec3d40d0" + integrity sha512-TN8TFQokcd7VyqGfbXO+KS8Q4K/gmsOFlv8dPnt/N596AncgV2Igxh5C3O+KVez11PDHNqoj1JzcDzzNVHrIRw== + dependencies: + "@nomicfoundation/ignition-core" "^0.15.8" + "@nomicfoundation/ignition-ui" "^0.15.8" + chalk "^4.0.0" + debug "^4.3.2" + fs-extra "^10.0.0" + json5 "^2.2.3" + prompts "^2.4.2" -"@redux-saga/delay-p@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@redux-saga/delay-p/-/delay-p-1.1.2.tgz#8f515f4b009b05b02a37a7c3d0ca9ddc157bb355" - integrity sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g== +"@nomicfoundation/hardhat-network-helpers@^1.0.0": + version "1.0.12" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz#2c0abec0c50b75f9d0d71776e49e3b5ef746d289" + integrity sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA== dependencies: - "@redux-saga/symbols" "^1.1.2" + ethereumjs-util "^7.1.4" -"@redux-saga/is@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@redux-saga/is/-/is-1.1.2.tgz#ae6c8421f58fcba80faf7cadb7d65b303b97e58e" - integrity sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w== +"@nomicfoundation/hardhat-toolbox-viem@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox-viem/-/hardhat-toolbox-viem-3.0.0.tgz#d50b6e2e3be220ccf6557c5072e999fbb4958aee" + integrity sha512-cr+aRozCtTwaRz5qc9OVY1kegWrnVwyhHZonICmlcm21cvJ31uvJnuPG688tMbjUvwRDw8tpZYZK0kI5M+4CKg== dependencies: - "@redux-saga/symbols" "^1.1.2" - "@redux-saga/types" "^1.1.0" - -"@redux-saga/symbols@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@redux-saga/symbols/-/symbols-1.1.2.tgz#216a672a487fc256872b8034835afc22a2d0595d" - integrity sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ== + chai-as-promised "^7.1.1" -"@redux-saga/types@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@redux-saga/types/-/types-1.1.0.tgz#0e81ce56b4883b4b2a3001ebe1ab298b84237204" - integrity sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg== - -"@repeaterjs/repeater@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@repeaterjs/repeater/-/repeater-3.0.4.tgz#a04d63f4d1bf5540a41b01a921c9a7fddc3bd1ca" - integrity sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA== - -"@rollup/plugin-babel@^5.3.0": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" - integrity sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@rollup/pluginutils" "^3.1.0" - -"@rollup/plugin-commonjs@^21.0.1": - version "21.0.2" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.2.tgz#0b9c539aa1837c94abfaf87945838b0fc8564891" - integrity sha512-d/OmjaLVO4j/aQX69bwpWPpbvI3TJkQuxoAk7BH8ew1PyoMBLTOuvJTjzG8oEoW7drIIqB0KCJtfFLu/2GClWg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - commondir "^1.0.1" - estree-walker "^2.0.1" - glob "^7.1.6" - is-reference "^1.2.1" - magic-string "^0.25.7" - resolve "^1.17.0" - -"@rollup/plugin-node-resolve@^13.1.3": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz#2ed277fb3ad98745424c1d2ba152484508a92d79" - integrity sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ== - dependencies: - "@rollup/pluginutils" "^3.1.0" - "@types/resolve" "1.17.1" - builtin-modules "^3.1.0" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.19.0" - -"@rollup/pluginutils@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== +"@nomicfoundation/hardhat-verify@^2.0.0": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.12.tgz#480819a245a2db0b127e473c62079f7b4f16daa8" + integrity sha512-Lg3Nu7DCXASQRVI/YysjuAX2z8jwOCbS0w5tz2HalWGSTZThqA0v9N0v0psHbKNqzPJa8bNOeapIVSziyJTnAg== dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^8.1.0" + debug "^4.1.1" + lodash.clonedeep "^4.5.0" + picocolors "^1.1.0" + semver "^6.3.0" + table "^6.8.0" + undici "^5.14.0" -"@rollup/pluginutils@^4.1.2": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.0.tgz#a14bbd058fdbba0a5647143b16ed0d86fb60bd08" - integrity sha512-2WUyJNRkyH5p487pGnn4tWAsxhEFKN/pT8CMgHshd5H+IXkOnKvKZwsz5ZWz+YCXkleZRAU5kwbfgF8CPfDRqA== +"@nomicfoundation/hardhat-viem@^2.0.5": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-viem/-/hardhat-viem-2.0.6.tgz#63abf87ddd1174bea5f87d02610342115da193a0" + integrity sha512-Pl5pvYK5VYKflfoUk4fVBESqKMNBtAIGPIT4j+Q8KNFueAe1vB2PsbRESeNJyW5YLL9pqKaD1RVqLmgIa1yvDg== dependencies: - estree-walker "^2.0.1" - picomatch "^2.2.2" + abitype "^0.9.8" + lodash.memoize "^4.1.2" -"@scure/base@~1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" - integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== - -"@scure/bip32@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.0.tgz#dea45875e7fbc720c2b4560325f1cf5d2246d95b" - integrity sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q== +"@nomicfoundation/ignition-core@^0.15.8": + version "0.15.8" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ignition-core/-/ignition-core-0.15.8.tgz#a5bf84f52d029d0305b5a34a289e6bb64bdcb5e6" + integrity sha512-U+CmTjKU9uwvh7qIabqboy/K/sDoClDgpsFRHoFvAj87DPDkXYb/mZBSkXPTU1wxTxrW6GTFE4lG3e7LAyF+kw== dependencies: - "@noble/hashes" "~1.1.1" - "@noble/secp256k1" "~1.6.0" - "@scure/base" "~1.1.0" + "@ethersproject/address" "5.6.1" + "@nomicfoundation/solidity-analyzer" "^0.1.1" + cbor "^9.0.0" + debug "^4.3.2" + ethers "^6.7.0" + fs-extra "^10.0.0" + immer "10.0.2" + lodash "4.17.21" + ndjson "2.0.0" -"@scure/bip39@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.0.tgz#92f11d095bae025f166bef3defcc5bf4945d419a" - integrity sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w== - dependencies: - "@noble/hashes" "~1.1.1" - "@scure/base" "~1.1.0" +"@nomicfoundation/ignition-ui@^0.15.8": + version "0.15.8" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.8.tgz#8c0dacec4809d8b90724a1901866656222beeda9" + integrity sha512-VUD5MsWrrv7E2P0AJO01pV8w8m66Du0uwBKXM0oUV5DRIzqm6eYHt9eCDb1KBINDpiFxOQiuyWQMdeKxgPp3qw== -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz#3a9c3b20d51360b20affb8f753e756d553d49557" + integrity sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw== -"@solidity-parser/parser@^0.14.0": - version "0.14.1" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.1.tgz#179afb29f4e295a77cc141151f26b3848abc3c46" - integrity sha512-eLjj2L6AuQjBB6s/ibwCAc0DwrR5Ge+ys+wgWo+bviU7fV2nTMQhU63CGaDKXg9iTmMxwhkyoggdIR7ZGRfMgw== - dependencies: - antlr4ts "^0.5.0-alpha.4" +"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz#74dcfabeb4ca373d95bd0d13692f44fcef133c28" + integrity sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw== -"@solidity-parser/parser@^0.14.1": - version "0.14.5" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" - integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== - dependencies: - antlr4ts "^0.5.0-alpha.4" +"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz#4af5849a89e5a8f511acc04f28eb5d4460ba2b6a" + integrity sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA== -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - -"@textile/buckets-grpc@2.6.6": - version "2.6.6" - resolved "https://registry.yarnpkg.com/@textile/buckets-grpc/-/buckets-grpc-2.6.6.tgz#304bdef37c81f0bdf2aa98f52d3b437bf4ab9d14" - integrity sha512-Gg+96RviTLNnSX8rhPxFgREJn3Ss2wca5Szk60nOenW+GoVIc+8dtsA9bE/6Vh5Gn85zAd17m1C2k6PbJK8x3Q== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@types/google-protobuf" "^3.7.4" - google-protobuf "^3.13.0" - -"@textile/buckets@^6.2.3": - version "6.2.3" - resolved "https://registry.yarnpkg.com/@textile/buckets/-/buckets-6.2.3.tgz#0fdb95c772dd82f9ac9071297382445b69d31409" - integrity sha512-wmZzAExQ3gFsYN8075OwgvKipXF1Ccw0kxdM23zuJZKMrSHk23LrjBXvhh4tU70JiGtO6hAzukIXaNHhIgSqoA== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@repeaterjs/repeater" "^3.0.4" - "@textile/buckets-grpc" "2.6.6" - "@textile/context" "^0.12.2" - "@textile/crypto" "^4.2.1" - "@textile/grpc-authentication" "^3.4.4" - "@textile/grpc-connection" "^2.5.3" - "@textile/grpc-transport" "^0.5.2" - "@textile/hub-grpc" "2.6.6" - "@textile/hub-threads-client" "^5.5.3" - "@textile/security" "^0.9.1" - "@textile/threads-id" "^0.6.1" - abort-controller "^3.0.0" - cids "^1.1.4" - it-drain "^1.0.3" - loglevel "^1.6.8" - native-abort-controller "^1.0.3" - paramap-it "^0.1.1" - -"@textile/context@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@textile/context/-/context-0.12.2.tgz#30c4b85e68ba2c838e63fcb95706ad9d7f688dc5" - integrity sha512-io5rjca4rjCvy39LHTHUXEdPhrhxtDhov05eqi4xftqm/ID4DbLmIsDJJpJqgk8T8/n9mU4cHSFfKbn1dhxHQw== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@textile/security" "^0.9.1" - -"@textile/crypto@^4.2.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@textile/crypto/-/crypto-4.2.1.tgz#96f03daab9e9a1b97967e490e2ca3f9b2fd66f89" - integrity sha512-7qxFLrXiSq5Tf3Wh3Oh6JKJMitF/6N3/AJyma6UAA8iQnAZBF98ShWz9tR59a3dvmGTc9MlyplOm16edbccscg== - dependencies: - "@types/ed2curve" "^0.2.2" - ed2curve "^0.3.0" - fastestsmallesttextencoderdecoder "^1.0.22" - multibase "^3.1.0" - tweetnacl "^1.0.3" +"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz#54036808a9a327b2ff84446c130a6687ee702a8e" + integrity sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA== -"@textile/grpc-authentication@^3.4.4": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@textile/grpc-authentication/-/grpc-authentication-3.4.4.tgz#b038e0dae471f124f8cb3bd007f12debf639b0db" - integrity sha512-OXOQhCJZEgyHNuK/GO8VuHosWkE2+gpq+Gg3seHog3NSsR+xapLdUY4EWNrEuD92ezi7VKXph4caoO7wLRn+Dw== - dependencies: - "@textile/context" "^0.12.2" - "@textile/crypto" "^4.2.1" - "@textile/grpc-connection" "^2.5.3" - "@textile/hub-threads-client" "^5.5.3" - "@textile/security" "^0.9.1" +"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz#466cda0d6e43691986c944b909fc6dbb8cfc594e" + integrity sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g== -"@textile/grpc-connection@^2.5.3": - version "2.5.3" - resolved "https://registry.yarnpkg.com/@textile/grpc-connection/-/grpc-connection-2.5.3.tgz#144b44e26172fde04ff5ca76115bc65b83e05a43" - integrity sha512-xtJgohjLjUsI2uEehqhN1MoziaAobUO5pziHUWv/ACQX5k9NdrLkKBwYorU1XJqHHoWLVWSbtDenTGsCRGIrig== - dependencies: - "@improbable-eng/grpc-web" "^0.12.0" - "@textile/context" "^0.12.2" - "@textile/grpc-transport" "^0.5.2" +"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz#2b35826987a6e94444140ac92310baa088ee7f94" + integrity sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg== -"@textile/grpc-powergate-client@^2.6.2": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@textile/grpc-powergate-client/-/grpc-powergate-client-2.6.2.tgz#c267cc3e3dd1e68673c234d5465ff70bed843df6" - integrity sha512-ODe22lveqPiSkBsxnhLIRKQzZVwvyqDVx6WBPQJZI4yxrja5SDOq6/yH2Dtmqyfxg8BOobFvn+tid3wexRZjnQ== - dependencies: - "@improbable-eng/grpc-web" "^0.14.0" - "@types/google-protobuf" "^3.15.2" - google-protobuf "^3.17.3" +"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz#e6363d13b8709ca66f330562337dbc01ce8bbbd9" + integrity sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA== -"@textile/grpc-transport@^0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@textile/grpc-transport/-/grpc-transport-0.5.2.tgz#79b63e0618d25479fb06f6b9be256d6a80e9fac4" - integrity sha512-XEC+Ubs7/pibZU2AHDJLeCEAVNtgEWmEXBXYJubpp4SVviuGUyd4h+zvqLw4FiIBGtlxx1u//cmzANhL0Ew7Rw== +"@nomicfoundation/solidity-analyzer@^0.1.0", "@nomicfoundation/solidity-analyzer@^0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz#8bcea7d300157bf3a770a851d9f5c5e2db34ac55" + integrity sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA== + optionalDependencies: + "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.2" + "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.2" + "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.2" + +"@nomiclabs/hardhat-solhint@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-solhint/-/hardhat-solhint-4.0.1.tgz#4e119a3e780e0ba6849e53ea1adfe71b2fb20f64" + integrity sha512-ekfbbGfUwMZGr9aPAurPa7GVMX/6XqKemppVEez+mC36H7G5UyBsnrUKZMhMDVHG9S7+ke9sLuaibnWvpdSrQA== dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@types/ws" "^7.2.6" - isomorphic-ws "^4.0.1" - loglevel "^1.6.6" - ws "^7.2.1" + solhint "^5.0.2" -"@textile/hub-filecoin@^2.2.3": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@textile/hub-filecoin/-/hub-filecoin-2.2.3.tgz#f83a0e3be2225aa3180e6b87abebc3559b2f6030" - integrity sha512-egFQbHb28/wAsG7RmmowA8Kz5+X3H8rxSu5eKJitPza14/CI1oANO+ikX4tfNGqbFwi5WvQUz0Bsdo3DtuoOmA== - dependencies: - "@improbable-eng/grpc-web" "^0.12.0" - "@textile/context" "^0.12.2" - "@textile/crypto" "^4.2.1" - "@textile/grpc-authentication" "^3.4.4" - "@textile/grpc-connection" "^2.5.3" - "@textile/grpc-powergate-client" "^2.6.2" - "@textile/hub-grpc" "2.6.6" - "@textile/security" "^0.9.1" - event-iterator "^2.0.0" - loglevel "^1.6.8" - -"@textile/hub-grpc@2.6.6": - version "2.6.6" - resolved "https://registry.yarnpkg.com/@textile/hub-grpc/-/hub-grpc-2.6.6.tgz#c99392490885760f357b58e72812066aac0ffeac" - integrity sha512-PHoLUE1lq0hyiVjIucPHRxps8r1oafXHIgmAR99+Lk4TwAF2MXx5rfxYhg1dEJ3ches8ZuNbVGkiNIXroIoZ8Q== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@types/google-protobuf" "^3.7.4" - google-protobuf "^3.13.0" - -"@textile/hub-threads-client@^5.5.3": - version "5.5.3" - resolved "https://registry.yarnpkg.com/@textile/hub-threads-client/-/hub-threads-client-5.5.3.tgz#87a55c098abddf1e7c2ad51eb2323e0a96212510" - integrity sha512-e0/2xbVoybM4U9LV7JxVWk9VrdQknrmKUGO9POGjl4vuH93uasH4QMuXVLmGc2yvr/jkgAy8dAZcwi7R7RplZA== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@textile/context" "^0.12.2" - "@textile/hub-grpc" "2.6.6" - "@textile/security" "^0.9.1" - "@textile/threads-client" "^2.3.3" - "@textile/threads-id" "^0.6.1" - "@textile/users-grpc" "2.6.6" - loglevel "^1.7.0" - -"@textile/hub@^6.0.2": - version "6.3.3" - resolved "https://registry.yarnpkg.com/@textile/hub/-/hub-6.3.3.tgz#0eb17ddc9cf2d76e078c7b433316121cd878fb54" - integrity sha512-PMLIIiB6D9Pp24pcc1HPEz0CmZmS6l2Wk2j3ny9v1TEX1p2ynbnDfHHuKwyj4juhy+yG7f2G7skZrrMn3AxgaQ== - dependencies: - "@textile/buckets" "^6.2.3" - "@textile/crypto" "^4.2.1" - "@textile/grpc-authentication" "^3.4.4" - "@textile/hub-filecoin" "^2.2.3" - "@textile/hub-grpc" "2.6.6" - "@textile/hub-threads-client" "^5.5.3" - "@textile/security" "^0.9.1" - "@textile/threads-id" "^0.6.1" - "@textile/users" "^6.2.3" - loglevel "^1.6.8" - multihashes "3.1.2" - -"@textile/multiaddr@^0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@textile/multiaddr/-/multiaddr-0.6.1.tgz#c3dc666866d7616ab7a31bceb390ffad4f5932fb" - integrity sha512-OQK/kXYhtUA8yN41xltCxCiCO98Pkk8yMgUdhPDAhogvptvX4k9g6Rg0Yob18uBwN58AYUg075V//SWSK1kUCQ== - dependencies: - "@textile/threads-id" "^0.6.1" - multiaddr "^8.1.2" - varint "^6.0.0" +"@openzeppelin/contracts@3.4.2-solc-0.7": + version "3.4.2-solc-0.7" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" + integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== + +"@openzeppelin/contracts@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.5.0.tgz#3fd75d57de172b3743cdfc1206883f56430409cc" + integrity sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA== + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@pnpm/config.env-replace@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c" + integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w== -"@textile/security@^0.9.1": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@textile/security/-/security-0.9.1.tgz#fe40cad3b27caf097252236b843b4fa71e81ffaf" - integrity sha512-pmiSOUezV/udTMoQsvyEZwZFfN0tMo6dOAof4VBqyFdDZZV6doeI5zTDpqSJZTg69n0swfWxsHw96ZWQIoWvsw== +"@pnpm/network.ca-file@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983" + integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA== dependencies: - "@consento/sync-randombytes" "^1.0.5" - fast-sha256 "^1.3.0" - fastestsmallesttextencoderdecoder "^1.0.22" - multibase "^3.1.0" + graceful-fs "4.2.10" -"@textile/threads-client-grpc@^1.1.2": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@textile/threads-client-grpc/-/threads-client-grpc-1.1.5.tgz#566efb645d9d46d97a0dfcfdd5319113e6df8aac" - integrity sha512-gJw3Eso9hdwAB+LbCDAWnzp3/uS6ahs9a+gYmA+xBxeYL4PfTP/3X01G6dJz8oZ9/pHcw1cxodH16dXn4INT5g== +"@pnpm/npm-conf@^2.1.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz#bb375a571a0bd63ab0a23bece33033c683e9b6b0" + integrity sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw== dependencies: - "@improbable-eng/grpc-web" "^0.14.1" - "@types/google-protobuf" "^3.15.5" - google-protobuf "^3.19.4" + "@pnpm/config.env-replace" "^1.1.0" + "@pnpm/network.ca-file" "^1.0.1" + config-chain "^1.1.11" -"@textile/threads-client@^2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@textile/threads-client/-/threads-client-2.3.3.tgz#b3dcebe0447d00030f0e3dc90f9d55b0f7e14617" - integrity sha512-HY0raf0rOHVEz8rEVaujiwW/1btCIELk67ruYftnJN0hxdsRthugNjjNCYrZZUbslxTFJ4bRmnRpAPMirwt8SQ== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@textile/context" "^0.12.2" - "@textile/crypto" "^4.2.1" - "@textile/grpc-transport" "^0.5.2" - "@textile/multiaddr" "^0.6.1" - "@textile/security" "^0.9.1" - "@textile/threads-client-grpc" "^1.1.2" - "@textile/threads-id" "^0.6.1" - "@types/to-json-schema" "^0.2.0" - fastestsmallesttextencoderdecoder "^1.0.22" - to-json-schema "^0.2.5" - -"@textile/threads-id@^0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@textile/threads-id/-/threads-id-0.6.1.tgz#ac6b5c93c9bd669f6c8f75ab2044b47a0f09627c" - integrity sha512-KwhbLjZ/eEquPorGgHFotw4g0bkKLTsqQmnsIxFeo+6C1mz40PQu4IOvJwohHr5GL6wedjlobry4Jj+uI3N+0w== - dependencies: - "@consento/sync-randombytes" "^1.0.4" - multibase "^3.1.0" - varint "^6.0.0" - -"@textile/users-grpc@2.6.6": - version "2.6.6" - resolved "https://registry.yarnpkg.com/@textile/users-grpc/-/users-grpc-2.6.6.tgz#dfec3ffc8f960892839c4e2e678af57b79f0d09a" - integrity sha512-pzI/jAWJx1/NqvSj03ukn2++aDNRdnyjwgbxh2drrsuxRZyCQEa1osBAA+SDkH5oeRf6dgxrc9dF8W1Ttjn0Yw== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@types/google-protobuf" "^3.7.4" - google-protobuf "^3.13.0" - -"@textile/users@^6.2.3": - version "6.2.3" - resolved "https://registry.yarnpkg.com/@textile/users/-/users-6.2.3.tgz#31d5384800714513d76d50ff4a911869b2d368cd" - integrity sha512-PJHal0gEV3J4plVk1rmtP0XZaTs7Rsc6l3yLJd+NHCJQ6mJGfp3lAwV1W2mPC3Lis4S1NlUvpMD6FgwuHtjLHg== - dependencies: - "@improbable-eng/grpc-web" "^0.13.0" - "@textile/buckets-grpc" "2.6.6" - "@textile/context" "^0.12.2" - "@textile/crypto" "^4.2.1" - "@textile/grpc-authentication" "^3.4.4" - "@textile/grpc-connection" "^2.5.3" - "@textile/grpc-transport" "^0.5.2" - "@textile/hub-grpc" "2.6.6" - "@textile/hub-threads-client" "^5.5.3" - "@textile/security" "^0.9.1" - "@textile/threads-id" "^0.6.1" - "@textile/users-grpc" "2.6.6" - event-iterator "^2.0.0" - loglevel "^1.7.0" - -"@truffle/abi-utils@^0.2.10": - version "0.2.10" - resolved "https://registry.yarnpkg.com/@truffle/abi-utils/-/abi-utils-0.2.10.tgz#2f2f986a8e044e1aa37191ea92524badcd5401a8" - integrity sha512-zG3PSXwq4mrXOOBKzgmOqNlVe2ZBUNAFv0xHAq5DwWew8PSQ/+a0ixPbWXXc3xYbApJMlIXRM716fB5MiZ22FA== - dependencies: - change-case "3.0.2" - faker "^5.3.1" - fast-check "^2.12.1" - -"@truffle/code-utils@^1.2.32": - version "1.2.32" - resolved "https://registry.yarnpkg.com/@truffle/code-utils/-/code-utils-1.2.32.tgz#fa5f27737947cdbc8abdf41fffcf8a4b5b15751a" - integrity sha512-OUP1zO8kkIGt+PhCfLZqai8K9Kel5eDYKvr/Z3ubt4RyTSb1rNwtnmJbiEszVhdsO7/Qi/w/vbW0ebS0clcjyg== - dependencies: - cbor "^5.1.0" - -"@truffle/codec@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@truffle/codec/-/codec-0.12.2.tgz#0248b4c049061970a97001807caf2d5effb1d103" - integrity sha512-UiWPPWtW8nkLbdzut0KkFXg5Xt70XXtgsdpwSG7lYOXJTPeLcCpGnVvjrDglsvwk3gz3iiOVrdtq6JwYo4om6Q== - dependencies: - "@truffle/abi-utils" "^0.2.10" - "@truffle/compile-common" "^0.7.29" - big.js "^5.2.2" - bn.js "^5.1.3" - cbor "^5.1.0" - debug "^4.3.1" - lodash "^4.17.21" - semver "^7.3.4" - utf8 "^3.0.0" - web3-utils "1.5.3" - -"@truffle/compile-common@^0.7.29": - version "0.7.29" - resolved "https://registry.yarnpkg.com/@truffle/compile-common/-/compile-common-0.7.29.tgz#6042578755a70d5e0918d13a08762dd4943a23f3" - integrity sha512-Z5h0jQh/GXsjnTBt02boV2QiQ1QlGlWlupZWsIcLHpBxQaw/TXTa7EvicPLWf7JQ3my56iaY3N5rkrQLAlFf1Q== - dependencies: - "@truffle/error" "^0.1.0" - colors "1.4.0" - -"@truffle/config@^1.3.22": - version "1.3.22" - resolved "https://registry.yarnpkg.com/@truffle/config/-/config-1.3.22.tgz#4defe8361993317c6b8e723f71a9b79730c9cbb3" - integrity sha512-To8N/VnWSg4YzxKA35GndOT8wHLa9AwAPAd+ZMo84u+dXTYlzVM5LMovOTtZipvU8lwU1aeM2oqpHFUDXG/OJQ== - dependencies: - "@truffle/error" "^0.1.0" - "@truffle/events" "^0.1.1" - "@truffle/provider" "^0.2.48" - conf "^10.0.2" - find-up "^2.1.0" - lodash "^4.17.21" - original-require "^1.0.1" +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@truffle/db-loader@^0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@truffle/db-loader/-/db-loader-0.1.6.tgz#6172bf1312a76353f90c30486ade0fdec52946a1" - integrity sha512-ztJcPg1OdNVuFgSaXorU1FYyAwA83gVuLoz5tiP1YN1es+uHEWE1fBCui26wq8rv7rTZaqyVUDodlE/zzQlnSw== - optionalDependencies: - "@truffle/db" "^0.5.56" - -"@truffle/db@^0.5.56": - version "0.5.56" - resolved "https://registry.yarnpkg.com/@truffle/db/-/db-0.5.56.tgz#d5ee12829d0b7ae913d21847d255166ddfe573cf" - integrity sha512-p48KmjwShrHZbVZNbor07kwrTZ4jcV2g70jdwV4bjB83wrolwzC7sRgapA1/zowsU54rDWw6jVGFgW5Fp8szTA== - dependencies: - "@graphql-tools/delegate" "^8.4.3" - "@graphql-tools/schema" "^8.3.1" - "@truffle/abi-utils" "^0.2.10" - "@truffle/code-utils" "^1.2.32" - "@truffle/config" "^1.3.22" - abstract-leveldown "^7.2.0" - apollo-server "^3.6.3" - debug "^4.3.1" - fs-extra "^9.1.0" - graphql "^15.3.0" - graphql-tag "^2.11.0" - json-stable-stringify "^1.0.1" - jsondown "^1.0.0" - pascal-case "^2.0.1" - pluralize "^8.0.0" - pouchdb "7.1.1" - pouchdb-adapter-memory "^7.1.1" - pouchdb-adapter-node-websql "^7.0.0" - pouchdb-debug "^7.1.1" - pouchdb-find "^7.0.0" - web3-utils "1.5.3" - -"@truffle/debugger@^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@truffle/debugger/-/debugger-10.0.0.tgz#3abebbf8ef09eb9868cc93f76f940f8df07e9bfd" - integrity sha512-+NlfP08gEL3I530oKFQe7t6hHgqvsOu956QqRms47C9iQfWt2KOgNB7l7Om0jjHJLJkbdJVtW9+eeY18QYjGwA== - dependencies: - "@truffle/abi-utils" "^0.2.10" - "@truffle/codec" "^0.12.2" - "@truffle/source-map-utils" "^1.3.74" - bn.js "^5.1.3" - debug "^4.3.1" - json-pointer "^0.6.1" - json-stable-stringify "^1.0.1" - lodash "^4.17.21" - redux "^3.7.2" - redux-saga "1.0.0" - reselect-tree "^1.3.5" - semver "^7.3.4" - web3 "1.5.3" - web3-eth-abi "1.5.3" +"@scure/base@^1.1.3", "@scure/base@~1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.1.tgz#dd0b2a533063ca612c17aa9ad26424a2ff5aa865" + integrity sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ== -"@truffle/error@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@truffle/error/-/error-0.1.0.tgz#5e9fed79e6cda624c926d314b280a576f8b22a36" - integrity sha512-RbUfp5VreNhsa2Q4YbBjz18rOQI909pG32bghl1hulO7IpvcqTS+C3Ge5cNbiWQ1WGzy1wIeKLW0tmQtHFB7qg== - -"@truffle/events@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@truffle/events/-/events-0.1.1.tgz#5f9d2f131586014d502b882170be9edc7e7599cb" - integrity sha512-nO6ltXo9jS2c9/xgXj+gqZREWmIQ7ZCCL0/UzeAuyVn14qkbK7fcWO4hKiXk5Z2PZYdhehGo+viTVXDxwlzW4A== - dependencies: - emittery "^0.4.1" - ora "^3.4.0" - web3-utils "1.5.3" - -"@truffle/hdwallet-provider@2.0.14": - version "2.0.14" - resolved "https://registry.yarnpkg.com/@truffle/hdwallet-provider/-/hdwallet-provider-2.0.14.tgz#b345bc9f9432e5a0a1e1469a19433c2d4ce295d4" - integrity sha512-SO/T4qImJk7Nrerh2H9pGphIJTVgskmbnQ4n/2h/OcieLr63ZULWetjwdyHoUJzprDieXx6NZuWEUeEn0f4dTQ== - dependencies: - "@ethereumjs/common" "^2.4.0" - "@ethereumjs/tx" "^3.3.0" - "@metamask/eth-sig-util" "4.0.1" - ethereum-cryptography "1.1.2" - ethereum-protocol "^1.0.1" - ethereumjs-util "^7.1.5" - ethereumjs-wallet "^1.0.2" - web3-provider-engine "16.0.3" - -"@truffle/interface-adapter@^0.5.12": - version "0.5.12" - resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.5.12.tgz#8cc34e9a5363970bfec1001520ae55fad6a26bfd" - integrity sha512-Qrc5VARnvSILYqZNsAM0xsUHqGqphLXVdIvDnhUA1Xj1xyNz8iboTr8bXorMd+Uspw+PXmsW44BJ/Wioo/jL2A== - dependencies: - bn.js "^5.1.3" - ethers "^4.0.32" - web3 "1.5.3" - -"@truffle/preserve-fs@^0.2.7": - version "0.2.7" - resolved "https://registry.yarnpkg.com/@truffle/preserve-fs/-/preserve-fs-0.2.7.tgz#e79b235e00425f9771c5b8eb80057d0a4b13ed71" - integrity sha512-f4zHbIN86tFo6Q7L/xhvew+0tzjgY+CSYXvDtiWInqw5knjVg8O+G58rQrRTA6fqD312mQfJRVZRbyrxkKO/2Q== - dependencies: - "@truffle/preserve" "^0.2.7" - -"@truffle/preserve-to-buckets@^0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@truffle/preserve-to-buckets/-/preserve-to-buckets-0.2.8.tgz#7b107b4bc66273a018ea4110c1189c379aeaf468" - integrity sha512-Ryd7Kx4+G64tkUs51ajw13dgyzaQ2Z/UwiEE+ZTmJsG075S/KrPDAtqgPdjYOuiSOE9/jLJ/3c9Tly1ptr2txw== - dependencies: - "@textile/hub" "^6.0.2" - "@truffle/preserve" "^0.2.7" - cids "^1.1.5" - ipfs-http-client "^48.2.2" - isomorphic-ws "^4.0.1" - iter-tools "^7.0.2" - ws "^7.2.0" - -"@truffle/preserve-to-filecoin@^0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@truffle/preserve-to-filecoin/-/preserve-to-filecoin-0.2.8.tgz#9590d91eb4277f33bc725e5b0b70d1e15e24a4f9" - integrity sha512-msAtlcewclwNHkxCqJzSg9QKOc7nAPIEsgiooKj4F4t5z5XzuNf+4EhztF0PovncotMxywKoBO2w/2ILIDvWjA== - dependencies: - "@truffle/preserve" "^0.2.7" - "@trufflesuite/filecoin.js" "^0.0.2" - cids "^1.1.5" - delay "^5.0.0" - -"@truffle/preserve-to-ipfs@^0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@truffle/preserve-to-ipfs/-/preserve-to-ipfs-0.2.8.tgz#594cf075b1313815006d5428fa84c7cb448ff688" - integrity sha512-Wyz9aVfx+b2YQpeb0cPnOGRgLHyjFUJXMSJa+cJhlsRHyBPgaK1HFAMhXqCYIEm8vLGT+hu9K2DWIjXc1an91w== - dependencies: - "@truffle/preserve" "^0.2.7" - ipfs-http-client "^48.2.2" - iter-tools "^7.0.2" - -"@truffle/preserve@^0.2.7": - version "0.2.7" - resolved "https://registry.yarnpkg.com/@truffle/preserve/-/preserve-0.2.7.tgz#fd149e4d0f1594e400fea3453c898362655d8588" - integrity sha512-A5pRuFre9IR2m2BB1JMF9CItgUSwR2eRhqHU2ltvPjWHNxbGAo4tMZat+124hed6zDBUduYsjmV5Yr5wo7kF8g== +"@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.3", "@scure/base@~1.1.6": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== + +"@scure/bip32@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" + integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== dependencies: - spinnies "^0.5.1" + "@noble/hashes" "~1.2.0" + "@noble/secp256k1" "~1.7.0" + "@scure/base" "~1.1.0" -"@truffle/provider@^0.2.24", "@truffle/provider@^0.2.48": - version "0.2.48" - resolved "https://registry.yarnpkg.com/@truffle/provider/-/provider-0.2.48.tgz#be3c8567570bbd1ec13fd63a3c312e24da88f9e9" - integrity sha512-jno7/OokETQaHKHZ451+leCV/D2D3xaxmmHIDvP2SLJtSaThCQ6J05+dXvPSDU0OMxfYXL1hzsLQpEVTiDUVnw== +"@scure/bip32@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.2.tgz#90e78c027d5e30f0b22c1f8d50ff12f3fb7559f8" + integrity sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA== dependencies: - "@truffle/error" "^0.1.0" - "@truffle/interface-adapter" "^0.5.12" - web3 "1.5.3" + "@noble/curves" "~1.2.0" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.2" -"@truffle/source-map-utils@^1.3.74": - version "1.3.74" - resolved "https://registry.yarnpkg.com/@truffle/source-map-utils/-/source-map-utils-1.3.74.tgz#e5ae2bc650767547db476e03a124c7735e253d1d" - integrity sha512-ckJvbVqq0HyN+wYsBh3YRr9kZ5vAxA0TdZQkW71oSQmjONAAmrJxOJ82KRzD8VXlIdLzRBD3wR/IDQuomw1x4Q== +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== dependencies: - "@truffle/code-utils" "^1.2.32" - "@truffle/codec" "^0.12.2" - debug "^4.3.1" - json-pointer "^0.6.1" - node-interval-tree "^1.3.3" - web3-utils "1.5.3" + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" -"@trufflesuite/bigint-buffer@1.1.10": - version "1.1.10" - resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz#a1d9ca22d3cad1a138b78baaf15543637a3e1692" - integrity sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw== +"@scure/bip32@1.6.0", "@scure/bip32@^1.5.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.6.0.tgz#6dbc6b4af7c9101b351f41231a879d8da47e0891" + integrity sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA== dependencies: - node-gyp-build "4.4.0" + "@noble/curves" "~1.7.0" + "@noble/hashes" "~1.6.0" + "@scure/base" "~1.2.1" -"@trufflesuite/bigint-buffer@1.1.9": - version "1.1.9" - resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.9.tgz#e2604d76e1e4747b74376d68f1312f9944d0d75d" - integrity sha512-bdM5cEGCOhDSwminryHJbRmXc1x7dPKg6Pqns3qyTwFlxsqUgxE29lsERS3PlIW1HTjoIGMUqsk1zQQwST1Yxw== +"@scure/bip39@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" + integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== dependencies: - node-gyp-build "4.3.0" + "@noble/hashes" "~1.2.0" + "@scure/base" "~1.1.0" -"@trufflesuite/filecoin.js@^0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@trufflesuite/filecoin.js/-/filecoin.js-0.0.2.tgz#a74c8b8d2475707ce5c4293f0cf549fcfa761297" - integrity sha512-oz5OpRcqQR4xwADvVKlXVaLxo4milW6f6vItLf64wRlqNsC+OeGh5KxloAEUc6ah6ylIclhVLfsMKO1LTnaaAg== - dependencies: - "@ledgerhq/hw-transport-webusb" "^5.22.0" - "@nodefactory/filsnap-adapter" "^0.2.1" - "@nodefactory/filsnap-types" "^0.2.1" - "@zondax/filecoin-signing-tools" "github:Digital-MOB-Filecoin/filecoin-signing-tools-js" - bignumber.js "^9.0.0" - bitcore-lib "^8.22.2" - bitcore-mnemonic "^8.22.2" - btoa-lite "^1.0.0" - events "^3.2.0" - isomorphic-ws "^4.0.1" - node-fetch "^2.6.0" - rpc-websockets "^7.4.17" - scrypt-async "^2.0.1" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" - websocket "^1.0.31" - ws "^7.3.1" +"@scure/bip39@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" + integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg== + dependencies: + "@noble/hashes" "~1.3.0" + "@scure/base" "~1.1.0" -"@trufflesuite/uws-js-unofficial@20.30.0-unofficial.0": - version "20.30.0-unofficial.0" - resolved "https://registry.yarnpkg.com/@trufflesuite/uws-js-unofficial/-/uws-js-unofficial-20.30.0-unofficial.0.tgz#2fbc2f8ef7e82fbeea6abaf7e8a9d42a02b479d3" - integrity sha512-r5X0aOQcuT6pLwTRLD+mPnAM/nlKtvIK4Z+My++A8tTOR0qTjNRx8UB8jzRj3D+p9PMAp5LnpCUUGmz7/TppwA== +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== dependencies: - ws "8.13.0" - optionalDependencies: - bufferutil "4.0.7" - utf-8-validate "6.0.3" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@scure/bip39@1.5.0", "@scure/bip39@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.5.0.tgz#c8f9533dbd787641b047984356531d84485f19be" + integrity sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A== + dependencies: + "@noble/hashes" "~1.6.0" + "@scure/base" "~1.2.1" + +"@sentry/core@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" + integrity sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/hub@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.30.0.tgz#2453be9b9cb903404366e198bd30c7ca74cdc100" + integrity sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ== + dependencies: + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/minimal@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.30.0.tgz#ce3d3a6a273428e0084adcb800bc12e72d34637b" + integrity sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@sentry/node@^5.18.1": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.30.0.tgz#4ca479e799b1021285d7fe12ac0858951c11cd48" + integrity sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg== + dependencies: + "@sentry/core" "5.30.0" + "@sentry/hub" "5.30.0" + "@sentry/tracing" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.30.0.tgz#501d21f00c3f3be7f7635d8710da70d9419d4e1f" + integrity sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/types@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402" + integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== + +"@sentry/utils@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" + integrity sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== + dependencies: + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@sindresorhus/is@^5.2.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== -"@typechain/ethers-v5@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-9.0.0.tgz#6aa93bea7425c0463bd8a61eea3643540ef851bd" - integrity sha512-bAanuPl1L2itaUdMvor/QvwnIH+TM/CmG00q17Ilv3ZZMeJ2j8HcarhgJUZ9pBY1teBb85P8cC03dz3mSSx+tQ== +"@solidity-parser/parser@^0.16.0": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.16.2.tgz#42cb1e3d88b3e8029b0c9befff00b634cd92d2fa" + integrity sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg== dependencies: - lodash "^4.17.15" - ts-essentials "^7.0.1" + antlr4ts "^0.5.0-alpha.4" -"@types/accepts@^1.3.5": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" - integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ== +"@solidity-parser/parser@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.18.0.tgz#8e77a02a09ecce957255a2f48c9a7178ec191908" + integrity sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA== + +"@solidity-parser/parser@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.19.0.tgz#37a8983b2725af9b14ff8c4a475fa0e98d773c3f" + integrity sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA== + +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== dependencies: - "@types/node" "*" + defer-to-connect "^2.0.1" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": +"@types/bn.js@^4.11.3": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== @@ -1688,67 +938,42 @@ "@types/node" "*" "@types/bn.js@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" - integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA== - dependencies: - "@types/node" "*" - -"@types/body-parser@*", "@types/body-parser@1.19.2": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" - integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + version "5.1.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.6.tgz#9ba818eec0c85e4d3c679518428afdf611d03203" + integrity sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w== dependencies: - "@types/connect" "*" "@types/node" "*" -"@types/connect@*": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== +"@types/chai-as-promised@^7.1.3", "@types/chai-as-promised@^7.1.6": + version "7.1.8" + resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz#f2b3d82d53c59626b5d6bbc087667ccb4b677fe9" + integrity sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw== dependencies: - "@types/node" "*" + "@types/chai" "*" -"@types/cors@2.8.12": - version "2.8.12" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" - integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== - -"@types/ed2curve@^0.2.2": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@types/ed2curve/-/ed2curve-0.2.2.tgz#8f8bc7e2c9a5895a941c63a4f7acd7a6a62a5b15" - integrity sha512-G1sTX5xo91ydevQPINbL2nfgVAj/s1ZiqZxC8OCWduwu+edoNGUm5JXtTkg9F3LsBZbRI46/0HES4CPUE2wc9g== +"@types/chai@*": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.0.1.tgz#2c3705555cf11f5f59c836a84c44afcfe4e5689d" + integrity sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA== dependencies: - tweetnacl "^1.0.0" + "@types/deep-eql" "*" -"@types/estree@*": - version "0.0.51" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/chai@^4.2.0": + version "4.3.20" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc" + integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - -"@types/express-serve-static-core@4.17.28", "@types/express-serve-static-core@^4.17.18": - version "4.17.28" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== +"@types/debug@^4.1.7": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" + "@types/ms" "*" -"@types/express@4.17.13": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" - integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.18" - "@types/qs" "*" - "@types/serve-static" "*" +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== "@types/glob@^7.1.1": version "7.2.0" @@ -1758,129 +983,69 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/google-protobuf@^3.15.2", "@types/google-protobuf@^3.15.5", "@types/google-protobuf@^3.7.4": - version "3.15.5" - resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.5.tgz#644b2be0f5613b1f822c70c73c6b0e0b5b5fa2ad" - integrity sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw== - -"@types/json-schema@*": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/http-cache-semantics@^4.0.2": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/long@^4.0.0", "@types/long@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" - integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== - -"@types/lru-cache@5.1.1": +"@types/lru-cache@^5.1.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== -"@types/mime@^1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" - integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== - "@types/minimatch@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== - -"@types/node@*", "@types/node@>=13.7.0": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== - -"@types/node@10.12.18": - version "10.12.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" - integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== - -"@types/node@11.11.6": - version "11.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" - integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== - -"@types/node@^10.1.0": - version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== - -"@types/node@^12.12.6": - version "12.20.47" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.47.tgz#ca9237d51f2a2557419688511dab1c8daf475188" - integrity sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg== - -"@types/pbkdf2@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" - integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== - dependencies: - "@types/node" "*" - -"@types/prettier@^2.1.1": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" - integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== +"@types/mocha@^10.0.8": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" + integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/ms@*": + version "0.7.34" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" + integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== -"@types/resolve@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" - integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== +"@types/node@*", "@types/node@>=18.0.0": + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== dependencies: - "@types/node" "*" + undici-types "~6.20.0" -"@types/secp256k1@^4.0.1": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" - integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== dependencies: - "@types/node" "*" - -"@types/seedrandom@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-3.0.1.tgz#1254750a4fec4aff2ebec088ccd0bb02e91fedb4" - integrity sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw== + undici-types "~6.19.2" -"@types/serve-static@*": - version "1.13.10" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" - integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== +"@types/pbkdf2@^3.0.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.2.tgz#2dc43808e9985a2c69ff02e2d2027bd4fe33e8dc" + integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== dependencies: - "@types/mime" "^1" "@types/node" "*" -"@types/to-json-schema@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@types/to-json-schema/-/to-json-schema-0.2.1.tgz#223346df86bc0c183d53c939ad5eb1ddfb0e9bf5" - integrity sha512-DlvjodmdSrih054SrUqgS3bIZ93allrfbzjFUFmUhAtC60O+B/doLfgB8stafkEFyrU/zXWtPlX/V1H94iKv/A== - dependencies: - "@types/json-schema" "*" - -"@types/ws@^7.2.6": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== +"@types/secp256k1@^4.0.1": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.6.tgz#d60ba2349a51c2cbc5e816dcd831a42029d376bf" + integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== dependencies: "@types/node" "*" +"@ungap/structured-clone@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd" + integrity sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA== + "@uniswap/lib@^4.0.1-alpha": version "4.0.1-alpha" resolved "https://registry.yarnpkg.com/@uniswap/lib/-/lib-4.0.1-alpha.tgz#2881008e55f075344675b3bca93f020b028fbd02" @@ -1907,40 +1072,6 @@ "@uniswap/v3-core" "^1.0.0" base64-sol "1.0.1" -"@yarn-tool/resolve-package@^1.0.40": - version "1.0.46" - resolved "https://registry.yarnpkg.com/@yarn-tool/resolve-package/-/resolve-package-1.0.46.tgz#db7354380e5ca7682294af59e5ab0f7fce640ac1" - integrity sha512-RJcBGTVywUqYGRtGkPSgJC/ozf0wK/xjUy66tXkbpL35U0o1oef4S0v23euxA/CiukqBWr2fRGtGY6FidESdTg== - dependencies: - pkg-dir "< 6 >= 5" - tslib "^2.3.1" - upath2 "^3.1.12" - -"@zondax/filecoin-signing-tools@github:Digital-MOB-Filecoin/filecoin-signing-tools-js": - version "0.2.0" - resolved "https://codeload.github.com/Digital-MOB-Filecoin/filecoin-signing-tools-js/tar.gz/8f8e92157cac2556d35cab866779e9a8ea8a4e25" - dependencies: - axios "^0.20.0" - base32-decode "^1.0.0" - base32-encode "^1.1.1" - bip32 "^2.0.5" - bip39 "^3.0.2" - blakejs "^1.1.0" - bn.js "^5.1.2" - ipld-dag-cbor "^0.17.0" - leb128 "0.0.5" - secp256k1 "^4.0.1" - -"@zxing/text-encoding@0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" - integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== - -abab@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" - integrity sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4= - abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1949,142 +1080,66 @@ abbrev@1: abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= - -abort-controller@3.0.0, abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -abstract-level@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" - integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== - dependencies: - buffer "^6.0.3" - catering "^2.1.0" - is-buffer "^2.0.5" - level-supports "^4.0.0" - level-transcoder "^1.0.1" - module-error "^1.0.1" - queue-microtask "^1.2.3" - -abstract-leveldown@7.2.0, abstract-leveldown@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" - integrity sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ== - dependencies: - buffer "^6.0.3" - catering "^2.0.0" - is-buffer "^2.0.5" - level-concat-iterator "^3.0.0" - level-supports "^2.0.1" - queue-microtask "^1.2.3" - -abstract-leveldown@^6.2.1: - version "6.3.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" - integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -abstract-leveldown@~2.6.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" - integrity sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA== - dependencies: - xtend "~4.0.0" - -abstract-leveldown@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" - integrity sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w== - dependencies: - xtend "~4.0.0" - -abstract-leveldown@~6.0.0, abstract-leveldown@~6.0.1: - version "6.0.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.0.3.tgz#b4b6159343c74b0c5197b2817854782d8f748c4a" - integrity sha512-jzewKKpZbaYUa6HTThnrl+GrJhzjEAeuc7hTVpZdzg7kupXZFoqQDFwyOwLNbmJKJlmzw8yiipMPkDiuKkT06Q== - dependencies: - level-concat-iterator "~2.0.0" - xtend "~4.0.0" + integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== -abstract-leveldown@~6.2.1: - version "6.2.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" - integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" +abitype@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" + integrity sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ== -accepts@^1.3.5, accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" +abitype@1.0.7, abitype@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.7.tgz#876a0005d211e1c9132825d45bcee7b46416b284" + integrity sha512-ZfYYSktDQUwc2eduYu8C4wOs+RDPmnRYMh7zNfzeMtGGgb0U+6tLGjixUic6mXf5xKKCcgT5Qp6cv39tOARVFw== -acorn-globals@^1.0.4: - version "1.0.9" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-1.0.9.tgz#55bb5e98691507b74579d0513413217c380c54cf" - integrity sha1-VbtemGkVB7dFedBRNBMhfDgMVM8= - dependencies: - acorn "^2.1.0" +abitype@^0.9.8: + version "0.9.10" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.10.tgz#fa6fa30a6465da98736f98b6c601a02ed49f6eec" + integrity sha512-FIS7U4n7qwAT58KibwYig5iFG4K61rbhAqaQh/UWj8v1Y8mjX3F8TC9gd8cz9yT1TYel9f8nS5NO5kZp2RW0jQ== -acorn-jsx@^5.0.0, acorn-jsx@^5.3.2: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^2.1.0, acorn@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" - integrity sha1-q259nYhqrKiwhbwzEreaGYQz8Oc= - -acorn@^6.0.7: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" -acorn@^8.8.0: - version "8.8.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" - integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== -address@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" - integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== +adm-zip@^0.4.16: + version "0.4.16" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" + integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== -aes-js@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" - integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: - ajv "^8.0.0" + clean-stack "^2.0.0" + indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.6.1, ajv@^6.9.1: +ajv@^6.12.4, ajv@^6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2094,57 +1149,51 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.6.1, ajv@^6.9.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.6.3: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== +ajv@^8.0.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: - fast-deep-equal "^3.1.1" + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.2.2" amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= - -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + integrity sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg== -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= +ansi-align@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== + dependencies: + string-width "^4.1.0" -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-colors@^4.1.1, ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -2158,157 +1207,29 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansicolors@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" - integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -antlr4@4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" - integrity sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ== +antlr4@^4.11.0, antlr4@^4.13.1-patch-1: + version "4.13.2" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.2.tgz#0d084ad0e32620482a9c3a0e2470c02e72e4006d" + integrity sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg== antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== -any-signal@^2.0.0, any-signal@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/any-signal/-/any-signal-2.1.2.tgz#8d48270de0605f8b218cf9abe8e9c6a0e7418102" - integrity sha512-B+rDnWasMi/eWcajPcCWSlYc7muXOrcYrqgyzcdKisl2H/WTlQ0gip1KyQfr0ZlxJdsuWCj/LWwQm7fhyhRfIQ== - dependencies: - abort-controller "^3.0.0" - native-abort-controller "^1.0.3" - -anymatch@~3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" -apollo-datasource@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-3.3.1.tgz#a1168dd68371930de3ed4245ad12fa8600efe2cc" - integrity sha512-Z3a8rEUXVPIZ1p8xrFL8bcNhWmhOmovgDArvwIwmJOBnh093ZpRfO+ESJEDAN4KswmyzCLDAwjsW4zQOONdRUw== - dependencies: - apollo-server-caching "^3.3.0" - apollo-server-env "^4.2.1" - -apollo-reporting-protobuf@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.0.tgz#2fc0f7508e488851eda8a6e7c8cc3b5a156ab44b" - integrity sha512-51Jwrg0NvHJfKz7TIGU8+Os3rUAqWtXeKRsRtKYtTeMSBPNhzz8UoGjAB3XyVmUXRE3IRmLtDPDRFL7qbxMI/w== - dependencies: - "@apollo/protobufjs" "1.2.2" - -apollo-server-caching@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-3.3.0.tgz#f501cbeb820a4201d98c2b768c085f22848d9dc5" - integrity sha512-Wgcb0ArjZ5DjQ7ID+tvxUcZ7Yxdbk5l1MxZL8D8gkyjooOkhPNzjRVQ7ubPoXqO54PrOMOTm1ejVhsF+AfIirQ== - dependencies: - lru-cache "^6.0.0" - -apollo-server-core@^3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-3.6.4.tgz#dcf3925173a8e9a501ed3975654cb2ed58af3710" - integrity sha512-zttpu/3IeDGhRgIGK84z9HwTgvETDl9zntXiQ0G1tBJgOhDvehSkMiOmy+FKR1HW9+94ao1Olz6ZIyhP0dvzSg== - dependencies: - "@apollographql/apollo-tools" "^0.5.1" - "@apollographql/graphql-playground-html" "1.6.29" - "@graphql-tools/mock" "^8.1.2" - "@graphql-tools/schema" "^8.0.0" - "@josephg/resolvable" "^1.0.0" - apollo-datasource "^3.3.1" - apollo-reporting-protobuf "^3.3.0" - apollo-server-caching "^3.3.0" - apollo-server-env "^4.2.1" - apollo-server-errors "^3.3.1" - apollo-server-plugin-base "^3.5.1" - apollo-server-types "^3.5.1" - async-retry "^1.2.1" - fast-json-stable-stringify "^2.1.0" - graphql-tag "^2.11.0" - lodash.sortby "^4.7.0" - loglevel "^1.6.8" - lru-cache "^6.0.0" - sha.js "^2.4.11" - uuid "^8.0.0" - -apollo-server-env@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-4.2.1.tgz#ea5b1944accdbdba311f179e4dfaeca482c20185" - integrity sha512-vm/7c7ld+zFMxibzqZ7SSa5tBENc4B0uye9LTfjJwGoQFY5xsUPH5FpO5j0bMUDZ8YYNbrF9SNtzc5Cngcr90g== - dependencies: - node-fetch "^2.6.7" - -apollo-server-errors@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-3.3.1.tgz#ba5c00cdaa33d4cbd09779f8cb6f47475d1cd655" - integrity sha512-xnZJ5QWs6FixHICXHxUfm+ZWqqxrNuPlQ+kj5m6RtEgIpekOPssH/SD9gf2B4HuWV0QozorrygwZnux8POvyPA== - -apollo-server-express@^3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-3.6.4.tgz#759b64047a41068deb3af068ce02381404e3d6d0" - integrity sha512-lN73Ka7UZJINJzvMeRFIFn7898hGjTxVtRQwAzzmw5XSpWZZHZkTcAkoDxUs0GwU6h2LE14ogu2WJ4G8AZVl1Q== - dependencies: - "@types/accepts" "^1.3.5" - "@types/body-parser" "1.19.2" - "@types/cors" "2.8.12" - "@types/express" "4.17.13" - "@types/express-serve-static-core" "4.17.28" - accepts "^1.3.5" - apollo-server-core "^3.6.4" - apollo-server-types "^3.5.1" - body-parser "^1.19.0" - cors "^2.8.5" - parseurl "^1.3.3" - -apollo-server-plugin-base@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-3.5.1.tgz#73fc1591522e36e32eff3d033975333e30cf1a7c" - integrity sha512-wgDHz3lLrCqpecDky3z6AOQ0vik0qs0Cya/Ti6n3ESYXJ9MdK3jE/QunATIrOYYJaa+NKl9V7YwU+/bojNfFuQ== - dependencies: - apollo-server-types "^3.5.1" - -apollo-server-types@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-3.5.1.tgz#73fc8aa82b3175fde3906fa3d6786ee4d3e8c982" - integrity sha512-zG7xLl4mmHuZMAYOfjWKHY/IC/GgIkJ3HnYuR7FRrnPpRA9Yt5Kf1M1rjm1Esuqzpb/dt8pM7cX40QaIQObCYQ== - dependencies: - apollo-reporting-protobuf "^3.3.0" - apollo-server-caching "^3.3.0" - apollo-server-env "^4.2.1" - -apollo-server@^3.6.3: - version "3.6.4" - resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-3.6.4.tgz#e1bc966eb7d03944274056af4b17b380f0ac8696" - integrity sha512-PIEDWtfiiiKt0uEMJ7/qiyULPat/ichDN/h9GrrroOFiz/tfU/yJXuHpoq8R/uzVyn4GpEc4OoibC2zOr59zig== - dependencies: - apollo-server-core "^3.6.4" - apollo-server-express "^3.6.4" - express "^4.17.1" - -app-module-path@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" - integrity sha1-ZBqlXft9am8KgUHEucCqULbCTdU= - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -are-we-there-yet@~1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" - integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -2326,35 +1247,24 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -argsarray@0.0.1, argsarray@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb" - integrity sha1-bnIHtOzbObCviDA/pa4ivajfYcs= - -array-back@^3.0.1, array-back@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" - integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== - -array-back@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" - integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-includes@^3.1.4: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^2.1.0: @@ -2362,463 +1272,148 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.flat@^1.2.5: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" -array.prototype.map@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.4.tgz#0d97b640cfdd036c1b41cfe706a5e699aa0711f2" - integrity sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA== +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - -asap@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - -asn1.js@^5.0.1, asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" -asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== dependencies: - safer-buffer "~2.1.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -ast-parents@0.0.1: +ast-parents@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" integrity sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async-eventemitter@0.2.4, async-eventemitter@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" - integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== - dependencies: - async "^2.4.0" - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async-mutex@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.2.6.tgz#0d7a3deb978bc2b984d5908a2038e1ae2e54ff40" - integrity sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw== - dependencies: - tslib "^2.0.0" - -async-retry@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" - integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== - dependencies: - retry "0.13.1" +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async@1.x, async@^1.4.2: +async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - -async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0: - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" + integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" -atomically@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/atomically/-/atomically-1.7.0.tgz#c07a0458432ea6dbc9a3506fffa424b48bccaafe" - integrity sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w== - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -axios@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd" - integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA== - dependencies: - follow-redirects "^1.10.0" - -axios@^0.26.1: - version "0.26.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" - integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== - dependencies: - follow-redirects "^1.14.8" - -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-generator@6.26.1: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-polyfill-corejs2@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" - integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== - dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-define-polyfill-provider" "^0.3.3" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" - integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - core-js-compat "^3.25.1" - -babel-plugin-polyfill-regenerator@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" - integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - -babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-traverse@6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon@6.18.0, babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - -backoff@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" - integrity sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA== - dependencies: - precond "0.2" +axios@^1.6.7: + version "1.7.9" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" + integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2, base-x@^3.0.8: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== +base-x@^3.0.2: + version "3.0.10" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.10.tgz#62de58653f8762b5d6f8d9fe30fa75f7b2585a75" + integrity sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ== dependencies: safe-buffer "^5.0.1" -base32-decode@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/base32-decode/-/base32-decode-1.0.0.tgz#2a821d6a664890c872f20aa9aca95a4b4b80e2a7" - integrity sha512-KNWUX/R7wKenwE/G/qFMzGScOgVntOmbE27vvc6GrniDGYb6a5+qWcuoXl8WIOQL7q0TpK7nZDm1Y04Yi3Yn5g== - -base32-encode@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/base32-encode/-/base32-encode-1.2.0.tgz#e150573a5e431af0a998e32bdfde7045725ca453" - integrity sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A== - dependencies: - to-data-view "^1.1.0" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - base64-sol@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/base64-sol/-/base64-sol-1.0.1.tgz#91317aa341f0bc763811783c5729f1c2574600f6" integrity sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg== -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - -bech32@=2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355" - integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -bigi@^1.1.0, bigi@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/bigi/-/bigi-1.4.2.tgz#9c665a95f88b8b08fc05cfd731f561859d725825" - integrity sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU= - -bignumber.js@^9.0.0, bignumber.js@^9.0.1: - version "9.0.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" - integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== - binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bindings@^1.3.0, bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bip-schnorr@=0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/bip-schnorr/-/bip-schnorr-0.6.4.tgz#6fde7f301fe6b207dbd05f8ec2caf08fa5a51d0d" - integrity sha512-dNKw7Lea8B0wMIN4OjEmOk/Z5qUGqoPDY0P2QttLqGk1hmDPytLWW8PR5Pb6Vxy6CprcdEgfJpOjUu+ONQveyg== - dependencies: - bigi "^1.4.2" - ecurve "^1.0.6" - js-sha256 "^0.9.0" - randombytes "^2.1.0" - safe-buffer "^5.2.1" - -bip32@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/bip32/-/bip32-2.0.6.tgz#6a81d9f98c4cd57d05150c60d8f9e75121635134" - integrity sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA== - dependencies: - "@types/node" "10.12.18" - bs58check "^2.1.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - tiny-secp256k1 "^1.1.3" - typeforce "^1.11.5" - wif "^2.0.6" - -bip39@^3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.4.tgz#5b11fed966840b5e1b8539f0f54ab6392969b2a0" - integrity sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw== - dependencies: - "@types/node" "11.11.6" - create-hash "^1.1.0" - pbkdf2 "^3.0.9" - randombytes "^2.0.1" - -bitcore-lib@^8.22.2, bitcore-lib@^8.25.25: - version "8.25.25" - resolved "https://registry.yarnpkg.com/bitcore-lib/-/bitcore-lib-8.25.25.tgz#113049722be84f6c4b11860b1f14c69c41e9f11b" - integrity sha512-H6qNCVl4M8/MglXhvc04mmeus1d6nrmqTJGQ+xezJLvL7hs7R3dyBPtOqSP3YSw0iq/GWspMd8f5OOlyXVipJQ== - dependencies: - bech32 "=2.0.0" - bip-schnorr "=0.6.4" - bn.js "=4.11.8" - bs58 "^4.0.1" - buffer-compare "=1.1.1" - elliptic "^6.5.3" - inherits "=2.0.1" - lodash "^4.17.20" - -bitcore-mnemonic@^8.22.2: - version "8.25.25" - resolved "https://registry.yarnpkg.com/bitcore-mnemonic/-/bitcore-mnemonic-8.25.25.tgz#c2401fcb16bae66204addd9b8d091d6ac2b411e1" - integrity sha512-7HvRxHrmd+Rh0Ohl0SEDMKQBAM+FoevXbCFnxGju6H+uZjtWMOToHA8vUg0+B91pfEMjdt9mQVB/wSA8GMqnCA== - dependencies: - bitcore-lib "^8.25.25" - unorm "^1.4.1" - -bl@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== blakejs@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702" - integrity sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg== - -blob-to-it@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/blob-to-it/-/blob-to-it-1.0.4.tgz#f6caf7a4e90b7bb9215fa6a318ed6bd8ad9898cb" - integrity sha512-iCmk0W4NdbrWgRRuxOriU8aM5ijeVLI61Zulsmg/lUHNr7pYjoj+U77opLefNagevtrrbMt3JQ5Qip7ar178kA== - dependencies: - browser-readablestream-to-it "^1.0.3" - -bluebird@^3.5.0, bluebird@^3.5.3: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== bn.js@4.11.6: version "4.11.6" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= + integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== -bn.js@=4.11.8: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== +bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: + version "4.12.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.1.tgz#215741fe3c9dba2d7e12c001d0cfdbae43975ba7" + integrity sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -body-parser@1.19.2, body-parser@^1.16.0, body-parser@^1.19.0: - version "1.19.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" - integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw== +boxen@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.9.7" - raw-body "2.4.3" - type-is "~1.6.18" - -boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -borc@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/borc/-/borc-2.1.2.tgz#6ce75e7da5ce711b963755117dd1b187f6f8cf19" - integrity sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w== - dependencies: - bignumber.js "^9.0.0" - buffer "^5.5.0" - commander "^2.15.0" - ieee754 "^1.1.13" - iso-url "~0.4.7" - json-text-sequence "~0.1.0" - readable-stream "^3.6.0" + ansi-align "^3.0.0" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.2" + type-fest "^0.20.2" + widest-line "^3.1.0" + wrap-ansi "^7.0.0" brace-expansion@^1.1.7: version "1.1.11" @@ -2835,34 +1430,29 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" -brorand@^1.0.1, brorand@^1.1.0: +brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== -browser-headers@^0.4.0, browser-headers@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/browser-headers/-/browser-headers-0.4.1.tgz#4308a7ad3b240f4203dbb45acedb38dc2d65dd02" - integrity sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg== - -browser-readablestream-to-it@^1.0.1, browser-readablestream-to-it@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/browser-readablestream-to-it/-/browser-readablestream-to-it-1.0.3.tgz#ac3e406c7ee6cdf0a502dd55db33bab97f7fba76" - integrity sha512-+12sHB+Br8HIh6VAMVEG5r3UXCyESIgDW7kzk3BjIXa43DVqVwL7GC5TW3jeh+72dtcH99pPVpw0X8i0jt+/kw== +brotli-wasm@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brotli-wasm/-/brotli-wasm-2.0.1.tgz#2b3f4dc3db0c3e60d2635c055e6bac4ddf4bd3f5" + integrity sha512-+3USgYsC7bzb5yU0/p2HnnynZl0ak0E6uoIm4UW4Aby/8s8HFCq6NCfrrf1E9c3O8OCSzq3oYO1tUVqIi61Nww== -browser-stdout@1.3.1: +browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: +browserify-aes@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== @@ -2874,77 +1464,14 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: inherits "^2.0.1" safe-buffer "^5.0.1" -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserslist@^4.17.5: - version "4.20.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.0.tgz#35951e3541078c125d36df76056e94738a52ebe9" - integrity sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ== - dependencies: - caniuse-lite "^1.0.30001313" - electron-to-chromium "^1.4.76" - escalade "^3.1.1" - node-releases "^2.0.2" - picocolors "^1.0.0" - -browserslist@^4.21.4: - version "4.21.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" - integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== - dependencies: - caniuse-lite "^1.0.30001400" - electron-to-chromium "^1.4.251" - node-releases "^2.0.6" - update-browserslist-db "^1.0.9" - -bs58@^4.0.0, bs58@^4.0.1: +bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== dependencies: base-x "^3.0.2" -bs58check@<3.0.0, bs58check@^2.1.1, bs58check@^2.1.2: +bs58check@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== @@ -2953,99 +1480,20 @@ bs58check@<3.0.0, bs58check@^2.1.1, bs58check@^2.1.2: create-hash "^1.1.0" safe-buffer "^5.1.2" -btoa-lite@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" - integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= - -btoa@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" - integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== - -buffer-compare@=1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-compare/-/buffer-compare-1.1.1.tgz#5be7be853af89198d1f4ddc090d1d66a48aef596" - integrity sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY= - -buffer-from@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" - integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== - -buffer-from@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer-pipe@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/buffer-pipe/-/buffer-pipe-0.0.3.tgz#242197681d4591e7feda213336af6c07a5ce2409" - integrity sha512-GlxfuD/NrKvCNs0Ut+7b1IHjylfdegMBxQIlZHj7bObKVQBxB5S84gtm2yu1mQ8/sSggceWBDPY0cPXgvX2MuA== - dependencies: - safe-buffer "^5.1.2" - -buffer-to-arraybuffer@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" - integrity sha1-YGSkD6dutDxyOrqe+PbhIW0QURo= - buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^5.0.5, buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -buffer@^6.0.1, buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.5.tgz#da9ea8166911cc276bf677b8aed2d02d31f59028" - integrity sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A== - dependencies: - node-gyp-build "^4.3.0" - -bufferutil@4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" - integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== - dependencies: - node-gyp-build "^4.3.0" - -bufferutil@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433" - integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== - dependencies: - node-gyp-build "^4.3.0" - -builtin-modules@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" - integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== builtins@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + version "5.1.0" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8" + integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== dependencies: semver "^7.0.0" @@ -3054,112 +1502,103 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840" + integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-errors "^1.3.0" + function-bind "^1.1.2" -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ== +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== dependencies: - callsites "^2.0.0" + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A== +call-bound@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.2.tgz#9dbd4daf9f5f753bec3e4c8fbb8a2ecc4de6c39b" + integrity sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg== dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ== + call-bind "^1.0.8" + get-intrinsic "^1.2.5" callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" - integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= - dependencies: - no-case "^2.2.0" - upper-case "^1.1.1" - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -caniuse-lite@^1.0.30001313: - version "1.0.30001317" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" - integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== - -caniuse-lite@^1.0.30001400: - version "1.0.30001409" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz#6135da9dcab34cd9761d9cdb12a68e6740c5e96e" - integrity sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ== +camelcase@^6.0.0, camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -cardinal@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" - integrity sha1-fMEFXYItISlU0HsIXeolHMe8VQU= +cbor@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.1.0.tgz#cfc56437e770b73417a2ecbfc9caf6b771af60d5" + integrity sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg== dependencies: - ansicolors "~0.3.2" - redeyed "~2.1.0" + nofilter "^3.1.0" -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -catering@^2.0.0, catering@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" - integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== +cbor@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-9.0.2.tgz#536b4f2d544411e70ec2b19a2453f10f83cd9fdb" + integrity sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ== + dependencies: + nofilter "^3.1.0" -cbor@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c" - integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A== +chai-as-promised@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.2.tgz#70cd73b74afd519754161386421fb71832c6d041" + integrity sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw== dependencies: - bignumber.js "^9.0.1" - nofilter "^1.0.4" + check-error "^1.0.2" -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= +chai@^4.x.x: + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" + ansi-styles "^4.1.0" + supports-color "^7.1.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -3168,198 +1607,71 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" +"charenc@>= 0.0.1": + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -change-case@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.0.2.tgz#fd48746cce02f03f0a672577d1d3a8dc2eceb037" - integrity sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA== - dependencies: - camel-case "^3.0.0" - constant-case "^2.0.0" - dot-case "^2.1.0" - header-case "^1.0.0" - is-lower-case "^1.1.0" - is-upper-case "^1.1.0" - lower-case "^1.1.1" - lower-case-first "^1.0.0" - no-case "^2.3.2" - param-case "^2.1.0" - pascal-case "^2.0.0" - path-case "^2.1.0" - sentence-case "^2.1.0" - snake-case "^2.1.0" - swap-case "^1.1.0" - title-case "^2.1.0" - upper-case "^1.1.1" - upper-case-first "^1.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -checkpoint-store@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" - integrity sha512-J/NdY2WvIx654cc6LWSq/IYFFCUf75fFTgwzFnmbqyORH4MwgiQCgswLLKBGzmsyTI5V7i5bp/So6sMbDWhedg== +check-error@^1.0.2, check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== dependencies: - functional-red-black-tree "^1.0.1" + get-func-name "^2.0.2" -cheerio@0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.20.0.tgz#5c710f2bab95653272842ba01c6ea61b3545ec35" - integrity sha1-XHEPK6uVZTJyhCugHG6mGzVF7DU= +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "~3.8.1" - lodash "^4.1.0" - optionalDependencies: - jsdom "^7.0.2" - -cheerio@1.0.0-rc.2: - version "1.0.0-rc.2" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db" - integrity sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs= - dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "^3.9.1" - lodash "^4.15.0" - parse5 "^3.0.1" - -chokidar@3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" - integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== - dependencies: - anymatch "~3.1.1" + anymatch "~3.1.2" braces "~3.0.2" - glob-parent "~5.1.0" + glob-parent "~5.1.2" is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.4.0" + readdirp "~3.6.0" optionalDependencies: - fsevents "~2.1.2" - -chownr@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + fsevents "~2.3.2" -cids@^0.7.1: - version "0.7.5" - resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" - integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== +chokidar@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41" + integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA== dependencies: - buffer "^5.5.0" - class-is "^1.1.0" - multibase "~0.6.0" - multicodec "^1.0.0" - multihashes "~0.4.15" + readdirp "^4.0.1" -cids@^1.0.0, cids@^1.1.4, cids@^1.1.5: - version "1.1.9" - resolved "https://registry.yarnpkg.com/cids/-/cids-1.1.9.tgz#402c26db5c07059377bcd6fb82f2a24e7f2f4a4f" - integrity sha512-l11hWRfugIcbGuTZwAM5PwpjPPjyb6UZOGwlHSnOBV5o07XhQ4gNpBN67FbODvpjyHtd+0Xs6KNvUcGBiDRsdg== - dependencies: - multibase "^4.0.1" - multicodec "^3.0.1" - multihashes "^4.0.1" - uint8arrays "^3.0.0" +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -circular-json@^0.5.9: - version "0.5.9" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" - integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== - -circular@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/circular/-/circular-1.0.5.tgz#7da77af98bbde9ce4b5b358cd556b5dded2d3149" - integrity sha512-n4Sspha+wxUl5zeA3JYp1zFCjsLz2VfXIe2gRKNQBrIX+7iPdGcCGZOF8W8IULtllZ/aejXtySfdFFt1wy/3JQ== - -class-is@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" - integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-cursor@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-logger@^0.5.40: - version "0.5.40" - resolved "https://registry.yarnpkg.com/cli-logger/-/cli-logger-0.5.40.tgz#097f0e11b072c7c698a26c47f588a29c20b48b0b" - integrity sha512-piXVCa0TLm/+A7xdVEhw7t4OSrsmJaZIekWcoGrVMY1bHtLJTXgiNzgHlKT0EVHQ14sCKWorQJazU7UWgZhXOQ== - dependencies: - circular "^1.0.5" - cli-util "~1.1.27" - -cli-regexp@~0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/cli-regexp/-/cli-regexp-0.1.2.tgz#6bcd93b09fb2ed1025d30a1155d5997954a53512" - integrity sha512-L++cAQ5g0Nu6aV56B3uaR+c7jEGSAa4WApY1ZN7XiD8niJ5jRfXE/qvMwgz3uZBG0rft4hJS75Vpz2F3mSm4Mg== - -cli-spinners@^2.0.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== - -cli-table@^0.3.1: - version "0.3.11" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.11.tgz#ac69cdecbe81dccdba4889b9a18b7da312a9d3ee" - integrity sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7" + integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw== dependencies: - colors "1.0.3" + inherits "^2.0.4" + safe-buffer "^5.2.1" -cli-util@~1.1.27: - version "1.1.27" - resolved "https://registry.yarnpkg.com/cli-util/-/cli-util-1.1.27.tgz#42d69e36a040a321fc9cf851c1513cadc5093054" - integrity sha512-Z6+zI0kIrqf9Oi+PmUm8J9AELp8bTf2vCLYseudYtdOPNJvzpNiExO95aHIm477IbPdu/8SE9Wvc/M1kJl4Anw== - dependencies: - cli-regexp "~0.1.0" +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-width@^2.0.0: +cli-boxes@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== +cli-table3@^0.6.3: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" cliui@^7.0.2: version "7.0.4" @@ -3370,33 +1682,6 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" -clone-buffer@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" - integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -clone@^2.0.0, clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -3411,241 +1696,70 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-logger@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/color-logger/-/color-logger-0.0.3.tgz#d9b22dd1d973e166b18bf313f9f481bba4df2018" - integrity sha1-2bIt0dlz4Waxi/MT+fSBu6TfIBg= - -color-logger@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/color-logger/-/color-logger-0.0.6.tgz#e56245ef29822657110c7cb75a9cd786cb69ed1b" - integrity sha1-5WJF7ymCJlcRDHy3WpzXhstp7Rs= - color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - -colors@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -command-line-args@^5.1.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" - integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== - dependencies: - array-back "^3.1.0" - find-replace "^3.0.0" - lodash.camelcase "^4.3.0" - typical "^4.0.0" - -command-line-usage@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.1.tgz#c908e28686108917758a49f45efb4f02f76bc03f" - integrity sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA== - dependencies: - array-back "^4.0.1" - chalk "^2.4.2" - table-layout "^1.0.1" - typical "^5.2.0" - -commander@2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" - integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ== +command-exists@^1.2.8: + version "1.2.9" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== -commander@^2.15.0, commander@^2.19.0, commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.0.0.tgz#86d58f24ee98126568936bd1d3574e0308a99a40" - integrity sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw== +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +commander@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concurrently@^7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-7.4.0.tgz#bb0e344964bc172673577c420db21e963f2f7368" - integrity sha512-M6AfrueDt/GEna/Vg9BqQ+93yuvzkSKmoTixnwEJkH0LlcGrRC2eCmjeG1tLLHIYfpYJABokqSGyMcXjm96AFA== +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== dependencies: - chalk "^4.1.0" - date-fns "^2.29.1" - lodash "^4.17.21" - rxjs "^7.0.0" - shell-quote "^1.7.3" - spawn-command "^0.0.2-1" - supports-color "^8.1.0" - tree-kill "^1.2.2" - yargs "^17.3.1" - -conf@^10.0.2: - version "10.1.1" - resolved "https://registry.yarnpkg.com/conf/-/conf-10.1.1.tgz#ff08046d5aeeee0eaff55d57f5b4319193c3dfda" - integrity sha512-z2civwq/k8TMYtcn3SVP0Peso4otIWnHtcTuHhQ0zDZDdP4NTxqEc8owfkz4zBsdMYdn/LFcE+ZhbCeqkhtq3Q== - dependencies: - ajv "^8.6.3" - ajv-formats "^2.1.1" - atomically "^1.7.0" - debounce-fn "^4.0.0" - dot-prop "^6.0.1" - env-paths "^2.2.1" - json-schema-typed "^7.0.3" - onetime "^5.1.2" - pkg-up "^3.1.0" - semver "^7.3.5" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + ini "^1.3.4" + proto-list "~1.2.1" -constant-case@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46" - integrity sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY= - dependencies: - snake-case "^2.1.0" - upper-case "^1.1.1" - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-hash@^2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" - integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== - dependencies: - cids "^0.7.1" - multicodec "^0.5.5" - multihashes "^0.4.15" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.2: +cookie@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -cookiejar@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" - integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== - -core-js-compat@^3.25.1: - version "3.25.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.2.tgz#7875573586809909c69e03ef310810c1969ee138" - integrity sha512-TxfyECD4smdn3/CjWxczVtJqVLEEC2up7/82t7vC0AzNogr+4nQ8vyF7abxAuTXWvjTClSbvGhU0RgqA4ToQaQ== - dependencies: - browserslist "^4.21.4" - -core-js@^2.4.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" - integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cors@^2.8.1, cors@^2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - -cosmiconfig@^5.0.7: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -coveralls@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.1.1.tgz#f5d4431d8b5ae69c5079c8f8ca00d64ac77cf081" - integrity sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww== +cosmiconfig@^8.0.0: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== dependencies: - js-yaml "^3.13.1" - lcov-parse "^1.0.0" - log-driver "^1.2.7" - minimist "^1.2.5" - request "^2.88.2" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" crc-32@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.1.tgz#436d2bcaad27bcb6bd073a2587139d3024a16460" - integrity sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w== - dependencies: - exit-on-epipe "~1.0.1" - printj "~1.3.1" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" @@ -3658,7 +1772,7 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: ripemd160 "^2.0.1" sha.js "^2.4.0" -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: +create-hmac@^1.1.4, create-hmac@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== @@ -3670,180 +1784,91 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-fetch@^2.1.0: - version "2.2.6" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.6.tgz#2ef0bb39a24ac034787965c457368a28730e220a" - integrity sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA== - dependencies: - node-fetch "^2.6.7" - whatwg-fetch "^2.0.4" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.0, cross-spawn@^7.0.2: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -crypto-browserify@3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-select@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-what@2.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" - integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== - -cssfilter@0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" - integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4= - -cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0": - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== +"crypt@>= 0.0.1": + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== -"cssstyle@>= 0.2.29 < 0.3.0": - version "0.2.37" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" - integrity sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ= +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== dependencies: - cssom "0.3.x" + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" -d@1, d@^1.0.1: +data-view-byte-length@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== dependencies: - es5-ext "^0.10.50" - type "^1.0.1" + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== dependencies: - assert-plus "^1.0.0" - -dataloader@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.0.0.tgz#41eaf123db115987e21ca93c005cd7753c55fe6f" - integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ== - -date-fns@^2.29.1: - version "2.29.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" - integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" death@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" - integrity sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg= - -debounce-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-4.0.0.tgz#ed76d206d8a50e60de0dd66d494d82835ffe61c7" - integrity sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ== - dependencies: - mimic-fn "^3.0.0" - -debug@2.6.9, debug@^2.2.0, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" + integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w== -debug@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== dependencies: - ms "^2.1.1" + ms "^2.1.3" -debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: +debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.3.2: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== dependencies: - ms "2.1.2" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + mimic-response "^3.1.0" -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -decompress-response@^3.2.0, decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= +deep-eql@^4.0.1, deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== dependencies: - mimic-response "^1.0.0" + type-detect "^4.0.0" -deep-extend@^0.6.0, deep-extend@~0.6.0: +deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== @@ -3853,132 +1878,55 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -deferred-leveldown@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" - integrity sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA== - dependencies: - abstract-leveldown "~2.6.0" - -deferred-leveldown@~5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.0.1.tgz#1642eb18b535dfb2b6ac4d39fb10a9cbcfd13b09" - integrity sha512-BXohsvTedWOLkj2n/TY+yqVlrCWa2Zs8LSxh3uCAgFOru7/pjxKyZAexGa1j83BaKloER4PqUyQ9rGPJLt9bqA== - dependencies: - abstract-leveldown "~6.0.0" - inherits "^2.0.3" - -deferred-leveldown@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" - integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== - dependencies: - abstract-leveldown "~6.2.1" - inherits "^2.0.3" +defer-to-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: - object-keys "^1.0.12" + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" -define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== +define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== dependencies: + define-data-property "^1.0.1" has-property-descriptors "^1.0.0" object-keys "^1.1.1" -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -delimit-stream@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/delimit-stream/-/delimit-stream-0.1.0.tgz#9b8319477c0e5f8aeb3ce357ae305fc25ea1cd2b" - integrity sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs= - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= - dependencies: - repeating "^2.0.0" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - -detect-port@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" - integrity sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ== - dependencies: - address "^1.0.1" - debug "^2.6.0" +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -diff@4.0.2, diff@^4.0.1: +diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + +difflib@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" + integrity sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w== dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" + heap ">= 0.2.0" dir-glob@^3.0.1: version "3.0.1" @@ -3987,15 +1935,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -dns-over-http-resolver@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz#194d5e140a42153f55bb79ac5a64dd2768c36af9" - integrity sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA== - dependencies: - debug "^4.3.1" - native-fetch "^3.0.0" - receptacle "^1.3.2" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -4010,142 +1949,26 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -dom-serializer@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" - integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== - dependencies: - domelementtype "^1.3.0" - entities "^1.1.1" - -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - -domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== - -domhandler@2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" - integrity sha1-LeWaCCLVAn+r/28DLCsloqir5zg= - dependencies: - domelementtype "1" - -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - -domutils@1.5, domutils@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^1.5.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -dot-case@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-2.1.1.tgz#34dcf37f50a8e93c2b3bca8bb7fb9155c7da3bee" - integrity sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4= - dependencies: - no-case "^2.2.0" - -dot-prop@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" - integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== - dependencies: - is-obj "^2.0.0" - dotenv@^16.0.2: - version "16.0.2" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.2.tgz#0b0f8652c016a3858ef795024508cddc4bffc5bf" - integrity sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA== + version "16.4.7" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" + integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== -double-ended-queue@2.1.0-0: - version "2.1.0-0" - resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" - integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw= - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ecurve@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/ecurve/-/ecurve-1.0.6.tgz#dfdabbb7149f8d8b78816be5a7d5b83fcf6de797" - integrity sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w== - dependencies: - bigi "^1.1.0" - safe-buffer "^5.0.1" - -ed2curve@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/ed2curve/-/ed2curve-0.3.0.tgz#322b575152a45305429d546b071823a93129a05d" - integrity sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ== - dependencies: - tweetnacl "1.x.x" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-fetch@^1.7.2: - version "1.7.4" - resolved "https://registry.yarnpkg.com/electron-fetch/-/electron-fetch-1.7.4.tgz#af975ab92a14798bfaa025f88dcd2e54a7b0b769" - integrity sha512-+fBLXEy4CJWQ5bz8dyaeSG1hD6JJ15kBZyj3eh24pIVrd3hLM47H/umffrdQfS6GZ0falF0g9JT9f3Rs6AVUhw== +dunder-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.0.tgz#c2fce098b3c8f8899554905f4377b6d85dabaa80" + integrity sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A== dependencies: - encoding "^0.1.13" + call-bind-apply-helpers "^1.0.0" + es-errors "^1.3.0" + gopd "^1.2.0" -electron-to-chromium@^1.4.251: - version "1.4.256" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz#c735032f412505e8e0482f147a8ff10cfca45bf4" - integrity sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw== - -electron-to-chromium@^1.4.76: - version "1.4.84" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.84.tgz#2700befbcb49c42c4ee162e137ff392c07658249" - integrity sha512-b+DdcyOiZtLXHdgEG8lncYJdxbdJWJvclPNMg0eLUDcSOSO876WA/pYjdSblUTd7eJdIs4YdIxHWGazx7UPSJw== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4: +elliptic@6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -4158,78 +1981,38 @@ elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5 minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -emittery@0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.0.tgz#bb373c660a9d421bb44706ec4967ed50c02a8026" - integrity sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ== - -emittery@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.4.1.tgz#abe9d3297389ba424ac87e53d1c701962ce7433d" - integrity sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ== - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +elliptic@^6.5.2, elliptic@^6.5.7: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -encoding-down@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" - integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== - dependencies: - abstract-leveldown "^6.2.1" - inherits "^2.0.3" - level-codec "^9.0.0" - level-errors "^2.0.0" - -encoding@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -end-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/end-stream/-/end-stream-0.1.0.tgz#32003f3f438a2b0143168137f8fa6e9866c81ed5" - integrity sha1-MgA/P0OKKwFDFoE3+PpumGbIHtU= +enquirer@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== dependencies: - write-stream "~0.4.3" - -entities@1.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" - integrity sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY= - -entities@^1.1.1, entities@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" -env-paths@^2.2.1: +env-paths@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== @@ -4239,23 +2022,6 @@ env-prompt@^2.0.3: resolved "https://registry.yarnpkg.com/env-prompt/-/env-prompt-2.0.3.tgz#359d6fc3d9911fd233f511daf0fcd21eaf6cf08f" integrity sha512-shXfCgysWEhZ3Ba3dXuTW8u959ZE8uthiAQWNk+mPmP6HMUXBVYErFCfAu7NOLw4OrsnSH5UW5ptTuKtf21QEA== -err-code@^2.0.0, err-code@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== - -err-code@^3.0.0, err-code@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" - integrity sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA== - -errno@~0.1.1: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.1" - error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -4263,153 +2029,119 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.18.5, es-abstract@^1.19.0: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-abstract@^1.20.4: - version "1.20.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.5.tgz#e6dc99177be37cacda5988e692c3fa8b218e95d2" - integrity sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ== - dependencies: - call-bind "^1.0.2" +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.2, es-abstract@^1.23.5: + version "1.23.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.5.tgz#f4599a4946d57ed467515ed10e4f157289cd52fb" + integrity sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" - get-symbol-description "^1.0.0" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.4" gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - internal-slot "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" + is-typed-array "^1.1.13" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.13.3" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.3" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== -es-get-iterator@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" - integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.0" - has-symbols "^1.0.1" - is-arguments "^1.1.0" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.5" - isarray "^2.0.5" +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-shim-unscopables@^1.0.0: +es-object-atoms@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== dependencies: - has "^1.0.3" + es-errors "^1.3.0" -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.58" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.58.tgz#5b97d94236285fb87c8ffc782cf42eb0a25d2ae0" - integrity sha512-LHO+KBBaHGwjy32ibSaMY+ZzjpC4K4I5bPoijICMBL7gXEXfrEUrzssmNP+KigbQEp1dRUnGkry/vUnxOqptLQ== +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== dependencies: - es6-iterator "^2.0.3" - es6-symbol "^3.1.3" - next-tick "^1.1.0" - -es6-denodeify@^0.1.1: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f" - integrity sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8= + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" -es6-iterator@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" + hasown "^2.0.0" -es6-symbol@^3.1.1, es6-symbol@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== +es-to-primitive@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== dependencies: - d "^1.0.1" - ext "^1.1.2" + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== -escape-html@1.0.3, escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: +escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - escodegen@1.8.x: version "1.8.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= + integrity sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A== dependencies: esprima "^2.7.1" estraverse "^1.9.1" @@ -4418,52 +2150,24 @@ escodegen@1.8.x: optionalDependencies: source-map "~0.2.0" -escodegen@^1.6.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -esdoc@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/esdoc/-/esdoc-1.1.0.tgz#07d40ebf791764cd537929c29111e20a857624f3" - integrity sha512-vsUcp52XJkOWg9m1vDYplGZN2iDzvmjDL5M/Mp8qkoDG3p2s0yIQCIjKR5wfPBaM3eV14a6zhQNYiNTCVzPnxA== - dependencies: - babel-generator "6.26.1" - babel-traverse "6.26.0" - babylon "6.18.0" - cheerio "1.0.0-rc.2" - color-logger "0.0.6" - escape-html "1.0.3" - fs-extra "5.0.0" - ice-cap "0.0.4" - marked "0.3.19" - minimist "1.2.0" - taffydb "2.7.3" - -eslint-config-standard@^17.0.0: - version "17.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz#fd5b6cf1dcf6ba8d29f200c461de2e19069888cf" - integrity sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg== - -eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== +eslint-config-standard@^17.0.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" + integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== dependencies: debug "^3.2.7" - resolve "^1.20.0" + is-core-module "^2.13.0" + resolve "^1.22.4" -eslint-module-utils@^2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== dependencies: debug "^3.2.7" @@ -4476,28 +2180,34 @@ eslint-plugin-es@^4.1.0: regexpp "^3.0.0" eslint-plugin-import@^2.25.2: - version "2.26.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" - integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== - dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.3" - has "^1.0.3" - is-core-module "^2.8.1" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.0" + hasown "^2.0.2" + is-core-module "^2.15.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.values "^1.1.5" - resolve "^1.22.0" - tsconfig-paths "^3.14.1" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + string.prototype.trimend "^1.0.8" + tsconfig-paths "^3.15.0" eslint-plugin-n@^15.0.0: - version "15.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-15.6.0.tgz#cfb1d2e2e427d620eb9008f8b3b5a40de0c84120" - integrity sha512-Hd/F7wz4Mj44Jp0H6Jtty13NcE69GNTY0rVlgTIj1XBnGGVI6UTdDrpE6vqu3AHo07bygq/N+7OH/lgz1emUJw== + version "15.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz#e29221d8f5174f84d18f2eb94765f2eeea033b90" + integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q== dependencies: builtins "^5.0.1" eslint-plugin-es "^4.1.0" @@ -4509,33 +2219,18 @@ eslint-plugin-n@^15.0.0: semver "^7.3.8" eslint-plugin-promise@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" - integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== - -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" + version "6.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz#acd3fd7d55cead7a10f92cf698f36c0aafcd717a" + integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^1.3.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - eslint-utils@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" @@ -4550,7 +2245,7 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: +eslint-visitor-keys@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -4560,134 +2255,82 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - -eslint@^5.6.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.2.3" - text-table "^0.2.0" +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.0.1: - version "8.31.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.31.0.tgz#75028e77cbcff102a9feae1d718135931532d524" - integrity sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA== - dependencies: - "@eslint/eslintrc" "^1.4.1" - "@humanwhocodes/config-array" "^0.11.8" + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" - esquery "^1.4.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" find-up "^5.0.0" glob-parent "^6.0.2" globals "^13.19.0" - grapheme-splitter "^1.0.4" + graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-sdsl "^4.1.4" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== - dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - -espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.8.0" + acorn "^8.9.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.1" esprima@2.7.x, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= + integrity sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A== -esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: +esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1, esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" -esrecurse@^4.1.0, esrecurse@^4.3.0: +esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -4697,191 +2340,26 @@ esrecurse@^4.1.0, esrecurse@^4.3.0: estraverse@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= - -estraverse@^4.1.1, estraverse@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + integrity sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA== estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" - integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== - -estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== - -estree-walker@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -eth-block-tracker@^4.4.2: - version "4.4.3" - resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz#766a0a0eb4a52c867a28328e9ae21353812cf626" - integrity sha512-A8tG4Z4iNg4mw5tP1Vung9N9IjgMNqpiMoJ/FouSFwNCGHv2X0mmOYwtQOJzki6XN7r7Tyo01S29p7b224I4jw== - dependencies: - "@babel/plugin-transform-runtime" "^7.5.5" - "@babel/runtime" "^7.5.5" - eth-query "^2.1.0" - json-rpc-random-id "^1.0.1" - pify "^3.0.0" - safe-event-emitter "^1.0.1" - -eth-ens-namehash@2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" - integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88= - dependencies: - idna-uts46-hx "^2.3.1" - js-sha3 "^0.5.7" - -eth-json-rpc-filters@^4.2.1: - version "4.2.2" - resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.2.2.tgz#eb35e1dfe9357ace8a8908e7daee80b2cd60a10d" - integrity sha512-DGtqpLU7bBg63wPMWg1sCpkKCf57dJ+hj/k3zF26anXMzkmtSBDExL8IhUu7LUd34f0Zsce3PYNO2vV2GaTzaw== - dependencies: - "@metamask/safe-event-emitter" "^2.0.0" - async-mutex "^0.2.6" - eth-json-rpc-middleware "^6.0.0" - eth-query "^2.1.2" - json-rpc-engine "^6.1.0" - pify "^5.0.0" - -eth-json-rpc-infura@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-5.1.0.tgz#e6da7dc47402ce64c54e7018170d89433c4e8fb6" - integrity sha512-THzLye3PHUSGn1EXMhg6WTLW9uim7LQZKeKaeYsS9+wOBcamRiCQVGHa6D2/4P0oS0vSaxsBnU/J6qvn0MPdow== - dependencies: - eth-json-rpc-middleware "^6.0.0" - eth-rpc-errors "^3.0.0" - json-rpc-engine "^5.3.0" - node-fetch "^2.6.0" - -eth-json-rpc-middleware@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-6.0.0.tgz#4fe16928b34231a2537856f08a5ebbc3d0c31175" - integrity sha512-qqBfLU2Uq1Ou15Wox1s+NX05S9OcAEL4JZ04VZox2NS0U+RtCMjSxzXhLFWekdShUPZ+P8ax3zCO2xcPrp6XJQ== - dependencies: - btoa "^1.2.1" - clone "^2.1.1" - eth-query "^2.1.2" - eth-rpc-errors "^3.0.0" - eth-sig-util "^1.4.2" - ethereumjs-util "^5.1.2" - json-rpc-engine "^5.3.0" - json-stable-stringify "^1.0.1" - node-fetch "^2.6.1" - pify "^3.0.0" - safe-event-emitter "^1.0.1" - -eth-lib@0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" - integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - xhr-request-promise "^0.1.2" - -eth-lib@^0.1.26: - version "0.1.29" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" - integrity sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - nano-json-stream-parser "^0.1.2" - servify "^0.1.12" - ws "^3.0.0" - xhr-request-promise "^0.1.2" - -eth-query@^2.1.0, eth-query@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" - integrity sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA== - dependencies: - json-rpc-random-id "^1.0.0" - xtend "^4.0.1" - -eth-rpc-errors@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz#d7b22653c70dbf9defd4ef490fd08fe70608ca10" - integrity sha512-iPPNHPrLwUlR9xCSYm7HHQjWBasor3+KZfRvwEWxMz3ca0yqnlBeJrnyphkGIXZ4J7AMAaOLmwy4AWhnxOiLxg== - dependencies: - fast-safe-stringify "^2.0.6" - -eth-rpc-errors@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" - integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg== - dependencies: - fast-safe-stringify "^2.0.6" - -eth-sig-util@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" - integrity sha512-iNZ576iTOGcfllftB73cPB5AN+XUQAT/T8xzsILsghXC1o8gJUqe3RHlcDqagu+biFpYQ61KQrZZJza8eRSYqw== - dependencies: - ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util "^5.1.1" - -eth-sig-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-3.0.1.tgz#8753297c83a3f58346bd13547b59c4b2cd110c96" - integrity sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ== - dependencies: - ethereumjs-abi "^0.6.8" - ethereumjs-util "^5.1.1" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.0" - ethereum-bloom-filters@^1.0.6: - version "1.0.10" - resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" - integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== - dependencies: - js-sha3 "^0.8.0" - -ethereum-common@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" - integrity sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA== - -ethereum-common@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - integrity sha512-EoltVQTRNg2Uy4o84qpa2aXymXDJhxm7eos/ACOg0DG4baAbMjhbdAEsx9GeE8sC3XCxnYvrrzZDH8D8MtA2iQ== - -ethereum-cryptography@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz#74f2ac0f0f5fe79f012c889b3b8446a9a6264e6d" - integrity sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ== + version "1.2.0" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz#8294f074c1a6cbd32c39d2cc77ce86ff14797dab" + integrity sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA== dependencies: - "@noble/hashes" "1.1.2" - "@noble/secp256k1" "1.6.3" - "@scure/bip32" "1.1.0" - "@scure/bip39" "1.1.0" + "@noble/hashes" "^1.4.0" -ethereum-cryptography@^0.1.3: +ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== @@ -4902,10 +2380,25 @@ ethereum-cryptography@^0.1.3: secp256k1 "^4.0.1" setimmediate "^1.0.5" -ethereum-protocol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ethereum-protocol/-/ethereum-protocol-1.0.1.tgz#b7d68142f4105e0ae7b5e178cf42f8d4dc4b93cf" - integrity sha512-3KLX1mHuEsBW0dKG+c6EOJS1NBNqdCICvZW9sInmZTt5aY0oxmHVggYRE0lJu1tcnMD1K+AKHdLi6U43Awm1Vg== +ethereum-cryptography@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" + integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== + dependencies: + "@noble/hashes" "1.2.0" + "@noble/secp256k1" "1.7.1" + "@scure/bip32" "1.1.5" + "@scure/bip39" "1.1.1" + +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2, ethereum-cryptography@^2.1.3: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz#58f2810f8e020aecb97de8c8c76147600b0b8ccf" + integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== + dependencies: + "@noble/curves" "1.4.2" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" ethereumjs-abi@^0.6.8: version "0.6.8" @@ -4915,78 +2408,6 @@ ethereumjs-abi@^0.6.8: bn.js "^4.11.8" ethereumjs-util "^6.0.0" -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": - version "0.6.8" - resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0" - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-account@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" - integrity sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA== - dependencies: - ethereumjs-util "^5.0.0" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-block@^1.2.2: - version "1.7.1" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" - integrity sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg== - dependencies: - async "^2.0.1" - ethereum-common "0.2.0" - ethereumjs-tx "^1.2.2" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-block@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" - integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg== - dependencies: - async "^2.0.1" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-common@^1.1.0, ethereumjs-common@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" - integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== - -ethereumjs-tx@^1.2.2: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - integrity sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA== - dependencies: - ethereum-common "^0.0.18" - ethereumjs-util "^5.0.0" - -ethereumjs-tx@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - -ethereumjs-util@^5.0.0, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.5: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" - integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "^0.1.3" - rlp "^2.0.0" - safe-buffer "^5.1.1" - ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" @@ -5000,18 +2421,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.4.tgz#a6885bcdd92045b06f596c7626c3e89ab3312458" - integrity sha512-p6KmuPCX4mZIqsQzXfmSx9Y0l2hqf+VkAiwSisW3UKUFdk8ZkAt+AYaor83z2nSi6CU2zSsXMlD80hAbNEGM0A== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - -ethereumjs-util@^7.1.5: +ethereumjs-util@^7.1.4: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -5022,97 +2432,28 @@ ethereumjs-util@^7.1.5: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethereumjs-vm@^2.3.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" - integrity sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw== - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - ethereumjs-account "^2.0.3" - ethereumjs-block "~2.2.0" - ethereumjs-common "^1.1.0" - ethereumjs-util "^6.0.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - -ethereumjs-wallet@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz#2c000504b4c71e8f3782dabe1113d192522e99b6" - integrity sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA== - dependencies: - aes-js "^3.1.2" - bs58check "^2.1.2" - ethereum-cryptography "^0.1.3" - ethereumjs-util "^7.1.2" - randombytes "^2.1.0" - scrypt-js "^3.0.1" - utf8 "^3.0.0" - uuid "^8.3.2" - -ethers@^4.0.32: - version "4.0.49" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" - integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg== +ethers@^6.13.4, ethers@^6.7.0: + version "6.13.4" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c" + integrity sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA== dependencies: - aes-js "3.0.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.3" - js-sha3 "0.5.7" - scrypt-js "2.0.4" - setimmediate "1.0.4" - uuid "2.0.1" - xmlhttprequest "1.8.0" - -ethers@^5.5.4: - version "5.6.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.6.0.tgz#924eb965dc03963fad0a09ce687efdf49aca3b45" - integrity sha512-00FP71jt6bW3ndO5DhgH9mLIZhoCGnAKFLu8qig5KmV03ubEChKf2ilB3g6fX512tTYo+tSMDJ5WpCJWdBHkBQ== - dependencies: - "@ethersproject/abi" "5.6.0" - "@ethersproject/abstract-provider" "5.6.0" - "@ethersproject/abstract-signer" "5.6.0" - "@ethersproject/address" "5.6.0" - "@ethersproject/base64" "5.6.0" - "@ethersproject/basex" "5.6.0" - "@ethersproject/bignumber" "5.6.0" - "@ethersproject/bytes" "5.6.0" - "@ethersproject/constants" "5.6.0" - "@ethersproject/contracts" "5.6.0" - "@ethersproject/hash" "5.6.0" - "@ethersproject/hdnode" "5.6.0" - "@ethersproject/json-wallets" "5.6.0" - "@ethersproject/keccak256" "5.6.0" - "@ethersproject/logger" "5.6.0" - "@ethersproject/networks" "5.6.0" - "@ethersproject/pbkdf2" "5.6.0" - "@ethersproject/properties" "5.6.0" - "@ethersproject/providers" "5.6.0" - "@ethersproject/random" "5.6.0" - "@ethersproject/rlp" "5.6.0" - "@ethersproject/sha2" "5.6.0" - "@ethersproject/signing-key" "5.6.0" - "@ethersproject/solidity" "5.6.0" - "@ethersproject/strings" "5.6.0" - "@ethersproject/transactions" "5.6.0" - "@ethersproject/units" "5.6.0" - "@ethersproject/wallet" "5.6.0" - "@ethersproject/web" "5.6.0" - "@ethersproject/wordlists" "5.6.0" + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "22.7.5" + aes-js "4.0.0-beta.5" + tslib "2.7.0" + ws "8.17.1" ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" - integrity sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk= + integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== dependencies: bn.js "4.11.6" number-to-bn "1.7.0" -ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6: +ethjs-util@0.1.6, ethjs-util@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== @@ -5120,37 +2461,12 @@ ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" -event-iterator@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/event-iterator/-/event-iterator-1.2.0.tgz#2e71dc6ca56f1cf8ebcb2b9be7fdfd10acabbb76" - integrity sha512-Daq7YUl0Mv1i4QEgzGQlz0jrx7hUFNyLGbiF+Ap7NCMCjDLCCnolyj6s0TAc6HmrBziO5rNVHsPwGMp7KdRPvw== - -event-iterator@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/event-iterator/-/event-iterator-2.0.0.tgz#10f06740cc1e9fd6bc575f334c2bc1ae9d2dbf62" - integrity sha512-KGft0ldl31BZVV//jj+IAIGCxkvvUkkON+ScH6zfoX+l+omX6001ggyRSpI0Io2Hlro0ThXotswCtfzS8UkIiQ== - -event-target-shim@^5.0.0: +eventemitter3@5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -eventemitter3@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" - integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== - -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -events@^3.0.0, events@^3.2.0, events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: +evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== @@ -5158,134 +2474,20 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -exit-on-epipe@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" - integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== - -express@^4.14.0, express@^4.17.1: - version "4.17.3" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" - integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.19.2" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.4.2" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.9.7" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.17.2" - serve-static "1.14.2" - setprototypeof "1.2.0" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" - integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== - dependencies: - type "^2.5.0" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== - -fake-merkle-patricia-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" - integrity sha512-Tgq37lkc9pUIgIKw5uitNUKcgcYL3R6JvXtKQbOf/ZSavXbidsksgp/pAY6p//uhw0I4yoMsvTSovvVIsk/qxA== - dependencies: - checkpoint-store "^1.1.0" - -faker@^5.3.1: - version "5.5.3" - resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" - integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== - -fast-check@^2.12.1: - version "2.23.0" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.23.0.tgz#adc2c7ec91f43ce314c15c4fafe901a812bfad10" - integrity sha512-aV1kOi6zUCytkICuhu9s8MBtJjlAos6MIU5NYCcgt5u2UVdgaAsqTI+u0n6Cea1hKFXdfSmfz6wfxce6Ozcj2w== - dependencies: - pure-rand "^5.0.0" - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-fifo@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.1.0.tgz#17d1a3646880b9891dfa0c54e69c5fef33cad779" - integrity sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g== - -fast-future@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fast-future/-/fast-future-1.0.2.tgz#8435a9aaa02d79248d17d704e76259301d99280a" - integrity sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo= +fast-diff@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== fast-glob@^3.0.3: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -5293,7 +2495,7 @@ fast-glob@^3.0.3: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: +fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5301,58 +2503,24 @@ fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fast-safe-stringify@^2.0.6: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - -fast-sha256@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-sha256/-/fast-sha256-1.3.0.tgz#7916ba2054eeb255982608cccd0f6660c79b7ae6" - integrity sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ== + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fastestsmallesttextencoderdecoder@^1.0.22: - version "1.0.22" - resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93" - integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== +fast-uri@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.3.tgz#892a1c91802d5d7860de728f18608a0573142241" + integrity sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw== fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" -fetch-cookie@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.10.1.tgz#5ea88f3d36950543c87997c27ae2aeafb4b5c4d4" - integrity sha512-beB+VEd4cNeVG1PY+ee74+PkuCQnik78pgLi5Ah/7qdUfov8IctU0vLUbBT8/10Ma5GMBeI4wtxhGrEfKNYs2g== - dependencies: - tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" - -fetch-cookie@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.7.0.tgz#a6fc137ad8363aa89125864c6451b86ecb7de802" - integrity sha512-Mm5pGlT3agW6t71xVM7vMZPIvI7T4FaTuFW4jari6dVzYHFDb3WZZsGpN22r/o3XMdkM0E7sPd1EGeyVbH2Tgg== - dependencies: - es6-denodeify "^0.1.1" - tough-cookie "^2.3.1" - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" +fdir@^6.4.2: + version "6.4.2" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689" + integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ== file-entry-cache@^6.0.1: version "6.0.1" @@ -5361,48 +2529,14 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-replace@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" - integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== - dependencies: - array-back "^3.0.1" - -find-up@5.0.0, find-up@^5.0.0: +find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -5410,138 +2544,79 @@ find-up@5.0.0, find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: - flatted "^3.1.0" + flatted "^3.2.9" + keyv "^4.5.3" rimraf "^3.0.2" -flat@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" - integrity sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA== - dependencies: - is-buffer "~2.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== -follow-redirects@^1.10.0: - version "1.14.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" - integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== +follow-redirects@^1.12.1, follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== -follow-redirects@^1.14.8: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" -foreach@^2.0.4, foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== +form-data@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fp-ts@1.19.3: + version "1.19.3" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" + integrity sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg== -fs-extra@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" - integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" +fp-ts@^1.0.0: + version "1.19.5" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" + integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== fs-extra@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" - integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^7.0.0: +fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== @@ -5559,178 +2634,75 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.1, fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-minipass@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -functions-have-names@^1.2.2: +functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -ganache@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/ganache/-/ganache-7.0.3.tgz#c90a28b039378d2e1b5d9623b354969a1d877070" - integrity sha512-1O4V38YkAFd2B1YfBevauEepxEtoN0iTTK02SUJPUIcLOnxwrR49lSDq7liKpUWLkoZCOC2Bkrz/+XJAmEoNAQ== - dependencies: - "@trufflesuite/bigint-buffer" "1.1.9" - emittery "0.10.0" - keccak "3.0.1" - leveldown "6.1.0" - secp256k1 "4.0.2" - optionalDependencies: - bufferutil "4.0.5" - utf-8-validate "5.0.7" - -ganache@^7.9.2: - version "7.9.2" - resolved "https://registry.yarnpkg.com/ganache/-/ganache-7.9.2.tgz#77f506ad2735dd9109696ffa1834a9dd2f806449" - integrity sha512-7gsVVDpO9AhrFyDMWWl7SpMsPpqGcnAzjxz3k32LheIPNd64p2XsY9GYRdhWmKuryb60W1iaWPZWDkFKlbRWHA== - dependencies: - "@trufflesuite/bigint-buffer" "1.1.10" - "@trufflesuite/uws-js-unofficial" "20.30.0-unofficial.0" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "5.1.1" - "@types/seedrandom" "3.0.1" - abstract-level "1.0.3" - abstract-leveldown "7.2.0" - async-eventemitter "0.2.4" - emittery "0.10.0" - keccak "3.0.2" - leveldown "6.1.0" - secp256k1 "4.0.3" - optionalDependencies: - bufferutil "4.0.5" - utf-8-validate "5.0.7" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: +get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-intrinsic@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.6.tgz#43dd3dd0e7b49b82b2dfcad10dc824bf7fc265d5" + integrity sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA== + dependencies: + call-bind-apply-helpers "^1.0.1" + dunder-proto "^1.0.0" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + function-bind "^1.1.2" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.0.0" + +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-iterator@^1.0.2: +get-symbol-description@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.2.tgz#cd747c02b4c084461fac14f48f6b45a80ed25c82" - integrity sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg== - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-stream@^4.0.0, get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" ghost-testrpc@^0.0.2: version "0.0.2" @@ -5740,7 +2712,7 @@ ghost-testrpc@^0.0.2: chalk "^2.4.2" node-emoji "^1.10.0" -glob-parent@^5.1.2, glob-parent@~5.1.0: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -5754,22 +2726,22 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= + integrity sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA== dependencies: inflight "^1.0.4" inherits "2" @@ -5777,29 +2749,28 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@^7.0.0, glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.2: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== +glob@^8.0.3, glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.1.1" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" global-modules@^2.0.0: version "2.0.0" @@ -5817,37 +2788,20 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -global@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - -globals@^11.1.0, globals@^11.7.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - globals@^13.19.0: - version "13.19.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8" - integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ== + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - -globalthis@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b" - integrity sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ== +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - define-properties "^1.1.3" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^10.0.1: version "10.0.2" @@ -5863,123 +2817,135 @@ globby@^10.0.1: merge2 "^1.2.3" slash "^3.0.0" -google-protobuf@^3.13.0, google-protobuf@^3.17.3, google-protobuf@^3.19.4: - version "3.19.4" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.19.4.tgz#8d32c3e34be9250956f28c0fb90955d13f311888" - integrity sha512-OIPNCxsG2lkIvf+P5FNfJ/Km95CsXOBecS9ZcAU6m2Rq3svc0Apl9nB3GMDNKfQ9asNv4KjyAqGwPQFrVle3Yg== - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -got@9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -got@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== - -graphql-executor@0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/graphql-executor/-/graphql-executor-0.0.18.tgz#6aa4b39e1ca773e159c2a602621e90606df0109a" - integrity sha512-upUSl7tfZCZ5dWG1XkOvpG70Yk3duZKcCoi/uJso4WxJVT6KIrcK4nZ4+2X/hzx46pL8wAukgYHY6iNmocRN+g== - -graphql-tag@^2.11.0: - version "2.12.6" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" - integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== - dependencies: - tslib "^2.1.0" - -graphql@^15.3.0: - version "15.8.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" - integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +got@^12.1.0: + version "12.6.1" + resolved "https://registry.yarnpkg.com/got/-/got-12.6.1.tgz#8869560d1383353204b5a9435f782df9c091f549" + integrity sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + +graceful-fs@4.2.10: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== handlebars@^4.0.1: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== dependencies: minimist "^1.2.5" - neo-async "^2.6.0" + neo-async "^2.6.2" source-map "^0.6.1" wordwrap "^1.0.0" optionalDependencies: uglify-js "^3.1.4" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= +hardhat-chai-matchers-viem@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/hardhat-chai-matchers-viem/-/hardhat-chai-matchers-viem-2.0.8.tgz#cdebf2dd0c09cae0890e835fb3b5b5fae35a154a" + integrity sha512-ryNgczdWvyt7n/vN/EbwAS1kk4BPV8301Z/cJkL3k4+wwSvCzkfp/hpQAkDu6tQhoxBeGAJO2KpY+pAOx+T39g== dependencies: - ansi-regex "^2.0.0" + "@types/chai-as-promised" "^7.1.3" + chai-as-promised "^7.1.1" + deep-eql "^4.0.1" + ordinal "^1.0.3" -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== +hardhat-gas-reporter@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/hardhat-gas-reporter/-/hardhat-gas-reporter-2.2.2.tgz#b1530b1938b994d67dffda207314504b7946af09" + integrity sha512-xlg3d00wrgUvP2S5tw3Zf6nO7OyS5crK3P6/ZP69i24pz4grM+6oFHGW/eJPSGqiDWBYX+gKp9XoqP4rwRXrdQ== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/units" "^5.7.0" + "@solidity-parser/parser" "^0.19.0" + axios "^1.6.7" + brotli-wasm "^2.0.1" + chalk "4.1.2" + cli-table3 "^0.6.3" + ethereum-cryptography "^2.1.3" + glob "^10.3.10" + jsonschema "^1.4.1" + lodash "^4.17.21" + markdown-table "2.0.0" + sha1 "^1.1.1" + viem "2.7.14" + +hardhat@^2.22.15: + version "2.22.17" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.17.tgz#96036bbe6bad8eb6a6b65c54dc5fbc1324541612" + integrity sha512-tDlI475ccz4d/dajnADUTRc1OJ3H8fpP9sWhXhBPpYsQOg8JHq5xrDimo53UhWPl7KJmAeDCm1bFG74xvpGRpg== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@metamask/eth-sig-util" "^4.0.0" + "@nomicfoundation/edr" "^0.6.5" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + "@nomicfoundation/solidity-analyzer" "^0.1.0" + "@sentry/node" "^5.18.1" + "@types/bn.js" "^5.1.0" + "@types/lru-cache" "^5.1.0" + adm-zip "^0.4.16" + aggregate-error "^3.0.0" + ansi-escapes "^4.3.0" + boxen "^5.1.2" + chokidar "^4.0.0" + ci-info "^2.0.0" + debug "^4.1.1" + enquirer "^2.3.0" + env-paths "^2.2.0" + ethereum-cryptography "^1.0.3" + ethereumjs-abi "^0.6.8" + find-up "^5.0.0" + fp-ts "1.19.3" + fs-extra "^7.0.1" + immutable "^4.0.0-rc.12" + io-ts "1.10.4" + json-stream-stringify "^3.1.4" + keccak "^3.0.2" + lodash "^4.17.11" + mnemonist "^0.38.0" + mocha "^10.0.0" + p-map "^4.0.0" + picocolors "^1.1.0" + raw-body "^2.4.1" + resolve "1.17.0" + semver "^6.3.0" + solc "0.8.26" + source-map-support "^0.5.13" + stacktrace-parser "^0.1.10" + tinyglobby "^0.2.6" + tsort "0.0.1" + undici "^5.14.0" + uuid "^8.3.2" + ws "^7.4.6" has-bigints@^1.0.2: version "1.0.2" @@ -5989,65 +2955,43 @@ has-bigints@^1.0.2: has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= - -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + integrity sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA== has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - -has-symbols@^1.0.0, has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - has-symbol-support-x "^1.4.1" + es-define-property "^1.0.0" -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-proto@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== dependencies: - has-symbols "^1.0.2" + dunder-proto "^1.0.0" -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - function-bind "^1.1.1" + has-symbols "^1.0.3" hash-base@^3.0.0: version "3.1.0" @@ -6058,14 +3002,6 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" -hash.js@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" @@ -6074,161 +3010,87 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" -he@1.2.0: +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -header-case@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d" - integrity sha1-lTWXMZfBRLCWE81l0xfvGZY70C0= - dependencies: - no-case "^2.2.0" - upper-case "^1.1.3" +"heap@>= 0.2.0": + version "0.2.7" + resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" + integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== dependencies: hash.js "^1.0.3" minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -htmlparser2@^3.9.1: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - -htmlparser2@~3.8.1: - version "3.8.3" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" - integrity sha1-mWwosZFRaovoZQGn15dX5ccMEGg= - dependencies: - domelementtype "1" - domhandler "2.3" - domutils "1.5" - entities "1.0" - readable-stream "1.1" - -http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== +http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-errors@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~1.1.2" + depd "2.0.0" inherits "2.0.4" setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" + statuses "2.0.1" toidentifier "1.0.1" -http-https@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" - integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" -ice-cap@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/ice-cap/-/ice-cap-0.0.4.tgz#8a6d31ab4cac8d4b56de4fa946df3352561b6e18" - integrity sha1-im0xq0ysjUtW3k+pRt8zUlYbbhg= +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: - cheerio "0.20.0" - color-logger "0.0.3" + agent-base "6" + debug "4" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -idna-uts46-hx@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" - integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== - dependencies: - punycode "2.1.0" - -ieee754@^1.1.13, ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore-walk@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" - integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== - dependencies: - minimatch "^3.0.4" - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== - -immediate@3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= - -immediate@3.3.0, immediate@^3.2.2, immediate@^3.2.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" - integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== +ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -immediate@~3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" - integrity sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw= +immer@10.0.2: + version "10.0.2" + resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.2.tgz#11636c5b77acf529e059582d76faf338beb56141" + integrity sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA== -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg== - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" +immutable@^4.0.0-rc.12: + version "4.3.7" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381" + integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -6241,230 +3103,76 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -inherits@=2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -ini@^1.3.5, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@^6.2.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== +internal-slot@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -ip-regex@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" - integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -ipfs-core-types@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ipfs-core-types/-/ipfs-core-types-0.2.1.tgz#460bf2116477ce621995468c962c685dbdc4ac6f" - integrity sha512-q93+93qSybku6woZaajE9mCrHeVoMzNtZ7S5m/zx0+xHRhnoLlg8QNnGGsb5/+uFQt/RiBArsIw/Q61K9Jwkzw== - dependencies: - cids "^1.1.5" - multiaddr "^8.0.0" - peer-id "^0.14.1" - -ipfs-core-utils@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/ipfs-core-utils/-/ipfs-core-utils-0.6.1.tgz#59d1ca9ff4a33bbf6497c4abe024573c3fd7d784" - integrity sha512-UFIklwE3CFcsNIhYFDuz0qB7E2QtdFauRfc76kskgiqhGWcjqqiDeND5zBCrAy0u8UMaDqAbFl02f/mIq1yKXw== - dependencies: - any-signal "^2.0.0" - blob-to-it "^1.0.1" - browser-readablestream-to-it "^1.0.1" - cids "^1.1.5" - err-code "^2.0.3" - ipfs-core-types "^0.2.1" - ipfs-utils "^5.0.0" - it-all "^1.0.4" - it-map "^1.0.4" - it-peekable "^1.0.1" - multiaddr "^8.0.0" - multiaddr-to-uri "^6.0.0" - parse-duration "^0.4.4" - timeout-abort-controller "^1.1.1" - uint8arrays "^1.1.0" - -ipfs-http-client@^48.2.2: - version "48.2.2" - resolved "https://registry.yarnpkg.com/ipfs-http-client/-/ipfs-http-client-48.2.2.tgz#b570fb99866f94df1c394a6101a2eb750ff46599" - integrity sha512-f3ppfWe913SJLvunm0UgqdA1dxVZSGQJPaEVJtqgjxPa5x0fPDiBDdo60g2MgkW1W6bhF9RGlxvHHIE9sv/tdg== - dependencies: - any-signal "^2.0.0" - bignumber.js "^9.0.0" - cids "^1.1.5" - debug "^4.1.1" - form-data "^3.0.0" - ipfs-core-types "^0.2.1" - ipfs-core-utils "^0.6.1" - ipfs-utils "^5.0.0" - ipld-block "^0.11.0" - ipld-dag-cbor "^0.17.0" - ipld-dag-pb "^0.20.0" - ipld-raw "^6.0.0" - it-last "^1.0.4" - it-map "^1.0.4" - it-tar "^1.2.2" - it-to-stream "^0.1.2" - merge-options "^2.0.0" - multiaddr "^8.0.0" - multibase "^3.0.0" - multicodec "^2.0.1" - multihashes "^3.0.1" - nanoid "^3.1.12" - native-abort-controller "~0.0.3" - parse-duration "^0.4.4" - stream-to-it "^0.2.2" - uint8arrays "^1.1.0" - -ipfs-utils@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ipfs-utils/-/ipfs-utils-5.0.1.tgz#7c0053d5e77686f45577257a73905d4523e6b4f7" - integrity sha512-28KZPgO4Uf5duT2ORLAYfboUp98iUshDD7yRAfbNxNAR8Dtidfn6o20rZfoXnkri2zKBVIPlJkuCPmPJB+6erg== - dependencies: - abort-controller "^3.0.0" - any-signal "^2.1.0" - buffer "^6.0.1" - electron-fetch "^1.7.2" - err-code "^2.0.0" - fs-extra "^9.0.1" - is-electron "^2.2.0" - iso-url "^1.0.0" - it-glob "0.0.10" - it-to-stream "^0.1.2" - merge-options "^2.0.0" - nanoid "^3.1.3" - native-abort-controller "0.0.3" - native-fetch "^2.0.0" - node-fetch "^2.6.0" - stream-to-it "^0.2.0" - -ipld-block@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/ipld-block/-/ipld-block-0.11.1.tgz#c3a7b41aee3244187bd87a73f980e3565d299b6e" - integrity sha512-sDqqLqD5qh4QzGq6ssxLHUCnH4emCf/8F8IwjQM2cjEEIEHMUj57XhNYgmGbemdYPznUhffxFGEHsruh5+HQRw== - dependencies: - cids "^1.0.0" - -ipld-dag-cbor@^0.17.0: - version "0.17.1" - resolved "https://registry.yarnpkg.com/ipld-dag-cbor/-/ipld-dag-cbor-0.17.1.tgz#842e6c250603e5791049168831a425ec03471fb1" - integrity sha512-Bakj/cnxQBdscORyf4LRHxQJQfoaY8KWc7PWROQgX+aw5FCzBt8ga0VM/59K+ABOznsqNvyLR/wz/oYImOpXJw== - dependencies: - borc "^2.1.2" - cids "^1.0.0" - is-circular "^1.0.2" - multicodec "^3.0.1" - multihashing-async "^2.0.0" - uint8arrays "^2.1.3" - -ipld-dag-pb@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/ipld-dag-pb/-/ipld-dag-pb-0.20.0.tgz#025c0343aafe6cb9db395dd1dc93c8c60a669360" - integrity sha512-zfM0EdaolqNjAxIrtpuGKvXxWk5YtH9jKinBuQGTcngOsWFQhyybGCTJHGNGGtRjHNJi2hz5Udy/8pzv4kcKyg== - dependencies: - cids "^1.0.0" - class-is "^1.1.0" - multicodec "^2.0.0" - multihashing-async "^2.0.0" - protons "^2.0.0" - reset "^0.1.0" - run "^1.4.0" - stable "^0.1.8" - uint8arrays "^1.0.0" - -ipld-raw@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/ipld-raw/-/ipld-raw-6.0.0.tgz#74d947fcd2ce4e0e1d5bb650c1b5754ed8ea6da0" - integrity sha512-UK7fjncAzs59iu/o2kwYtb8jgTtW6B+cNWIiNpAJkfRwqoMk1xD/6i25ktzwe4qO8gQgoR9RxA5ibC23nq8BLg== +io-ts@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" + integrity sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g== dependencies: - cids "^1.0.0" - multicodec "^2.0.0" - multihashing-async "^2.0.0" + fp-ts "^1.0.0" -is-arguments@^1.0.4, is-arguments@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: call-bind "^1.0.2" - has-tostringtag "^1.0.0" + get-intrinsic "^1.2.1" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== dependencies: - has-bigints "^1.0.1" + has-bigints "^1.0.2" is-binary-path@~2.1.0: version "2.1.0" @@ -6473,110 +3181,61 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== +is-boolean-object@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.1.tgz#c20d0c654be05da4fbc23c562635c019e93daf89" + integrity sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^2.0.5, is-buffer@~2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + call-bound "^1.0.2" + has-tostringtag "^1.0.2" -is-callable@^1.2.7: +is-callable@^1.1.3, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-circular@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-circular/-/is-circular-1.0.2.tgz#2e0ab4e9835f4c6b0ea2b9855a84acd501b8366c" - integrity sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA== - -is-core-module@^2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== - dependencies: - has "^1.0.3" - -is-core-module@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" - integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.0.tgz#6c01ffdd5e33c49c1d2abfa93334a85cb56bd81c" + integrity sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g== dependencies: - has "^1.0.3" + hasown "^2.0.2" -is-core-module@^2.9.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" - integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== +is-data-view@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== dependencies: - has "^1.0.3" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== dependencies: - has-tostringtag "^1.0.0" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw== - -is-electron@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.1.tgz#751b1dd8a74907422faa5c35aaa0cf66d98086e9" - integrity sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw== + call-bound "^1.0.2" + has-tostringtag "^1.0.2" is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-finite@^1.0.0: +is-finalizationregistry@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - -is-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" - integrity sha512-XoFPJQmsAShb3jEQRfzf2rqXavq7fIqF/jOekp308JlThqrODnMpweVSGilKTCXELfLhltGP2AGgbQGVP8F1dg== - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz#d74a7d0c5f3578e34a20729e69202e578d495dc2" + integrity sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA== dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + call-bind "^1.0.7" is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - -is-generator-function@^1.0.7: +is-generator-function@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== @@ -6593,351 +3252,152 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: is-hex-prefixed@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= - -is-ip@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8" - integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q== - dependencies: - ip-regex "^4.0.0" - -is-lower-case@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-1.1.3.tgz#7e147be4768dc466db3bfb21cc60b31e6ad69393" - integrity sha1-fhR75HaNxGbbO/shzGCzHmrWk5M= - dependencies: - lower-case "^1.1.0" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== -is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" - integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== -is-negative-zero@^2.0.1, is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== -is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== +is-number-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.0.tgz#5a867e9ecc3d294dda740d9f127835857af7eb05" + integrity sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw== dependencies: - has-tostringtag "^1.0.0" + call-bind "^1.0.7" + has-tostringtag "^1.0.2" is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" - integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== - is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-obj@^2.0.0: +is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-reference@^1.2.1: +is-regex@^1.1.4, is-regex@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" - integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== dependencies: - "@types/estree" "*" + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bind "^1.0.7" -is-retry-allowed@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== +is-string@^1.0.7, is-string@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.0.tgz#8cb83c5d57311bf8058bc6c8db294711641da45d" + integrity sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g== + dependencies: + call-bind "^1.0.7" + has-tostringtag "^1.0.2" -is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-symbol@^1.0.4, is-symbol@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-stream@^1.0.0, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - has-symbols "^1.0.2" + which-typed-array "^1.1.14" -is-typed-array@^1.1.3, is-typed-array@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" - integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-typedarray@^1.0.0, is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== -is-upper-case@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-1.1.2.tgz#8d0b1fa7e7933a1e58483600ec7d9661cbaf756f" - integrity sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8= +is-weakref@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.0.tgz#47e3472ae95a63fa9cf25660bcf0c181c39770ef" + integrity sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q== dependencies: - upper-case "^1.1.0" + call-bound "^1.0.2" -is-weakref@^1.0.1, is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== dependencies: - call-bind "^1.0.2" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + call-bind "^1.0.7" + get-intrinsic "^1.2.4" isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -iso-constants@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/iso-constants/-/iso-constants-0.1.2.tgz#3d2456ed5aeaa55d18564f285ba02a47a0d885b4" - integrity sha512-OTCM5ZCQsHBCI4Wdu4tSxvDIkmDHd5EwJDps5mKqnQnWJSKlnwMs3EDZ4n3Fh1tmkWkDlyd2vCDbEYuPbyrUNQ== - -iso-random-stream@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/iso-random-stream/-/iso-random-stream-2.0.2.tgz#a24f77c34cfdad9d398707d522a6a0cc640ff27d" - integrity sha512-yJvs+Nnelic1L2vH2JzWvvPQFA4r7kSTnpST/+LkAQjSz0hos2oqLD+qIVi9Qk38Hoe7mNDt3j0S27R58MVjLQ== - dependencies: - events "^3.3.0" - readable-stream "^3.4.0" - -iso-url@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-1.2.1.tgz#db96a49d8d9a64a1c889fc07cc525d093afb1811" - integrity sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng== - -iso-url@~0.4.7: - version "0.4.7" - resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-0.4.7.tgz#de7e48120dae46921079fe78f325ac9e9217a385" - integrity sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog== - -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -it-all@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/it-all/-/it-all-1.0.6.tgz#852557355367606295c4c3b7eff0136f07749335" - integrity sha512-3cmCc6Heqe3uWi3CVM/k51fa/XbMFpQVzFoDsV0IZNHSQDyAXl3c4MjHkFX5kF3922OGj7Myv1nSEUgRtcuM1A== - -it-concat@^1.0.0: +isows@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/it-concat/-/it-concat-1.0.3.tgz#84db9376e4c77bf7bc1fd933bb90f184e7cef32b" - integrity sha512-sjeZQ1BWQ9U/W2oI09kZgUyvSWzQahTkOkLIsnEPgyqZFaF9ME5gV6An4nMjlyhXKWQMKEakQU8oRHs2SdmeyA== - dependencies: - bl "^4.0.0" - -it-drain@^1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/it-drain/-/it-drain-1.0.5.tgz#0466d4e286b37bcd32599d4e99b37a87cb8cfdf6" - integrity sha512-r/GjkiW1bZswC04TNmUnLxa6uovme7KKwPhc+cb1hHU65E3AByypHH6Pm91WHuvqfFsm+9ws0kPtDBV3/8vmIg== + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74" + integrity sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg== -it-glob@0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/it-glob/-/it-glob-0.0.10.tgz#4defd9286f693847c3ff483d2ff65f22e1359ad8" - integrity sha512-p1PR15djgPV7pxdLOW9j4WcJdla8+91rJdUU2hU2Jm68vkxpIEXK55VHBeH8Lvqh2vqLtM83t8q4BuJxue6niA== - dependencies: - fs-extra "^9.0.1" - minimatch "^3.0.4" - -it-last@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/it-last/-/it-last-1.0.6.tgz#4106232e5905ec11e16de15a0e9f7037eaecfc45" - integrity sha512-aFGeibeiX/lM4bX3JY0OkVCFkAw8+n9lkukkLNivbJRvNz8lI3YXv5xcqhFUV2lDJiraEK3OXRDbGuevnnR67Q== - -it-map@^1.0.4: +isows@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/it-map/-/it-map-1.0.6.tgz#6aa547e363eedcf8d4f69d8484b450bc13c9882c" - integrity sha512-XT4/RM6UHIFG9IobGlQPFQUrlEKkU4eBUFG3qhWhfAdh1JfF2x11ShCrKCdmZ0OiZppPfoLuzcfA4cey6q3UAQ== - -it-peekable@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/it-peekable/-/it-peekable-1.0.3.tgz#8ebe933767d9c5aa0ae4ef8e9cb3a47389bced8c" - integrity sha512-5+8zemFS+wSfIkSZyf0Zh5kNN+iGyccN02914BY4w/Dj+uoFEoPSvj5vaWn8pNZJNSxzjW0zHRxC3LUb2KWJTQ== - -it-reader@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/it-reader/-/it-reader-2.1.0.tgz#b1164be343f8538d8775e10fb0339f61ccf71b0f" - integrity sha512-hSysqWTO9Tlwc5EGjVf8JYZzw0D2FsxD/g+eNNWrez9zODxWt6QlN6JAMmycK72Mv4jHEKEXoyzUN4FYGmJaZw== - dependencies: - bl "^4.0.0" - -it-tar@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/it-tar/-/it-tar-1.2.2.tgz#8d79863dad27726c781a4bcc491f53c20f2866cf" - integrity sha512-M8V4a9I+x/vwXTjqvixcEZbQZHjwDIb8iUQ+D4M2QbhAdNs3WKVSl+45u5/F2XFx6jYMFOGzMVlKNK/uONgNIA== - dependencies: - bl "^4.0.0" - buffer "^5.4.3" - iso-constants "^0.1.2" - it-concat "^1.0.0" - it-reader "^2.0.0" - p-defer "^3.0.0" - -it-to-stream@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/it-to-stream/-/it-to-stream-0.1.2.tgz#7163151f75b60445e86b8ab1a968666acaacfe7b" - integrity sha512-DTB5TJRZG3untmZehcaFN0kGWl2bNv7tnJRgQHAO9QEt8jfvVRrebZtnD5NZd4SCj4WVPjl0LSrugNWE/UaZRQ== - dependencies: - buffer "^5.6.0" - fast-fifo "^1.0.0" - get-iterator "^1.0.2" - p-defer "^3.0.0" - p-fifo "^1.0.0" - readable-stream "^3.6.0" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7" + integrity sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw== -iter-tools@^7.0.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/iter-tools/-/iter-tools-7.2.2.tgz#e363923b1944f9bb67c8e3c6b620ba8c3efcb9d3" - integrity sha512-4PFLfSmndJgzA5wmyAZTJmgrJiDlQK2cGFdfEu9QPzzAnjY59yTbSnzFM/6sclMRQ+Y1MbdhLcVl74djK8PCVQ== - dependencies: - "@babel/runtime" "^7.12.1" - -iterate-iterator@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.2.tgz#551b804c9eaa15b847ea6a7cdc2f5bf1ec150f91" - integrity sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw== - -iterate-value@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-value/-/iterate-value-1.0.2.tgz#935115bd37d006a52046535ebc8d07e9c9337f57" - integrity sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: - es-get-iterator "^1.0.2" - iterate-iterator "^1.0.1" - -js-sdsl@^4.1.4: - version "4.2.0" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.2.0.tgz#278e98b7bea589b8baaf048c20aeb19eb7ad09d0" - integrity sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ== - -js-sha256@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" - integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== - -js-sha3@0.5.7, js-sha3@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" -js-sha3@0.8.0, js-sha3@^0.8.0: +js-sha3@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -js-yaml@3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1: +js-yaml@3.x: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -6952,79 +3412,15 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^7.0.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-7.2.2.tgz#40b402770c2bda23469096bee91ab675e3b1fc6e" - integrity sha1-QLQCdwwr2iNGkJa+6Rq2deOx/G4= - dependencies: - abab "^1.0.0" - acorn "^2.4.0" - acorn-globals "^1.0.4" - cssom ">= 0.3.0 < 0.4.0" - cssstyle ">= 0.2.29 < 0.3.0" - escodegen "^1.6.1" - nwmatcher ">= 1.3.7 < 2.0.0" - parse5 "^1.5.1" - request "^2.55.0" - sax "^1.1.4" - symbol-tree ">= 3.1.0 < 4.0.0" - tough-cookie "^2.2.0" - webidl-conversions "^2.0.0" - whatwg-url-compat "~0.6.5" - xml-name-validator ">= 2.0.1 < 3.0.0" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-pointer@^0.6.1: - version "0.6.2" - resolved "https://registry.yarnpkg.com/json-pointer/-/json-pointer-0.6.2.tgz#f97bd7550be5e9ea901f8c9264c9d436a22a93cd" - integrity sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw== - dependencies: - foreach "^2.0.4" - -json-rpc-engine@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz#75758609d849e1dba1e09021ae473f3ab63161e5" - integrity sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g== - dependencies: - eth-rpc-errors "^3.0.0" - safe-event-emitter "^1.0.1" - -json-rpc-engine@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393" - integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ== - dependencies: - "@metamask/safe-event-emitter" "^2.0.0" - eth-rpc-errors "^4.0.2" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-rpc-random-id@^1.0.0, json-rpc-random-id@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" - integrity sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" @@ -7036,66 +3432,37 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema-typed@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-7.0.3.tgz#23ff481b8b4eebcd2ca123b4fa0409e66469a2d9" - integrity sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A== - -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" +json-stream-stringify@^3.1.4: + version "3.1.6" + resolved "https://registry.yarnpkg.com/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz#ebe32193876fb99d4ec9f612389a8d8e2b5d54d4" + integrity sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog== -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json-text-sequence@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/json-text-sequence/-/json-text-sequence-0.1.1.tgz#a72f217dc4afc4629fff5feb304dc1bd51a2f3d2" - integrity sha1-py8hfcSvxGKf/1/rME3BvVGi89I= - dependencies: - delimit-stream "0.1.0" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^1.0.1: +json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" -json5@^2.1.0, json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - -jsondown@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/jsondown/-/jsondown-1.0.0.tgz#c5cc5cda65f515d2376136a104b5f535534f26e3" - integrity sha512-p6XxPaq59aXwcdDQV3ISMA5xk+1z6fJuctcwwSdR9iQgbYOcIrnknNrhcMGG+0FaUfKHGkdDpQNaZrovfBoyOw== - dependencies: - memdown "1.4.1" - mkdirp "0.5.1" +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== optionalDependencies: graceful-fs "^4.1.6" @@ -7108,1314 +3475,418 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - -jsonschema@^1.2.4: - version "1.4.0" - resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" - integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw== - -jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - -keccak@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.1.tgz#ae30a0e94dbe43414f741375cff6d64c8bea0bff" - integrity sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA== - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" +jsonschema@^1.2.4, jsonschema@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab" + integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== -keccak@3.0.2, keccak@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" - integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== +keccak@^3.0.0, keccak@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== dependencies: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" readable-stream "^3.6.0" -keypair@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/keypair/-/keypair-1.0.4.tgz#a749a45f388593f3950f18b3757d32a93bd8ce83" - integrity sha512-zwhgOhhniaL7oxMgUMKKw5219PWWABMO+dgMnzJOQ2/5L3XJtTJGhW2PEXlxXj9zaccdReZJZ83+4NPhVfNVDg== - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: - json-buffer "3.0.0" + json-buffer "3.0.1" kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -lcov-parse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0" - integrity sha1-6w1GtUER68VhrLTECO+TY73I9+A= +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -leb128@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/leb128/-/leb128-0.0.5.tgz#84524a86ef7799fb3933ce41345f6490e27ac948" - integrity sha512-elbNtfmu3GndZbesVF6+iQAfVjOXW9bM/aax9WwMlABZW+oK9sbAZEXoewaPHmL34sxa8kVwWsru8cNE/yn2gg== +latest-version@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-7.0.0.tgz#843201591ea81a4d404932eeb61240fe04e9e5da" + integrity sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg== dependencies: - bn.js "^5.0.0" - buffer-pipe "0.0.3" + package-json "^8.1.0" -level-codec@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.1.tgz#042f4aa85e56d4328ace368c950811ba802b7247" - integrity sha512-ajFP0kJ+nyq4i6kptSM+mAvJKLOg1X5FiFPtLG9M5gCEZyBmgDi3FkDrvlMkEzrUn1cWxtvVmrvoS4ASyO/q+Q== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" -level-codec@9.0.2, level-codec@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" - integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== dependencies: - buffer "^5.6.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" -level-codec@~7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" - integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -level-concat-iterator@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz#5235b1f744bc34847ed65a50548aa88d22e881cf" - integrity sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ== +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: - catering "^2.1.0" + p-locate "^5.0.0" -level-concat-iterator@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" - integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== -level-errors@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" - integrity sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w== +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: - errno "~0.1.1" + chalk "^4.1.0" + is-unicode-supported "^0.1.0" -level-errors@^2.0.0, level-errors@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" - integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== dependencies: - errno "~0.1.1" + get-func-name "^2.0.1" -level-errors@~1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" - integrity sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig== +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +markdown-table@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" + integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A== dependencies: - errno "~0.1.1" + repeat-string "^1.0.0" -level-iterator-stream@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" - integrity sha512-1qua0RHNtr4nrZBgYlpV0qHHeHpcRRWTxEZJ8xsemoHAXNL5tbooh4tPEEqIqsbWCAJBmUmkwYK/sW5OrFjWWw== +math-intrinsics@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.0.0.tgz#4e04bf87c85aa51e90d078dac2252b4eb5260817" + integrity sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== dependencies: + hash-base "^3.0.0" inherits "^2.0.1" - level-errors "^1.0.3" - readable-stream "^1.0.33" - xtend "^4.0.0" + safe-buffer "^5.1.2" -level-iterator-stream@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" - integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== - dependencies: - inherits "^2.0.4" - readable-stream "^3.4.0" - xtend "^4.0.2" +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== -level-js@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/level-js/-/level-js-4.0.2.tgz#fa51527fa38b87c4d111b0d0334de47fcda38f21" - integrity sha512-PeGjZsyMG4O89KHiez1zoMJxStnkM+oBIqgACjoo5PJqFiSUUm3GNod/KcbqN5ktyZa8jkG7I1T0P2u6HN9lIg== +merge2@^1.2.3, merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - abstract-leveldown "~6.0.1" - immediate "~3.2.3" - inherits "^2.0.3" - ltgt "^2.1.2" - typedarray-to-buffer "~3.1.5" + braces "^3.0.3" + picomatch "^2.3.1" -level-packager@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" - integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - encoding-down "^6.3.0" - levelup "^4.3.2" + mime-db "1.52.0" -level-supports@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" - integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -level-supports@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" - integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== -level-supports@~1.0.0: +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" - integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== - dependencies: - xtend "^4.0.2" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -level-transcoder@^1.0.1: +minimalistic-crypto-utils@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" - integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== - dependencies: - buffer "^6.0.3" - module-error "^1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -level-write-stream@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/level-write-stream/-/level-write-stream-1.0.0.tgz#3f7fbb679a55137c0feb303dee766e12ee13c1dc" - integrity sha1-P3+7Z5pVE3wP6zA97nZuEu4Twdw= +"minimatch@2 || 3", minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: - end-stream "~0.1.0" + brace-expansion "^1.1.7" -level-ws@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" - integrity sha512-XUTaO/+Db51Uiyp/t7fCMGVFOTdtLS/NIACxE/GHsij15mKzxksZifKVjlXDF41JMUP/oM1Oc4YNGdKnc3dVLw== +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: - readable-stream "~1.0.15" - xtend "~2.1.1" + brace-expansion "^2.0.1" -level@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/level/-/level-5.0.1.tgz#8528cc1ee37ac413270129a1eab938c610be3ccb" - integrity sha512-wcak5OQeA4rURGacqS62R/xNHjCYnJSQDBOlm4KNUGJVE9bWv2B04TclqReYejN+oD65PzD4FsqeWoI5wNC5Lg== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: - level-js "^4.0.0" - level-packager "^5.0.0" - leveldown "^5.0.0" - opencollective-postinstall "^2.0.0" + brace-expansion "^2.0.1" -leveldown@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.0.2.tgz#c8edc2308c8abf893ffc81e66ab6536111cae92c" - integrity sha512-Ib6ygFYBleS8x2gh3C1AkVsdrUShqXpe6jSTnZ6sRycEXKhqVf+xOSkhgSnjidpPzyv0d95LJVFrYQ4NuXAqHA== - dependencies: - abstract-leveldown "~6.0.0" - fast-future "~1.0.2" - napi-macros "~1.8.1" - node-gyp-build "~3.8.0" +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -leveldown@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.0.tgz#7ab1297706f70c657d1a72b31b40323aa612b9ee" - integrity sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w== - dependencies: - abstract-leveldown "^7.2.0" - napi-macros "~2.0.0" - node-gyp-build "^4.3.0" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== -leveldown@^5.0.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98" - integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== +mkdirp@0.5.x: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - abstract-leveldown "~6.2.1" - napi-macros "~2.0.0" - node-gyp-build "~4.1.0" + minimist "^1.2.6" -levelup@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.0.2.tgz#bcb8d28d0a82ee97f1c6d00f20ea6d32c2803c5b" - integrity sha512-cx9PmLENwbGA3svWBEbeO2HazpOSOYSXH4VA+ahVpYyurvD+SDSfURl29VBY2qgyk+Vfy2dJd71SBRckj/EZVA== +mnemonist@^0.38.0: + version "0.38.5" + resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" + integrity sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg== dependencies: - deferred-leveldown "~5.0.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - xtend "~4.0.0" + obliterator "^2.0.0" -levelup@4.4.0, levelup@^4.3.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" - integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== - dependencies: - deferred-leveldown "~5.3.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -levelup@^1.2.1: - version "1.3.9" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" - integrity sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ== - dependencies: - deferred-leveldown "~1.2.1" - level-codec "~7.0.0" - level-errors "~1.0.3" - level-iterator-stream "~1.3.0" - prr "~1.0.1" - semver "~5.4.1" - xtend "~4.0.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= +mocha@^10.0.0, mocha@^10.2.0: + version "10.8.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.8.2.tgz#8d8342d016ed411b12a429eb731b825f961afb96" + integrity sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg== dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -libp2p-crypto@^0.19.0: - version "0.19.7" - resolved "https://registry.yarnpkg.com/libp2p-crypto/-/libp2p-crypto-0.19.7.tgz#e96a95bd430e672a695209fe0fbd2bcbd348bc35" - integrity sha512-Qb5o/3WFKF2j6mYSt4UBPyi2kbKl3jYV0podBJoJCw70DlpM5Xc+oh3fFY9ToSunu8aSQQ5GY8nutjXgX/uGRA== - dependencies: - err-code "^3.0.1" - is-typedarray "^1.0.0" - iso-random-stream "^2.0.0" - keypair "^1.0.1" - multiformats "^9.4.5" - node-forge "^0.10.0" - pem-jwk "^2.0.0" - protobufjs "^6.11.2" - secp256k1 "^4.0.0" - uint8arrays "^3.0.0" - ursa-optional "^0.10.1" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash-es@^4.2.1: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= - -lodash.keys@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" - integrity sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU= - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.omit@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" - integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - -lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash.without@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" - integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= - -lodash.xor@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6" - integrity sha1-TUjtfpgJWwYyWCunFNP/iuj7HbY= - -lodash@^4.1.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.2.1: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-driver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" - integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== - -log-symbols@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" - integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== - dependencies: - chalk "^4.0.0" - -log-symbols@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - -loglevel@^1.6.6, loglevel@^1.6.8, loglevel@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" - integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== - -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - -loose-envify@^1.0.0, loose-envify@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lower-case-first@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1" - integrity sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E= - dependencies: - lower-case "^1.1.2" - -lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" - integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -ltgt@2.2.1, ltgt@^2.1.2, ltgt@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU= - -magic-string@^0.25.3, magic-string@^0.25.7: - version "0.25.9" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" - integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== - dependencies: - sourcemap-codec "^1.4.8" - -make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -marked-terminal@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-3.3.0.tgz#25ce0c0299285998c7636beaefc87055341ba1bd" - integrity sha512-+IUQJ5VlZoAFsM5MHNT7g3RHSkA3eETqhRCdXv4niUMAKHQ7lb1yvAcuGPmm4soxhmtX13u4Li6ZToXtvSEH+A== - dependencies: - ansi-escapes "^3.1.0" - cardinal "^2.1.1" - chalk "^2.4.1" - cli-table "^0.3.1" - node-emoji "^1.4.1" - supports-hyperlinks "^1.0.1" - -marked@0.3.19: - version "0.3.19" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790" - integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg== - -marked@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e" - integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg== - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -memdown@1.4.1, memdown@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" - integrity sha1-tOThkhdGZP+65BNhqlAPMRnv4hU= - dependencies: - abstract-leveldown "~2.7.1" - functional-red-black-tree "^1.0.1" - immediate "^3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.1.1" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -merge-options@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-2.0.0.tgz#36ca5038badfc3974dbde5e58ba89d3df80882c3" - integrity sha512-S7xYIeWHl2ZUKF7SDeBhGg6rfv5bKxVBdk95s/I7wVF8d+hjLSztJ/B271cnUiF6CAFduEQ5Zn3HYwAjT16DlQ== - dependencies: - is-plain-obj "^2.0.0" - -merge2@^1.2.3, merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" - integrity sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g== - dependencies: - async "^1.4.2" - ethereumjs-util "^5.0.0" - level-ws "0.0.0" - levelup "^1.2.1" - memdown "^1.0.0" - readable-stream "^2.0.0" - rlp "^2.0.0" - semaphore ">=1.0.1" - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-fn@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" - integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@*: - version "5.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== - dependencies: - brace-expansion "^2.0.1" - -"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minimist@^1.2.6, minimist@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== - -minipass@^2.6.0, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - -mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= - dependencies: - mkdirp "*" - -mkdirp@*, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -mkdirp@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -mkdirp@0.5.x, mkdirp@^0.5.1, mkdirp@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mocha@8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.1.2.tgz#d67fad13300e4f5cd48135a935ea566f96caf827" - integrity sha512-I8FRAcuACNMLQn3lS4qeWLxXqLvGf6r2CaLstDpZmMUUSmvW6Cnm1AuHxgbc7ctZVRcfwspCRbDHymPsi3dkJw== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.4.2" - debug "4.1.1" - diff "4.0.2" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.1.6" - growl "1.10.5" - he "1.2.0" - js-yaml "3.14.0" - log-symbols "4.0.0" - minimatch "3.0.4" - ms "2.1.2" - object.assign "4.1.0" - promise.allsettled "1.0.2" - serialize-javascript "4.0.0" - strip-json-comments "3.0.1" - supports-color "7.1.0" - which "2.0.2" - wide-align "1.1.3" - workerpool "6.0.0" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.1" - -mock-fs@^4.1.0: - version "4.14.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" - integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== - -module-error@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" - integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" -ms@2.1.3, ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multiaddr-to-uri@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/multiaddr-to-uri/-/multiaddr-to-uri-6.0.0.tgz#8f08a75c6eeb2370d5d24b77b8413e3f0fa9bcc0" - integrity sha512-OjpkVHOXEmIKMO8WChzzQ7aZQcSQX8squxmvtDbRpy7/QNmJ3Z7jv6qyD74C28QtaeNie8O8ngW2AkeiMmKP7A== - dependencies: - multiaddr "^8.0.0" - -multiaddr@^8.0.0, multiaddr@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/multiaddr/-/multiaddr-8.1.2.tgz#74060ff8636ba1c01b2cf0ffd53950b852fa9b1f" - integrity sha512-r13IzW8+Sv9zab9Gt8RPMIN2WkptIPq99EpAzg4IbJ/zTELhiEwXWr9bAmEatSCI4j/LSA6ESJzvz95JZ+ZYXQ== - dependencies: - cids "^1.0.0" - class-is "^1.1.0" - dns-over-http-resolver "^1.0.0" - err-code "^2.0.3" - is-ip "^3.1.0" - multibase "^3.0.0" - uint8arrays "^1.1.0" - varint "^5.0.0" - -multibase@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" - integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multibase@^3.0.0, multibase@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-3.1.2.tgz#59314e1e2c35d018db38e4c20bb79026827f0f2f" - integrity sha512-bpklWHs70LO3smJUHOjcnzGceJJvn9ui0Vau6Za0B/GBepaXswmW8Ufea0uD9pROf/qCQ4N4lZ3sf3U+SNf0tw== - dependencies: - "@multiformats/base-x" "^4.0.1" - web-encoding "^1.0.6" - -multibase@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-4.0.6.tgz#6e624341483d6123ca1ede956208cb821b440559" - integrity sha512-x23pDe5+svdLz/k5JPGCVdfn7Q5mZVMBETiC+ORfO+sor9Sgs0smJzAjfTbM5tckeCqnaUuMYoz+k3RXMmJClQ== - dependencies: - "@multiformats/base-x" "^4.0.1" - -multibase@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" - integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multicodec@^0.5.5: - version "0.5.7" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" - integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== - dependencies: - varint "^5.0.0" - -multicodec@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" - integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== - dependencies: - buffer "^5.6.0" - varint "^5.0.0" - -multicodec@^2.0.0, multicodec@^2.0.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-2.1.3.tgz#b9850635ad4e2a285a933151b55b4a2294152a5d" - integrity sha512-0tOH2Gtio39uO41o+2xl9UhRkCWxU5ZmZSbFCh/OjGzkWJI8e6lkN/s4Mj1YfyWoBod+2+S3W+6wO6nhkwN8pA== - dependencies: - uint8arrays "1.1.0" - varint "^6.0.0" - -multicodec@^3.0.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-3.2.1.tgz#82de3254a0fb163a107c1aab324f2a91ef51efb2" - integrity sha512-+expTPftro8VAW8kfvcuNNNBgb9gPeNYV9dn+z1kJRWF2vih+/S79f2RVeIwmrJBUJ6NT9IUPWnZDQvegEh5pw== - dependencies: - uint8arrays "^3.0.0" - varint "^6.0.0" - -multiformats@^9.4.2, multiformats@^9.4.5: - version "9.6.4" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.6.4.tgz#5dce1f11a407dbb69aa612cb7e5076069bb759ca" - integrity sha512-fCCB6XMrr6CqJiHNjfFNGT0v//dxOBMrOMqUIzpPc/mmITweLEyhvMpY9bF+jZ9z3vaMAau5E8B68DW77QMXkg== - -multihashes@3.1.2, multihashes@^3.0.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-3.1.2.tgz#ffa5e50497aceb7911f7b4a3b6cada9b9730edfc" - integrity sha512-AP4IoV/YzkNrfbQKZE3OMPibrmy350OmCd6cJkwyM8oExaXIlOY4UnOOVSQtAEuq/LR01XfXKCESidzZvSwHCQ== - dependencies: - multibase "^3.1.0" - uint8arrays "^2.0.5" - varint "^6.0.0" - -multihashes@^0.4.15, multihashes@~0.4.15: - version "0.4.21" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" - integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== - dependencies: - buffer "^5.5.0" - multibase "^0.7.0" - varint "^5.0.0" - -multihashes@^4.0.1, multihashes@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-4.0.3.tgz#426610539cd2551edbf533adeac4c06b3b90fb05" - integrity sha512-0AhMH7Iu95XjDLxIeuCOOE4t9+vQZsACyKZ9Fxw2pcsRmlX4iCn1mby0hS0bb+nQOVpdQYWPpnyusw4da5RPhA== - dependencies: - multibase "^4.0.1" - uint8arrays "^3.0.0" - varint "^5.0.2" - -multihashing-async@^2.0.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-2.1.4.tgz#26dce2ec7a40f0e7f9e732fc23ca5f564d693843" - integrity sha512-sB1MiQXPSBTNRVSJc2zM157PXgDtud2nMFUEIvBrsq5Wv96sUclMRK/ecjoP1T/W61UJBqt4tCTwMkUpt2Gbzg== - dependencies: - blakejs "^1.1.0" - err-code "^3.0.0" - js-sha3 "^0.8.0" - multihashes "^4.0.1" - murmurhash3js-revisited "^3.0.0" - uint8arrays "^3.0.0" - -murmurhash3js-revisited@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" - integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ== - -nan@^2.12.1, nan@^2.13.2, nan@^2.14.2: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - -nano-json-stream-parser@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" - integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= - -nanoid@^3.1.12, nanoid@^3.1.3: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - -napi-macros@~1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-1.8.2.tgz#299265c1d8aa401351ad0675107d751228c03eda" - integrity sha512-Tr0DNY4RzTaBG2W2m3l7ZtFuJChTH6VZhXVhkGGjF/4cZTt+i8GcM9ozD+30Lmr4mDoZ5Xx34t2o4GJqYWDGcg== - -napi-macros@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" - integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== - -native-abort-controller@0.0.3, native-abort-controller@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/native-abort-controller/-/native-abort-controller-0.0.3.tgz#4c528a6c9c7d3eafefdc2c196ac9deb1a5edf2f8" - integrity sha512-YIxU5nWqSHG1Xbu3eOu3pdFRD882ivQpIcu6AiPVe2oSVoRbfYW63DVkZm3g1gHiMtZSvZzF6THSzTGEBYl8YA== - dependencies: - globalthis "^1.0.1" - -native-abort-controller@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/native-abort-controller/-/native-abort-controller-1.0.4.tgz#39920155cc0c18209ff93af5bc90be856143f251" - integrity sha512-zp8yev7nxczDJMoP6pDxyD20IU0T22eX8VwN2ztDccKvSZhRaV33yP1BGwKSZfXuqWUzsXopVFjBdau9OOAwMQ== - -native-fetch@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-2.0.1.tgz#319d53741a7040def92d5dc8ea5fe9416b1fad89" - integrity sha512-gv4Bea+ga9QdXINurpkEqun3ap3vnB+WYoe4c8ddqUYEH7B2h6iD39RF8uVN7OwmSfMY3RDxkvBnoI4e2/vLXQ== - dependencies: - globalthis "^1.0.1" - -native-fetch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-3.0.0.tgz#06ccdd70e79e171c365c75117959cf4fe14a09bb" - integrity sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -needle@^2.2.1: - version "2.9.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" - integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== +ndjson@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ndjson/-/ndjson-2.0.0.tgz#320ac86f6fe53f5681897349b86ac6f43bfa3a19" + integrity sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ== dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + json-stringify-safe "^5.0.1" + minimist "^1.2.5" + readable-stream "^3.6.0" + split2 "^3.0.0" + through2 "^4.0.0" -neo-async@^2.6.0: +neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -no-case@^2.2.0, no-case@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" - integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== - dependencies: - lower-case "^1.1.1" - node-addon-api@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-emoji@^1.10.0, node-emoji@^1.4.1: +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + +node-emoji@^1.10.0: version "1.11.0" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A== dependencies: lodash "^4.17.21" -node-fetch@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.4.1.tgz#b2e38f1117b8acbedbe0524f041fb3177188255d" - integrity sha512-P9UbpFK87NyqBZzUuDBDz4f6Yiys8xm8j7ACDbi6usvFm6KItklQUKjeoqTrYS/S1k6I8oaOC2YLLDr/gg26Mw== - -node-fetch@2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== - -node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-forge@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" - integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== - -node-gyp-build@4.3.0, node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" - integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== - -node-gyp-build@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" - integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== - -node-gyp-build@~3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.8.0.tgz#0f57efeb1971f404dfcbfab975c284de7c70f14a" - integrity sha512-bYbpIHyRqZ7sVWXxGpz8QIRug5JZc/hzZH4GbdT9HTZi6WmKCZ8GLvP8OZ9TTiIBvwPFKgtGrlWQSXDAvYdsPw== - -node-gyp-build@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" - integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== - -node-interval-tree@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/node-interval-tree/-/node-interval-tree-1.3.3.tgz#15ffb904cde08270214acace8dc7653e89ae32b7" - integrity sha512-K9vk96HdTK5fEipJwxSvIIqwTqr4e3HRJeJrNxBSeVMNSC/JWARRaX7etOLOuTmrRMeOI/K5TCJu3aWIwZiNTw== - dependencies: - shallowequal "^1.0.2" - -node-pre-gyp@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" - integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -node-releases@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" - integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== - -node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== +node-gyp-build@^4.2.0: + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== -nofilter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e" - integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA== - -noop-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/noop-fn/-/noop-fn-1.0.0.tgz#5f33d47f13d2150df93e0cb036699e982f78ffbf" - integrity sha1-XzPUfxPSFQ35PgywNmmemC94/78= +nofilter@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.1.0.tgz#c757ba68801d41ff930ba2ec55bab52ca184aa66" + integrity sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g== nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + integrity sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg== dependencies: abbrev "1" -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - -npm-bundled@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" - integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== - dependencies: - npm-normalize-package-bin "^1.0.1" - -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-packlist@^1.1.6: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-normalize-package-bin "^1.0.1" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -nth-check@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= +normalize-url@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" + integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== number-to-bn@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== dependencies: bn.js "4.11.6" strip-hex-prefix "1.0.0" -"nwmatcher@>= 1.3.7 < 2.0.0": - version "1.4.4" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" - integrity sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +object-inspect@^1.13.3: + version "1.13.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a" + integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== -object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - -object-inspect@^1.12.2: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw== - -object.assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" + call-bind "^1.0.5" + define-properties "^1.2.1" has-symbols "^1.0.3" object-keys "^1.1.1" -object.values@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -oboe@2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.5.tgz#5554284c543a2266d7a38f17e073821fbde393cd" - integrity sha1-VVQoTFQ6ImbXo48X4HOCH73jk80= +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - http-https "^1.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= +object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - ee-first "1.1.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +obliterator@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" + integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== -once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@1.x, once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -opencollective-postinstall@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== - -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -8427,94 +3898,45 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" word-wrap "~1.2.3" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" - -ora@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" - integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== - dependencies: - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-spinners "^2.0.0" - log-symbols "^2.2.0" - strip-ansi "^5.2.0" - wcwidth "^1.0.1" + word-wrap "^1.2.5" -original-require@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/original-require/-/original-require-1.0.1.tgz#0f130471584cd33511c5ec38c8d59213f9ac5e20" - integrity sha1-DxMEcVhM0zURxew4yNWSE/msXiA= - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= +ordinal@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" + integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-defer@^3.0.0: +ox@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.1.2.tgz#0f791be2ccabeaf4928e6d423498fe1c8094e560" + integrity sha512-ak/8K0Rtphg9vnRJlbOdaX9R7cmxD2MiSthjWGaQdMk3D7hrAlDoM+6Lxn7hN52Za3vrXfZ7enfke/5WjolDww== + dependencies: + "@adraffy/ens-normalize" "^1.10.1" + "@noble/curves" "^1.6.0" + "@noble/hashes" "^1.5.0" + "@scure/bip32" "^1.5.0" + "@scure/bip39" "^1.4.0" + abitype "^1.0.6" + eventemitter3 "5.0.1" + +p-cancelable@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83" - integrity sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw== - -p-fifo@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-fifo/-/p-fifo-1.0.0.tgz#e29d5cf17c239ba87f51dde98c1d26a9cfe20a63" - integrity sha512-IjoCxXW48tqdtDFz6fqo5q1UfFVjjVZe8TC1QRflvNUJtNfCUhxOUw6MOVZhDPjqhSzc26xKdugsO17gmzd5+A== - dependencies: - fast-fifo "^1.0.0" - p-defer "^3.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== p-limit@^3.0.2: version "3.1.0" @@ -8523,27 +3945,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -8551,36 +3952,27 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + aggregate-error "^3.0.0" -param-case@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" - integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= - dependencies: - no-case "^2.2.0" +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== -paramap-it@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/paramap-it/-/paramap-it-0.1.1.tgz#dad5963c003315c0993b84402a9c08f8c36e80d9" - integrity sha512-3uZmCAN3xCw7Am/4ikGzjjR59aNMJVXGSU7CjG2Z6DfOAdhnLdCOd0S0m1sTkN4ov9QhlE3/jkzyu953hq0uwQ== +package-json@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-8.1.1.tgz#3e9948e43df40d1e8e78a85485f1070bf8f03dc8" + integrity sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA== dependencies: - event-iterator "^1.0.0" + got "^12.1.0" + registry-auth-token "^5.0.1" + registry-url "^6.0.0" + semver "^7.3.7" parent-module@^1.0.0: version "1.0.1" @@ -8589,489 +3981,99 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-duration@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/parse-duration/-/parse-duration-0.4.4.tgz#11c0f51a689e97d06c57bd772f7fda7dc013243c" - integrity sha512-KbAJuYGUhZkB9gotDiKLnZ7Z3VTacK3fgwmDdB6ZVDtJbMBT6MfLga0WJaYpPDu0mzqT0NgHtHDt5PY4l0nidg== - -parse-headers@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" - integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: + "@babel/code-frame" "^7.0.0" error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse5@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" - integrity sha1-m387DeMr543CQBsXVzzK8Pb1nZQ= - -parse5@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" - integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA== - dependencies: - "@types/node" "*" - -parseurl@^1.3.3, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascal-case@^2.0.0, pascal-case@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e" - integrity sha1-LVeNNFX2YNpl7KGO+VtODekSdh4= - dependencies: - camel-case "^3.0.0" - upper-case-first "^1.1.0" - -path-case@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5" - integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU= - dependencies: - no-case "^2.2.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== - -path-is-network-drive@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/path-is-network-drive/-/path-is-network-drive-1.0.13.tgz#c9aa0183eb72c328aa83f43def93ddcb9d7ec4d4" - integrity sha512-Hg74mRN6mmXV+gTm3INjFK40ncAmC/Lo4qoQaSZ+GT3hZzlKdWQSqAjqyPeW0SvObP2W073WyYEBWY9d3wOm3A== - dependencies: - tslib "^2.3.1" - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-strip-sep@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/path-strip-sep/-/path-strip-sep-1.0.10.tgz#2be4e789406b298af8709ff79af716134b733b98" - integrity sha512-JpCy+8LAJQQTO1bQsb/84s1g+/Stm3h39aOpPRBQ/paMUGVPPZChLTOTKHoaCkc/6sKuF7yVsnq5Pe1S6xQGcA== - dependencies: - tslib "^2.3.1" - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -peer-id@^0.14.1: - version "0.14.8" - resolved "https://registry.yarnpkg.com/peer-id/-/peer-id-0.14.8.tgz#667c6bedc8ab313c81376f6aca0baa2140266fab" - integrity sha512-GpuLpob/9FrEFvyZrKKsISEkaBYsON2u0WtiawLHj1ii6ewkoeRiSDFLyIefYhw0jGvQoeoZS05jaT52X7Bvig== - dependencies: - cids "^1.1.5" - class-is "^1.1.0" - libp2p-crypto "^0.19.0" - minimist "^1.2.5" - multihashes "^4.0.2" - protobufjs "^6.10.2" - uint8arrays "^2.0.5" - -pem-jwk@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pem-jwk/-/pem-jwk-2.0.0.tgz#1c5bb264612fc391340907f5c1de60c06d22f085" - integrity sha512-rFxu7rVoHgQ5H9YsP50dDWf0rHjreVA2z0yPiWr5WdH/UHb29hKtF7h6l8vNd1cbYR1t0QL+JKhW55a2ZV4KtA== - dependencies: - asn1.js "^5.0.1" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - -"pkg-dir@< 6 >= 5": - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.0.0" - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -pluralize@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" - integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== - -pouchdb-abstract-mapreduce@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-7.2.2.tgz#dd1b10a83f8d24361dce9aaaab054614b39f766f" - integrity sha512-7HWN/2yV2JkwMnGnlp84lGvFtnm0Q55NiBUdbBcaT810+clCGKvhssBCrXnmwShD1SXTwT83aszsgiSfW+SnBA== - dependencies: - pouchdb-binary-utils "7.2.2" - pouchdb-collate "7.2.2" - pouchdb-collections "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-fetch "7.2.2" - pouchdb-mapreduce-utils "7.2.2" - pouchdb-md5 "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-adapter-leveldb-core@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-adapter-leveldb-core/-/pouchdb-adapter-leveldb-core-7.2.2.tgz#e0aa6a476e2607d7ae89f4a803c9fba6e6d05a8a" - integrity sha512-K9UGf1Ivwe87mjrMqN+1D07tO/DfU7ariVDrGffuOjvl+3BcvUF25IWrxsBObd4iPOYCH7NVQWRpojhBgxULtQ== - dependencies: - argsarray "0.0.1" - buffer-from "1.1.1" - double-ended-queue "2.1.0-0" - levelup "4.4.0" - pouchdb-adapter-utils "7.2.2" - pouchdb-binary-utils "7.2.2" - pouchdb-collections "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-json "7.2.2" - pouchdb-md5 "7.2.2" - pouchdb-merge "7.2.2" - pouchdb-utils "7.2.2" - sublevel-pouchdb "7.2.2" - through2 "3.0.2" - -pouchdb-adapter-memory@^7.1.1: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-adapter-memory/-/pouchdb-adapter-memory-7.2.2.tgz#c0ec2e87928d516ca9d1b5badc7269df6f95e5ea" - integrity sha512-9o+zdItPEq7rIrxdkUxgsLNaZkDJAGEqqoYgeYdrHidOCZnlhxhX3g7/R/HcpDKC513iEPqJWDJQSfeT6nVKkw== - dependencies: - memdown "1.4.1" - pouchdb-adapter-leveldb-core "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-adapter-node-websql@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-adapter-node-websql/-/pouchdb-adapter-node-websql-7.0.0.tgz#64ad88dd45b23578e454bf3032a3a79f9d1e4008" - integrity sha512-fNaOMO8bvMrRTSfmH4RSLSpgnKahRcCA7Z0jg732PwRbGvvMdGbreZwvKPPD1fg2tm2ZwwiXWK2G3+oXyoqZYw== - dependencies: - pouchdb-adapter-websql-core "7.0.0" - pouchdb-utils "7.0.0" - websql "1.0.0" - -pouchdb-adapter-utils@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-adapter-utils/-/pouchdb-adapter-utils-7.0.0.tgz#1ac8d34481911e0e9a9bf51024610a2e7351dc80" - integrity sha512-UWKPC6jkz6mHUzZefrU7P5X8ZGvBC8LSNZ7BIp0hWvJE6c20cnpDwedTVDpZORcCbVJpDmFOHBYnOqEIblPtbA== - dependencies: - pouchdb-binary-utils "7.0.0" - pouchdb-collections "7.0.0" - pouchdb-errors "7.0.0" - pouchdb-md5 "7.0.0" - pouchdb-merge "7.0.0" - pouchdb-utils "7.0.0" - -pouchdb-adapter-utils@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-adapter-utils/-/pouchdb-adapter-utils-7.2.2.tgz#c64426447d9044ba31517a18500d6d2d28abd47d" - integrity sha512-2CzZkTyTyHZkr3ePiWFMTiD5+56lnembMjaTl8ohwegM0+hYhRyJux0biAZafVxgIL4gnCUC4w2xf6WVztzKdg== - dependencies: - pouchdb-binary-utils "7.2.2" - pouchdb-collections "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-md5 "7.2.2" - pouchdb-merge "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-adapter-websql-core@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-adapter-websql-core/-/pouchdb-adapter-websql-core-7.0.0.tgz#27b3e404159538e515b2567baa7869f90caac16c" - integrity sha512-NyMaH0bl20SdJdOCzd+fwXo8JZ15a48/MAwMcIbXzsRHE4DjFNlRcWAcjUP6uN4Ezc+Gx+r2tkBBMf71mIz1Aw== - dependencies: - pouchdb-adapter-utils "7.0.0" - pouchdb-binary-utils "7.0.0" - pouchdb-collections "7.0.0" - pouchdb-errors "7.0.0" - pouchdb-json "7.0.0" - pouchdb-merge "7.0.0" - pouchdb-utils "7.0.0" - -pouchdb-binary-utils@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-7.0.0.tgz#cb71a288b09572a231f6bab1b4aed201c4d219a7" - integrity sha512-yUktdOPIPvOVouCjJN3uop+bCcpdPwePrLm9eUAZNgEYnUFu0njdx7Q0WRsZ7UJ6l75HinL5ZHk4bnvEt86FLw== - dependencies: - buffer-from "1.1.0" - -pouchdb-binary-utils@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-7.2.2.tgz#0690b348052c543b1e67f032f47092ca82bcb10e" - integrity sha512-shacxlmyHbUrNfE6FGYpfyAJx7Q0m91lDdEAaPoKZM3SzAmbtB1i+OaDNtYFztXjJl16yeudkDb3xOeokVL3Qw== - dependencies: - buffer-from "1.1.1" - -pouchdb-collate@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-7.2.2.tgz#fc261f5ef837c437e3445fb0abc3f125d982c37c" - integrity sha512-/SMY9GGasslknivWlCVwXMRMnQ8myKHs4WryQ5535nq1Wj/ehpqWloMwxEQGvZE1Sda3LOm7/5HwLTcB8Our+w== - -pouchdb-collections@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-7.0.0.tgz#fd1f632337dc6301b0ff8649732ca79204e41780" - integrity sha512-DaoUr/vU24Q3gM6ghj0va9j/oBanPwkbhkvnqSyC3Dm5dgf5pculNxueLF9PKMo3ycApoWzHMh6N2N8KJbDU2Q== + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" -pouchdb-collections@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-7.2.2.tgz#aeed77f33322429e3f59d59ea233b48ff0e68572" - integrity sha512-6O9zyAYlp3UdtfneiMYuOCWdUCQNo2bgdjvNsMSacQX+3g8WvIoFQCYJjZZCpTttQGb+MHeRMr8m2U95lhJTew== +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -pouchdb-debug@^7.1.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/pouchdb-debug/-/pouchdb-debug-7.2.1.tgz#f5f869f6113c12ccb97cddf5b0a32b6e0e67e961" - integrity sha512-eP3ht/AKavLF2RjTzBM6S9gaI2/apcW6xvaKRQhEdOfiANqerFuksFqHCal3aikVQuDO+cB/cw+a4RyJn/glBw== - dependencies: - debug "3.1.0" +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -pouchdb-errors@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-7.0.0.tgz#4e2a5a8b82af20cbe5f9970ca90b7ec74563caa0" - integrity sha512-dTusY8nnTw4HIztCrNl7AoGgwvS1bVf/3/97hDaGc4ytn72V9/4dK8kTqlimi3UpaurohYRnqac0SGXYP8vgXA== - dependencies: - inherits "2.0.3" +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -pouchdb-errors@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-7.2.2.tgz#80d811d65c766c9d20b755c6e6cc123f8c3c4792" - integrity sha512-6GQsiWc+7uPfgEHeavG+7wuzH3JZW29Dnrvz8eVbDFE50kVFxNDVm3EkYHskvo5isG7/IkOx7PV7RPTA3keG3g== - dependencies: - inherits "2.0.4" +path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -pouchdb-fetch@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-fetch/-/pouchdb-fetch-7.2.2.tgz#492791236d60c899d7e9973f9aca0d7b9cc02230" - integrity sha512-lUHmaG6U3zjdMkh8Vob9GvEiRGwJfXKE02aZfjiVQgew+9SLkuOxNw3y2q4d1B6mBd273y1k2Lm0IAziRNxQnA== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - abort-controller "3.0.0" - fetch-cookie "0.10.1" - node-fetch "2.6.0" + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -pouchdb-find@^7.0.0: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-find/-/pouchdb-find-7.2.2.tgz#1227afdd761812d508fe0794b3e904518a721089" - integrity sha512-BmFeFVQ0kHmDehvJxNZl9OmIztCjPlZlVSdpijuFbk/Fi1EFPU1BAv3kLC+6DhZuOqU/BCoaUBY9sn66pPY2ag== - dependencies: - pouchdb-abstract-mapreduce "7.2.2" - pouchdb-collate "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-fetch "7.2.2" - pouchdb-md5 "7.2.2" - pouchdb-selector-core "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-json@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-json/-/pouchdb-json-7.0.0.tgz#d9860f66f27a359ac6e4b24da4f89b6909f37530" - integrity sha512-w0bNRu/7VmmCrFWMYAm62n30wvJJUT2SokyzeTyj3hRohj4GFwTRg1mSZ+iAmxgRKOFE8nzZstLG/WAB4Ymjew== - dependencies: - vuvuzela "1.0.3" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pouchdb-json@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-json/-/pouchdb-json-7.2.2.tgz#b939be24b91a7322e9a24b8880a6e21514ec5e1f" - integrity sha512-3b2S2ynN+aoB7aCNyDZc/4c0IAdx/ir3nsHB+/RrKE9cM3QkQYbnnE3r/RvOD1Xvr6ji/KOCBie+Pz/6sxoaug== - dependencies: - vuvuzela "1.0.3" +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -pouchdb-mapreduce-utils@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-7.2.2.tgz#13a46a3cc2a3f3b8e24861da26966904f2963146" - integrity sha512-rAllb73hIkU8rU2LJNbzlcj91KuulpwQu804/F6xF3fhZKC/4JQMClahk+N/+VATkpmLxp1zWmvmgdlwVU4HtQ== +pbkdf2@^3.0.17: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== dependencies: - argsarray "0.0.1" - inherits "2.0.4" - pouchdb-collections "7.2.2" - pouchdb-utils "7.2.2" + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" -pouchdb-md5@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-7.0.0.tgz#935dc6bb507a5f3978fb653ca5790331bae67c96" - integrity sha512-yaSJKhLA3QlgloKUQeb2hLdT3KmUmPfoYdryfwHZuPTpXIRKTnMQTR9qCIRUszc0ruBpDe53DRslCgNUhAyTNQ== - dependencies: - pouchdb-binary-utils "7.0.0" - spark-md5 "3.0.0" +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -pouchdb-md5@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-7.2.2.tgz#415401acc5a844112d765bd1fb4e5d9f38fb0838" - integrity sha512-c/RvLp2oSh8PLAWU5vFBnp6ejJABIdKqboZwRRUrWcfGDf+oyX8RgmJFlYlzMMOh4XQLUT1IoaDV8cwlsuryZw== - dependencies: - pouchdb-binary-utils "7.2.2" - spark-md5 "3.0.1" +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pouchdb-merge@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-7.0.0.tgz#9f476ce7e32aae56904ad770ae8a1dfe14b57547" - integrity sha512-tci5u6NpznQhGcPv4ho1h0miky9rs+ds/T9zQ9meQeDZbUojXNaX1Jxsb0uYEQQ+HMqdcQs3Akdl0/u0mgwPGg== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -pouchdb-merge@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-7.2.2.tgz#940d85a2b532d6a93a6cab4b250f5648511bcc16" - integrity sha512-6yzKJfjIchBaS7Tusuk8280WJdESzFfQ0sb4jeMUNnrqs4Cx3b0DIEOYTRRD9EJDM+je7D3AZZ4AT0tFw8gb4A== +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pouchdb-selector-core@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-7.2.2.tgz#264d7436a8c8ac3801f39960e79875ef7f3879a0" - integrity sha512-XYKCNv9oiNmSXV5+CgR9pkEkTFqxQGWplnVhO3W9P154H08lU0ZoNH02+uf+NjZ2kjse7Q1fxV4r401LEcGMMg== - dependencies: - pouchdb-collate "7.2.2" - pouchdb-utils "7.2.2" +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== -pouchdb-utils@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-7.0.0.tgz#48bfced6665b8f5a2b2d2317e2aa57635ed1e88e" - integrity sha512-1bnoX1KdZYHv9wicDIFdO0PLiVIMzNDUBUZ/yOJZ+6LW6niQCB8aCv09ZztmKfSQcU5nnN3fe656tScBgP6dOQ== - dependencies: - argsarray "0.0.1" - clone-buffer "1.0.0" - immediate "3.0.6" - inherits "2.0.3" - pouchdb-collections "7.0.0" - pouchdb-errors "7.0.0" - pouchdb-md5 "7.0.0" - uuid "3.2.1" - -pouchdb-utils@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-7.2.2.tgz#c17c4788f1d052b0daf4ef8797bbc4aaa3945aa4" - integrity sha512-XmeM5ioB4KCfyB2MGZXu1Bb2xkElNwF1qG+zVFbQsKQij0zvepdOUfGuWvLRHxTOmt4muIuSOmWZObZa3NOgzQ== - dependencies: - argsarray "0.0.1" - clone-buffer "1.0.0" - immediate "3.3.0" - inherits "2.0.4" - pouchdb-collections "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-md5 "7.2.2" - uuid "8.1.0" +pony-cause@^2.1.10: + version "2.1.11" + resolved "https://registry.yarnpkg.com/pony-cause/-/pony-cause-2.1.11.tgz#d69a20aaccdb3bdb8f74dd59e5c68d8e6772e4bd" + integrity sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg== -pouchdb@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-7.1.1.tgz#f5f8dcd1fc440fb76651cb26f6fc5d97a39cd6ce" - integrity sha512-8bXWclixNJZqokvxGHRsG19zehSJiaZaz4dVYlhXhhUctz7gMcNTElHjPBzBdZlKKvt9aFDndmXN1VVE53Co8g== - dependencies: - argsarray "0.0.1" - buffer-from "1.1.0" - clone-buffer "1.0.0" - double-ended-queue "2.1.0-0" - fetch-cookie "0.7.0" - immediate "3.0.6" - inherits "2.0.3" - level "5.0.1" - level-codec "9.0.1" - level-write-stream "1.0.0" - leveldown "5.0.2" - levelup "4.0.2" - ltgt "2.2.1" - node-fetch "2.4.1" - readable-stream "1.0.33" - spark-md5 "3.0.0" - through2 "3.0.1" - uuid "3.2.1" - vuvuzela "1.0.3" - -precond@0.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" - integrity sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ== +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== prelude-ls@^1.2.1: version "1.2.1" @@ -9081,226 +4083,69 @@ prelude-ls@^1.2.1: prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== prettier@2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.1.tgz#4e1fd11c34e2421bc1da9aea9bd8127cd0a35efc" integrity sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg== -prettier@^1.14.3: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -prettier@^2.1.2: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== - -printj@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" - integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -promise-to-callback@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" - integrity sha512-uhMIZmKM5ZteDMfLgJnoSq9GCwsNKrYau73Awf1jIy6/eUcuuZ3P+CD9zUv0kJsIUbU+x6uLNIhXhLHDs1pNPA== - dependencies: - is-fn "^1.0.0" - set-immediate-shim "^1.0.1" - -promise.allsettled@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.2.tgz#d66f78fbb600e83e863d893e98b3d4376a9c47c9" - integrity sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg== - dependencies: - array.prototype.map "^1.0.1" - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - iterate-value "^1.0.0" - -promise@^8.0.2: - version "8.1.0" - resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" - integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q== - dependencies: - asap "~2.0.6" - -protobufjs@^6.10.2, protobufjs@^6.11.2: - version "6.11.2" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b" - integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^4.0.0" - -protocol-buffers-schema@^3.3.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03" - integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw== - -protons@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/protons/-/protons-2.0.3.tgz#94f45484d04b66dfedc43ad3abff1e8907994bb2" - integrity sha512-j6JikP/H7gNybNinZhAHMN07Vjr1i4lVupg598l4I9gSTjJqOvKnwjzYX2PzvBTSVf2eZ2nWv4vG+mtW8L6tpA== - dependencies: - protocol-buffers-schema "^3.3.1" - signed-varint "^2.0.1" - uint8arrays "^3.0.0" - varint "^5.0.0" - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -psl@^1.1.28, psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" +prettier@^2.8.3: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== +prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - integrity sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -pure-rand@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-5.0.0.tgz#87f5bdabeadbd8904e316913a5c0b8caac517b37" - integrity sha512-lD2/y78q+7HqBx2SaT6OT4UcwtvXNRfEpzYEzl0EQ+9gZq2Qi3fa0HDnYPeqQwhlHJFBUhT7AO3mLU3+8bynHA== - -qs@6.9.7: - version "6.9.7" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" - integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== + kleur "^3.0.3" + sisteransi "^1.0.5" -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -querystring@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -queue-microtask@^1.2.2, queue-microtask@^1.2.3: +queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" - integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g== +raw-body@^2.4.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" - http-errors "1.8.1" + http-errors "2.0.0" iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.7: +rc@1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -9310,256 +4155,103 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@1.0.33: - version "1.0.33" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.33.tgz#3a360dd66c1b1d7fd4705389860eda1d0f61126c" - integrity sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@1.1: - version "1.1.13" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" - integrity sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@1.1.14, readable-stream@^1.0.33: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -"readable-stream@2 || 3", readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.2.9: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@~0.0.2: - version "0.0.4" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-0.0.4.tgz#f32d76e3fb863344a548d79923007173665b3b8d" - integrity sha1-8y124/uGM0SlSNeZIwBxc2ZbO40= - -readable-stream@~1.0.15: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readdirp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" - integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== - dependencies: - picomatch "^2.2.1" +readdirp@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" + integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA== -receptacle@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/receptacle/-/receptacle-1.3.2.tgz#a7994c7efafc7a01d0e2041839dab6c4951360d2" - integrity sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A== +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: - ms "^2.1.1" + picomatch "^2.2.1" rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== dependencies: resolve "^1.1.6" recursive-readdir@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" - integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== - dependencies: - minimatch "3.0.4" - -redeyed@~2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" - integrity sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs= - dependencies: - esprima "~4.0.0" - -reduce-flatten@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" - integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== - -redux-saga@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-1.0.0.tgz#acb8b3ed9180fecbe75f342011d75af3ac11045b" - integrity sha512-GvJWs/SzMvEQgeaw6sRMXnS2FghlvEGsHiEtTLpJqc/FHF3I5EE/B+Hq5lyHZ8LSoT2r/X/46uWvkdCnK9WgHA== - dependencies: - "@redux-saga/core" "^1.0.0" - -redux@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b" - integrity sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A== - dependencies: - lodash "^4.2.1" - lodash-es "^4.2.1" - loose-envify "^1.1.0" - symbol-observable "^1.0.3" - -redux@^4.0.4: - version "4.1.2" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" - integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== + version "2.2.3" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372" + integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== dependencies: - "@babel/runtime" "^7.9.2" - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + minimatch "^3.0.5" -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== +reflect.getprototypeof@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz#c58afb17a4007b4d1118c07b92c23fca422c5d82" + integrity sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + dunder-proto "^1.0.0" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + gopd "^1.2.0" + which-builtin-type "^1.2.0" + +regexp.prototype.flags@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" + integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.2" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0, regexpp@^3.2.0: +regexpp@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= +registry-auth-token@^5.0.1: + version "5.0.3" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-5.0.3.tgz#417d758c8164569de8cf5cabff16cc937902dcc6" + integrity sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA== dependencies: - is-finite "^1.0.0" + "@pnpm/npm-conf" "^2.1.0" -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise@^4.2.2: - version "4.2.6" - resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.6.tgz#7e7e5b9578630e6f598e3813c0f8eb342a27f0a2" - integrity sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ== - dependencies: - bluebird "^3.5.0" - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.55.0, request@^2.79.0, request@^2.85.0, request@^2.88.0, request@^2.88.2: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" +registry-url@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-6.0.1.tgz#056d9343680f2f64400032b1e199faa692286c58" + integrity sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q== + dependencies: + rc "1.2.8" + +repeat-string@^1.0.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -reselect-tree@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/reselect-tree/-/reselect-tree-1.3.5.tgz#9ff58ad76f2e64584947f1d1b3285e037a448c23" - integrity sha512-h/iXrz7wGBidwMmNFu5L1z0sDvqU6SAdJ2TKr5IIsyGKeyXQchi0gXbfbIJJfGWD8VGcDYjzGAbhy1KaGD4FWQ== - dependencies: - debug "^3.1.0" - esdoc "^1.0.4" - json-pointer "^0.6.1" - reselect "^4.0.0" - source-map-support "^0.5.3" - -reselect@^4.0.0: - version "4.1.5" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" - integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== - -reset@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/reset/-/reset-0.1.0.tgz#9fc7314171995ae6cb0b7e58b06ce7522af4bafb" - integrity sha1-n8cxQXGZWubLC35YsGznUir0uvs= - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== +resolve-alpn@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== resolve-from@^4.0.0: version "4.0.0" @@ -9569,78 +4261,36 @@ resolve-from@^4.0.0: resolve@1.1.x: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== -resolve@^1.1.6, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== +resolve@1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" + path-parse "^1.0.6" -resolve@^1.14.2, resolve@^1.22.0, resolve@^1.22.1: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== +resolve@^1.1.6, resolve@^1.22.1, resolve@^1.22.4: + version "1.22.9" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.9.tgz#6da76e4cdc57181fa4471231400e8851d0a924f3" + integrity sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.16.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -retimer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/retimer/-/retimer-2.0.0.tgz#e8bd68c5e5a8ec2f49ccb5c636db84c04063bbca" - integrity sha512-KLXY85WkEq2V2bKex/LOO1ViXVn2KGYe4PYysAdYdjmraYIUsVkXu8O4am+8+5UbaaGl1qho4aqAAPHNQ4GSbg== - -retry@0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + lowercase-keys "^3.0.0" reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^2.6.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -9656,79 +4306,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4: +rlp@^2.2.3, rlp@^2.2.4: version "2.2.7" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== dependencies: bn.js "^5.2.0" -rollup-plugin-inject@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz#e4233855bfba6c0c12a312fd6649dff9a13ee9f4" - integrity sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w== - dependencies: - estree-walker "^0.6.1" - magic-string "^0.25.3" - rollup-pluginutils "^2.8.1" - -rollup-plugin-node-polyfills@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz#53092a2744837164d5b8a28812ba5f3ff61109fd" - integrity sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA== - dependencies: - rollup-plugin-inject "^3.0.0" - -rollup-plugin-peer-deps-external@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.4.tgz#8a420bbfd6dccc30aeb68c9bf57011f2f109570d" - integrity sha512-AWdukIM1+k5JDdAqV/Cxd+nejvno2FVLVeZ74NKggm3Q5s9cbbcOgUPGdbxPi4BXu7xGaZ8HG12F+thImYu/0g== - -rollup-plugin-typescript2@^0.31.2: - version "0.31.2" - resolved "https://registry.yarnpkg.com/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.31.2.tgz#463aa713a7e2bf85b92860094b9f7fb274c5a4d8" - integrity sha512-hRwEYR1C8xDGVVMFJQdEVnNAeWRvpaY97g5mp3IeLnzhNXzSVq78Ye/BJ9PAaUfN4DXa/uDnqerifMOaMFY54Q== - dependencies: - "@rollup/pluginutils" "^4.1.2" - "@yarn-tool/resolve-package" "^1.0.40" - find-cache-dir "^3.3.2" - fs-extra "^10.0.0" - resolve "^1.20.0" - tslib "^2.3.1" - -rollup-pluginutils@^2.8.1: - version "2.8.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" - integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== - dependencies: - estree-walker "^0.6.1" - -rollup@^2.67.2: - version "2.70.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.1.tgz#824b1f1f879ea396db30b0fc3ae8d2fead93523e" - integrity sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA== - optionalDependencies: - fsevents "~2.3.2" - -rpc-websockets@^7.4.17: - version "7.4.17" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.4.17.tgz#f38845dd96db0442bff9e15fba9df781beb44cc0" - integrity sha512-eolVi/qlXS13viIUH9aqrde902wzSLAai0IjmOZSRefp5I3CSG/vCnD0c0fDSYCWuEyUoRL1BHQA8K1baEUyow== - dependencies: - "@babel/runtime" "^7.11.2" - circular-json "^0.5.9" - eventemitter3 "^4.0.7" - uuid "^8.3.0" - ws "^7.4.5" - optionalDependencies: - bufferutil "^4.0.1" - utf-8-validate "^5.0.2" - -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -9736,68 +4320,36 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -run@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/run/-/run-1.4.0.tgz#e17d9e9043ab2fe17776cb299e1237f38f0b4ffa" - integrity sha1-4X2ekEOrL+F3dsspnhI3848LT/o= - dependencies: - minimatch "*" - -rustbn.js@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== - -rxjs@6, rxjs@^6.4.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -rxjs@^7.0.0: - version "7.5.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39" - integrity sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA== +safe-array-concat@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== dependencies: - tslib "^2.1.0" + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-event-emitter@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" - integrity sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg== - dependencies: - events "^3.0.0" - -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== +safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.1.4, sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - sc-istanbul@^0.4.5: version "0.4.6" resolved "https://registry.yarnpkg.com/sc-istanbul/-/sc-istanbul-0.4.6.tgz#cf6784355ff2076f92d70d59047d71c13703e839" @@ -9818,159 +4370,75 @@ sc-istanbul@^0.4.5: which "^1.1.1" wordwrap "^1.0.0" -scrypt-async@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/scrypt-async/-/scrypt-async-2.0.1.tgz#4318dae48a8b7cc3b8fe05f75f4164a7d973d25d" - integrity sha512-wHR032jldwZNy7Tzrfu7RccOgGf8r5hyDMSP2uV6DpLiBUsR8JsDcx/in73o2UGVVrH5ivRFdNsFPcjtl3LErQ== - -scrypt-js@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" - integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw== - -scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: +scrypt-js@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== -secp256k1@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.2.tgz#15dd57d0f0b9fdb54ac1fa1694f40e5e9a54f4a1" - integrity sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg== - dependencies: - elliptic "^6.5.2" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -secp256k1@4.0.3, secp256k1@^4.0.0, secp256k1@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== +secp256k1@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.4.tgz#58f0bfe1830fe777d9ca1ffc7574962a8189f8ab" + integrity sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw== dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" + elliptic "^6.5.7" + node-addon-api "^5.0.0" node-gyp-build "^4.2.0" -seedrandom@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" - integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== - -semaphore@>=1.0.1, semaphore@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== +semver@^5.5.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^5.3.0, semver@^5.5.0, semver@^5.5.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.0.0, semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - -semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -semver@~5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== - -send@0.17.2: - version "0.17.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" - integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "1.8.1" - mime "1.6.0" - ms "2.1.3" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -sentence-case@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-2.1.1.tgz#1f6e2dda39c168bf92d13f86d4a918933f667ed4" - integrity sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ= - dependencies: - no-case "^2.2.0" - upper-case-first "^1.1.2" +semver@^7.0.0, semver@^7.3.4, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -serialize-javascript@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: randombytes "^2.1.0" -serve-static@1.14.2: - version "1.14.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" - integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.2" + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" -servify@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" - integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: - body-parser "^1.16.0" - cors "^2.8.1" - express "^4.14.0" - request "^2.79.0" - xhr "^2.3.3" - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ== - -setimmediate@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" - integrity sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48= + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: +sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== @@ -9978,17 +4446,13 @@ sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shallowequal@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= +sha1@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/sha1/-/sha1-1.1.1.tgz#addaa7a93168f393f19eb2b15091618e2700f848" + integrity sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA== dependencies: - shebang-regex "^1.0.0" + charenc ">= 0.0.1" + crypt ">= 0.0.1" shebang-command@^2.0.0: version "2.0.0" @@ -9997,21 +4461,11 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" - integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== - shelljs@^0.8.3: version "0.8.5" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" @@ -10021,114 +4475,165 @@ shelljs@^0.8.3: interpret "^1.0.0" rechoir "^0.6.2" -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + es-errors "^1.3.0" + object-inspect "^1.13.3" -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -signed-varint@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/signed-varint/-/signed-varint-2.0.1.tgz#50a9989da7c98c2c61dad119bc97470ef8528129" - integrity sha1-UKmYnafJjCxh2tEZvJdHDvhSgSk= +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== dependencies: - varint "~5.0.0" + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" -simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" -simple-get@^2.7.0: - version "2.8.2" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" - integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== dependencies: - decompress-response "^3.3.0" - once "^1.3.1" - simple-concat "^1.0.0" + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" -snake-case@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f" - integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8= +solc@0.8.26: + version "0.8.26" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.26.tgz#afc78078953f6ab3e727c338a2fefcd80dd5b01a" + integrity sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g== dependencies: - no-case "^2.2.0" + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" solhint@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.3.7.tgz#b5da4fedf7a0fee954cb613b6c55a5a2b0063aa7" - integrity sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ== - dependencies: - "@solidity-parser/parser" "^0.14.1" - ajv "^6.6.1" - antlr4 "4.7.1" - ast-parents "0.0.1" - chalk "^2.4.2" - commander "2.18.0" - cosmiconfig "^5.0.7" - eslint "^5.6.0" - fast-diff "^1.1.2" - glob "^7.1.3" - ignore "^4.0.6" - js-yaml "^3.12.0" - lodash "^4.17.11" - semver "^6.3.0" + version "3.6.2" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.2.tgz#2b2acbec8fdc37b2c68206a71ba89c7f519943fe" + integrity sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ== + dependencies: + "@solidity-parser/parser" "^0.16.0" + ajv "^6.12.6" + antlr4 "^4.11.0" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + +solhint@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-5.0.3.tgz#b57f6d2534fe09a60f9db1b92e834363edd1cbde" + integrity sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ== + dependencies: + "@solidity-parser/parser" "^0.18.0" + ajv "^6.12.6" + antlr4 "^4.13.1-patch-1" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + latest-version "^7.0.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" optionalDependencies: - prettier "^1.14.3" + prettier "^2.8.3" -solidity-coverage@^0.7.20: - version "0.7.20" - resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.7.20.tgz#246e9b0dd62f698bb8ddeecdcc46cab26c48b637" - integrity sha512-edOXTugUYdqxrtEnIn4vgrGjLPxdexcL0WD8LzAvVA3d1dwgcfRO3k8xQR02ZQnOnWMBi8Cqs0F+kAQQp3JW8g== +solidity-coverage@^0.8.0: + version "0.8.14" + resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.14.tgz#db9bfcc10e3bc369fc074b35b267d665bcc6ae2e" + integrity sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA== dependencies: - "@solidity-parser/parser" "^0.14.0" - "@truffle/provider" "^0.2.24" + "@ethersproject/abi" "^5.0.9" + "@solidity-parser/parser" "^0.19.0" chalk "^2.4.2" death "^1.1.0" - detect-port "^1.3.0" + difflib "^0.2.4" fs-extra "^8.1.0" ghost-testrpc "^0.0.2" global-modules "^2.0.0" globby "^10.0.1" jsonschema "^1.2.4" - lodash "^4.17.15" + lodash "^4.17.21" + mocha "^10.2.0" node-emoji "^1.10.0" pify "^4.0.1" recursive-readdir "^2.2.2" sc-istanbul "^0.4.5" semver "^7.3.4" shelljs "^0.8.3" - web3-utils "^1.3.0" + web3-utils "^1.3.6" solmate@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/solmate/-/solmate-6.2.0.tgz#edd29b5f3d6faafafdcf65fe4d1d959b4841cfa8" - integrity sha512-AM38ioQ2P8zRsA42zenb9or6OybRjOLXIu3lhIT8rhddUuduCt76pUEuLxOIg9GByGojGz+EbpFdCB6B+QZVVA== + version "6.8.0" + resolved "https://registry.yarnpkg.com/solmate/-/solmate-6.8.0.tgz#acb665d88783745899e2f6345e3ac66d5b7df2ab" + integrity sha512-/oI8kgEvSxGG1mrFv3FmCEZd0F8Z9VzRmoYMIhzmmzt6mjtPwfdCm3oh8yOL7bMHJBSfXJuMpnMPrM0uyaKsKg== -source-map-support@^0.5.17, source-map-support@^0.5.3: +source-map-support@^0.5.13: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -10136,12 +4641,7 @@ source-map-support@^0.5.17, source-map-support@^0.5.3: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.5.0, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -10149,117 +4649,35 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= + integrity sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA== dependencies: amdefine ">=0.0.4" -sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - -spark-md5@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.0.tgz#3722227c54e2faf24b1dc6d933cc144e6f71bfef" - integrity sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8= - -spark-md5@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.1.tgz#83a0e255734f2ab4e5c466e5a2cfc9ba2aa2124d" - integrity sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig== - -spawn-command@^0.0.2-1: - version "0.0.2-1" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" - integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== - -spinnies@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/spinnies/-/spinnies-0.5.1.tgz#6ac88455d9117c7712d52898a02c969811819a7e" - integrity sha512-WpjSXv9NQz0nU3yCT9TFEOfpFrXADY9C5fG6eAJqixLhvTX1jP3w92Y8IE5oafIe42nlF9otjhllnXN/QCaB3A== +split2@^3.0.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== dependencies: - chalk "^2.4.2" - cli-cursor "^3.0.0" - strip-ansi "^5.2.0" + readable-stream "^3.0.0" sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sqlite3@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-4.2.0.tgz#49026d665e9fc4f922e56fb9711ba5b4c85c4901" - integrity sha512-roEOz41hxui2Q7uYnWsjMOTry6TcNUNmp8audCx18gF10P2NknwdpF+E+HKvz/F2NvPKGGBF4NGc+ZPQ+AABwg== - dependencies: - nan "^2.12.1" - node-pre-gyp "^0.11.0" - -sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -stream-to-it@^0.2.0, stream-to-it@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/stream-to-it/-/stream-to-it-0.2.4.tgz#d2fd7bfbd4a899b4c0d6a7e6a533723af5749bd0" - integrity sha512-4vEbkSs83OahpmBybNJXlJd7d6/RxzkkSdT3I0mnGt79Xd2Kk+e1JqbvAvsQfCeKj3aKb0QIWkyK3/n0j506vQ== - dependencies: - get-iterator "^1.0.2" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-format@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" - integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= +stacktrace-parser@^0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" + type-fest "^0.7.1" -"string-width@^1.0.2 || 2", string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10268,48 +4686,55 @@ string-width@^1.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.trim@^1.2.9: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.8: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1: version "1.3.0" @@ -10318,38 +4743,12 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^4.1.0" + ansi-regex "^5.0.1" strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" @@ -10358,68 +4757,43 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - strip-hex-prefix@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - integrity sha1-DF8VX+8RUTczd96du1iNoFUA428= + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== dependencies: is-hex-prefixed "1.0.0" -strip-json-comments@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" - integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== - -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -sublevel-pouchdb@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/sublevel-pouchdb/-/sublevel-pouchdb-7.2.2.tgz#49e46cd37883bf7ff5006d7c5b9bcc7bcc1f422f" - integrity sha512-y5uYgwKDgXVyPZceTDGWsSFAhpSddY29l9PJbXqMJLfREdPmQTY8InpatohlEfCXX7s1LGcrfYAhxPFZaJOLnQ== - dependencies: - inherits "2.0.4" - level-codec "9.0.2" - ltgt "2.2.1" - readable-stream "1.1.14" - -supports-color@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== supports-color@^3.1.0: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + integrity sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A== dependencies: has-flag "^1.0.0" -supports-color@^5.0.0, supports-color@^5.3.0: +supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -10433,200 +4807,56 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.1.0: +supports-color@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" -supports-hyperlinks@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz#71daedf36cc1060ac5100c351bb3da48c29c0ef7" - integrity sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw== - dependencies: - has-flag "^2.0.0" - supports-color "^5.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -swap-case@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3" - integrity sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM= - dependencies: - lower-case "^1.1.1" - upper-case "^1.1.1" - -swarm-js@^0.1.40: - version "0.1.40" - resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" - integrity sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA== - dependencies: - bluebird "^3.5.0" - buffer "^5.0.5" - eth-lib "^0.1.26" - fs-extra "^4.0.2" - got "^7.1.0" - mime-types "^2.1.16" - mkdirp-promise "^5.0.1" - mock-fs "^4.1.0" - setimmediate "^1.0.5" - tar "^4.0.2" - xhr-request "^1.0.1" - -symbol-observable@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== - -"symbol-tree@>= 3.1.0 < 4.0.0": - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -table-layout@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" - integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== - dependencies: - array-back "^4.0.1" - deep-extend "~0.6.0" - typical "^5.2.0" - wordwrapjs "^4.0.0" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== +table@^6.8.0, table@^6.8.1: + version "6.9.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.9.0.tgz#50040afa6264141c7566b3b81d4d82c47a8668f5" + integrity sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -taffydb@2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.7.3.tgz#2ad37169629498fca5bc84243096d3cde0ec3a34" - integrity sha1-KtNxaWKUmPylvIQkMJbTzeDsOjQ= - -tar@^4, tar@^4.0.2: - version "4.4.19" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" - integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== - dependencies: - chownr "^1.1.4" - fs-minipass "^1.2.7" - minipass "^2.9.0" - minizlib "^1.3.3" - mkdirp "^0.5.5" - safe-buffer "^5.2.1" - yallist "^3.1.1" + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -through2@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" - integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== - dependencies: - readable-stream "2 || 3" - -through2@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" - integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== - dependencies: - inherits "^2.0.4" - readable-stream "2 || 3" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - -timeout-abort-controller@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/timeout-abort-controller/-/timeout-abort-controller-1.1.1.tgz#2c3c3c66f13c783237987673c276cbd7a9762f29" - integrity sha512-BsF9i3NAJag6T0ZEjki9j654zoafI2X6ayuNd6Tp8+Ul6Tr5s4jo973qFeiWrRSweqvskC+AHDKUmIW4b7pdhQ== - dependencies: - abort-controller "^3.0.0" - retimer "^2.0.0" - -tiny-queue@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" - integrity sha1-JaZ/LG4lOyypQZd7XvdELvl6YEY= - -tiny-secp256k1@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz#7e224d2bee8ab8283f284e40e6b4acb74ffe047c" - integrity sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA== +through2@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== dependencies: - bindings "^1.3.0" - bn.js "^4.11.8" - create-hmac "^1.1.7" - elliptic "^6.4.0" - nan "^2.13.2" + readable-stream "3" -title-case@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa" - integrity sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o= +tinyglobby@^0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f" + integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew== dependencies: - no-case "^2.2.0" - upper-case "^1.0.3" + fdir "^6.4.2" + picomatch "^4.0.2" -tmp@^0.0.33: +tmp@0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" -to-data-view@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/to-data-view/-/to-data-view-1.1.0.tgz#08d6492b0b8deb9b29bdf1f61c23eadfa8994d00" - integrity sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ== - -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-json-schema@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/to-json-schema/-/to-json-schema-0.2.5.tgz#ef3c3f11ad64460dcfbdbafd0fd525d69d62a98f" - integrity sha512-jP1ievOee8pec3tV9ncxLSS48Bnw7DIybgy112rhMCEhf3K4uyVNZZHr03iQQBzbV5v5Hos+dlZRRyk6YSMNDw== - dependencies: - lodash.isequal "^4.5.0" - lodash.keys "^4.2.0" - lodash.merge "^4.6.2" - lodash.omit "^4.5.0" - lodash.without "^4.4.0" - lodash.xor "^4.5.0" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -10639,158 +4869,60 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tough-cookie@^2.2.0, tough-cookie@^2.3.1, tough-cookie@^2.3.3, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.1.2" - -tr46@~0.0.1, tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -tree-kill@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - -truffle-assertions@^0.9.2: - version "0.9.2" - resolved "https://registry.yarnpkg.com/truffle-assertions/-/truffle-assertions-0.9.2.tgz#0f8360f53ad92b6d8fdb8ceb5dce54c1fc392e23" - integrity sha512-9g2RhaxU2F8DeWhqoGQvL/bV8QVoSnQ6PY+ZPvYRP5eF7+/8LExb4mjLx/FeliLTjc3Tv1SABG05Gu5qQ/ErmA== - dependencies: - assertion-error "^1.1.0" - lodash.isequal "^4.5.0" - -truffle-plugin-verify@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/truffle-plugin-verify/-/truffle-plugin-verify-0.6.0.tgz#7dccdc64837deb3538c01d7c6e0f133b4cf0a125" - integrity sha512-nu0qDbbgAOTmqbJPZzBpEC9gaNDnTmm9cxuvyAfrO9d5g0dC+VAdDSqVP8+MNnjhQ6ZXri88s6F+IiffhpYfaA== - dependencies: - axios "^0.26.1" - cli-logger "^0.5.40" - delay "^5.0.0" - querystring "^0.2.1" - tunnel "0.0.6" - -truffle@^5.4.32: - version "5.5.4" - resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.5.4.tgz#78d6d0c232cabad4f99d06bc4205a6bd26a5275a" - integrity sha512-bynZsS20y67wmvj6pGID4XryMVn6PUP4d6KNYy19wbxu82MKmmpDJF1xsDET8YUVglH4kRd0r0RAR2Vgx/8ovw== - dependencies: - "@truffle/db-loader" "^0.1.6" - "@truffle/debugger" "^10.0.0" - app-module-path "^2.2.0" - ganache "^7.0.3" - mocha "8.1.2" - original-require "^1.0.1" - optionalDependencies: - "@truffle/db" "^0.5.56" - "@truffle/preserve-fs" "^0.2.7" - "@truffle/preserve-to-buckets" "^0.2.8" - "@truffle/preserve-to-filecoin" "^0.2.8" - "@truffle/preserve-to-ipfs" "^0.2.8" - -ts-command-line-args@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.2.1.tgz#fd6913e542099012c0ffb2496126a8f38305c7d6" - integrity sha512-mnK68QA86FYzQYTSA/rxIjT/8EpKsvQw9QkawPic8I8t0gjAOw3Oa509NIRoaY1FmH7hdrncMp7t7o+vYoceNQ== - dependencies: - chalk "^4.1.0" - command-line-args "^5.1.1" - command-line-usage "^6.1.0" - string-format "^2.0.0" - -ts-essentials@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a" - integrity sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ== - -ts-essentials@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" - integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== - -ts-node@^8.0.2: - version "8.10.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" - integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== - dependencies: +ts-node@>=8.0.0: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" arg "^4.1.0" + create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" - source-map-support "^0.5.17" + v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsconfig-paths@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" - integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" - json5 "^1.0.1" + json5 "^1.0.2" minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.9.0: +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - -tslib@^2.1.0, tslib@^2.3.1, tslib@~2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tunnel@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" - integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== +tsort@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" + integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== -tweetnacl-util@^0.15.0, tweetnacl-util@^0.15.1: +tweetnacl-util@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== -tweetnacl@1.x.x, tweetnacl@^1.0.0, tweetnacl@^1.0.3: +tweetnacl@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -10801,136 +4933,84 @@ type-check@^0.4.0, type-check@~0.4.0: type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== dependencies: prelude-ls "~1.1.2" -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f" - integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ== - -typechain@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-7.0.1.tgz#65411991327a7031895b1d57b7e0ce7fc9c66376" - integrity sha512-4c+ecLW4mTiKwTDdofiN8ToDp7TkFC2Bzp2Pt/+qeKzkmELWzy2eDjCiv0IWHswAZhE2y9KXBhTmShzhIzD+LQ== - dependencies: - "@types/prettier" "^2.1.1" - debug "^4.1.1" - fs-extra "^7.0.0" - glob "^7.1.6" - js-sha3 "^0.8.0" - lodash "^4.17.15" - mkdirp "^1.0.4" - prettier "^2.1.2" - ts-command-line-args "^2.2.0" - ts-essentials "^7.0.1" - -typedarray-to-buffer@^3.1.5, typedarray-to-buffer@~3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typeforce@^1.11.5: - version "1.18.0" - resolved "https://registry.yarnpkg.com/typeforce/-/typeforce-1.18.0.tgz#d7416a2c5845e085034d70fcc5b6cc4a90edbfdc" - integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== - -typescript-compare@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/typescript-compare/-/typescript-compare-0.0.2.tgz#7ee40a400a406c2ea0a7e551efd3309021d5f425" - integrity sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA== - dependencies: - typescript-logic "^0.0.0" - -typescript-logic@^0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/typescript-logic/-/typescript-logic-0.0.0.tgz#66ebd82a2548f2b444a43667bec120b496890196" - integrity sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q== - -typescript-tuple@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/typescript-tuple/-/typescript-tuple-2.2.1.tgz#7d9813fb4b355f69ac55032e0363e8bb0f04dad2" - integrity sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q== - dependencies: - typescript-compare "^0.0.2" +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== -typescript@^4.5.5: - version "4.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" - integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typical@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" - integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typical@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" - integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -uglify-js@^3.1.4: - version "3.15.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471" - integrity sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" -uint8arrays@1.1.0, uint8arrays@^1.0.0, uint8arrays@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-1.1.0.tgz#d034aa65399a9fd213a1579e323f0b29f67d0ed2" - integrity sha512-cLdlZ6jnFczsKf5IH1gPHTtcHtPGho5r4CvctohmQjw8K7Q3gFdfIGHxSTdTaCKrL4w09SsPRJTqRS0drYeszA== +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: - multibase "^3.0.0" - web-encoding "^1.0.2" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -uint8arrays@^2.0.5, uint8arrays@^2.1.3: - version "2.1.10" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-2.1.10.tgz#34d023c843a327c676e48576295ca373c56e286a" - integrity sha512-Q9/hhJa2836nQfEJSZTmr+pg9+cDJS9XEAp7N2Vg5MzL3bK/mkMVfjscRGYruP9jNda6MAdf4QD/y78gSzkp6A== +typed-array-byte-offset@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz#3fa9f22567700cc86aaf86a1e7176f74b59600f2" + integrity sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw== dependencies: - multiformats "^9.4.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + reflect.getprototypeof "^1.0.6" -uint8arrays@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.0.0.tgz#260869efb8422418b6f04e3fac73a3908175c63b" - integrity sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA== +typed-array-length@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== dependencies: - multiformats "^9.4.2" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== +typescript@5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.3.tgz#fe976f0c826a88d0a382007681cbb2da44afdedf" + integrity sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA== -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== unbox-primitive@^1.0.2: version "1.0.2" @@ -10942,54 +5022,37 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -universalify@^0.1.0, universalify@^0.1.2: +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + +undici@^5.14.0: + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== + dependencies: + "@fastify/busboy" "^2.0.0" + +universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -unorm@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" - integrity sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -upath2@^3.1.12: - version "3.1.12" - resolved "https://registry.yarnpkg.com/upath2/-/upath2-3.1.12.tgz#441b3dfbadde21731017bd1b7beb169498efd0a9" - integrity sha512-yC3eZeCyCXFWjy7Nu4pgjLhXNYjuzuUmJiRgSSw6TJp8Emc+E4951HGPJf+bldFC5SL7oBLeNbtm1fGzXn2gxw== - dependencies: - path-is-network-drive "^1.0.13" - path-strip-sep "^1.0.10" - tslib "^2.3.1" - -update-browserslist-db@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz#2924d3927367a38d5c555413a7ce138fc95fcb18" - integrity sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -upper-case-first@^1.1.0, upper-case-first@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115" - integrity sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU= - dependencies: - upper-case "^1.1.1" - -upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" - integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== uri-js@^4.2.2: version "4.4.1" @@ -10998,588 +5061,177 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url-join@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" - integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -url-set-query@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" - integrity sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk= - -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= - -ursa-optional@^0.10.1: - version "0.10.2" - resolved "https://registry.yarnpkg.com/ursa-optional/-/ursa-optional-0.10.2.tgz#bd74e7d60289c22ac2a69a3c8dea5eb2817f9681" - integrity sha512-TKdwuLboBn7M34RcvVTuQyhvrA8gYKapuVdm0nBP0mnBc7oECOfUQZrY91cefL3/nm64ZyrejSRrhTVdX7NG/A== - dependencies: - bindings "^1.5.0" - nan "^2.14.2" - -utf-8-validate@5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.7.tgz#c15a19a6af1f7ad9ec7ddc425747ca28c3644922" - integrity sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q== - dependencies: - node-gyp-build "^4.3.0" - -utf-8-validate@6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-6.0.3.tgz#7d8c936d854e86b24d1d655f138ee27d2636d777" - integrity sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA== - dependencies: - node-gyp-build "^4.3.0" - -utf-8-validate@^5.0.2: - version "5.0.9" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.9.tgz#ba16a822fbeedff1a58918f2a6a6b36387493ea3" - integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q== - dependencies: - node-gyp-build "^4.3.0" - -utf8@3.0.0, utf8@^3.0.0: +utf8@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== -util-deprecate@^1.0.1, util-deprecate@~1.0.1: +util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util@^0.12.0, util@^0.12.3: - version "0.12.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" - integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - safe-buffer "^5.1.2" - which-typed-array "^1.1.2" - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" - integrity sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w= - -uuid@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" - integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA== - -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - -uuid@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d" - integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: +uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -value-or-promise@1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" - integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== - -varint@^5.0.0, varint@^5.0.2, varint@~5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" - integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== - -varint@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" - integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vuvuzela@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" - integrity sha1-O+FF5YJxxzylUnndhR8SpoIRSws= - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -web-encoding@^1.0.2, web-encoding@^1.0.6: - version "1.1.5" - resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" - integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA== - dependencies: - util "^0.12.3" - optionalDependencies: - "@zxing/text-encoding" "0.9.0" - -web3-bzz@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.5.3.tgz#e36456905ce051138f9c3ce3623cbc73da088c2b" - integrity sha512-SlIkAqG0eS6cBS9Q2eBOTI1XFzqh83RqGJWnyrNZMDxUwsTVHL+zNnaPShVPvrWQA1Ub5b0bx1Kc5+qJVxsTJg== - dependencies: - "@types/node" "^12.12.6" - got "9.6.0" - swarm-js "^0.1.40" - -web3-core-helpers@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.5.3.tgz#099030235c477aadf39a94199ef40092151d563c" - integrity sha512-Ip1IjB3S8vN7Kf1PPjK41U5gskmMk6IJQlxIVuS8/1U7n/o0jC8krqtpRwiMfAgYyw3TXwBFtxSRTvJtnLyXZw== - dependencies: - web3-eth-iban "1.5.3" - web3-utils "1.5.3" - -web3-core-method@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.5.3.tgz#6cff97ed19fe4ea2e9183d6f703823a079f5132c" - integrity sha512-8wJrwQ2qD9ibWieF9oHXwrJsUGrv3XAtEkNeyvyNMpktNTIjxJ2jaFGQUuLiyUrMubD18XXgLk4JS6PJU4Loeg== - dependencies: - "@ethereumjs/common" "^2.4.0" - "@ethersproject/transactions" "^5.0.0-beta.135" - web3-core-helpers "1.5.3" - web3-core-promievent "1.5.3" - web3-core-subscriptions "1.5.3" - web3-utils "1.5.3" - -web3-core-promievent@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.5.3.tgz#3f11833c3dc6495577c274350b61144e0a4dba01" - integrity sha512-CFfgqvk3Vk6PIAxtLLuX+pOMozxkKCY+/GdGr7weMh033mDXEPvwyVjoSRO1PqIKj668/hMGQsVoIgbyxkJ9Mg== - dependencies: - eventemitter3 "4.0.4" - -web3-core-requestmanager@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.5.3.tgz#b339525815fd40e3a2a81813c864ddc413f7b6f7" - integrity sha512-9k/Bze2rs8ONix5IZR+hYdMNQv+ark2Ek2kVcrFgWO+LdLgZui/rn8FikPunjE+ub7x7pJaKCgVRbYFXjo3ZWg== - dependencies: - util "^0.12.0" - web3-core-helpers "1.5.3" - web3-providers-http "1.5.3" - web3-providers-ipc "1.5.3" - web3-providers-ws "1.5.3" - -web3-core-subscriptions@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.5.3.tgz#d7d69c4caad65074212028656e9dc56ca5c2159d" - integrity sha512-L2m9vG1iRN6thvmv/HQwO2YLhOQlmZU8dpLG6GSo9FBN14Uch868Swk0dYVr3rFSYjZ/GETevSXU+O+vhCummA== - dependencies: - eventemitter3 "4.0.4" - web3-core-helpers "1.5.3" - -web3-core@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.5.3.tgz#59f8728b27c8305b349051326aa262b9b7e907bf" - integrity sha512-ACTbu8COCu+0eUNmd9pG7Q9EVsNkAg2w3Y7SqhDr+zjTgbSHZV01jXKlapm9z+G3AN/BziV3zGwudClJ4u4xXQ== - dependencies: - "@types/bn.js" "^4.11.5" - "@types/node" "^12.12.6" - bignumber.js "^9.0.0" - web3-core-helpers "1.5.3" - web3-core-method "1.5.3" - web3-core-requestmanager "1.5.3" - web3-utils "1.5.3" - -web3-eth-abi@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.5.3.tgz#5aea9394d797f99ca0d9bd40c3417eb07241c96c" - integrity sha512-i/qhuFsoNrnV130CSRYX/z4SlCfSQ4mHntti5yTmmQpt70xZKYZ57BsU0R29ueSQ9/P+aQrL2t2rqkQkAloUxg== - dependencies: - "@ethersproject/abi" "5.0.7" - web3-utils "1.5.3" - -web3-eth-accounts@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.5.3.tgz#076c816ff4d68c9dffebdc7fd2bfaddcfc163d77" - integrity sha512-pdGhXgeBaEJENMvRT6W9cmji3Zz/46ugFSvmnLLw79qi5EH7XJhKISNVb41eWCrs4am5GhI67GLx5d2s2a72iw== - dependencies: - "@ethereumjs/common" "^2.3.0" - "@ethereumjs/tx" "^3.2.1" - crypto-browserify "3.12.0" - eth-lib "0.2.8" - ethereumjs-util "^7.0.10" - scrypt-js "^3.0.1" - uuid "3.3.2" - web3-core "1.5.3" - web3-core-helpers "1.5.3" - web3-core-method "1.5.3" - web3-utils "1.5.3" - -web3-eth-contract@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.5.3.tgz#12b03a4a16ce583a945f874bea2ff2fb4c5b81ad" - integrity sha512-Gdlt1L6cdHe83k7SdV6xhqCytVtOZkjD0kY/15x441AuuJ4JLubCHuqu69k2Dr3tWifHYVys/vG8QE/W16syGg== - dependencies: - "@types/bn.js" "^4.11.5" - web3-core "1.5.3" - web3-core-helpers "1.5.3" - web3-core-method "1.5.3" - web3-core-promievent "1.5.3" - web3-core-subscriptions "1.5.3" - web3-eth-abi "1.5.3" - web3-utils "1.5.3" - -web3-eth-ens@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.5.3.tgz#ef6eee1ddf32b1ff9536fc7c599a74f2656bafe1" - integrity sha512-QmGFFtTGElg0E+3xfCIFhiUF+1imFi9eg/cdsRMUZU4F1+MZCC/ee+IAelYLfNTGsEslCqfAusliKOT9DdGGnw== - dependencies: - content-hash "^2.5.2" - eth-ens-namehash "2.0.8" - web3-core "1.5.3" - web3-core-helpers "1.5.3" - web3-core-promievent "1.5.3" - web3-eth-abi "1.5.3" - web3-eth-contract "1.5.3" - web3-utils "1.5.3" - -web3-eth-iban@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.5.3.tgz#91b1475893a877b10eac1de5cce6eb379fb81b5d" - integrity sha512-vMzmGqolYZvRHwP9P4Nf6G8uYM5aTLlQu2a34vz78p0KlDC+eV1th3+90Qeaupa28EG7OO0IT1F0BejiIauOPw== - dependencies: - bn.js "^4.11.9" - web3-utils "1.5.3" - -web3-eth-personal@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.5.3.tgz#4ebe09e9a77dd49d23d93b36b36cfbf4a6dae713" - integrity sha512-JzibJafR7ak/Icas8uvos3BmUNrZw1vShuNR5Cxjo+vteOC8XMqz1Vr7RH65B4bmlfb3bm9xLxetUHO894+Sew== - dependencies: - "@types/node" "^12.12.6" - web3-core "1.5.3" - web3-core-helpers "1.5.3" - web3-core-method "1.5.3" - web3-net "1.5.3" - web3-utils "1.5.3" - -web3-eth@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.5.3.tgz#d7d1ac7198f816ab8a2088c01e0bf1eda45862fe" - integrity sha512-saFurA1L23Bd7MEf7cBli6/jRdMhD4X/NaMiO2mdMMCXlPujoudlIJf+VWpRWJpsbDFdu7XJ2WHkmBYT5R3p1Q== - dependencies: - web3-core "1.5.3" - web3-core-helpers "1.5.3" - web3-core-method "1.5.3" - web3-core-subscriptions "1.5.3" - web3-eth-abi "1.5.3" - web3-eth-accounts "1.5.3" - web3-eth-contract "1.5.3" - web3-eth-ens "1.5.3" - web3-eth-iban "1.5.3" - web3-eth-personal "1.5.3" - web3-net "1.5.3" - web3-utils "1.5.3" - -web3-net@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.5.3.tgz#545fee49b8e213b0c55cbe74ffd0295766057463" - integrity sha512-0W/xHIPvgVXPSdLu0iZYnpcrgNnhzHMC888uMlGP5+qMCt8VuflUZHy7tYXae9Mzsg1kxaJAS5lHVNyeNw4CoQ== - dependencies: - web3-core "1.5.3" - web3-core-method "1.5.3" - web3-utils "1.5.3" - -web3-provider-engine@16.0.3: - version "16.0.3" - resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-16.0.3.tgz#8ff93edf3a8da2f70d7f85c5116028c06a0d9f07" - integrity sha512-Q3bKhGqLfMTdLvkd4TtkGYJHcoVQ82D1l8jTIwwuJp/sAp7VHnRYb9YJ14SW/69VMWoOhSpPLZV2tWb9V0WJoA== - dependencies: - "@ethereumjs/tx" "^3.3.0" - async "^2.5.0" - backoff "^2.5.0" - clone "^2.0.0" - cross-fetch "^2.1.0" - eth-block-tracker "^4.4.2" - eth-json-rpc-filters "^4.2.1" - eth-json-rpc-infura "^5.1.0" - eth-json-rpc-middleware "^6.0.0" - eth-rpc-errors "^3.0.0" - eth-sig-util "^1.4.2" - ethereumjs-block "^1.2.2" - ethereumjs-util "^5.1.5" - ethereumjs-vm "^2.3.4" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - readable-stream "^2.2.9" - request "^2.85.0" - semaphore "^1.0.3" - ws "^5.1.1" - xhr "^2.2.0" - xtend "^4.0.1" - -web3-providers-http@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.5.3.tgz#74f170fc3d79eb7941d9fbc34e2a067d61ced0b2" - integrity sha512-5DpUyWGHtDAr2RYmBu34Fu+4gJuBAuNx2POeiJIooUtJ+Mu6pIx4XkONWH6V+Ez87tZAVAsFOkJRTYuzMr3rPw== - dependencies: - web3-core-helpers "1.5.3" - xhr2-cookies "1.1.0" - -web3-providers-ipc@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.5.3.tgz#4bd7f5e445c2f3c2595fce0929c72bb879320a3f" - integrity sha512-JmeAptugVpmXI39LGxUSAymx0NOFdgpuI1hGQfIhbEAcd4sv7fhfd5D+ZU4oLHbRI8IFr4qfGU0uhR8BXhDzlg== - dependencies: - oboe "2.1.5" - web3-core-helpers "1.5.3" - -web3-providers-ws@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.5.3.tgz#eec6cfb32bb928a4106de506f13a49070a21eabf" - integrity sha512-6DhTw4Q7nm5CFYEUHOJM0gAb3xFx+9gWpVveg3YxJ/ybR1BUvEWo3bLgIJJtX56cYX0WyY6DS35a7f0LOI1kVg== - dependencies: - eventemitter3 "4.0.4" - web3-core-helpers "1.5.3" - websocket "^1.0.32" - -web3-shh@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.5.3.tgz#3c04aa4cda9ba0b746d7225262401160f8e38b13" - integrity sha512-COfEXfsqoV/BkcsNLRxQqnWc1Teb8/9GxdGag5GtPC5gQC/vsN+7hYVJUwNxY9LtJPKYTij2DHHnx6UkITng+Q== - dependencies: - web3-core "1.5.3" - web3-core-method "1.5.3" - web3-core-subscriptions "1.5.3" - web3-net "1.5.3" +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== -web3-utils@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.5.3.tgz#e914c9320cd663b2a09a5cb920ede574043eb437" - integrity sha512-56nRgA+Ad9SEyCv39g36rTcr5fpsd4L9LgV3FK0aB66nAMazLAA6Qz4lH5XrUKPDyBIPGJIR+kJsyRtwcu2q1Q== - dependencies: - bn.js "^4.11.9" - eth-lib "0.2.8" - ethereum-bloom-filters "^1.0.6" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - utf8 "3.0.0" +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +viem@2.7.14: + version "2.7.14" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.14.tgz#347d316cb5400f0b896b2205b1bc8073aa5e27e0" + integrity sha512-5b1KB1gXli02GOQHZIUsRluNUwssl2t4hqdFAzyWPwJ744N83jAOBOjOkrGz7K3qMIv9b0GQt3DoZIErSQTPkQ== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "1.0.0" + isows "1.0.3" + ws "8.13.0" -web3-utils@^1.3.0: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.7.1.tgz#77d8bacaf426c66027d8aa4864d77f0ed211aacd" - integrity sha512-fef0EsqMGJUgiHPdX+KN9okVWshbIumyJPmR+btnD1HgvoXijKEkuKBv0OmUqjbeqmLKP2/N9EiXKJel5+E1Dw== - dependencies: - bn.js "^4.11.9" +viem@^2.21.37: + version "2.21.55" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.21.55.tgz#a57ad31fcf2a0f6c011b1909f02c94421ec4f781" + integrity sha512-PgXew7C11cAuEtOSgRyQx2kJxEOPUwIwZA9dMglRByqJuFVA7wSGZZOOo/93iylAA8E15bEdqy9xulU3oKZ70Q== + dependencies: + "@noble/curves" "1.7.0" + "@noble/hashes" "1.6.1" + "@scure/bip32" "1.6.0" + "@scure/bip39" "1.5.0" + abitype "1.0.7" + isows "1.0.6" + ox "0.1.2" + webauthn-p256 "0.0.10" + ws "8.18.0" + +web3-utils@^1.3.6: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" + integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== + dependencies: + "@ethereumjs/util" "^8.1.0" + bn.js "^5.2.1" ethereum-bloom-filters "^1.0.6" - ethereumjs-util "^7.1.0" + ethereum-cryptography "^2.1.2" ethjs-unit "0.1.6" number-to-bn "1.7.0" randombytes "^2.1.0" utf8 "3.0.0" -web3@1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.5.3.tgz#11882679453c645bf33620fbc255a243343075aa" - integrity sha512-eyBg/1K44flfv0hPjXfKvNwcUfIVDI4NX48qHQe6wd7C8nPSdbWqo9vLy6ksZIt9NLa90HjI8HsGYgnMSUxn6w== - dependencies: - web3-bzz "1.5.3" - web3-core "1.5.3" - web3-eth "1.5.3" - web3-eth-personal "1.5.3" - web3-net "1.5.3" - web3-shh "1.5.3" - web3-utils "1.5.3" - -webidl-conversions@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-2.0.1.tgz#3bf8258f7d318c7443c36f2e169402a1a6703506" - integrity sha1-O/glj30xjHRDw28uFpQCoaZwNQY= - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -websocket@^1.0.31, websocket@^1.0.32: - version "1.0.34" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" - integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - -websql@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/websql/-/websql-1.0.0.tgz#1bd00b27392893134715d5dd6941fd89e730bab5" - integrity sha512-7iZ+u28Ljw5hCnMiq0BCOeSYf0vCFQe/ORY0HgscTiKjQed8WqugpBUggJ2NTnB9fahn1kEnPRX2jf8Px5PhJw== +webauthn-p256@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/webauthn-p256/-/webauthn-p256-0.0.10.tgz#877e75abe8348d3e14485932968edf3325fd2fdd" + integrity sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA== dependencies: - argsarray "^0.0.1" - immediate "^3.2.2" - noop-fn "^1.0.0" - sqlite3 "^4.0.0" - tiny-queue "^0.2.1" - -whatwg-fetch@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== + "@noble/curves" "^1.4.0" + "@noble/hashes" "^1.4.0" -whatwg-url-compat@~0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz#00898111af689bb097541cd5a45ca6c8798445bf" - integrity sha1-AImBEa9om7CXVBzVpFymyHmERb8= +which-boxed-primitive@^1.0.2, which-boxed-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.0.tgz#2d850d6c4ac37b95441a67890e19f3fda8b6c6d9" + integrity sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng== dependencies: - tr46 "~0.0.1" + is-bigint "^1.1.0" + is-boolean-object "^1.2.0" + is-number-object "^1.1.0" + is-string "^1.1.0" + is-symbol "^1.1.0" -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" +which-builtin-type@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" -which-boxed-primitive@^1.0.2: +which-collection@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which-typed-array@^1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" - integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.7" - -which@2.0.2, which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.16: + version "1.1.16" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.16.tgz#db4db429c4706feca2f01677a144278e4a8c216b" + integrity sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" -which@^1.1.1, which@^1.2.9, which@^1.3.1: +which@^1.1.1, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -wide-align@^1.1.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: - string-width "^1.0.2 || 2 || 3 || 4" + isexe "^2.0.0" -wif@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/wif/-/wif-2.0.6.tgz#08d3f52056c66679299726fade0d432ae74b4704" - integrity sha1-CNP1IFbGZnkplyb63g1DKudLRwQ= +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== dependencies: - bs58check "<3.0.0" + string-width "^4.0.0" -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +word-wrap@^1.2.5, word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - -wordwrapjs@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" - integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== - dependencies: - reduce-flatten "^2.0.0" - typical "^5.2.0" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -workerpool@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.0.0.tgz#85aad67fa1a2c8ef9386a1b43539900f61d03d58" - integrity sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA== +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^7.0.0: version "7.0.0" @@ -11590,225 +5242,72 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-stream@~0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/write-stream/-/write-stream-0.4.3.tgz#83cc8c0347d0af6057a93862b4e3ae01de5c81c1" - integrity sha1-g8yMA0fQr2BXqThitOOuAd5cgcE= - dependencies: - readable-stream "~0.0.2" - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@8.13.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== -ws@^3.0.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - -ws@^5.1.1: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" - integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== - dependencies: - async-limiter "~1.0.0" - -ws@^7.2.0, ws@^7.2.1, ws@^7.3.1, ws@^7.4.5: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== - -xhr-request-promise@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" - integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== - dependencies: - xhr-request "^1.1.0" - -xhr-request@^1.0.1, xhr-request@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" - integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== - dependencies: - buffer-to-arraybuffer "^0.0.5" - object-assign "^4.1.1" - query-string "^5.0.1" - simple-get "^2.7.0" - timed-out "^4.0.1" - url-set-query "^1.0.0" - xhr "^2.0.4" - -xhr2-cookies@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" - integrity sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg= - dependencies: - cookiejar "^2.1.1" - -xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" - integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== - dependencies: - global "~4.4.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - -"xml-name-validator@>= 2.0.1 < 3.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" - integrity sha1-TYuPHszTQZqjYgYb7O9RXh5VljU= - -xmlhttprequest@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" - integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= - -xss@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.11.tgz#211cb82e95b5071d4c75d597283c021157ebe46a" - integrity sha512-EimjrjThZeK2MO7WKR9mN5ZC1CSqivSl55wvUK5EtU6acf0rzEE1pN+9ZDrFXJ82BRp3JL38pPE6S4o/rpp1zQ== - dependencies: - commander "^2.20.3" - cssfilter "0.0.10" - -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ== - dependencies: - object-keys "~0.4.0" +ws@8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== +ws@^7.4.6: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= - -yallist@^3.0.0, yallist@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@13.1.2, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^15.0.1: - version "15.0.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.3.tgz#316e263d5febe8b38eef61ac092b33dfcc9b1115" - integrity sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA== +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" -yargs-parser@^21.0.0: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs-unparser@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.1.tgz#bd4b0ee05b4c94d058929c32cb09e3fce71d3c5f" - integrity sha512-qZV14lK9MWsGCmcr7u5oXGH0dbGqZAIxTDrWXZDo5zUr6b6iUmelNKO6x6R1dQT24AH3LgRxJpr8meWy2unolA== - dependencies: - camelcase "^5.3.1" - decamelize "^1.2.0" - flat "^4.1.0" - is-plain-obj "^1.1.0" - yargs "^14.2.3" - -yargs@13.3.2: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^14.2.3: - version "14.2.3" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" - integrity sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg== - dependencies: - cliui "^5.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^15.0.1" - -yargs@^17.3.1: - version "17.5.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" - integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.3" + string-width "^4.2.0" y18n "^5.0.5" - yargs-parser "^21.0.0" + yargs-parser "^20.2.2" yn@3.1.1: version "3.1.1"