diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 65956706d2..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: 2.1 -executors: - general-test-executor: - docker: - - image: cimg/node:16.18 - -jobs: - contract-test: - executor: general-test-executor - working_directory: ~/token-bridge-contracts - steps: - - checkout - - run: fgrep .only -R test/ && exit 1 || exit 0 - - run: | - yarn install - yarn build - yarn test:storage - yarn test - -workflows: - build-test-workflow: - jobs: - - contract-test diff --git a/.env-sample b/.env-sample new file mode 100644 index 0000000000..0fd2718b05 --- /dev/null +++ b/.env-sample @@ -0,0 +1,13 @@ +## Rollup on top of which token bridge will be created +ROLLUP_ADDRESS="" +ROLLUP_OWNER="" +L1_TOKEN_BRIDGE_CREATOR="" +# needed for verification +L1_RETRYABLE_SENDER="" + +## RPC endpoints +BASECHAIN_RPC="" +ORBIT_RPC="" + +## Deployer key used for deploying creator and creating token bridge +BASECHAIN_DEPLOYER_KEY="" diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 0000000000..509b874003 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,91 @@ +name: Build and test + +on: + workflow_dispatch: + pull_request: + +jobs: + test-unit: + name: Test unit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Setup node/yarn + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' + + - name: Install packages + run: yarn + + - name: Run tests + run: yarn test:unit + + test-only-doesnt-exist: + name: No .only + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Check if .only exists in integration test + run: fgrep .only -R test/ && exit 1 || exit 0 + + test-hardhat: + name: Test hardhat + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup node/yarn + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' + + - name: Install packages + run: yarn + + - name: Compile contracts + run: yarn build + + - name: Run integration tests + run: yarn test + + test-storage: + name: Test storage layout + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup node/yarn + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' + + - name: Install packages + run: yarn + + - name: Build + run: yarn build + + - name: Test Storage Layouts + run: yarn run test:storage diff --git a/.gitignore b/.gitignore index f4fbcf4c70..ae5e00a019 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,20 @@ +.gitignore +.env node_modules +.vscode/ #Hardhat files cache build artifacts deployment.json + +#Foundry files +out/ +forge-cache/ + +#Storage layout test files test/storage/*-old.dot + +# local deployment files +network.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..e19917d6cd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,7 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "lib/nitro-contracts"] + path = lib/nitro-contracts + url = git@github.com:OffchainLabs/nitro-contracts.git + branch = feature-orbit-bridge diff --git a/.solhint.json b/.solhint.json index b1167a3c90..d2c46a0f97 100644 --- a/.solhint.json +++ b/.solhint.json @@ -4,6 +4,6 @@ "rules": { "mark-callable-contracts": "none", "prettier/prettier": "error", - "compiler-version": ["error", "^0.6.11"] + "compiler-version": ["error", "^0.8.0"] } } diff --git a/contracts/rpc-utils/NodeInterface.sol b/contracts/rpc-utils/NodeInterface.sol index 08c37e0351..7c753cddcd 100644 --- a/contracts/rpc-utils/NodeInterface.sol +++ b/contracts/rpc-utils/NodeInterface.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // solhint-disable-next-line compiler-version -pragma solidity >=0.4.21 <0.7.0; +pragma solidity >=0.4.21 <0.9.0; /** @title Interface for providing Outbox proof data * @notice This contract doesn't exist on-chain. Instead it is a virtual interface accessible at 0x00000000000000000000000000000000000000C8 diff --git a/contracts/rpc-utils/RetryableTicketCreator.sol b/contracts/rpc-utils/RetryableTicketCreator.sol index 38c55b19de..1207af560c 100644 --- a/contracts/rpc-utils/RetryableTicketCreator.sol +++ b/contracts/rpc-utils/RetryableTicketCreator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // solhint-disable-next-line compiler-version -pragma solidity >=0.4.21 <0.7.0; +pragma solidity >=0.4.21 <0.9.0; interface RetryableTicketCreator { /** diff --git a/contracts/tokenbridge/arbitrum/L2ArbitrumMessenger.sol b/contracts/tokenbridge/arbitrum/L2ArbitrumMessenger.sol index e9069fd4a4..2431170be2 100644 --- a/contracts/tokenbridge/arbitrum/L2ArbitrumMessenger.sol +++ b/contracts/tokenbridge/arbitrum/L2ArbitrumMessenger.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; diff --git a/contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol b/contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol new file mode 100644 index 0000000000..4859535812 --- /dev/null +++ b/contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.4; + +import {L2GatewayRouter} from "./gateway/L2GatewayRouter.sol"; +import {L2ERC20Gateway} from "./gateway/L2ERC20Gateway.sol"; +import {L2CustomGateway} from "./gateway/L2CustomGateway.sol"; +import {L2WethGateway} from "./gateway/L2WethGateway.sol"; +import {StandardArbERC20} from "./StandardArbERC20.sol"; +import {IUpgradeExecutor} from "@offchainlabs/upgrade-executor/src/IUpgradeExecutor.sol"; +import {BeaconProxyFactory} from "../libraries/ClonableBeaconProxy.sol"; +import {aeWETH} from "../libraries/aeWETH.sol"; +import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import { + TransparentUpgradeableProxy, + ITransparentUpgradeableProxy +} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; + +/** + * @title Layer2 token bridge creator + * @notice This contract is used to deploy token bridge on L2 chain. + * @dev L1AtomicTokenBridgeCreator shall call `deployL2Contracts` using retryable and that will result in deployment of canonical token bridge contracts. + */ +contract L2AtomicTokenBridgeFactory { + error L2AtomicTokenBridgeFactory_AlreadyExists(); + + function deployL2Contracts( + L2RuntimeCode calldata l2Code, + address l1Router, + address l1StandardGateway, + address l1CustomGateway, + address l1WethGateway, + address l1Weth, + address l2StandardGatewayCanonicalAddress, + address rollupOwner, + address aliasedL1UpgradeExecutor + ) external { + // Create proxyAdmin which will be used for all contracts. Revert if canonical deployment already exists + { + address proxyAdminAddress = Create2.computeAddress( + _getL2Salt(OrbitSalts.L2_PROXY_ADMIN), + keccak256(type(ProxyAdmin).creationCode), + address(this) + ); + if (proxyAdminAddress.code.length > 0) { + revert L2AtomicTokenBridgeFactory_AlreadyExists(); + } + } + address proxyAdmin = + address(new ProxyAdmin{ salt: _getL2Salt(OrbitSalts.L2_PROXY_ADMIN) }()); + + // deploy router/gateways/executor + address upgradeExecutor = _deployUpgradeExecutor( + l2Code.upgradeExecutor, rollupOwner, proxyAdmin, aliasedL1UpgradeExecutor + ); + address router = + _deployRouter(l2Code.router, l1Router, l2StandardGatewayCanonicalAddress, proxyAdmin); + _deployStandardGateway( + l2Code.standardGateway, l1StandardGateway, router, proxyAdmin, upgradeExecutor + ); + _deployCustomGateway(l2Code.customGateway, l1CustomGateway, router, proxyAdmin); + + // fee token based creator will provide address(0) as WETH is not used in ERC20-based chains + if (l1WethGateway != address(0)) { + _deployWethGateway( + l2Code.wethGateway, l2Code.aeWeth, l1WethGateway, l1Weth, router, proxyAdmin + ); + } + + // deploy multicall + Create2.deploy(0, _getL2Salt(OrbitSalts.L2_MULTICALL), _creationCodeFor(l2Code.multicall)); + + // transfer ownership to L2 upgradeExecutor + ProxyAdmin(proxyAdmin).transferOwnership(upgradeExecutor); + } + + function _deployUpgradeExecutor( + bytes calldata runtimeCode, + address rollupOwner, + address proxyAdmin, + address aliasedL1UpgradeExecutor + ) internal returns (address) { + // canonical L2 upgrade executor with dummy logic + address canonicalUpgradeExecutor = _deploySeedProxy( + proxyAdmin, _getL2Salt(OrbitSalts.L2_EXECUTOR), _getL2Salt(OrbitSalts.L2_EXECUTOR_LOGIC) + ); + + // create UpgradeExecutor logic and upgrade to it + address upExecutorLogic = Create2.deploy( + 0, _getL2Salt(OrbitSalts.L2_EXECUTOR_LOGIC), _creationCodeFor(runtimeCode) + ); + ProxyAdmin(proxyAdmin).upgrade( + ITransparentUpgradeableProxy(canonicalUpgradeExecutor), upExecutorLogic + ); + + // init upgrade executor + address[] memory executors = new address[](2); + executors[0] = rollupOwner; + executors[1] = aliasedL1UpgradeExecutor; + IUpgradeExecutor(canonicalUpgradeExecutor).initialize(canonicalUpgradeExecutor, executors); + + return canonicalUpgradeExecutor; + } + + function _deployRouter( + bytes calldata runtimeCode, + address l1Router, + address l2StandardGatewayCanonicalAddress, + address proxyAdmin + ) internal returns (address) { + // canonical L2 router with dummy logic + address canonicalRouter = _deploySeedProxy( + proxyAdmin, _getL2Salt(OrbitSalts.L2_ROUTER), _getL2Salt(OrbitSalts.L2_ROUTER_LOGIC) + ); + + // create L2 router logic and upgrade + address routerLogic = + Create2.deploy(0, _getL2Salt(OrbitSalts.L2_ROUTER_LOGIC), _creationCodeFor(runtimeCode)); + ProxyAdmin(proxyAdmin).upgrade(ITransparentUpgradeableProxy(canonicalRouter), routerLogic); + + // init + L2GatewayRouter(canonicalRouter).initialize(l1Router, l2StandardGatewayCanonicalAddress); + + return canonicalRouter; + } + + function _deployStandardGateway( + bytes calldata runtimeCode, + address l1StandardGateway, + address router, + address proxyAdmin, + address upgradeExecutor + ) internal { + // canonical L2 standard gateway with dummy logic + address canonicalStdGateway = _deploySeedProxy( + proxyAdmin, + _getL2Salt(OrbitSalts.L2_STANDARD_GATEWAY), + _getL2Salt(OrbitSalts.L2_STANDARD_GATEWAY_LOGIC) + ); + + // create L2 standard gateway logic and upgrade + address stdGatewayLogic = Create2.deploy( + 0, _getL2Salt(OrbitSalts.L2_STANDARD_GATEWAY_LOGIC), _creationCodeFor(runtimeCode) + ); + ProxyAdmin(proxyAdmin).upgrade( + ITransparentUpgradeableProxy(canonicalStdGateway), stdGatewayLogic + ); + + // create beacon + StandardArbERC20 standardArbERC20 = new StandardArbERC20{ + salt: _getL2Salt(OrbitSalts.L2_STANDARD_ERC20) + }(); + UpgradeableBeacon beacon = new UpgradeableBeacon{ + salt: _getL2Salt(OrbitSalts.UPGRADEABLE_BEACON) + }(address(standardArbERC20)); + BeaconProxyFactory beaconProxyFactory = new BeaconProxyFactory{ + salt: _getL2Salt(OrbitSalts.BEACON_PROXY_FACTORY) + }(); + + // init contracts + beaconProxyFactory.initialize(address(beacon)); + L2ERC20Gateway(canonicalStdGateway).initialize( + l1StandardGateway, router, address(beaconProxyFactory) + ); + + // make L2 executor the beacon owner + beacon.transferOwnership(upgradeExecutor); + } + + function _deployCustomGateway( + bytes calldata runtimeCode, + address l1CustomGateway, + address router, + address proxyAdmin + ) internal { + // canonical L2 custom gateway with dummy logic + address canonicalCustomGateway = _deploySeedProxy( + proxyAdmin, + _getL2Salt(OrbitSalts.L2_CUSTOM_GATEWAY), + _getL2Salt(OrbitSalts.L2_CUSTOM_GATEWAY_LOGIC) + ); + + // create L2 custom gateway logic and upgrade + address customGatewayLogicAddress = Create2.deploy( + 0, _getL2Salt(OrbitSalts.L2_CUSTOM_GATEWAY_LOGIC), _creationCodeFor(runtimeCode) + ); + ProxyAdmin(proxyAdmin).upgrade( + ITransparentUpgradeableProxy(canonicalCustomGateway), customGatewayLogicAddress + ); + + // init + L2GatewayRouter(canonicalCustomGateway).initialize(l1CustomGateway, router); + } + + function _deployWethGateway( + bytes calldata wethGatewayRuntimeCode, + bytes calldata aeWethRuntimeCode, + address l1WethGateway, + address l1Weth, + address router, + address proxyAdmin + ) internal { + // canonical L2 WETH with dummy logic + address canonicalL2Weth = _deploySeedProxy( + proxyAdmin, _getL2Salt(OrbitSalts.L2_WETH), _getL2Salt(OrbitSalts.L2_WETH_LOGIC) + ); + + // create L2WETH logic and upgrade + address l2WethLogic = Create2.deploy( + 0, _getL2Salt(OrbitSalts.L2_WETH_LOGIC), _creationCodeFor(aeWethRuntimeCode) + ); + ProxyAdmin(proxyAdmin).upgrade(ITransparentUpgradeableProxy(canonicalL2Weth), l2WethLogic); + + // canonical L2 WETH gateway with dummy logic + address canonicalL2WethGateway = _deploySeedProxy( + proxyAdmin, + _getL2Salt(OrbitSalts.L2_WETH_GATEWAY), + _getL2Salt(OrbitSalts.L2_WETH_GATEWAY_LOGIC) + ); + + // create L2WETH gateway logic and upgrade + address l2WethGatewayLogic = Create2.deploy( + 0, + _getL2Salt(OrbitSalts.L2_WETH_GATEWAY_LOGIC), + _creationCodeFor(wethGatewayRuntimeCode) + ); + ProxyAdmin(proxyAdmin).upgrade( + ITransparentUpgradeableProxy(canonicalL2WethGateway), l2WethGatewayLogic + ); + + // init gateway + L2WethGateway(payable(canonicalL2WethGateway)).initialize( + l1WethGateway, router, l1Weth, address(canonicalL2Weth) + ); + + // init L2Weth + aeWETH(payable(canonicalL2Weth)).initialize( + "WETH", "WETH", 18, canonicalL2WethGateway, l1Weth + ); + } + + /** + * In addition to hard-coded prefix, salt for L2 contracts depends on msg.sender and the chainId. Deploying L2 token bridge contracts is + * permissionless. By making msg.sender part of the salt we know exactly which set of contracts is the "canonical" one for given chain, + * deployed by L1TokenBridgeRetryableSender via retryable ticket. + */ + function _getL2Salt(bytes memory prefix) internal view returns (bytes32) { + return keccak256(abi.encodePacked(prefix, block.chainid, msg.sender)); + } + + /** + * Deploys a proxy with empty logic contract in order to get deterministic address which does not depend on actual logic contract. + */ + function _deploySeedProxy(address proxyAdmin, bytes32 proxySalt, bytes32 logicSalt) + internal + returns (address) + { + return address( + new TransparentUpgradeableProxy{ salt: proxySalt }( + address(new CanonicalAddressSeed{ salt: logicSalt}()), + proxyAdmin, + bytes("") + ) + ); + } + + /** + * @notice Generate a creation code that results on a contract with `code` as bytecode. + * Source - https://github.com/0xsequence/sstore2/blob/master/contracts/utils/Bytecode.sol + * @param code The returning value of the resulting `creationCode` + * @return creationCode (constructor) for new contract + */ + function _creationCodeFor(bytes memory code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked(hex"63", uint32(code.length), hex"80600E6000396000F3", code); + } +} + +/** + * Dummy contract used as initial logic contract for proxies, in order to get canonical (CREATE2 based) address. Then we can upgrade to any logic without having canonical addresses impacted. + */ +contract CanonicalAddressSeed {} + +/** + * Placeholder for bytecode of token bridge contracts which is sent from L1 to L2 through retryable ticket. + */ +struct L2RuntimeCode { + bytes router; + bytes standardGateway; + bytes customGateway; + bytes wethGateway; + bytes aeWeth; + bytes upgradeExecutor; + bytes multicall; +} + +/** + * Collection of salts used in CREATE2 deployment of L2 token bridge contracts. + */ +library OrbitSalts { + bytes public constant L1_PROXY_ADMIN = bytes("OrbitL1ProxyAdmin"); + bytes public constant L1_ROUTER = bytes("OrbitL1GatewayRouterProxy"); + bytes public constant L1_STANDARD_GATEWAY = bytes("OrbitL1StandardGatewayProxy"); + bytes public constant L1_CUSTOM_GATEWAY = bytes("OrbitL1CustomGatewayProxy"); + bytes public constant L1_WETH_GATEWAY = bytes("OrbitL1WethGatewayProxy"); + + bytes public constant L2_PROXY_ADMIN = bytes("OrbitL2ProxyAdmin"); + bytes public constant L2_ROUTER_LOGIC = bytes("OrbitL2GatewayRouterLogic"); + bytes public constant L2_ROUTER = bytes("OrbitL2GatewayRouterProxy"); + bytes public constant L2_STANDARD_GATEWAY_LOGIC = bytes("OrbitL2StandardGatewayLogic"); + bytes public constant L2_STANDARD_GATEWAY = bytes("OrbitL2StandardGatewayProxy"); + bytes public constant L2_CUSTOM_GATEWAY_LOGIC = bytes("OrbitL2CustomGatewayLogic"); + bytes public constant L2_CUSTOM_GATEWAY = bytes("OrbitL2CustomGatewayProxy"); + bytes public constant L2_WETH_GATEWAY_LOGIC = bytes("OrbitL2WethGatewayLogic"); + bytes public constant L2_WETH_GATEWAY = bytes("OrbitL2WethGatewayProxy"); + bytes public constant L2_WETH_LOGIC = bytes("OrbitL2WETH"); + bytes public constant L2_WETH = bytes("OrbitL2WETHProxy"); + bytes public constant L2_STANDARD_ERC20 = bytes("OrbitStandardArbERC20"); + bytes public constant UPGRADEABLE_BEACON = bytes("OrbitUpgradeableBeacon"); + bytes public constant BEACON_PROXY_FACTORY = bytes("OrbitBeaconProxyFactory"); + bytes public constant L2_EXECUTOR_LOGIC = bytes("OrbitL2UpgradeExecutorLogic"); + bytes public constant L2_EXECUTOR = bytes("OrbitL2UpgradeExecutorProxy"); + bytes public constant L2_MULTICALL = bytes("OrbitL2Multicall"); +} diff --git a/contracts/tokenbridge/arbitrum/StandardArbERC20.sol b/contracts/tokenbridge/arbitrum/StandardArbERC20.sol index 6394fa58ca..8f43e3ab2f 100644 --- a/contracts/tokenbridge/arbitrum/StandardArbERC20.sol +++ b/contracts/tokenbridge/arbitrum/StandardArbERC20.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../libraries/Cloneable.sol"; import "../libraries/L2GatewayToken.sol"; diff --git a/contracts/tokenbridge/arbitrum/gateway/L2ArbitrumGateway.sol b/contracts/tokenbridge/arbitrum/gateway/L2ArbitrumGateway.sol index b717c49241..30487e4aa1 100644 --- a/contracts/tokenbridge/arbitrum/gateway/L2ArbitrumGateway.sol +++ b/contracts/tokenbridge/arbitrum/gateway/L2ArbitrumGateway.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Address.sol"; import "../../libraries/AddressAliasHelper.sol"; diff --git a/contracts/tokenbridge/arbitrum/gateway/L2CustomGateway.sol b/contracts/tokenbridge/arbitrum/gateway/L2CustomGateway.sol index ad47799f37..898b7e8330 100644 --- a/contracts/tokenbridge/arbitrum/gateway/L2CustomGateway.sol +++ b/contracts/tokenbridge/arbitrum/gateway/L2CustomGateway.sol @@ -16,12 +16,10 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L2ArbitrumGateway.sol"; import "../../libraries/gateway/ICustomGateway.sol"; - -import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract L2CustomGateway is L2ArbitrumGateway, ICustomGateway { diff --git a/contracts/tokenbridge/arbitrum/gateway/L2ERC20Gateway.sol b/contracts/tokenbridge/arbitrum/gateway/L2ERC20Gateway.sol index 0004d0e530..904d25fc0f 100644 --- a/contracts/tokenbridge/arbitrum/gateway/L2ERC20Gateway.sol +++ b/contracts/tokenbridge/arbitrum/gateway/L2ERC20Gateway.sol @@ -16,9 +16,9 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; -import "@openzeppelin/contracts/proxy/UpgradeableBeacon.sol"; +import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "@openzeppelin/contracts/utils/Create2.sol"; import "./L2ArbitrumGateway.sol"; import "../StandardArbERC20.sol"; diff --git a/contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol b/contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol index e4ee6c79f4..71394ac542 100644 --- a/contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol +++ b/contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../../libraries/gateway/GatewayRouter.sol"; import "../../ethereum/gateway/L1GatewayRouter.sol"; diff --git a/contracts/tokenbridge/arbitrum/gateway/L2ReverseCustomGateway.sol b/contracts/tokenbridge/arbitrum/gateway/L2ReverseCustomGateway.sol index 34d2ce47d9..3b8a9436a0 100644 --- a/contracts/tokenbridge/arbitrum/gateway/L2ReverseCustomGateway.sol +++ b/contracts/tokenbridge/arbitrum/gateway/L2ReverseCustomGateway.sol @@ -16,12 +16,10 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L2CustomGateway.sol"; - -import "@openzeppelin/contracts/math/SafeMath.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title L2 Gateway for reverse "custom" bridging functionality @@ -58,6 +56,6 @@ contract L2ReverseCustomGateway is L2CustomGateway { // and after to calculate the amount of tokens that were transferred IERC20(_l2Token).safeTransferFrom(_from, address(this), _amount); uint256 postBalance = IERC20(_l2Token).balanceOf(address(this)); - return SafeMath.sub(postBalance, prevBalance); + return postBalance - prevBalance; } } diff --git a/contracts/tokenbridge/arbitrum/gateway/L2WethGateway.sol b/contracts/tokenbridge/arbitrum/gateway/L2WethGateway.sol index fbb5a9e567..c4bb7d9e88 100644 --- a/contracts/tokenbridge/arbitrum/gateway/L2WethGateway.sol +++ b/contracts/tokenbridge/arbitrum/gateway/L2WethGateway.sol @@ -16,12 +16,12 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L2ArbitrumGateway.sol"; import "../../libraries/IWETH9.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract L2WethGateway is L2ArbitrumGateway { using SafeERC20 for IERC20; diff --git a/contracts/tokenbridge/ethereum/ICustomToken.sol b/contracts/tokenbridge/ethereum/ICustomToken.sol index afe3f56c9a..2f0a280e3b 100644 --- a/contracts/tokenbridge/ethereum/ICustomToken.sol +++ b/contracts/tokenbridge/ethereum/ICustomToken.sol @@ -20,7 +20,9 @@ pragma solidity >=0.6.9 <0.9.0; interface ArbitrumEnabledToken { - /// @notice should return `0xa4b1` if token is enabled for arbitrum gateways + /// @notice should return `0xb1` if token is enabled for arbitrum gateways + /// @dev Previous implmentation used to return `uint8(0xa4b1)`, however that causes compile time error in Solidity 0.8. due to type mismatch. + /// In current version `uint8(0xb1)` shall be returned, which results in no change as that's the same value as truncated `uint8(0xa4b1)`. function isArbitrumEnabled() external view returns (uint8); } diff --git a/contracts/tokenbridge/ethereum/L1ArbitrumMessenger.sol b/contracts/tokenbridge/ethereum/L1ArbitrumMessenger.sol index 2ff577182d..f433a706a7 100644 --- a/contracts/tokenbridge/ethereum/L1ArbitrumMessenger.sol +++ b/contracts/tokenbridge/ethereum/L1ArbitrumMessenger.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol"; import "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; @@ -94,12 +94,14 @@ abstract contract L1ArbitrumMessenger { uint256 _gasPriceBid, bytes memory _data ) internal returns (uint256) { - uint256 seqNum = IInbox(_inbox).createRetryableTicket{ value: _l1CallValue }( + uint256 seqNum = _createRetryable( + _inbox, _to, + _refundTo, + _user, + _l1CallValue, _l2CallValue, _maxSubmissionCost, - _refundTo, // only refund excess fee to the custom address - _user, // user can cancel the retryable and receive call value refund _maxGas, _gasPriceBid, _data @@ -146,4 +148,57 @@ abstract contract L1ArbitrumMessenger { require(l2ToL1Sender != address(0), "NO_SENDER"); return l2ToL1Sender; } + + /** + * @notice Calls inbox to create retryable ticket. Default implementation is for standard Eth-based rollup, but it can be overriden to create retryable in ERC20-based rollup. + * @param _inbox address of the rollup's inbox + * @param _to destination L2 contract address + * @param _refundTo refund address for excess fee + * @param _user refund address for callvalue + * @param _totalFeeAmount amount of fees to pay, in Eth or native token, for retryable's execution + * @param _l2CallValue call value for retryable L2 message + * @param _maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee + * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution + * @param _gasPriceBid price bid for L2 execution + * @param _data ABI encoded data of L2 message + * @return unique message number of the retryable transaction + */ + function _createRetryable( + address _inbox, + address _to, + address _refundTo, + address _user, + uint256 _totalFeeAmount, + uint256 _l2CallValue, + uint256 _maxSubmissionCost, + uint256 _maxGas, + uint256 _gasPriceBid, + bytes memory _data + ) internal virtual returns (uint256) { + return + IInbox(_inbox).createRetryableTicket{ value: _totalFeeAmount }( + _to, + _l2CallValue, + _maxSubmissionCost, + _refundTo, + _user, + _maxGas, + _gasPriceBid, + _data + ); + } } + +interface IERC20Inbox { + function createRetryableTicket( + address to, + uint256 l2CallValue, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + uint256 tokenTotalFeeAmount, + bytes calldata data + ) external returns (uint256); +} \ No newline at end of file diff --git a/contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol b/contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol new file mode 100644 index 0000000000..9a2fa9ddec --- /dev/null +++ b/contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol @@ -0,0 +1,746 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.4; + +import { + L1TokenBridgeRetryableSender, + L1DeploymentAddresses, + RetryableParams, + L2TemplateAddresses, + IERC20Inbox, + IERC20, + SafeERC20 +} from "./L1TokenBridgeRetryableSender.sol"; +import {L1GatewayRouter} from "./gateway/L1GatewayRouter.sol"; +import {L1ERC20Gateway} from "./gateway/L1ERC20Gateway.sol"; +import {L1CustomGateway} from "./gateway/L1CustomGateway.sol"; +import {L1WethGateway} from "./gateway/L1WethGateway.sol"; +import {L1OrbitGatewayRouter} from "./gateway/L1OrbitGatewayRouter.sol"; +import {L1OrbitERC20Gateway} from "./gateway/L1OrbitERC20Gateway.sol"; +import {L1OrbitCustomGateway} from "./gateway/L1OrbitCustomGateway.sol"; +import { + L2AtomicTokenBridgeFactory, + CanonicalAddressSeed, + OrbitSalts, + L2RuntimeCode, + ProxyAdmin +} from "../arbitrum/L2AtomicTokenBridgeFactory.sol"; +import {BytesLib} from "../libraries/BytesLib.sol"; +import { + IUpgradeExecutor, + UpgradeExecutor +} from "@offchainlabs/upgrade-executor/src/UpgradeExecutor.sol"; +import {AddressAliasHelper} from "../libraries/AddressAliasHelper.sol"; +import {IInbox, IBridge, IOwnable} from "@arbitrum/nitro-contracts/src/bridge/IInbox.sol"; +import {AddressAliasHelper} from "../libraries/AddressAliasHelper.sol"; +import {ArbMulticall2} from "../../rpc-utils/MulticallV2.sol"; +import {BeaconProxyFactory, ClonableBeaconProxy} from "../libraries/ClonableBeaconProxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import { + Initializable, + OwnableUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {IAccessControlUpgradeable} from + "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol"; + +/** + * @title Layer1 token bridge creator + * @notice This contract is used to deploy token bridge on custom L2 chains. + * @dev Throughout the contract terms L1 and L2 are used, but those can be considered as base (N) chain and child (N+1) chain + */ +contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable { + using SafeERC20 for IERC20; + + error L1AtomicTokenBridgeCreator_OnlyRollupOwner(); + error L1AtomicTokenBridgeCreator_InvalidRouterAddr(); + error L1AtomicTokenBridgeCreator_TemplatesNotSet(); + error L1AtomicTokenBridgeCreator_RollupOwnershipMisconfig(); + error L1AtomicTokenBridgeCreator_ProxyAdminNotFound(); + + event OrbitTokenBridgeCreated( + address indexed inbox, + address indexed owner, + address router, + address standardGateway, + address customGateway, + address wethGateway, + address proxyAdmin, + address upgradeExecutor + ); + event OrbitTokenBridgeTemplatesUpdated(); + event NonCanonicalRouterSet(address indexed inbox, address indexed router); + + struct L1Templates { + L1GatewayRouter routerTemplate; + L1ERC20Gateway standardGatewayTemplate; + L1CustomGateway customGatewayTemplate; + L1WethGateway wethGatewayTemplate; + L1OrbitGatewayRouter feeTokenBasedRouterTemplate; + L1OrbitERC20Gateway feeTokenBasedStandardGatewayTemplate; + L1OrbitCustomGateway feeTokenBasedCustomGatewayTemplate; + IUpgradeExecutor upgradeExecutor; + } + + // non-canonical router registry + mapping(address => address) public inboxToNonCanonicalRouter; + + // Hard-code gas to make sure gas limit is big enough for L2 factory deployment to succeed. + // If retryable would've reverted due to too low gas limit, nonce 0 would be burned and + // canonical address for L2 factory would've been unobtainable + uint256 public gasLimitForL2FactoryDeployment; + + // contract which creates retryables for deploying L2 side of token bridge + L1TokenBridgeRetryableSender public retryableSender; + + // L1 logic contracts shared by all token bridges + L1Templates public l1Templates; + + // L2 contracts deployed to L1 as bytecode placeholders + address public l2TokenBridgeFactoryTemplate; + address public l2RouterTemplate; + address public l2StandardGatewayTemplate; + address public l2CustomGatewayTemplate; + address public l2WethGatewayTemplate; + address public l2WethTemplate; + + // WETH address on L1 + address public l1Weth; + + // Multicall2 address on L1, this should NOT be ArbMulticall2 + address public l1Multicall; + + // immutable canonical address for L2 factory + // other canonical addresses (dependent on L2 template implementations) can be fetched through `getCanonicalL2***Address` functions + address public canonicalL2FactoryAddress; + + // immutable ArbMulticall2 template deployed on L1 + // Note - due to contract size limits, multicall template and its bytecode hash are set in constructor as immutables + address public immutable l2MulticallTemplate; + // code hash used for calculation of L2 multicall address + bytes32 public immutable ARB_MULTICALL_CODE_HASH; + + constructor(address _l2MulticallTemplate) { + l2MulticallTemplate = _l2MulticallTemplate; + ARB_MULTICALL_CODE_HASH = keccak256(_creationCodeFor(l2MulticallTemplate.code)); + _disableInitializers(); + } + + function initialize(L1TokenBridgeRetryableSender _retryableSender) public initializer { + __Ownable_init(); + + // store retryable sender and initialize it. This contract will be set as owner + retryableSender = _retryableSender; + retryableSender.initialize(); + + canonicalL2FactoryAddress = + _computeAddress(AddressAliasHelper.applyL1ToL2Alias(address(this)), 0); + } + + /** + * @notice Set addresses of L1 logic contracts and L2 contracts which are deployed on L1. + * @dev L2 contracts are deployed to L1 as bytecode placeholders - that bytecode will be part of retryable + * payload used to deploy contracts on L2 side. + */ + function setTemplates( + L1Templates calldata _l1Templates, + address _l2TokenBridgeFactoryTemplate, + address _l2RouterTemplate, + address _l2StandardGatewayTemplate, + address _l2CustomGatewayTemplate, + address _l2WethGatewayTemplate, + address _l2WethTemplate, + address _l1Weth, + address _l1Multicall, + uint256 _gasLimitForL2FactoryDeployment + ) external onlyOwner { + l1Templates = _l1Templates; + + l2TokenBridgeFactoryTemplate = _l2TokenBridgeFactoryTemplate; + l2RouterTemplate = _l2RouterTemplate; + l2StandardGatewayTemplate = _l2StandardGatewayTemplate; + l2CustomGatewayTemplate = _l2CustomGatewayTemplate; + l2WethGatewayTemplate = _l2WethGatewayTemplate; + l2WethTemplate = _l2WethTemplate; + + l1Weth = _l1Weth; + l1Multicall = _l1Multicall; + + gasLimitForL2FactoryDeployment = _gasLimitForL2FactoryDeployment; + + emit OrbitTokenBridgeTemplatesUpdated(); + } + + /** + * @notice Deploy and initialize token bridge, both L1 and L2 sides, as part of a single TX. + * @dev This is a single entrypoint of L1 token bridge creator. Function deploys L1 side of token bridge and then uses + * 2 retryable tickets to deploy L2 side. 1st retryable deploys L2 factory. And then 'retryable sender' contract + * is called to issue 2nd retryable which deploys and inits the rest of the contracts. L2 chain is determined + * by `inbox` parameter. + * + * Token bridge can be deployed only once for certain inbox. Any further calls to `createTokenBridge` will revert + * because L1 salts are already used at that point and L1 contracts are already deployed at canonical addresses + * for that inbox. + */ + function createTokenBridge( + address inbox, + address rollupOwner, + uint256 maxGasForContracts, + uint256 gasPriceBid + ) external payable { + // templates have to be in place + if (address(l1Templates.routerTemplate) == address(0)) { + revert L1AtomicTokenBridgeCreator_TemplatesNotSet(); + } + + // Check that the rollupOwner account has EXECUTOR role + // on the upgrade executor which is the owner of the rollup + address upgradeExecutor = IInbox(inbox).bridge().rollup().owner(); + if ( + !IAccessControlUpgradeable(upgradeExecutor).hasRole( + UpgradeExecutor(upgradeExecutor).EXECUTOR_ROLE(), rollupOwner + ) + ) { + revert L1AtomicTokenBridgeCreator_RollupOwnershipMisconfig(); + } + + uint256 rollupChainId = IRollupCore(address(IInbox(inbox).bridge().rollup())).chainId(); + + /// deploy L1 side of token bridge + bool isUsingFeeToken = _getFeeToken(inbox) != address(0); + L1DeploymentAddresses memory l1DeploymentAddresses = + _deployL1Contracts(inbox, rollupOwner, upgradeExecutor, isUsingFeeToken, rollupChainId); + + /// deploy factory and then L2 contracts through L2 factory, using 2 retryables calls + if (isUsingFeeToken) { + _deployL2Factory(inbox, gasPriceBid, isUsingFeeToken); + _deployL2ContractsUsingFeeToken( + l1DeploymentAddresses, + inbox, + maxGasForContracts, + gasPriceBid, + rollupOwner, + upgradeExecutor, + rollupChainId + ); + } else { + uint256 valueSpentForFactory = _deployL2Factory(inbox, gasPriceBid, isUsingFeeToken); + uint256 fundsRemaining = msg.value - valueSpentForFactory; + _deployL2ContractsUsingEth( + l1DeploymentAddresses, + inbox, + maxGasForContracts, + gasPriceBid, + fundsRemaining, + rollupOwner, + upgradeExecutor, + rollupChainId + ); + } + } + + /** + * @notice Rollup owner can override canonical router address by registering other non-canonical router. + * @dev Non-canonical router can be unregistered by re-setting it to address(0) - it makes canonical router the valid one. + */ + function setNonCanonicalRouter(address inbox, address nonCanonicalRouter) external { + if (msg.sender != IInbox(inbox).bridge().rollup().owner()) { + revert L1AtomicTokenBridgeCreator_OnlyRollupOwner(); + } + if (nonCanonicalRouter == getCanonicalL1RouterAddress(inbox)) { + revert L1AtomicTokenBridgeCreator_InvalidRouterAddr(); + } + + inboxToNonCanonicalRouter[inbox] = nonCanonicalRouter; + emit NonCanonicalRouterSet(inbox, nonCanonicalRouter); + } + + function getRouter(address inbox) public view returns (address) { + address nonCanonicalRouter = inboxToNonCanonicalRouter[inbox]; + + if (nonCanonicalRouter != address(0)) { + return nonCanonicalRouter; + } + + return getCanonicalL1RouterAddress(inbox); + } + + function _deployL1Contracts( + address inbox, + address rollupOwner, + address upgradeExecutor, + bool isUsingFeeToken, + uint256 chainId + ) internal returns (L1DeploymentAddresses memory l1Addresses) { + // get existing proxy admin and upgrade executor + address proxyAdmin = IInbox_ProxyAdmin(inbox).getProxyAdmin(); + if (proxyAdmin == address(0)) { + revert L1AtomicTokenBridgeCreator_ProxyAdminNotFound(); + } + + // deploy router + address routerTemplate = isUsingFeeToken + ? address(l1Templates.feeTokenBasedRouterTemplate) + : address(l1Templates.routerTemplate); + l1Addresses.router = address( + new TransparentUpgradeableProxy{ salt: _getL1Salt(OrbitSalts.L1_ROUTER, inbox) }( + routerTemplate, + proxyAdmin, + bytes("") + ) + ); + + // deploy and init gateways + l1Addresses.standardGateway = _deployL1StandardGateway( + proxyAdmin, l1Addresses.router, inbox, isUsingFeeToken, chainId + ); + l1Addresses.customGateway = _deployL1CustomGateway( + proxyAdmin, l1Addresses.router, inbox, upgradeExecutor, isUsingFeeToken, chainId + ); + l1Addresses.wethGateway = isUsingFeeToken + ? address(0) + : _deployL1WethGateway(proxyAdmin, l1Addresses.router, inbox, chainId); + l1Addresses.weth = isUsingFeeToken ? address(0) : l1Weth; + + // init router + L1GatewayRouter(l1Addresses.router).initialize( + upgradeExecutor, + l1Addresses.standardGateway, + address(0), + getCanonicalL2RouterAddress(chainId), + inbox + ); + + // emit it + emit OrbitTokenBridgeCreated( + inbox, + rollupOwner, + l1Addresses.router, + l1Addresses.standardGateway, + l1Addresses.customGateway, + l1Addresses.wethGateway, + proxyAdmin, + upgradeExecutor + ); + } + + function _deployL1StandardGateway( + address proxyAdmin, + address router, + address inbox, + bool isUsingFeeToken, + uint256 chainId + ) internal returns (address) { + address template = isUsingFeeToken + ? address(l1Templates.feeTokenBasedStandardGatewayTemplate) + : address(l1Templates.standardGatewayTemplate); + + L1ERC20Gateway standardGateway = L1ERC20Gateway( + address( + new TransparentUpgradeableProxy{ + salt: _getL1Salt(OrbitSalts.L1_STANDARD_GATEWAY, inbox) + }(template, proxyAdmin, bytes("")) + ) + ); + + standardGateway.initialize( + getCanonicalL2StandardGatewayAddress(chainId), + router, + inbox, + keccak256(type(ClonableBeaconProxy).creationCode), + getCanonicalL2BeaconProxyFactoryAddress(chainId) + ); + + return address(standardGateway); + } + + function _deployL1CustomGateway( + address proxyAdmin, + address router, + address inbox, + address upgradeExecutor, + bool isUsingFeeToken, + uint256 chainId + ) internal returns (address) { + address template = isUsingFeeToken + ? address(l1Templates.feeTokenBasedCustomGatewayTemplate) + : address(l1Templates.customGatewayTemplate); + + L1CustomGateway customGateway = L1CustomGateway( + address( + new TransparentUpgradeableProxy{ + salt: _getL1Salt(OrbitSalts.L1_CUSTOM_GATEWAY, inbox) + }(template, proxyAdmin, bytes("")) + ) + ); + + customGateway.initialize( + getCanonicalL2CustomGatewayAddress(chainId), router, inbox, upgradeExecutor + ); + + return address(customGateway); + } + + function _deployL1WethGateway( + address proxyAdmin, + address router, + address inbox, + uint256 chainId + ) internal returns (address) { + L1WethGateway wethGateway = L1WethGateway( + payable( + address( + new TransparentUpgradeableProxy{ + salt: _getL1Salt(OrbitSalts.L1_WETH_GATEWAY, inbox) + }(address(l1Templates.wethGatewayTemplate), proxyAdmin, bytes("")) + ) + ) + ); + + wethGateway.initialize( + getCanonicalL2WethGatewayAddress(chainId), + router, + inbox, + l1Weth, + getCanonicalL2WethAddress(chainId) + ); + + return address(wethGateway); + } + + function _deployL2Factory(address inbox, uint256 gasPriceBid, bool isUsingFeeToken) + internal + returns (uint256) + { + // encode L2 factory bytecode + bytes memory deploymentData = _creationCodeFor(l2TokenBridgeFactoryTemplate.code); + + if (isUsingFeeToken) { + // transfer fee tokens to inbox to pay for 1st retryable + address feeToken = _getFeeToken(inbox); + uint256 retryableFee = gasLimitForL2FactoryDeployment * gasPriceBid; + IERC20(feeToken).safeTransferFrom(msg.sender, inbox, retryableFee); + + IERC20Inbox(inbox).createRetryableTicket( + address(0), + 0, + 0, + msg.sender, + msg.sender, + gasLimitForL2FactoryDeployment, + gasPriceBid, + retryableFee, + deploymentData + ); + return 0; + } else { + uint256 maxSubmissionCost = + IInbox(inbox).calculateRetryableSubmissionFee(deploymentData.length, 0); + uint256 retryableFee = maxSubmissionCost + gasLimitForL2FactoryDeployment * gasPriceBid; + + IInbox(inbox).createRetryableTicket{value: retryableFee}( + address(0), + 0, + maxSubmissionCost, + msg.sender, + msg.sender, + gasLimitForL2FactoryDeployment, + gasPriceBid, + deploymentData + ); + return retryableFee; + } + } + + function _deployL2ContractsUsingEth( + L1DeploymentAddresses memory l1Addresses, + address inbox, + uint256 maxGas, + uint256 gasPriceBid, + uint256 availableFunds, + address rollupOwner, + address upgradeExecutor, + uint256 chainId + ) internal { + retryableSender.sendRetryableUsingEth{value: availableFunds}( + RetryableParams( + inbox, canonicalL2FactoryAddress, msg.sender, msg.sender, maxGas, gasPriceBid + ), + L2TemplateAddresses( + l2RouterTemplate, + l2StandardGatewayTemplate, + l2CustomGatewayTemplate, + l2WethGatewayTemplate, + l2WethTemplate, + address(l1Templates.upgradeExecutor), + l2MulticallTemplate + ), + l1Addresses, + getCanonicalL2StandardGatewayAddress(chainId), + rollupOwner, + msg.sender, + AddressAliasHelper.applyL1ToL2Alias(upgradeExecutor) + ); + } + + function _deployL2ContractsUsingFeeToken( + L1DeploymentAddresses memory l1Addresses, + address inbox, + uint256 maxGas, + uint256 gasPriceBid, + address rollupOwner, + address upgradeExecutor, + uint256 chainId + ) internal { + // transfer fee tokens to inbox to pay for 2nd retryable + address feeToken = _getFeeToken(inbox); + uint256 fee = maxGas * gasPriceBid; + IERC20(feeToken).safeTransferFrom(msg.sender, inbox, fee); + + retryableSender.sendRetryableUsingFeeToken( + RetryableParams( + inbox, canonicalL2FactoryAddress, msg.sender, msg.sender, maxGas, gasPriceBid + ), + L2TemplateAddresses( + l2RouterTemplate, + l2StandardGatewayTemplate, + l2CustomGatewayTemplate, + address(0), + address(0), + address(l1Templates.upgradeExecutor), + l2MulticallTemplate + ), + l1Addresses, + getCanonicalL2StandardGatewayAddress(chainId), + rollupOwner, + AddressAliasHelper.applyL1ToL2Alias(upgradeExecutor) + ); + } + + function getCanonicalL1RouterAddress(address inbox) public view returns (address) { + address expectedL1ProxyAdminAddress = Create2.computeAddress( + _getL1Salt(OrbitSalts.L1_PROXY_ADMIN, inbox), + keccak256(type(ProxyAdmin).creationCode), + address(this) + ); + + bool isUsingFeeToken = _getFeeToken(inbox) != address(0); + address template = isUsingFeeToken + ? address(l1Templates.feeTokenBasedRouterTemplate) + : address(l1Templates.routerTemplate); + + return Create2.computeAddress( + _getL1Salt(OrbitSalts.L1_ROUTER, inbox), + keccak256( + abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode(template, expectedL1ProxyAdminAddress, bytes("")) + ) + ), + address(this) + ); + } + + function getCanonicalL2RouterAddress(uint256 chainId) public view returns (address) { + return _getProxyAddress( + _getL2Salt(OrbitSalts.L2_ROUTER_LOGIC, chainId), + _getL2Salt(OrbitSalts.L2_ROUTER, chainId), + chainId + ); + } + + function getCanonicalL2StandardGatewayAddress(uint256 chainId) public view returns (address) { + return _getProxyAddress( + _getL2Salt(OrbitSalts.L2_STANDARD_GATEWAY_LOGIC, chainId), + _getL2Salt(OrbitSalts.L2_STANDARD_GATEWAY, chainId), + chainId + ); + } + + function getCanonicalL2CustomGatewayAddress(uint256 chainId) public view returns (address) { + return _getProxyAddress( + _getL2Salt(OrbitSalts.L2_CUSTOM_GATEWAY_LOGIC, chainId), + _getL2Salt(OrbitSalts.L2_CUSTOM_GATEWAY, chainId), + chainId + ); + } + + function getCanonicalL2WethGatewayAddress(uint256 chainId) public view returns (address) { + return _getProxyAddress( + _getL2Salt(OrbitSalts.L2_WETH_GATEWAY_LOGIC, chainId), + _getL2Salt(OrbitSalts.L2_WETH_GATEWAY, chainId), + chainId + ); + } + + function getCanonicalL2WethAddress(uint256 chainId) public view returns (address) { + return _getProxyAddress( + _getL2Salt(OrbitSalts.L2_WETH_LOGIC, chainId), + _getL2Salt(OrbitSalts.L2_WETH, chainId), + chainId + ); + } + + function getCanonicalL2ProxyAdminAddress(uint256 chainId) public view returns (address) { + return Create2.computeAddress( + _getL2Salt(OrbitSalts.L2_PROXY_ADMIN, chainId), + keccak256(type(ProxyAdmin).creationCode), + canonicalL2FactoryAddress + ); + } + + function getCanonicalL2BeaconProxyFactoryAddress(uint256 chainId) + public + view + returns (address) + { + return Create2.computeAddress( + _getL2Salt(OrbitSalts.BEACON_PROXY_FACTORY, chainId), + keccak256(type(BeaconProxyFactory).creationCode), + canonicalL2FactoryAddress + ); + } + + function getCanonicalL2UpgradeExecutorAddress(uint256 chainId) public view returns (address) { + return _getProxyAddress( + _getL2Salt(OrbitSalts.L2_EXECUTOR_LOGIC, chainId), + _getL2Salt(OrbitSalts.L2_EXECUTOR, chainId), + chainId + ); + } + + function getCanonicalL2Multicall(uint256 chainId) public view returns (address) { + return Create2.computeAddress( + _getL2Salt(OrbitSalts.L2_MULTICALL, chainId), + ARB_MULTICALL_CODE_HASH, + canonicalL2FactoryAddress + ); + } + + function _getFeeToken(address inbox) internal view returns (address) { + address bridge = address(IInbox(inbox).bridge()); + + (bool success, bytes memory feeTokenAddressData) = + bridge.staticcall(abi.encodeWithSelector(IERC20Bridge.nativeToken.selector)); + + if (!success || feeTokenAddressData.length < 32) { + return address(0); + } + + return BytesLib.toAddress(feeTokenAddressData, 12); + } + + /** + * @notice Compute address of contract deployed using CREATE opcode + * @dev The contract address is derived by RLP encoding the deployer's address and the nonce using the Keccak-256 hashing algorithm. + * More formally: keccak256(rlp.encode([origin, nonce])[12:] + * + * First part of the function implementation does RLP encoding of [origin, nonce]. + * - nonce's prefix is encoded depending on its size -> 0x80 + lenInBytes(nonce) + * - origin is 20 bytes long so its encoded prefix is 0x80 + 0x14 = 0x94 + * - prefix of the whole list is 0xc0 + lenInBytes(RLP(list)) + * After we have RLP encoding in place last step is to hash it, take last 20 bytes and cast is to an address. + * + * @return computed address + */ + function _computeAddress(address origin, uint256 nonce) internal pure returns (address) { + bytes memory data; + if (nonce == 0x00) { + data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), origin, bytes1(0x80)); + } else if (nonce <= 0x7f) { + data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), origin, uint8(nonce)); + } else if (nonce <= 0xff) { + data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), origin, bytes1(0x81), uint8(nonce)); + } else if (nonce <= 0xffff) { + data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), origin, bytes1(0x82), uint16(nonce)); + } else if (nonce <= 0xffffff) { + data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), origin, bytes1(0x83), uint24(nonce)); + } else { + data = abi.encodePacked(bytes1(0xda), bytes1(0x94), origin, bytes1(0x84), uint32(nonce)); + } + return address(uint160(uint256(keccak256(data)))); + } + + /** + * @notice Generate a creation code that results on a contract with `code` as bytecode. + * Source - https://github.com/0xsequence/sstore2/blob/master/contracts/utils/Bytecode.sol + * @param code The returning value of the resulting `creationCode` + * @return creationCode (constructor) for new contract + */ + function _creationCodeFor(bytes memory code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked(hex"63", uint32(code.length), hex"80600E6000396000F3", code); + } + + /** + * @notice L2 contracts are deployed as proxy with dummy seed logic contracts using CREATE2. That enables + * us to upfront calculate the expected canonical addresses. + */ + function _getProxyAddress(bytes32 logicSalt, bytes32 proxySalt, uint256 chainId) + internal + view + returns (address) + { + address logicSeedAddress = Create2.computeAddress( + logicSalt, keccak256(type(CanonicalAddressSeed).creationCode), canonicalL2FactoryAddress + ); + + return Create2.computeAddress( + proxySalt, + keccak256( + abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode( + logicSeedAddress, getCanonicalL2ProxyAdminAddress(chainId), bytes("") + ) + ) + ), + canonicalL2FactoryAddress + ); + } + + /** + * @notice We want to have exactly one set of canonical token bridge contracts for every rollup. For that + * reason we make rollup's inbox address part of the salt. It prevents deploying more than one + * token bridge. + */ + function _getL1Salt(bytes memory prefix, address inbox) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(prefix, inbox)); + } + + /** + * @notice Salt for L2 token bridge contracts depends on the chainId and caller's address. Canonical token bridge + * will be deployed by retryable ticket which is created by `retryableSender` contract. That + * means `retryableSender`'s alias will be used on L2 side to calculate the salt for deploying + * L2 contracts, in addition to chainId (_getL2Salt function in L2AtomicTokenBridgeFactory). + */ + function _getL2Salt(bytes memory prefix, uint256 chainId) internal view returns (bytes32) { + return keccak256( + abi.encodePacked( + prefix, chainId, AddressAliasHelper.applyL1ToL2Alias(address(retryableSender)) + ) + ); + } +} + +interface IERC20Bridge { + function nativeToken() external view returns (address); +} + +interface IInbox_ProxyAdmin { + function getProxyAdmin() external view returns (address); +} + +interface IRollupCore { + function chainId() external view returns (uint256); +} diff --git a/contracts/tokenbridge/ethereum/L1TokenBridgeRetryableSender.sol b/contracts/tokenbridge/ethereum/L1TokenBridgeRetryableSender.sol new file mode 100644 index 0000000000..bde3de250b --- /dev/null +++ b/contracts/tokenbridge/ethereum/L1TokenBridgeRetryableSender.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.4; + +import {IInbox} from "@arbitrum/nitro-contracts/src/bridge/IInbox.sol"; +import { + L2AtomicTokenBridgeFactory, + L2RuntimeCode, + ProxyAdmin +} from "../arbitrum/L2AtomicTokenBridgeFactory.sol"; +import { + Initializable, + OwnableUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @title Token Bridge Retryable Ticket Sender + * @notice This contract is intended to simply send out retryable ticket to deploy L2 side of the token bridge. + * Ticket data is prepared by L1AtomicTokenBridgeCreator. Retryable ticket issuance is done separately + * from L1 creator in order to have different senders for deployment of L2 factory vs. deployment of + * rest of L2 contracts. Having same sender can lead to edge cases where retryables are executed out + * order - that would prevent us from having canonical set of L2 addresses. + * + */ +contract L1TokenBridgeRetryableSender is Initializable, OwnableUpgradeable { + error L1TokenBridgeRetryableSender_RefundFailed(); + + function initialize() public initializer { + __Ownable_init(); + } + + /** + * @notice Creates retryable which deploys L2 side of the token bridge. + * @dev Function will build retryable data, calculate submission cost and retryable value, create retryable + * and then refund the remaining funds to original delpoyer. + */ + function sendRetryableUsingEth( + RetryableParams calldata retryableParams, + L2TemplateAddresses calldata l2, + L1DeploymentAddresses calldata l1, + address l2StandardGatewayAddress, + address rollupOwner, + address deployer, + address aliasedL1UpgradeExecutor + ) external payable onlyOwner { + bytes memory data = abi.encodeCall( + L2AtomicTokenBridgeFactory.deployL2Contracts, + ( + L2RuntimeCode( + l2.routerTemplate.code, + l2.standardGatewayTemplate.code, + l2.customGatewayTemplate.code, + l2.wethGatewayTemplate.code, + l2.wethTemplate.code, + l2.upgradeExecutorTemplate.code, + l2.multicallTemplate.code + ), + l1.router, + l1.standardGateway, + l1.customGateway, + l1.wethGateway, + l1.weth, + l2StandardGatewayAddress, + rollupOwner, + aliasedL1UpgradeExecutor + ) + ); + + uint256 maxSubmissionCost = + IInbox(retryableParams.inbox).calculateRetryableSubmissionFee(data.length, 0); + uint256 retryableValue = + maxSubmissionCost + retryableParams.maxGas * retryableParams.gasPriceBid; + _createRetryableUsingEth(retryableParams, maxSubmissionCost, retryableValue, data); + + // refund excess value to the deployer + uint256 refund = msg.value - retryableValue; + (bool success,) = deployer.call{value: refund}(""); + if (!success) revert L1TokenBridgeRetryableSender_RefundFailed(); + } + + /** + * @notice Creates retryable which deploys L2 side of the token bridge. + * @dev Function will build retryable data, calculate submission cost and retryable value, create retryable + * and then refund the remaining funds to original delpoyer. + */ + function sendRetryableUsingFeeToken( + RetryableParams calldata retryableParams, + L2TemplateAddresses calldata l2, + L1DeploymentAddresses calldata l1, + address l2StandardGatewayAddress, + address rollupOwner, + address aliasedL1UpgradeExecutor + ) external payable onlyOwner { + bytes memory data = abi.encodeCall( + L2AtomicTokenBridgeFactory.deployL2Contracts, + ( + L2RuntimeCode( + l2.routerTemplate.code, + l2.standardGatewayTemplate.code, + l2.customGatewayTemplate.code, + "", + "", + l2.upgradeExecutorTemplate.code, + l2.multicallTemplate.code + ), + l1.router, + l1.standardGateway, + l1.customGateway, + address(0), + address(0), + l2StandardGatewayAddress, + rollupOwner, + aliasedL1UpgradeExecutor + ) + ); + + uint256 retryableFee = retryableParams.maxGas * retryableParams.gasPriceBid; + + _createRetryableUsingFeeToken(retryableParams, retryableFee, data); + } + + function _createRetryableUsingEth( + RetryableParams calldata retryableParams, + uint256 maxSubmissionCost, + uint256 value, + bytes memory data + ) internal { + IInbox(retryableParams.inbox).createRetryableTicket{value: value}( + retryableParams.target, + 0, + maxSubmissionCost, + retryableParams.excessFeeRefundAddress, + retryableParams.callValueRefundAddress, + retryableParams.maxGas, + retryableParams.gasPriceBid, + data + ); + } + + function _createRetryableUsingFeeToken( + RetryableParams calldata retryableParams, + uint256 retryableFee, + bytes memory data + ) internal { + IERC20Inbox(retryableParams.inbox).createRetryableTicket( + retryableParams.target, + 0, + 0, + retryableParams.excessFeeRefundAddress, + retryableParams.callValueRefundAddress, + retryableParams.maxGas, + retryableParams.gasPriceBid, + retryableFee, + data + ); + } +} + +/** + * retryableParams needed to send retryable ticket + */ +struct RetryableParams { + address inbox; + address target; + address excessFeeRefundAddress; + address callValueRefundAddress; + uint256 maxGas; + uint256 gasPriceBid; +} + +/** + * Addresses of L2 templates deployed on L1 + */ +struct L2TemplateAddresses { + address routerTemplate; + address standardGatewayTemplate; + address customGatewayTemplate; + address wethGatewayTemplate; + address wethTemplate; + address upgradeExecutorTemplate; + address multicallTemplate; +} + +/** + * L1 side of token bridge addresses + */ +struct L1DeploymentAddresses { + address router; + address standardGateway; + address customGateway; + address wethGateway; + address weth; +} + +interface IERC20Inbox { + function createRetryableTicket( + address to, + uint256 l2CallValue, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + uint256 tokenTotalFeeAmount, + bytes calldata data + ) external returns (uint256); +} diff --git a/contracts/tokenbridge/ethereum/gateway/L1ArbitrumExtendedGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1ArbitrumExtendedGateway.sol index 46d4c680d4..63bb7c434c 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1ArbitrumExtendedGateway.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1ArbitrumExtendedGateway.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../../libraries/ITransferAndCall.sol"; @@ -31,6 +31,8 @@ interface ITradeableExitReceiver { } abstract contract L1ArbitrumExtendedGateway is L1ArbitrumGateway { + using Address for address; + struct ExitData { bool isExit; address _newTo; diff --git a/contracts/tokenbridge/ethereum/gateway/L1ArbitrumGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1ArbitrumGateway.sol index 3ac89dee43..8ac88717a4 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1ArbitrumGateway.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1ArbitrumGateway.sol @@ -16,13 +16,12 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Create2.sol"; import "@openzeppelin/contracts/utils/Address.sol"; -import "@openzeppelin/contracts/math/SafeMath.sol"; import "../L1ArbitrumMessenger.sol"; import "./IL1ArbitrumGateway.sol"; import "../../libraries/ProxyUtil.sol"; @@ -253,6 +252,7 @@ abstract contract L1ArbitrumGateway is bytes memory extraData; { uint256 _maxSubmissionCost; + uint256 tokenTotalFeeAmount; if (super.isRouter(msg.sender)) { // router encoded (_from, extraData) = GatewayMessageHandler.parseFromRouterToGateway(_data); @@ -260,8 +260,9 @@ abstract contract L1ArbitrumGateway is _from = msg.sender; extraData = _data; } - // user encoded - (_maxSubmissionCost, extraData) = abi.decode(extraData, (uint256, bytes)); + // unpack user encoded data + (_maxSubmissionCost, extraData, tokenTotalFeeAmount) = _parseUserEncodedData(extraData); + // the inboundEscrowAndCall functionality has been disabled, so no data is allowed require(extraData.length == 0, "EXTRA_DATA_DISABLED"); @@ -274,13 +275,14 @@ abstract contract L1ArbitrumGateway is // we override the res field to save on the stack res = getOutboundCalldata(_l1Token, _from, _to, _amount, extraData); - seqNum = createOutboundTxCustomRefund( + seqNum = _initiateDeposit( _refundTo, _from, _amount, _maxGas, _gasPriceBid, _maxSubmissionCost, + tokenTotalFeeAmount, res ); } @@ -298,7 +300,7 @@ abstract contract L1ArbitrumGateway is uint256 prevBalance = IERC20(_l1Token).balanceOf(address(this)); IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount); uint256 postBalance = IERC20(_l1Token).balanceOf(address(this)); - return SafeMath.sub(postBalance, prevBalance); + return postBalance - prevBalance; } function getOutboundCalldata( @@ -339,4 +341,64 @@ abstract contract L1ArbitrumGateway is interfaceId == this.outboundTransferCustomRefund.selector || super.supportsInterface(interfaceId); } + + /** + * @notice Parse data that was encoded by user and passed into the outbound TX entrypoint + * @dev In case of standard ETH-based rollup, format of encoded data is expected to be: + * - maxSubmissionCost (uint256) + * - callHookData (bytes) + * In case of ERC20-based rollup, format of encoded data is expected to be: + * - maxSubmissionCost (uint256) + * - tokenTotalFeeAmount (uint256) + * - callHookData (bytes) + * @param data data encoded by user + * @return maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee + * @return callHookData Calldata for extra call in inboundEscrowAndCall on L2 + * @return tokenTotalFeeAmount Amount of fees to be deposited in native token to cover for retryable ticket cost (used only in ERC20-based rollups, otherwise 0) + */ + function _parseUserEncodedData(bytes memory data) + internal + pure + virtual + returns ( + uint256 maxSubmissionCost, + bytes memory callHookData, + uint256 tokenTotalFeeAmount + ) + { + (maxSubmissionCost, callHookData) = abi.decode(data, (uint256, bytes)); + } + + /** + * @notice Intermediate internal function that passes on parameters needed to trigger creation of retryable ticket. + * @param _refundTo Account, or its L2 alias if it have code in L1, to be credited with excess gas refund in L2 + * @param _from Initiator of deposit + * @param _amount Token amount being deposited + * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution + * @param _gasPriceBid Gas price for L2 execution + * @param _maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee + * @param _data encoded data from router and user + * @return res abi encoded inbox sequence number + */ + function _initiateDeposit( + address _refundTo, + address _from, + uint256 _amount, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256, // tokenTotalFeeAmount - amount of fees to be deposited in native token to cover for retryable ticket cost (used only in ERC20-based rollups) + bytes memory _data + ) internal virtual returns (uint256) { + return + createOutboundTxCustomRefund( + _refundTo, + _from, + _amount, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + _data + ); + } } diff --git a/contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol index 079c24cbbd..f5c13c82ec 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import { ArbitrumEnabledToken } from "../ICustomToken.sol"; import "./L1ArbitrumExtendedGateway.sol"; @@ -113,7 +113,12 @@ contract L1CustomGateway is L1ArbitrumExtendedGateway, ICustomGateway { * @param l1ERC20 address of L1 token * @return L2 address of a bridged ERC20 token */ - function calculateL2TokenAddress(address l1ERC20) public view override returns (address) { + function calculateL2TokenAddress(address l1ERC20) + public + view + override(ITokenGateway, TokenGateway) + returns (address) + { return l1ToL2Token[l1ERC20]; } @@ -130,7 +135,7 @@ contract L1CustomGateway is L1ArbitrumExtendedGateway, ICustomGateway { uint256 _maxGas, uint256 _gasPriceBid, uint256 _maxSubmissionCost - ) external payable returns (uint256) { + ) external payable virtual returns (uint256) { return registerTokenToL2(_l2Address, _maxGas, _gasPriceBid, _maxSubmissionCost, msg.sender); } @@ -150,15 +155,36 @@ contract L1CustomGateway is L1ArbitrumExtendedGateway, ICustomGateway { uint256 _maxSubmissionCost, address _creditBackAddress ) public payable virtual returns (uint256) { - require( - ArbitrumEnabledToken(msg.sender).isArbitrumEnabled() == uint8(0xa4b1), - "NOT_ARB_ENABLED" - ); + return + _registerTokenToL2( + _l2Address, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + _creditBackAddress, + msg.value + ); + } + + function _registerTokenToL2( + address _l2Address, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + address _creditBackAddress, + uint256 _feeAmount + ) internal returns (uint256) { + { + require( + ArbitrumEnabledToken(msg.sender).isArbitrumEnabled() == uint8(0xb1), + "NOT_ARB_ENABLED" + ); - address currL2Addr = l1ToL2Token[msg.sender]; - if (currL2Addr != address(0)) { - // if token is already set, don't allow it to set a different L2 address - require(currL2Addr == _l2Address, "NO_UPDATE_TO_DIFFERENT_ADDR"); + address currL2Addr = l1ToL2Token[msg.sender]; + if (currL2Addr != address(0)) { + // if token is already set, don't allow it to set a different L2 address + require(currL2Addr == _l2Address, "NO_UPDATE_TO_DIFFERENT_ADDR"); + } } l1ToL2Token[msg.sender] = _l2Address; @@ -181,7 +207,7 @@ contract L1CustomGateway is L1ArbitrumExtendedGateway, ICustomGateway { inbox, counterpartGateway, _creditBackAddress, - msg.value, + _feeAmount, 0, _maxSubmissionCost, _maxGas, @@ -211,7 +237,26 @@ contract L1CustomGateway is L1ArbitrumExtendedGateway, ICustomGateway { uint256 _maxGas, uint256 _gasPriceBid, uint256 _maxSubmissionCost - ) external payable onlyOwner returns (uint256) { + ) external payable virtual onlyOwner returns (uint256) { + return + _forceRegisterTokenToL2( + _l1Addresses, + _l2Addresses, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + msg.value + ); + } + + function _forceRegisterTokenToL2( + address[] calldata _l1Addresses, + address[] calldata _l2Addresses, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 _feeAmount + ) internal returns (uint256) { require(_l1Addresses.length == _l2Addresses.length, "INVALID_LENGTHS"); for (uint256 i = 0; i < _l1Addresses.length; i++) { @@ -232,7 +277,7 @@ contract L1CustomGateway is L1ArbitrumExtendedGateway, ICustomGateway { inbox, counterpartGateway, msg.sender, - msg.value, + _feeAmount, 0, _maxSubmissionCost, _maxGas, diff --git a/contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol b/contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol index b9d3a4fd6e..bbf48bab47 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L1ArbitrumExtendedGateway.sol"; import "@openzeppelin/contracts/utils/Create2.sol"; @@ -62,7 +62,7 @@ contract L1ERC20Gateway is L1ArbitrumExtendedGateway { uint256 _maxGas, uint256 _gasPriceBid, bytes calldata _data - ) public payable override nonReentrant returns (bytes memory res) { + ) public payable virtual override nonReentrant returns (bytes memory res) { return super.outboundTransferCustomRefund( _l1Token, @@ -149,7 +149,12 @@ contract L1ERC20Gateway is L1ArbitrumExtendedGateway { return outboundCalldata; } - function calculateL2TokenAddress(address l1ERC20) public view override returns (address) { + function calculateL2TokenAddress(address l1ERC20) + public + view + override(ITokenGateway, TokenGateway) + returns (address) + { bytes32 salt = getSalt(l1ERC20); return Create2.computeAddress(salt, cloneableProxyHash, l2BeaconProxyFactory); } diff --git a/contracts/tokenbridge/ethereum/gateway/L1ForceOnlyReverseCustomGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1ForceOnlyReverseCustomGateway.sol index 2e5c2f5727..32d0026df7 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1ForceOnlyReverseCustomGateway.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1ForceOnlyReverseCustomGateway.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L1ReverseCustomGateway.sol"; diff --git a/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol b/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol index e035aca87f..f5aef49d97 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../../libraries/Whitelist.sol"; @@ -39,6 +39,8 @@ contract L1GatewayRouter is ERC165, IL1GatewayRouter { + using Address for address; + address public override owner; address public override inbox; @@ -65,7 +67,24 @@ contract L1GatewayRouter is uint256 _maxGas, uint256 _gasPriceBid, uint256 _maxSubmissionCost - ) external payable onlyOwner returns (uint256) { + ) external payable virtual onlyOwner returns (uint256) { + return + _setDefaultGateway( + newL1DefaultGateway, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + msg.value + ); + } + + function _setDefaultGateway( + address newL1DefaultGateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 feeAmount + ) internal returns (uint256) { defaultGateway = newL1DefaultGateway; emit DefaultGatewayUpdated(newL1DefaultGateway); @@ -86,7 +105,7 @@ contract L1GatewayRouter is inbox, counterpartGateway, msg.sender, - msg.value, + feeAmount, 0, L2GasParams({ _maxSubmissionCost: _maxSubmissionCost, @@ -103,54 +122,6 @@ contract L1GatewayRouter is owner = newOwner; } - function _setGateways( - address[] memory _token, - address[] memory _gateway, - uint256 _maxGas, - uint256 _gasPriceBid, - uint256 _maxSubmissionCost, - address _creditBackAddress - ) internal returns (uint256) { - require(_token.length == _gateway.length, "WRONG_LENGTH"); - - for (uint256 i = 0; i < _token.length; i++) { - l1TokenToGateway[_token[i]] = _gateway[i]; - emit GatewaySet(_token[i], _gateway[i]); - // overwrite memory so the L2 router receives the L2 address of each gateway - if (_gateway[i] != address(0) && _gateway[i] != DISABLED) { - // if we are assigning a gateway to the token, the address oracle of the gateway - // must return something other than the 0 address - // this check helps avoid misconfiguring gateways - require( - TokenGateway(_gateway[i]).calculateL2TokenAddress(_token[i]) != address(0), - "TOKEN_NOT_HANDLED_BY_GATEWAY" - ); - _gateway[i] = TokenGateway(_gateway[i]).counterpartGateway(); - } - } - - bytes memory data = abi.encodeWithSelector( - L2GatewayRouter.setGateway.selector, - _token, - _gateway - ); - - return - sendTxToL2( - inbox, - counterpartGateway, - _creditBackAddress, - msg.value, - 0, - L2GasParams({ - _maxSubmissionCost: _maxSubmissionCost, - _maxGas: _maxGas, - _gasPriceBid: _gasPriceBid - }), - data - ); - } - /** * @notice Allows L1 Token contract to trustlessly register its gateway. (other setGateway method allows excess eth recovery from _maxSubmissionCost and is recommended) * @param _gateway l1 gateway address @@ -164,7 +135,7 @@ contract L1GatewayRouter is uint256 _maxGas, uint256 _gasPriceBid, uint256 _maxSubmissionCost - ) external payable override returns (uint256) { + ) external payable virtual override returns (uint256) { return setGateway(_gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, msg.sender); } @@ -183,11 +154,31 @@ contract L1GatewayRouter is uint256 _gasPriceBid, uint256 _maxSubmissionCost, address _creditBackAddress - ) public payable override returns (uint256) { + ) public payable virtual override returns (uint256) { + return + _setGatewayWithCreditBack( + _gateway, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + _creditBackAddress, + msg.value + ); + } + + function _setGatewayWithCreditBack( + address _gateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + address _creditBackAddress, + uint256 feeAmount + ) internal returns (uint256) { require( - ArbitrumEnabledToken(msg.sender).isArbitrumEnabled() == uint8(0xa4b1), + ArbitrumEnabledToken(msg.sender).isArbitrumEnabled() == uint8(0xb1), "NOT_ARB_ENABLED" ); + require(_gateway.isContract(), "NOT_TO_CONTRACT"); address currGateway = getGateway(msg.sender); @@ -209,7 +200,8 @@ contract L1GatewayRouter is _maxGas, _gasPriceBid, _maxSubmissionCost, - _creditBackAddress + _creditBackAddress, + feeAmount ); } @@ -219,11 +211,68 @@ contract L1GatewayRouter is uint256 _maxGas, uint256 _gasPriceBid, uint256 _maxSubmissionCost - ) external payable onlyOwner returns (uint256) { + ) external payable virtual onlyOwner returns (uint256) { // it is assumed that token and gateway are both contracts // require(_token[i].isContract() && _gateway[i].isContract(), "NOT_CONTRACT"); return - _setGateways(_token, _gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, msg.sender); + _setGateways( + _token, + _gateway, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + msg.sender, + msg.value + ); + } + + function _setGateways( + address[] memory _token, + address[] memory _gateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + address _creditBackAddress, + uint256 feeAmount + ) internal returns (uint256) { + require(_token.length == _gateway.length, "WRONG_LENGTH"); + + for (uint256 i = 0; i < _token.length; i++) { + l1TokenToGateway[_token[i]] = _gateway[i]; + emit GatewaySet(_token[i], _gateway[i]); + // overwrite memory so the L2 router receives the L2 address of each gateway + if (_gateway[i] != address(0) && _gateway[i] != DISABLED) { + // if we are assigning a gateway to the token, the address oracle of the gateway + // must return something other than the 0 address + // this check helps avoid misconfiguring gateways + require( + TokenGateway(_gateway[i]).calculateL2TokenAddress(_token[i]) != address(0), + "TOKEN_NOT_HANDLED_BY_GATEWAY" + ); + _gateway[i] = TokenGateway(_gateway[i]).counterpartGateway(); + } + } + + bytes memory data = abi.encodeWithSelector( + L2GatewayRouter.setGateway.selector, + _token, + _gateway + ); + + return + sendTxToL2( + inbox, + counterpartGateway, + _creditBackAddress, + feeAmount, + 0, + L2GasParams({ + _maxSubmissionCost: _maxSubmissionCost, + _maxGas: _maxGas, + _gasPriceBid: _gasPriceBid + }), + data + ); } function outboundTransfer( diff --git a/contracts/tokenbridge/ethereum/gateway/L1OrbitCustomGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1OrbitCustomGateway.sol new file mode 100644 index 0000000000..a1851d886b --- /dev/null +++ b/contracts/tokenbridge/ethereum/gateway/L1OrbitCustomGateway.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1CustomGateway } from "./L1CustomGateway.sol"; +import { IERC20Inbox } from "../L1ArbitrumMessenger.sol"; +import { IERC20Bridge } from "../../libraries/IERC20Bridge.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @title Gateway for "custom" bridging functionality in an ERC20-based rollup. + * @notice Adds new entrypoints that have `_feeAmount` as parameter, while entrypoints without that parameter are reverted. + */ +contract L1OrbitCustomGateway is L1CustomGateway { + using SafeERC20 for IERC20; + + /** + * @notice Allows L1 Token contract to trustlessly register its custom L2 counterpart, in an ERC20-based rollup. Retryable costs are paid in native token. + * @param _l2Address counterpart address of L1 token + * @param _maxGas max gas for L2 retryable execution + * @param _gasPriceBid gas price for L2 retryable ticket + * @param _maxSubmissionCost base submission cost for L2 retryable ticket + * @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge. + * @return Retryable ticket ID + */ + function registerTokenToL2( + address _l2Address, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 _feeAmount + ) external returns (uint256) { + return + registerTokenToL2( + _l2Address, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + msg.sender, + _feeAmount + ); + } + + /** + * @notice Allows L1 Token contract to trustlessly register its custom L2 counterpart, in an ERC20-based rollup. Retryable costs are paid in native token. + * @param _l2Address counterpart address of L1 token + * @param _maxGas max gas for L2 retryable execution + * @param _gasPriceBid gas price for L2 retryable ticket + * @param _maxSubmissionCost base submission cost for L2 retryable ticket + * @param _creditBackAddress address for crediting back overpayment of _maxSubmissionCost + * @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge. + * @return Retryable ticket ID + */ + function registerTokenToL2( + address _l2Address, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + address _creditBackAddress, + uint256 _feeAmount + ) public returns (uint256) { + return + _registerTokenToL2( + _l2Address, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + _creditBackAddress, + _feeAmount + ); + } + + /** + * @notice Allows owner to force register a custom L1/L2 token pair. + * @dev _l1Addresses[i] counterpart is assumed to be _l2Addresses[i] + * @param _l1Addresses array of L1 addresses + * @param _l2Addresses array of L2 addresses + * @param _maxGas max gas for L2 retryable execution + * @param _gasPriceBid gas price for L2 retryable ticket + * @param _maxSubmissionCost base submission cost for L2 retryable ticket + * @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge. + * @return Retryable ticket ID + */ + function forceRegisterTokenToL2( + address[] calldata _l1Addresses, + address[] calldata _l2Addresses, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 _feeAmount + ) external onlyOwner returns (uint256) { + return + _forceRegisterTokenToL2( + _l1Addresses, + _l2Addresses, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + _feeAmount + ); + } + + /** + * @notice Revert 'registerTokenToL2' entrypoint which doesn't have total amount of token fees as an argument. + */ + function registerTokenToL2( + address, + uint256, + uint256, + uint256, + address + ) public payable override returns (uint256) { + revert("NOT_SUPPORTED_IN_ORBIT"); + } + + /** + * @notice Revert 'registerTokenToL2' entrypoint which doesn't have total amount of token fees as an argument. + */ + function registerTokenToL2( + address, + uint256, + uint256, + uint256 + ) external payable override returns (uint256) { + revert("NOT_SUPPORTED_IN_ORBIT"); + } + + /** + * @notice Revert 'forceRegisterTokenToL2' entrypoint which doesn't have total amount of token fees as an argument. + */ + function forceRegisterTokenToL2( + address[] calldata, + address[] calldata, + uint256, + uint256, + uint256 + ) external payable override onlyOwner returns (uint256) { + revert("NOT_SUPPORTED_IN_ORBIT"); + } + + function _parseUserEncodedData(bytes memory data) + internal + pure + override + returns ( + uint256 maxSubmissionCost, + bytes memory callHookData, + uint256 tokenTotalFeeAmount + ) + { + (maxSubmissionCost, callHookData, tokenTotalFeeAmount) = abi.decode( + data, + (uint256, bytes, uint256) + ); + } + + function _initiateDeposit( + address _refundTo, + address _from, + uint256, // _amount, this info is already contained in _data + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 tokenTotalFeeAmount, + bytes memory _data + ) internal override returns (uint256) { + return + sendTxToL2CustomRefund( + inbox, + counterpartGateway, + _refundTo, + _from, + tokenTotalFeeAmount, + 0, + L2GasParams({ + _maxSubmissionCost: _maxSubmissionCost, + _maxGas: _maxGas, + _gasPriceBid: _gasPriceBid + }), + _data + ); + } + + function _createRetryable( + address _inbox, + address _to, + address _refundTo, + address _user, + uint256 _totalFeeAmount, + uint256 _l2CallValue, + uint256 _maxSubmissionCost, + uint256 _maxGas, + uint256 _gasPriceBid, + bytes memory _data + ) internal override returns (uint256) { + { + // Transfer native token amount needed to pay for retryable fees to the inbox. + // Fee tokens will be transferred from user who initiated the action - that's `_user` account in + // case call was routed by router, or msg.sender in case gateway's entrypoint was called directly. + address nativeFeeToken = IERC20Bridge(address(getBridge(_inbox))).nativeToken(); + uint256 inboxNativeTokenBalance = IERC20(nativeFeeToken).balanceOf(_inbox); + if (inboxNativeTokenBalance < _totalFeeAmount) { + address transferFrom = isRouter(msg.sender) ? _user : msg.sender; + IERC20(nativeFeeToken).safeTransferFrom( + transferFrom, + _inbox, + _totalFeeAmount - inboxNativeTokenBalance + ); + } + } + + return + IERC20Inbox(_inbox).createRetryableTicket( + _to, + _l2CallValue, + _maxSubmissionCost, + _refundTo, + _user, + _maxGas, + _gasPriceBid, + _totalFeeAmount, + _data + ); + } +} diff --git a/contracts/tokenbridge/ethereum/gateway/L1OrbitERC20Gateway.sol b/contracts/tokenbridge/ethereum/gateway/L1OrbitERC20Gateway.sol new file mode 100644 index 0000000000..ca272641ce --- /dev/null +++ b/contracts/tokenbridge/ethereum/gateway/L1OrbitERC20Gateway.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1ERC20Gateway, IERC20 } from "./L1ERC20Gateway.sol"; +import { IERC20Inbox } from "../L1ArbitrumMessenger.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { IERC20Bridge } from "../../libraries/IERC20Bridge.sol"; + +/** + * @title Layer 1 Gateway contract for bridging standard ERC20s in ERC20-based rollup + * @notice This contract handles token deposits, holds the escrowed tokens on layer 1, and (ultimately) finalizes withdrawals. + * @dev Any ERC20 that requires non-standard functionality should use a separate gateway. + * Messages to layer 2 use the inbox's createRetryableTicket method. + */ +contract L1OrbitERC20Gateway is L1ERC20Gateway { + using SafeERC20 for IERC20; + + function outboundTransferCustomRefund( + address _l1Token, + address _refundTo, + address _to, + uint256 _amount, + uint256 _maxGas, + uint256 _gasPriceBid, + bytes calldata _data + ) public payable override returns (bytes memory res) { + // fees are paid in native token, so there is no use for ether + require(msg.value == 0, "NO_VALUE"); + + // We don't allow bridging of native token to avoid having multiple representations of it + // on child chain. Native token can be bridged directly through inbox using depositERC20(). + require(_l1Token != _getNativeFeeToken(), "NOT_ALLOWED_TO_BRIDGE_FEE_TOKEN"); + + return + super.outboundTransferCustomRefund( + _l1Token, + _refundTo, + _to, + _amount, + _maxGas, + _gasPriceBid, + _data + ); + } + + function _parseUserEncodedData(bytes memory data) + internal + pure + override + returns ( + uint256 maxSubmissionCost, + bytes memory callHookData, + uint256 tokenTotalFeeAmount + ) + { + (maxSubmissionCost, callHookData, tokenTotalFeeAmount) = abi.decode( + data, + (uint256, bytes, uint256) + ); + } + + function _initiateDeposit( + address _refundTo, + address _from, + uint256, // _amount, this info is already contained in _data + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 tokenTotalFeeAmount, + bytes memory _data + ) internal override returns (uint256) { + return + sendTxToL2CustomRefund( + inbox, + counterpartGateway, + _refundTo, + _from, + tokenTotalFeeAmount, + 0, + L2GasParams({ + _maxSubmissionCost: _maxSubmissionCost, + _maxGas: _maxGas, + _gasPriceBid: _gasPriceBid + }), + _data + ); + } + + function _createRetryable( + address _inbox, + address _to, + address _refundTo, + address _user, + uint256 _totalFeeAmount, + uint256 _l2CallValue, + uint256 _maxSubmissionCost, + uint256 _maxGas, + uint256 _gasPriceBid, + bytes memory _data + ) internal override returns (uint256) { + { + // Transfer native token amount needed to pay for retryable fees to the inbox. + // Fee tokens will be transferred from user who initiated the action - that's `_user` account in + // case call was routed by router, or msg.sender in case gateway's entrypoint was called directly. + address nativeFeeToken = _getNativeFeeToken(); + uint256 inboxNativeTokenBalance = IERC20(nativeFeeToken).balanceOf(_inbox); + if (inboxNativeTokenBalance < _totalFeeAmount) { + address transferFrom = isRouter(msg.sender) ? _user : msg.sender; + IERC20(nativeFeeToken).safeTransferFrom( + transferFrom, + _inbox, + _totalFeeAmount - inboxNativeTokenBalance + ); + } + } + + return + IERC20Inbox(_inbox).createRetryableTicket( + _to, + _l2CallValue, + _maxSubmissionCost, + _refundTo, + _user, + _maxGas, + _gasPriceBid, + _totalFeeAmount, + _data + ); + } + + /** + * @notice get rollup's native token that's used to pay for fees + */ + function _getNativeFeeToken() internal view returns (address) { + address bridge = address(getBridge(inbox)); + return IERC20Bridge(bridge).nativeToken(); + } +} diff --git a/contracts/tokenbridge/ethereum/gateway/L1OrbitGatewayRouter.sol b/contracts/tokenbridge/ethereum/gateway/L1OrbitGatewayRouter.sol new file mode 100644 index 0000000000..a7322eba4e --- /dev/null +++ b/contracts/tokenbridge/ethereum/gateway/L1OrbitGatewayRouter.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1GatewayRouter } from "./L1GatewayRouter.sol"; +import { IERC20Inbox } from "../L1ArbitrumMessenger.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { IERC20Bridge } from "../../libraries/IERC20Bridge.sol"; + +/** + * @title Handles deposits from L1 into L2 in ERC20-based rollups where custom token is used to pay for fees. Tokens are routed to their appropriate L1 gateway. + * @notice Router itself also conforms to the Gateway interface. Router also serves as an L1-L2 token address oracle. + */ +contract L1OrbitGatewayRouter is L1GatewayRouter { + using SafeERC20 for IERC20; + + /** + * @notice Allows owner to register the default gateway. + * @param newL1DefaultGateway default gateway address + * @param _maxGas max gas for L2 retryable execution + * @param _gasPriceBid gas price for L2 retryable ticket + * @param _maxSubmissionCost base submission cost for L2 retryable ticket + * @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge. + * @return Retryable ticket ID + */ + function setDefaultGateway( + address newL1DefaultGateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 _feeAmount + ) external onlyOwner returns (uint256) { + return + _setDefaultGateway( + newL1DefaultGateway, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + _feeAmount + ); + } + + /** + * @notice Allows L1 Token contract to trustlessly register its gateway. + * @dev Other setGateway method allows excess eth recovery from _maxSubmissionCost and is recommended. + * @param _gateway l1 gateway address + * @param _maxGas max gas for L2 retryable execution + * @param _gasPriceBid gas price for L2 retryable ticket + * @param _maxSubmissionCost base submission cost for L2 retryable ticket + * @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge. + * @return Retryable ticket ID + */ + function setGateway( + address _gateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 _feeAmount + ) external returns (uint256) { + return + setGateway(_gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, msg.sender, _feeAmount); + } + + /** + * @notice Allows L1 Token contract to trustlessly register its gateway. + * @dev Other setGateway method allows excess eth recovery from _maxSubmissionCost and is recommended. + * @param _gateway l1 gateway address + * @param _maxGas max gas for L2 retryable execution + * @param _gasPriceBid gas price for L2 retryable ticket + * @param _maxSubmissionCost base submission cost L2 retryable tick3et + * @param _creditBackAddress address for crediting back overpayment of _maxSubmissionCost + * @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge. + * @return Retryable ticket ID + */ + function setGateway( + address _gateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + address _creditBackAddress, + uint256 _feeAmount + ) public returns (uint256) { + return + _setGatewayWithCreditBack( + _gateway, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + _creditBackAddress, + _feeAmount + ); + } + + /** + * @notice Allows owner to register gateways for specific tokens. + * @param _token list of L1 token addresses + * @param _gateway list of L1 gateway addresses + * @param _maxGas max gas for L2 retryable execution + * @param _gasPriceBid gas price for L2 retryable ticket + * @param _maxSubmissionCost base submission cost for L2 retryable ticket + * @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge. + * @return Retryable ticket ID + */ + function setGateways( + address[] memory _token, + address[] memory _gateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + uint256 _feeAmount + ) external onlyOwner returns (uint256) { + return + _setGateways( + _token, + _gateway, + _maxGas, + _gasPriceBid, + _maxSubmissionCost, + msg.sender, + _feeAmount + ); + } + + function _createRetryable( + address _inbox, + address _to, + address _refundTo, + address _user, + uint256 _totalFeeAmount, + uint256 _l2CallValue, + uint256 _maxSubmissionCost, + uint256 _maxGas, + uint256 _gasPriceBid, + bytes memory _data + ) internal override returns (uint256) { + { + // Transfer native token amount needed to pay for retryable fees to the inbox. + // Fee tokens will be transferred from msg.sender + address nativeFeeToken = IERC20Bridge(address(getBridge(_inbox))).nativeToken(); + uint256 inboxNativeTokenBalance = IERC20(nativeFeeToken).balanceOf(_inbox); + if (inboxNativeTokenBalance < _totalFeeAmount) { + uint256 diff = _totalFeeAmount - inboxNativeTokenBalance; + IERC20(nativeFeeToken).safeTransferFrom(msg.sender, _inbox, diff); + } + } + + return + IERC20Inbox(_inbox).createRetryableTicket( + _to, + _l2CallValue, + _maxSubmissionCost, + _refundTo, + _user, + _maxGas, + _gasPriceBid, + _totalFeeAmount, + _data + ); + } + + /** + * @notice Revert 'setGateway' entrypoint which doesn't have total amount of token fees as an argument. + */ + function setGateway( + address, + uint256, + uint256, + uint256, + address + ) public payable override returns (uint256) { + revert("NOT_SUPPORTED_IN_ORBIT"); + } + + /** + * @notice Revert 'setDefaultGateway' entrypoint which doesn't have total amount of token fees as an argument. + */ + function setDefaultGateway( + address, + uint256, + uint256, + uint256 + ) external payable override onlyOwner returns (uint256) { + revert("NOT_SUPPORTED_IN_ORBIT"); + } + + /** + * @notice Revert 'setGateway' entrypoint which doesn't have total amount of token fees as an argument. + */ + function setGateway( + address, + uint256, + uint256, + uint256 + ) external payable override returns (uint256) { + revert("NOT_SUPPORTED_IN_ORBIT"); + } + + /** + * @notice Revert 'setGateways' entrypoint which doesn't have total amount of token fees as an argument. + */ + function setGateways( + address[] memory, + address[] memory, + uint256, + uint256, + uint256 + ) external payable override onlyOwner returns (uint256) { + revert("NOT_SUPPORTED_IN_ORBIT"); + } +} diff --git a/contracts/tokenbridge/ethereum/gateway/L1OrbitReverseCustomGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1OrbitReverseCustomGateway.sol new file mode 100644 index 0000000000..da07bb5dd7 --- /dev/null +++ b/contracts/tokenbridge/ethereum/gateway/L1OrbitReverseCustomGateway.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1OrbitCustomGateway } from "./L1OrbitCustomGateway.sol"; +import { IArbToken } from "../../arbitrum/IArbToken.sol"; + +/** + * @title L1 Gateway for reverse "custom" bridging functionality in an ERC20-based rollup. + * @notice Handles some (but not all!) reverse custom Gateway needs. + * Use the reverse custom gateway instead of the normal custom + * gateway if you want total supply to be tracked on the L2 + * rather than the L1. + * @dev The reverse custom gateway burns on the l2 and escrows on the l1 + * which is the opposite of the way the normal custom gateway works + * This means that the total supply L2 isn't affected by bridging, which + * is helpful for observers calculating the total supply especially if + * if minting is also occuring on L2 + */ +contract L1OrbitReverseCustomGateway is L1OrbitCustomGateway { + function inboundEscrowTransfer( + address _l1Address, + address _dest, + uint256 _amount + ) internal virtual override { + IArbToken(_l1Address).bridgeMint(_dest, _amount); + } + + function outboundEscrowTransfer( + address _l1Token, + address _from, + uint256 _amount + ) internal override returns (uint256) { + IArbToken(_l1Token).bridgeBurn(_from, _amount); + // by default we assume that the amount we send to bridgeBurn is the amount burnt + // this might not be the case for every token + return _amount; + } +} diff --git a/contracts/tokenbridge/ethereum/gateway/L1ReverseCustomGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1ReverseCustomGateway.sol index ed6f01ff29..29023c48c8 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1ReverseCustomGateway.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1ReverseCustomGateway.sol @@ -16,11 +16,9 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L1CustomGateway.sol"; - -import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; /** diff --git a/contracts/tokenbridge/ethereum/gateway/L1WethGateway.sol b/contracts/tokenbridge/ethereum/gateway/L1WethGateway.sol index 68161ab8f6..8c36307686 100644 --- a/contracts/tokenbridge/ethereum/gateway/L1WethGateway.sol +++ b/contracts/tokenbridge/ethereum/gateway/L1WethGateway.sol @@ -16,10 +16,10 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../libraries/IWETH9.sol"; import "../../test/TestWETH9.sol"; @@ -101,7 +101,12 @@ contract L1WethGateway is L1ArbitrumExtendedGateway { * @param l1ERC20 address of L1 token * @return L2 address of a bridged ERC20 token */ - function calculateL2TokenAddress(address l1ERC20) public view override returns (address) { + function calculateL2TokenAddress(address l1ERC20) + public + view + override(ITokenGateway, TokenGateway) + returns (address) + { if (l1ERC20 != l1Weth) { // invalid L1 weth address return address(0); diff --git a/contracts/tokenbridge/libraries/AddressAliasHelper.sol b/contracts/tokenbridge/libraries/AddressAliasHelper.sol index 02ebd61215..7bcdbb9615 100644 --- a/contracts/tokenbridge/libraries/AddressAliasHelper.sol +++ b/contracts/tokenbridge/libraries/AddressAliasHelper.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; library AddressAliasHelper { uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); @@ -26,7 +26,9 @@ library AddressAliasHelper { /// @param l1Address the address in the L1 that triggered the tx to L2 /// @return l2Address L2 address as viewed in msg.sender function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { - l2Address = address(uint160(l1Address) + offset); + unchecked { + l2Address = address(uint160(l1Address) + offset); + } } /// @notice Utility function that converts the msg.sender viewed in the L2 to the @@ -34,6 +36,8 @@ library AddressAliasHelper { /// @param l2Address L2 address as viewed in msg.sender /// @return l1Address the address in the L1 that triggered the tx to L2 function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) { - l1Address = address(uint160(l2Address) - offset); + unchecked { + l1Address = address(uint160(l2Address) - offset); + } } } diff --git a/contracts/tokenbridge/libraries/BytesLib.sol b/contracts/tokenbridge/libraries/BytesLib.sol index 97b46a2537..6acacb1a79 100644 --- a/contracts/tokenbridge/libraries/BytesLib.sol +++ b/contracts/tokenbridge/libraries/BytesLib.sol @@ -8,7 +8,7 @@ * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; /* solhint-disable no-inline-assembly */ library BytesLib { diff --git a/contracts/tokenbridge/libraries/BytesParser.sol b/contracts/tokenbridge/libraries/BytesParser.sol index 39c623d8ea..2ec2e4b7a1 100644 --- a/contracts/tokenbridge/libraries/BytesParser.sol +++ b/contracts/tokenbridge/libraries/BytesParser.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./BytesLib.sol"; diff --git a/contracts/tokenbridge/libraries/ClonableBeaconProxy.sol b/contracts/tokenbridge/libraries/ClonableBeaconProxy.sol index b74c1011d1..29620f1af2 100644 --- a/contracts/tokenbridge/libraries/ClonableBeaconProxy.sol +++ b/contracts/tokenbridge/libraries/ClonableBeaconProxy.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 // solhint-disable-next-line compiler-version -pragma solidity >=0.6.0 <0.8.0; +pragma solidity >=0.6.0 <0.9.0; -import "@openzeppelin/contracts/proxy/BeaconProxy.sol"; -import "@openzeppelin/contracts/proxy/UpgradeableBeacon.sol"; +import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; +import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "@openzeppelin/contracts/utils/Create2.sol"; interface ProxySetter { @@ -11,7 +11,7 @@ interface ProxySetter { } contract ClonableBeaconProxy is BeaconProxy { - constructor() public BeaconProxy(ProxySetter(msg.sender).beacon(), "") {} + constructor() BeaconProxy(ProxySetter(msg.sender).beacon(), "") {} } contract BeaconProxyFactory is ProxySetter { diff --git a/contracts/tokenbridge/libraries/Cloneable.sol b/contracts/tokenbridge/libraries/Cloneable.sol index 450e6a5ac4..fa3a383903 100644 --- a/contracts/tokenbridge/libraries/Cloneable.sol +++ b/contracts/tokenbridge/libraries/Cloneable.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./ICloneable.sol"; @@ -25,7 +25,7 @@ contract Cloneable is ICloneable { bool private isMasterCopy; - constructor() public { + constructor() { isMasterCopy = true; } diff --git a/contracts/tokenbridge/libraries/ERC165.sol b/contracts/tokenbridge/libraries/ERC165.sol index cd62415e51..89a3e6314f 100644 --- a/contracts/tokenbridge/libraries/ERC165.sol +++ b/contracts/tokenbridge/libraries/ERC165.sol @@ -4,7 +4,7 @@ // With pragma modification to support ^0.6.11 // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.6/contracts/utils/introspection/ERC165.sol -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./IERC165.sol"; diff --git a/contracts/tokenbridge/libraries/ERC20Upgradeable.sol b/contracts/tokenbridge/libraries/ERC20Upgradeable.sol new file mode 100644 index 0000000000..16a7042c51 --- /dev/null +++ b/contracts/tokenbridge/libraries/ERC20Upgradeable.sol @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is based on OpenZeppelin implementation (https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.8.3/contracts/token/ERC20/ERC20Upgradeable.sol) + * with a small modification. OZ implementation removed `decimals` storage variable when they did upgrade to Solidity 0.8. Since we're already using older OZ implementation, here we're + * adding back the `decimals` storage variable along with the appropriate getter and setter. That way we avoid changes in storage layout that would've happen due to OZ removing token + * decimals storage variable. + * + */ +contract ERC20Upgradeable is + Initializable, + ContextUpgradeable, + IERC20Upgradeable, + IERC20MetadataUpgradeable +{ + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * The default value of {decimals} is 18. To select a different value for + * {decimals} you should overload it. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { + __ERC20_init_unchained(name_, symbol_); + } + + function __ERC20_init_unchained(string memory name_, string memory symbol_) + internal + onlyInitializing + { + _name = name_; + _symbol = symbol_; + _decimals = 18; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called; + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual override returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual override returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address to, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + view + virtual + override + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + * - the caller must have allowance for ``from``'s tokens of at least + * `amount`. + */ + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue); + } + + return true; + } + + /** + * @dev Moves `amount` of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + */ + function _transfer( + address from, + address to, + uint256 amount + ) internal virtual { + require(from != address(0), "ERC20: transfer from the zero address"); + require(to != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by + // decrementing then incrementing. + _balances[to] += amount; + } + + emit Transfer(from, to, amount); + + _afterTokenTransfer(from, to, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply += amount; + unchecked { + // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. + _balances[account] += amount; + } + emit Transfer(address(0), account, amount); + + _afterTokenTransfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + uint256 accountBalance = _balances[account]; + require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); + unchecked { + _balances[account] = accountBalance - amount; + // Overflow not possible: amount <= accountBalance <= totalSupply. + _totalSupply -= amount; + } + + emit Transfer(account, address(0), amount); + + _afterTokenTransfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Sets {decimals} to a value other than the default one of 18. + * + * WARNING: This function should only be called from the constructor. Most + * applications that interact with token contracts will not expect + * {decimals} to ever change, and may work incorrectly if it does. + */ + function _setupDecimals(uint8 decimals_) internal virtual { + _decimals = decimals_; + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * Does not update the allowance amount in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Might emit an {Approval} event. + */ + function _spendAllowance( + address owner, + address spender, + uint256 amount + ) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC20: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} + + /** + * @dev Hook that is called after any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * has been transferred to `to`. + * - when `from` is zero, `amount` tokens have been minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens have been burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[44] private __gap; +} diff --git a/contracts/tokenbridge/libraries/IERC20Bridge.sol b/contracts/tokenbridge/libraries/IERC20Bridge.sol new file mode 100644 index 0000000000..d850579311 --- /dev/null +++ b/contracts/tokenbridge/libraries/IERC20Bridge.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +interface IERC20Bridge { + /** + * @dev token that is escrowed in bridge on L1 side and minted on L2 as native currency. Also fees are paid in this token. + */ + function nativeToken() external view returns (address); +} diff --git a/contracts/tokenbridge/libraries/ITransferAndCall.sol b/contracts/tokenbridge/libraries/ITransferAndCall.sol index a894e942c9..05c27c5ada 100644 --- a/contracts/tokenbridge/libraries/ITransferAndCall.sol +++ b/contracts/tokenbridge/libraries/ITransferAndCall.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version -pragma solidity >0.6.0 <0.8.0; +pragma solidity >0.6.0 <0.9.0; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; diff --git a/contracts/tokenbridge/libraries/L2CustomGatewayToken.sol b/contracts/tokenbridge/libraries/L2CustomGatewayToken.sol index 680d9d3eaa..2397b0fbaf 100644 --- a/contracts/tokenbridge/libraries/L2CustomGatewayToken.sol +++ b/contracts/tokenbridge/libraries/L2CustomGatewayToken.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L2GatewayToken.sol"; diff --git a/contracts/tokenbridge/libraries/L2GatewayToken.sol b/contracts/tokenbridge/libraries/L2GatewayToken.sol index 5c595bd82e..a3b363c8ea 100644 --- a/contracts/tokenbridge/libraries/L2GatewayToken.sol +++ b/contracts/tokenbridge/libraries/L2GatewayToken.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./aeERC20.sol"; import "./BytesParser.sol"; diff --git a/contracts/tokenbridge/libraries/ProxyUtil.sol b/contracts/tokenbridge/libraries/ProxyUtil.sol index 19cf08ecc0..cc146b59ff 100644 --- a/contracts/tokenbridge/libraries/ProxyUtil.sol +++ b/contracts/tokenbridge/libraries/ProxyUtil.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; library ProxyUtil { function getProxyAdmin() internal view returns (address admin) { diff --git a/contracts/tokenbridge/libraries/TransferAndCallToken.sol b/contracts/tokenbridge/libraries/TransferAndCallToken.sol index 8d8796b0a0..dcbf6520e2 100644 --- a/contracts/tokenbridge/libraries/TransferAndCallToken.sol +++ b/contracts/tokenbridge/libraries/TransferAndCallToken.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version -pragma solidity >0.6.0 <0.8.0; +pragma solidity >0.6.0 <0.9.0; -import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import "./ERC20Upgradeable.sol"; import "./ITransferAndCall.sol"; // Implementation from https://github.com/smartcontractkit/LinkToken/blob/master/contracts/v0.6/TransferAndCallToken.sol diff --git a/contracts/tokenbridge/libraries/Whitelist.sol b/contracts/tokenbridge/libraries/Whitelist.sol index 0392bc1719..c70aae537a 100644 --- a/contracts/tokenbridge/libraries/Whitelist.sol +++ b/contracts/tokenbridge/libraries/Whitelist.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; abstract contract WhitelistConsumer { address public whitelist; @@ -44,7 +44,7 @@ contract Whitelist { event OwnerUpdated(address newOwner); event WhitelistUpgraded(address newWhitelist, address[] targets); - constructor() public { + constructor() { owner = msg.sender; } diff --git a/contracts/tokenbridge/libraries/aeERC20.sol b/contracts/tokenbridge/libraries/aeERC20.sol index b76dfe4d17..e179e5d285 100644 --- a/contracts/tokenbridge/libraries/aeERC20.sol +++ b/contracts/tokenbridge/libraries/aeERC20.sol @@ -16,9 +16,9 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; -import "@openzeppelin/contracts-upgradeable/drafts/ERC20PermitUpgradeable.sol"; +import "../libraries/draft-ERC20PermitUpgradeable.sol"; import "./TransferAndCallToken.sol"; /// @title Arbitrum extended ERC20 @@ -27,7 +27,7 @@ import "./TransferAndCallToken.sol"; contract aeERC20 is ERC20PermitUpgradeable, TransferAndCallToken { using AddressUpgradeable for address; - constructor() public initializer { + constructor() initializer { // this is expected to be used as the logic contract behind a proxy // override the constructor if you don't wish to use the initialize method } diff --git a/contracts/tokenbridge/libraries/aeWETH.sol b/contracts/tokenbridge/libraries/aeWETH.sol index 5ed81a83f0..6b19e43818 100644 --- a/contracts/tokenbridge/libraries/aeWETH.sol +++ b/contracts/tokenbridge/libraries/aeWETH.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./L2GatewayToken.sol"; import "./IWETH9.sol"; diff --git a/contracts/tokenbridge/libraries/draft-ERC20PermitUpgradeable.sol b/contracts/tokenbridge/libraries/draft-ERC20PermitUpgradeable.sol new file mode 100644 index 0000000000..6cd3887daf --- /dev/null +++ b/contracts/tokenbridge/libraries/draft-ERC20PermitUpgradeable.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol) + +pragma solidity ^0.8.0; + +import "./ERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +/** + * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * This implementation is based on OpenZeppelin implementation (https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.8.3/contracts/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol). + * The only difference is that we are importing our own `ERC20Upgradeable` implementation instead of the OpenZeppelin's one. + * + */ +abstract contract ERC20PermitUpgradeable is + Initializable, + ERC20Upgradeable, + IERC20PermitUpgradeable, + EIP712Upgradeable +{ + using CountersUpgradeable for CountersUpgradeable.Counter; + + mapping(address => CountersUpgradeable.Counter) private _nonces; + + // solhint-disable-next-line var-name-mixedcase + bytes32 private constant _PERMIT_TYPEHASH = + keccak256( + "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" + ); + /** + * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. + * However, to ensure consistency with the upgradeable transpiler, we will continue + * to reserve a slot. + * @custom:oz-renamed-from _PERMIT_TYPEHASH + */ + // solhint-disable-next-line var-name-mixedcase + bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; + + /** + * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. + * + * It's a good idea to use the same `name` that is defined as the ERC20 token name. + */ + function __ERC20Permit_init(string memory name) internal onlyInitializing { + __EIP712_init_unchained(name, "1"); + } + + function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {} + + /** + * @dev See {IERC20Permit-permit}. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override { + require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); + + bytes32 structHash = keccak256( + abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline) + ); + + bytes32 hash = _hashTypedDataV4(structHash); + + address signer = ECDSAUpgradeable.recover(hash, v, r, s); + require(signer == owner, "ERC20Permit: invalid signature"); + + _approve(owner, spender, value); + } + + /** + * @dev See {IERC20Permit-nonces}. + */ + function nonces(address owner) public view virtual override returns (uint256) { + return _nonces[owner].current(); + } + + /** + * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view override returns (bytes32) { + return _domainSeparatorV4(); + } + + /** + * @dev "Consume a nonce": return the current value and increment. + * + * _Available since v4.1._ + */ + function _useNonce(address owner) internal virtual returns (uint256 current) { + CountersUpgradeable.Counter storage nonce = _nonces[owner]; + current = nonce.current(); + nonce.increment(); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[49] private __gap; +} diff --git a/contracts/tokenbridge/libraries/gateway/GatewayMessageHandler.sol b/contracts/tokenbridge/libraries/gateway/GatewayMessageHandler.sol index b593edb031..3f12d8df6a 100644 --- a/contracts/tokenbridge/libraries/gateway/GatewayMessageHandler.sol +++ b/contracts/tokenbridge/libraries/gateway/GatewayMessageHandler.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; /// @notice this library manages encoding and decoding of gateway communication library GatewayMessageHandler { diff --git a/contracts/tokenbridge/libraries/gateway/GatewayRouter.sol b/contracts/tokenbridge/libraries/gateway/GatewayRouter.sol index 0da136abae..a041154bf7 100644 --- a/contracts/tokenbridge/libraries/gateway/GatewayRouter.sol +++ b/contracts/tokenbridge/libraries/gateway/GatewayRouter.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../ProxyUtil.sol"; import "@openzeppelin/contracts/utils/Address.sol"; @@ -36,16 +36,6 @@ abstract contract GatewayRouter is TokenGateway, IGatewayRouter { mapping(address => address) public l1TokenToGateway; address public override defaultGateway; - event TransferRouted( - address indexed token, - address indexed _userFrom, - address indexed _userTo, - address gateway - ); - - event GatewaySet(address indexed l1Token, address indexed gateway); - event DefaultGatewayUpdated(address newDefaultGateway); - function postUpgradeInit() external { // it is assumed the L2 Arbitrum Gateway contract is behind a Proxy controlled by a proxy admin // this function can only be called by the proxy admin contract diff --git a/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol b/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol index bf03ab33ec..07a3382379 100644 --- a/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol +++ b/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../ProxyUtil.sol"; import "@openzeppelin/contracts/utils/Address.sol"; diff --git a/contracts/tokenbridge/libraries/gateway/TokenGateway.sol b/contracts/tokenbridge/libraries/gateway/TokenGateway.sol index fb09509d63..8614864b68 100644 --- a/contracts/tokenbridge/libraries/gateway/TokenGateway.sol +++ b/contracts/tokenbridge/libraries/gateway/TokenGateway.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./ITokenGateway.sol"; import "@openzeppelin/contracts/utils/Address.sol"; diff --git a/contracts/tokenbridge/test/AddressMappingTest.sol b/contracts/tokenbridge/test/AddressMappingTest.sol index c6b1e12d0a..f78a279c7d 100644 --- a/contracts/tokenbridge/test/AddressMappingTest.sol +++ b/contracts/tokenbridge/test/AddressMappingTest.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../arbitrum/L2ArbitrumMessenger.sol"; import "../libraries/AddressAliasHelper.sol"; diff --git a/contracts/tokenbridge/test/ArbSysMock.sol b/contracts/tokenbridge/test/ArbSysMock.sol index f8721f9110..51bf2b84ce 100644 --- a/contracts/tokenbridge/test/ArbSysMock.sol +++ b/contracts/tokenbridge/test/ArbSysMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; contract ArbSysMock { event ArbSysL2ToL1Tx(address from, address to, uint256 value, bytes data); diff --git a/contracts/tokenbridge/test/InboxMock.sol b/contracts/tokenbridge/test/InboxMock.sol index 33a557ddb4..7113840f92 100644 --- a/contracts/tokenbridge/test/InboxMock.sol +++ b/contracts/tokenbridge/test/InboxMock.sol @@ -16,19 +16,38 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import "@arbitrum/nitro-contracts/src/bridge/IBridge.sol"; -import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -contract InboxMock { - address l2ToL1SenderMock = address(0); +abstract contract AbsInboxMock { + address public l2ToL1SenderMock = address(0); + uint256 public seqNum = 0; event TicketData(uint256 maxSubmissionCost); event RefundAddresses(address excessFeeRefundAddress, address callValueRefundAddress); event InboxRetryableTicket(address from, address to, uint256 value, uint256 maxGas, bytes data); + function bridge() external view returns (IBridge) { + return IBridge(address(this)); + } + + function activeOutbox() external view returns (address) { + return address(this); + } + + function setL2ToL1Sender(address sender) external { + l2ToL1SenderMock = sender; + } + + function l2ToL1Sender() external view returns (address) { + return l2ToL1SenderMock; + } +} + +contract InboxMock is AbsInboxMock { function createRetryableTicket( address to, uint256 l2CallValue, @@ -45,22 +64,61 @@ contract InboxMock { emit TicketData(maxSubmissionCost); emit RefundAddresses(excessFeeRefundAddress, callValueRefundAddress); emit InboxRetryableTicket(msg.sender, to, l2CallValue, gasLimit, data); - return 0; + return seqNum++; } +} - function bridge() external view returns (IBridge) { - return IBridge(address(this)); - } +contract ERC20InboxMock is AbsInboxMock { + address public nativeToken; - function activeOutbox() external view returns (address) { - return address(this); - } + event ERC20InboxRetryableTicket( + address from, + address to, + uint256 l2CallValue, + uint256 maxGas, + uint256 gasPrice, + uint256 tokenTotalFeeAmount, + bytes data + ); - function setL2ToL1Sender(address sender) external { - l2ToL1SenderMock = sender; + function createRetryableTicket( + address to, + uint256 l2CallValue, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + uint256 tokenTotalFeeAmount, + bytes calldata data + ) external returns (uint256) { + // ensure the user's deposit alone will make submission succeed + if (tokenTotalFeeAmount < (maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas)) { + revert("WRONG_TOKEN_VALUE"); + } + + emit TicketData(maxSubmissionCost); + emit RefundAddresses(excessFeeRefundAddress, callValueRefundAddress); + emit ERC20InboxRetryableTicket( + msg.sender, + to, + l2CallValue, + gasLimit, + maxFeePerGas, + tokenTotalFeeAmount, + data + ); + + // transfer out received native tokens (to simulate bridge spending those funds) + uint256 balance = IERC20(address(nativeToken)).balanceOf(address(this)); + if (balance > 0) { + IERC20(address(nativeToken)).transfer(address(1), balance); + } + + return seqNum++; } - function l2ToL1Sender() external view returns (address) { - return l2ToL1SenderMock; + function setMockNativeToken(address _nativeToken) external { + nativeToken = _nativeToken; } } diff --git a/contracts/tokenbridge/test/TestArbCustomToken.sol b/contracts/tokenbridge/test/TestArbCustomToken.sol index 8639c88d3c..e5dcee79e8 100644 --- a/contracts/tokenbridge/test/TestArbCustomToken.sol +++ b/contracts/tokenbridge/test/TestArbCustomToken.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../arbitrum/IArbToken.sol"; import "../arbitrum/ReverseArbToken.sol"; @@ -31,7 +31,7 @@ contract TestArbCustomToken is aeERC20, IArbToken { _; } - constructor(address _l2Gateway, address _l1Address) public { + constructor(address _l2Gateway, address _l1Address) { l2Gateway = _l2Gateway; l1Address = _l1Address; aeERC20._initialize("TestCustomToken", "CARB", uint8(18)); @@ -50,7 +50,6 @@ contract TestArbCustomToken is aeERC20, IArbToken { contract MintableTestArbCustomToken is TestArbCustomToken { constructor(address _l2Gateway, address _l1Address) - public TestArbCustomToken(_l2Gateway, _l1Address) {} @@ -68,7 +67,7 @@ contract ReverseTestArbCustomToken is aeERC20, IArbToken, ReverseArbToken { _; } - constructor(address _l2Gateway, address _l1Address) public { + constructor(address _l2Gateway, address _l1Address) { l2Gateway = _l2Gateway; l1Address = _l1Address; aeERC20._initialize("TestReverseCustomToken", "RARB", uint8(18)); diff --git a/contracts/tokenbridge/test/TestArbCustomTokenBurnFee.sol b/contracts/tokenbridge/test/TestArbCustomTokenBurnFee.sol index d393f96efd..3ca3f52df8 100644 --- a/contracts/tokenbridge/test/TestArbCustomTokenBurnFee.sol +++ b/contracts/tokenbridge/test/TestArbCustomTokenBurnFee.sol @@ -16,13 +16,12 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "./TestArbCustomToken.sol"; contract TestArbCustomTokenBurnFee is TestArbCustomToken { constructor(address _l2Gateway, address _l1Address) - public TestArbCustomToken(_l2Gateway, _l1Address) {} diff --git a/contracts/tokenbridge/test/TestBytesParser.sol b/contracts/tokenbridge/test/TestBytesParser.sol index 43fc67eb4e..421defdf71 100644 --- a/contracts/tokenbridge/test/TestBytesParser.sol +++ b/contracts/tokenbridge/test/TestBytesParser.sol @@ -16,7 +16,7 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../libraries/BytesParser.sol"; diff --git a/contracts/tokenbridge/test/TestCustomTokenL1.sol b/contracts/tokenbridge/test/TestCustomTokenL1.sol index 761921ad74..cc2cc33e51 100644 --- a/contracts/tokenbridge/test/TestCustomTokenL1.sol +++ b/contracts/tokenbridge/test/TestCustomTokenL1.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../libraries/aeERC20.sol"; import "../ethereum/ICustomToken.sol"; import "../ethereum/gateway/L1CustomGateway.sol"; import "../ethereum/gateway/L1GatewayRouter.sol"; -import "@openzeppelin/contracts/GSN/Context.sol"; +import { IERC20Bridge } from "../libraries/IERC20Bridge.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; interface IL1CustomGateway { function registerTokenToL2( @@ -20,6 +21,17 @@ interface IL1CustomGateway { ) external payable returns (uint256); } +interface IL1OrbitCustomGateway { + function registerTokenToL2( + address _l2Address, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + address _creditBackAddress, + uint256 _feeAmount + ) external returns (uint256); +} + interface IGatewayRouter2 { function setGateway( address _gateway, @@ -30,12 +42,25 @@ interface IGatewayRouter2 { ) external payable returns (uint256); } +interface IOrbitGatewayRouter { + function setGateway( + address _gateway, + uint256 _maxGas, + uint256 _gasPriceBid, + uint256 _maxSubmissionCost, + address _creditBackAddress, + uint256 _feeAmount + ) external returns (uint256); + + function inbox() external returns (address); +} + contract TestCustomTokenL1 is aeERC20, ICustomToken { address public gateway; address public router; - bool private shouldRegisterGateway; + bool internal shouldRegisterGateway; - constructor(address _gateway, address _router) public { + constructor(address _gateway, address _router) { gateway = _gateway; router = _router; aeERC20._initialize("TestCustomToken", "CARB", uint8(18)); @@ -49,15 +74,17 @@ contract TestCustomTokenL1 is aeERC20, ICustomToken { address sender, address recipient, uint256 amount - ) public virtual override(ERC20Upgradeable, ICustomToken) returns (bool) { + ) public virtual override(IERC20Upgradeable, ERC20Upgradeable, ICustomToken) returns (bool) { return ERC20Upgradeable.transferFrom(sender, recipient, amount); } - function balanceOf(address account) + function balanceOf( + address account + ) public view virtual - override(ERC20Upgradeable, ICustomToken) + override(IERC20Upgradeable, ERC20Upgradeable, ICustomToken) returns (uint256) { return ERC20Upgradeable.balanceOf(account); @@ -66,7 +93,7 @@ contract TestCustomTokenL1 is aeERC20, ICustomToken { /// @dev we only set shouldRegisterGateway to true when in `registerTokenOnL2` function isArbitrumEnabled() external view override returns (uint8) { require(shouldRegisterGateway, "NOT_EXPECTED_CALL"); - return uint8(0xa4b1); + return uint8(0xb1); } function registerTokenOnL2( @@ -79,7 +106,7 @@ contract TestCustomTokenL1 is aeERC20, ICustomToken { uint256 valueForGateway, uint256 valueForRouter, address creditBackAddress - ) public payable override { + ) public payable virtual override { // we temporarily set `shouldRegisterGateway` to true for the callback in registerTokenToL2 to succeed bool prev = shouldRegisterGateway; shouldRegisterGateway = true; @@ -104,29 +131,90 @@ contract TestCustomTokenL1 is aeERC20, ICustomToken { } } +contract TestOrbitCustomTokenL1 is TestCustomTokenL1 { + using SafeERC20 for IERC20; + + constructor(address _gateway, address _router) TestCustomTokenL1(_gateway, _router) {} + + function registerTokenOnL2( + address l2CustomTokenAddress, + uint256 maxSubmissionCostForCustomGateway, + uint256 maxSubmissionCostForRouter, + uint256 maxGasForCustomGateway, + uint256 maxGasForRouter, + uint256 gasPriceBid, + uint256 valueForGateway, + uint256 valueForRouter, + address creditBackAddress + ) public payable override { + // we temporarily set `shouldRegisterGateway` to true for the callback in registerTokenToL2 to succeed + bool prev = shouldRegisterGateway; + shouldRegisterGateway = true; + + address inbox = IOrbitGatewayRouter(router).inbox(); + address bridge = address(IInbox(inbox).bridge()); + + // transfer fees from user to here, and approve router to use it + { + address nativeToken = IERC20Bridge(bridge).nativeToken(); + + IERC20(nativeToken).safeTransferFrom( + msg.sender, + address(this), + valueForGateway + valueForRouter + ); + IERC20(nativeToken).approve(router, valueForRouter); + IERC20(nativeToken).approve(gateway, valueForGateway); + } + + IL1OrbitCustomGateway(gateway).registerTokenToL2( + l2CustomTokenAddress, + maxGasForCustomGateway, + gasPriceBid, + maxSubmissionCostForCustomGateway, + creditBackAddress, + valueForGateway + ); + + IOrbitGatewayRouter(router).setGateway( + gateway, + maxGasForRouter, + gasPriceBid, + maxSubmissionCostForRouter, + creditBackAddress, + valueForRouter + ); + + // reset allowance back to 0 in case not all approved native tokens are spent + { + address nativeToken = IERC20Bridge(bridge).nativeToken(); + + IERC20(nativeToken).approve(router, 0); + IERC20(nativeToken).approve(gateway, 0); + } + + shouldRegisterGateway = prev; + } +} + contract MintableTestCustomTokenL1 is L1MintableToken, TestCustomTokenL1 { - constructor(address _gateway, address _router) public TestCustomTokenL1(_gateway, _router) {} + constructor(address _gateway, address _router) TestCustomTokenL1(_gateway, _router) {} modifier onlyGateway() { require(msg.sender == gateway, "ONLY_l1GATEWAY"); _; } - function bridgeMint(address account, uint256 amount) - public - override(L1MintableToken) - onlyGateway - { + function bridgeMint( + address account, + uint256 amount + ) public override(L1MintableToken) onlyGateway { _mint(account, amount); } - function balanceOf(address account) - public - view - virtual - override(TestCustomTokenL1, ICustomToken) - returns (uint256 amount) - { + function balanceOf( + address account + ) public view virtual override(TestCustomTokenL1, ICustomToken) returns (uint256 amount) { return super.balanceOf(account); } @@ -140,25 +228,18 @@ contract MintableTestCustomTokenL1 is L1MintableToken, TestCustomTokenL1 { } contract ReverseTestCustomTokenL1 is L1ReverseToken, MintableTestCustomTokenL1 { - constructor(address _gateway, address _router) - public - MintableTestCustomTokenL1(_gateway, _router) - {} + constructor(address _gateway, address _router) MintableTestCustomTokenL1(_gateway, _router) {} - function bridgeBurn(address account, uint256 amount) - public - override(L1ReverseToken) - onlyGateway - { + function bridgeBurn( + address account, + uint256 amount + ) public override(L1ReverseToken) onlyGateway { _burn(account, amount); } - function balanceOf(address account) - public - view - override(MintableTestCustomTokenL1, ICustomToken) - returns (uint256 amount) - { + function balanceOf( + address account + ) public view override(MintableTestCustomTokenL1, ICustomToken) returns (uint256 amount) { return super.balanceOf(account); } diff --git a/contracts/tokenbridge/test/TestERC20.sol b/contracts/tokenbridge/test/TestERC20.sol index 88e3e28283..71dd2c005b 100644 --- a/contracts/tokenbridge/test/TestERC20.sol +++ b/contracts/tokenbridge/test/TestERC20.sol @@ -16,13 +16,12 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../libraries/aeERC20.sol"; -import "@openzeppelin/contracts-upgradeable/drafts/ERC20PermitUpgradeable.sol"; contract TestERC20 is aeERC20 { - constructor() public { + constructor() { aeERC20._initialize("IntArbTestToken", "IARB", uint8(18)); } diff --git a/contracts/tokenbridge/test/TestPostDepositCall.sol b/contracts/tokenbridge/test/TestPostDepositCall.sol index a710489938..b55deaa801 100644 --- a/contracts/tokenbridge/test/TestPostDepositCall.sol +++ b/contracts/tokenbridge/test/TestPostDepositCall.sol @@ -16,14 +16,14 @@ * limitations under the License. */ -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../libraries/ITransferAndCall.sol"; contract L2Called is ITransferAndCallReceiver { event Called(uint256 num); - constructor() public {} + constructor() {} // This function can be anything function postDepositHook(uint256 num) public { diff --git a/contracts/tokenbridge/test/TestWETH9.sol b/contracts/tokenbridge/test/TestWETH9.sol index c225ea1fbd..2b3fe3eb79 100644 --- a/contracts/tokenbridge/test/TestWETH9.sol +++ b/contracts/tokenbridge/test/TestWETH9.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.6.11; +pragma solidity ^0.8.0; import "../libraries/IWETH9.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/proxy/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; contract TestWETH9 is ERC20, IWETH9 { - constructor(string memory name_, string memory symbol_) public ERC20(name_, symbol_) {} + constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {} function deposit() external payable override { _mint(msg.sender, msg.value); diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 0000000000..ba6691c9fe --- /dev/null +++ b/foundry.toml @@ -0,0 +1,14 @@ +[profile.default] +src = 'contracts' +out = 'out' +libs = ["node_modules", "lib"] +test = 'test-foundry' +cache_path = 'forge-cache' +optimizer = true +optimizer_runs = 100 +via_ir = false + +[fmt] +number_underscore = 'thousands' +line_length = 100 +# See more config options https://github.com/foundry-rs/foundry/tree/master/config \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 03827eb0b0..d2b790bc1a 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -6,6 +6,7 @@ import 'solidity-coverage' import 'hardhat-gas-reporter' import '@nomiclabs/hardhat-etherscan' import 'hardhat-deploy' +import 'hardhat-contract-sizer' import { task } from 'hardhat/config' import '@nomiclabs/hardhat-ethers' @@ -35,7 +36,7 @@ const config = { }, }, { - version: '0.8.7', + version: '0.8.16', settings: { optimizer: { enabled: true, diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 0000000000..2b58ecbcf3 --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 2b58ecbcf3dfde7a75959dc7b4eb3d0670278de6 diff --git a/lib/nitro-contracts b/lib/nitro-contracts new file mode 160000 index 0000000000..d5d33c2b8d --- /dev/null +++ b/lib/nitro-contracts @@ -0,0 +1 @@ +Subproject commit d5d33c2b8d5615563b8c553ca2a1bb936c039924 diff --git a/package.json b/package.json index e672dbce5d..df01055d5f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@arbitrum/token-bridge-contracts", - "version": "1.0.1-beta.2", + "version": "1.1.0", "license": "Apache-2.0", "scripts": { "prepublishOnly": "hardhat clean && hardhat compile", @@ -17,7 +17,13 @@ "test:e2e": "hardhat test test/*.e2e.ts", "test:l1": "hardhat test test/*.l1.ts", "test:l2": "hardhat test test/*.l2.ts", + "test:unit": "forge test", + "test:e2e:local-env": "yarn hardhat test test-e2e/*", "test:storage": "./scripts/storage_layout_test.bash", + "deploy:local:token-bridge": "ts-node ./scripts/local-deployment/deployCreatorAndCreateTokenBridge.ts", + "deploy:goerli:token-bridge-creator": "ts-node ./scripts/goerli-deployment/deployTokenBridgeCreator.ts", + "create:goerli:token-bridge": "ts-node ./scripts/goerli-deployment/createTokenBridge.ts", + "test:tokenbridge:deployment": "hardhat test test-e2e/tokenBridgeDeploymentTest.ts", "typechain": "hardhat typechain", "deploy:tokenbridge": "hardhat run scripts/deploy_token_bridge_l1.ts --network mainnet", "gen:uml": "sol2uml ./contracts/tokenbridge/arbitrum,./contracts/tokenbridge/ethereum,./contracts/tokenbridge/libraries -o ./gatewayUML.svg", @@ -28,15 +34,16 @@ }, "files": [ "contracts", - "build/contracts" + "build/contracts/contracts" ], "dependencies": { - "@arbitrum/nitro-contracts": "1.0.0-beta.8", - "@openzeppelin/contracts": "3.4.2", - "@openzeppelin/contracts-upgradeable": "3.4.2", - "hardhat": "2.9.9" + "@arbitrum/nitro-contracts": "^1.0.0-beta.8", + "@offchainlabs/upgrade-executor": "1.1.0-beta.0", + "@openzeppelin/contracts": "4.8.3", + "@openzeppelin/contracts-upgradeable": "4.8.3" }, "devDependencies": { + "@arbitrum/sdk": "^3.1.3", "@nomiclabs/hardhat-ethers": "^2.0.1", "@nomiclabs/hardhat-etherscan": "^3.1.0", "@nomiclabs/hardhat-waffle": "^2.0.1", @@ -58,6 +65,8 @@ "eslint-plugin-prettier": "^4.0.0", "ethereum-waffle": "^3.2.0", "ethers": "^5.4.5", + "hardhat": "2.17.3", + "hardhat-contract-sizer": "^2.10.0", "hardhat-deploy": "^0.9.1", "hardhat-gas-reporter": "^1.0.4", "prettier": "^2.3.2", @@ -73,6 +82,6 @@ "typescript": "^4.2.2" }, "optionalDependencies": { - "@openzeppelin/upgrades-core": "^1.7.6" + "@openzeppelin/upgrades-core": "^1.24.1" } } diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 0000000000..18d5a0c9ed --- /dev/null +++ b/remappings.txt @@ -0,0 +1,7 @@ +ds-test/=lib/forge-std/lib/ds-test/src/ +forge-std/=lib/forge-std/src/ +@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/ +@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ + + + diff --git a/scripts/atomicTokenBridgeDeployer.ts b/scripts/atomicTokenBridgeDeployer.ts new file mode 100644 index 0000000000..9026fa15e8 --- /dev/null +++ b/scripts/atomicTokenBridgeDeployer.ts @@ -0,0 +1,585 @@ +import { BigNumber, Signer, Wallet, ethers } from 'ethers' +import { + L1CustomGateway__factory, + L1ERC20Gateway__factory, + L1GatewayRouter__factory, + L1AtomicTokenBridgeCreator__factory, + L2AtomicTokenBridgeFactory__factory, + L2GatewayRouter__factory, + L2ERC20Gateway__factory, + L2CustomGateway__factory, + L1AtomicTokenBridgeCreator, + L2WethGateway__factory, + AeWETH__factory, + L1WethGateway__factory, + TransparentUpgradeableProxy__factory, + ProxyAdmin__factory, + L1TokenBridgeRetryableSender__factory, + L1OrbitERC20Gateway__factory, + L1OrbitCustomGateway__factory, + L1OrbitGatewayRouter__factory, + IInbox__factory, + IERC20Bridge__factory, + IERC20__factory, + ArbMulticall2__factory, + IRollupCore__factory, + IBridge__factory, + Multicall2__factory, +} from '../build/types' +import { + abi as UpgradeExecutorABI, + bytecode as UpgradeExecutorBytecode, +} from '@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json' +import { JsonRpcProvider } from '@ethersproject/providers' +import { + L1ToL2MessageGasEstimator, + L1ToL2MessageStatus, + L1TransactionReceipt, +} from '@arbitrum/sdk' +import { exit } from 'process' +import { getBaseFee } from '@arbitrum/sdk/dist/lib/utils/lib' +import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory' +import { ContractVerifier } from './contractVerifier' + +/** + * Use already deployed L1TokenBridgeCreator to create and init token bridge contracts. + * Function first gets estimates for 2 retryable tickets - one for deploying L2 factory and + * one for deploying L2 side of token bridge. Then it creates retryables, waits for + * until they're executed, and finally it picks up addresses of new contracts. + * + * @param l1Signer + * @param l2Provider + * @param l1TokenBridgeCreator + * @param rollupAddress + * @returns + */ +export const createTokenBridge = async ( + l1Signer: Signer, + l2Provider: ethers.providers.Provider, + l1TokenBridgeCreator: L1AtomicTokenBridgeCreator, + rollupAddress: string, + rollupOwnerAddress: string +) => { + const gasPrice = await l2Provider.getGasPrice() + + //// run retryable estimate for deploying L2 factory + const deployFactoryGasParams = await getEstimateForDeployingFactory( + l1Signer, + l2Provider + ) + + const maxGasForFactory = + await l1TokenBridgeCreator.gasLimitForL2FactoryDeployment() + const maxSubmissionCostForFactory = deployFactoryGasParams.maxSubmissionCost + + //// run retryable estimate for deploying L2 contracts + //// we do this estimate using L2 factory template on L1 because on L2 factory does not yet exist + const l2FactoryTemplate = L2AtomicTokenBridgeFactory__factory.connect( + await l1TokenBridgeCreator.l2TokenBridgeFactoryTemplate(), + l1Signer + ) + const l2Code = { + router: L2GatewayRouter__factory.bytecode, + standardGateway: L2ERC20Gateway__factory.bytecode, + customGateway: L2CustomGateway__factory.bytecode, + wethGateway: L2WethGateway__factory.bytecode, + aeWeth: AeWETH__factory.bytecode, + upgradeExecutor: UpgradeExecutorBytecode, + multicall: ArbMulticall2__factory.bytecode, + } + const gasEstimateToDeployContracts = + await l2FactoryTemplate.estimateGas.deployL2Contracts( + l2Code, + ethers.Wallet.createRandom().address, + ethers.Wallet.createRandom().address, + ethers.Wallet.createRandom().address, + ethers.Wallet.createRandom().address, + ethers.Wallet.createRandom().address, + ethers.Wallet.createRandom().address, + ethers.Wallet.createRandom().address, + ethers.Wallet.createRandom().address + ) + const maxGasForContracts = gasEstimateToDeployContracts.mul(2) + const maxSubmissionCostForContracts = + deployFactoryGasParams.maxSubmissionCost.mul(2) + + let retryableFee = maxSubmissionCostForFactory + .add(maxSubmissionCostForContracts) + .add(maxGasForFactory.mul(gasPrice)) + .add(maxGasForContracts.mul(gasPrice)) + + // get inbox from rollup contract + const inbox = await RollupAdminLogic__factory.connect( + rollupAddress, + l1Signer.provider! + ).inbox() + + // if fee token is used approve the fee + const feeToken = await _getFeeToken(inbox, l1Signer.provider!) + if (feeToken != ethers.constants.AddressZero) { + await ( + await IERC20__factory.connect(feeToken, l1Signer).approve( + l1TokenBridgeCreator.address, + retryableFee + ) + ).wait() + retryableFee = BigNumber.from(0) + } + + /// do it - create token bridge + const receipt = await ( + await l1TokenBridgeCreator.createTokenBridge( + inbox, + rollupOwnerAddress, + maxGasForContracts, + gasPrice, + { value: retryableFee } + ) + ).wait() + + console.log('Deployment TX:', receipt.transactionHash) + + /// wait for execution of both tickets + const l1TxReceipt = new L1TransactionReceipt(receipt) + const messages = await l1TxReceipt.getL1ToL2Messages(l2Provider) + const messageResults = await Promise.all( + messages.map(message => message.waitForStatus()) + ) + + // if both tickets are not redeemed log it and exit + if ( + messageResults[0].status !== L1ToL2MessageStatus.REDEEMED || + messageResults[1].status !== L1ToL2MessageStatus.REDEEMED + ) { + console.log( + `Retryable ticket (ID ${messages[0].retryableCreationId}) status: ${ + L1ToL2MessageStatus[messageResults[0].status] + }` + ) + console.log( + `Retryable ticket (ID ${messages[1].retryableCreationId}) status: ${ + L1ToL2MessageStatus[messageResults[1].status] + }` + ) + exit() + } + + /// pick up L2 factory address from 1st ticket + const l2AtomicTokenBridgeFactory = + L2AtomicTokenBridgeFactory__factory.connect( + messageResults[0].l2TxReceipt.contractAddress, + l2Provider + ) + console.log('L2AtomicTokenBridgeFactory', l2AtomicTokenBridgeFactory.address) + + /// pick up L1 contracts from events + const { + router: l1Router, + standardGateway: l1StandardGateway, + customGateway: l1CustomGateway, + wethGateway: l1WethGateway, + proxyAdmin: l1ProxyAdmin, + } = getParsedLogs( + receipt.logs, + l1TokenBridgeCreator.interface, + 'OrbitTokenBridgeCreated' + )[0].args + + const rollup = await IBridge__factory.connect( + await IInbox__factory.connect(inbox, l1Signer).bridge(), + l1Signer + ).rollup() + const chainId = await IRollupCore__factory.connect(rollup, l1Signer).chainId() + + /// pick up L2 contracts + const l2Router = await l1TokenBridgeCreator.getCanonicalL2RouterAddress( + chainId + ) + const l2StandardGateway = L2ERC20Gateway__factory.connect( + await l1TokenBridgeCreator.getCanonicalL2StandardGatewayAddress(chainId), + l2Provider + ) + const beaconProxyFactory = await l2StandardGateway.beaconProxyFactory() + const l2CustomGateway = + await l1TokenBridgeCreator.getCanonicalL2CustomGatewayAddress(chainId) + + const isUsingFeeToken = feeToken != ethers.constants.AddressZero + const l2WethGateway = isUsingFeeToken + ? ethers.constants.AddressZero + : L2WethGateway__factory.connect( + await l1TokenBridgeCreator.getCanonicalL2WethGatewayAddress(chainId), + l2Provider + ).address + const l1Weth = await l1TokenBridgeCreator.l1Weth() + const l2Weth = isUsingFeeToken + ? ethers.constants.AddressZero + : await l1TokenBridgeCreator.getCanonicalL2WethAddress(chainId) + const l2ProxyAdmin = + await l1TokenBridgeCreator.getCanonicalL2ProxyAdminAddress(chainId) + + return { + l1Router, + l1StandardGateway, + l1CustomGateway, + l1WethGateway, + l1ProxyAdmin, + l2Router, + l2StandardGateway: l2StandardGateway.address, + l2CustomGateway, + l2WethGateway, + l1Weth, + l2Weth, + beaconProxyFactory, + l2ProxyAdmin, + } +} + +/** + * Deploy token bridge creator contract to base chain and set all the templates + * @param l1Deployer + * @param l2Provider + * @param l1WethAddress + * @returns + */ +export const deployL1TokenBridgeCreator = async ( + l1Deployer: Signer, + l2Provider: ethers.providers.Provider, + l1WethAddress: string, + verifyContracts: boolean = false +) => { + /// deploy creator behind proxy + const l2MulticallAddressOnL1Fac = await new ArbMulticall2__factory( + l1Deployer + ).deploy() + const l2MulticallAddressOnL1 = await l2MulticallAddressOnL1Fac.deployed() + + const l1TokenBridgeCreatorProxyAdmin = await new ProxyAdmin__factory( + l1Deployer + ).deploy() + await l1TokenBridgeCreatorProxyAdmin.deployed() + + const l1TokenBridgeCreatorLogic = + await new L1AtomicTokenBridgeCreator__factory(l1Deployer).deploy( + l2MulticallAddressOnL1.address + ) + await l1TokenBridgeCreatorLogic.deployed() + + const l1TokenBridgeCreatorProxy = + await new TransparentUpgradeableProxy__factory(l1Deployer).deploy( + l1TokenBridgeCreatorLogic.address, + l1TokenBridgeCreatorProxyAdmin.address, + '0x' + ) + await l1TokenBridgeCreatorProxy.deployed() + + const l1TokenBridgeCreator = L1AtomicTokenBridgeCreator__factory.connect( + l1TokenBridgeCreatorProxy.address, + l1Deployer + ) + + /// deploy retryable sender behind proxy + const retryableSenderLogic = await new L1TokenBridgeRetryableSender__factory( + l1Deployer + ).deploy() + await retryableSenderLogic.deployed() + + const retryableSenderProxy = await new TransparentUpgradeableProxy__factory( + l1Deployer + ).deploy( + retryableSenderLogic.address, + l1TokenBridgeCreatorProxyAdmin.address, + '0x' + ) + await retryableSenderProxy.deployed() + + const retryableSender = L1TokenBridgeRetryableSender__factory.connect( + retryableSenderProxy.address, + l1Deployer + ) + + /// init creator + await (await l1TokenBridgeCreator.initialize(retryableSender.address)).wait() + + /// deploy L1 logic contracts + const routerTemplate = await new L1GatewayRouter__factory(l1Deployer).deploy() + await routerTemplate.deployed() + + const standardGatewayTemplate = await new L1ERC20Gateway__factory( + l1Deployer + ).deploy() + await standardGatewayTemplate.deployed() + + const customGatewayTemplate = await new L1CustomGateway__factory( + l1Deployer + ).deploy() + await customGatewayTemplate.deployed() + + const wethGatewayTemplate = await new L1WethGateway__factory( + l1Deployer + ).deploy() + await wethGatewayTemplate.deployed() + + const feeTokenBasedRouterTemplate = await new L1OrbitGatewayRouter__factory( + l1Deployer + ).deploy() + await feeTokenBasedRouterTemplate.deployed() + + const feeTokenBasedStandardGatewayTemplate = + await new L1OrbitERC20Gateway__factory(l1Deployer).deploy() + await feeTokenBasedStandardGatewayTemplate.deployed() + + const feeTokenBasedCustomGatewayTemplate = + await new L1OrbitCustomGateway__factory(l1Deployer).deploy() + await feeTokenBasedCustomGatewayTemplate.deployed() + + const upgradeExecutorFactory = new ethers.ContractFactory( + UpgradeExecutorABI, + UpgradeExecutorBytecode, + l1Deployer + ) + const upgradeExecutor = await upgradeExecutorFactory.deploy() + + const l1Templates = { + routerTemplate: routerTemplate.address, + standardGatewayTemplate: standardGatewayTemplate.address, + customGatewayTemplate: customGatewayTemplate.address, + wethGatewayTemplate: wethGatewayTemplate.address, + feeTokenBasedRouterTemplate: feeTokenBasedRouterTemplate.address, + feeTokenBasedStandardGatewayTemplate: + feeTokenBasedStandardGatewayTemplate.address, + feeTokenBasedCustomGatewayTemplate: + feeTokenBasedCustomGatewayTemplate.address, + upgradeExecutor: upgradeExecutor.address, + } + + /// deploy L2 contracts as placeholders on L1 + const l2TokenBridgeFactoryOnL1 = + await new L2AtomicTokenBridgeFactory__factory(l1Deployer).deploy() + await l2TokenBridgeFactoryOnL1.deployed() + + const l2GatewayRouterOnL1 = await new L2GatewayRouter__factory( + l1Deployer + ).deploy() + await l2GatewayRouterOnL1.deployed() + + const l2StandardGatewayAddressOnL1 = await new L2ERC20Gateway__factory( + l1Deployer + ).deploy() + await l2StandardGatewayAddressOnL1.deployed() + + const l2CustomGatewayAddressOnL1 = await new L2CustomGateway__factory( + l1Deployer + ).deploy() + await l2CustomGatewayAddressOnL1.deployed() + + const l2WethGatewayAddressOnL1 = await new L2WethGateway__factory( + l1Deployer + ).deploy() + await l2WethGatewayAddressOnL1.deployed() + + const l2WethAddressOnL1 = await new AeWETH__factory(l1Deployer).deploy() + await l2WethAddressOnL1.deployed() + + const l1Multicall = await new Multicall2__factory(l1Deployer).deploy() + await l1Multicall.deployed() + + //// run retryable estimate for deploying L2 factory + const deployFactoryGasParams = await getEstimateForDeployingFactory( + l1Deployer, + l2Provider + ) + + await ( + await l1TokenBridgeCreator.setTemplates( + l1Templates, + l2TokenBridgeFactoryOnL1.address, + l2GatewayRouterOnL1.address, + l2StandardGatewayAddressOnL1.address, + l2CustomGatewayAddressOnL1.address, + l2WethGatewayAddressOnL1.address, + l2WethAddressOnL1.address, + l1WethAddress, + l1Multicall.address, + deployFactoryGasParams.gasLimit + ) + ).wait() + + ///// verify contracts + if (verifyContracts) { + console.log('\n\n Start contract verification \n\n') + const l1Verifier = new ContractVerifier( + (await l1Deployer.provider!.getNetwork()).chainId, + process.env.ARBISCAN_API_KEY! + ) + const abi = ethers.utils.defaultAbiCoder + + await l1Verifier.verifyWithAddress( + 'l1TokenBridgeCreatorProxyAdmin', + l1TokenBridgeCreatorProxyAdmin.address + ) + await l1Verifier.verifyWithAddress( + 'l1TokenBridgeCreatorLogic', + l1TokenBridgeCreatorLogic.address + ) + await l1Verifier.verifyWithAddress( + 'l1TokenBridgeCreatorProxy', + l1TokenBridgeCreatorProxy.address, + abi.encode( + ['address', 'address', 'bytes'], + [ + l1TokenBridgeCreatorLogic.address, + l1TokenBridgeCreatorProxyAdmin.address, + '0x', + ] + ) + ) + await l1Verifier.verifyWithAddress( + 'retryableSenderLogic', + retryableSenderLogic.address + ) + await l1Verifier.verifyWithAddress( + 'retryableSenderProxy', + retryableSenderProxy.address, + abi.encode( + ['address', 'address', 'bytes'], + [ + retryableSenderLogic.address, + l1TokenBridgeCreatorProxyAdmin.address, + '0x', + ] + ) + ) + await l1Verifier.verifyWithAddress('routerTemplate', routerTemplate.address) + await l1Verifier.verifyWithAddress( + 'standardGatewayTemplate', + standardGatewayTemplate.address + ) + await l1Verifier.verifyWithAddress( + 'customGatewayTemplate', + customGatewayTemplate.address + ) + await l1Verifier.verifyWithAddress( + 'wethGatewayTemplate', + wethGatewayTemplate.address + ) + await l1Verifier.verifyWithAddress( + 'feeTokenBasedRouterTemplate', + feeTokenBasedRouterTemplate.address + ) + await l1Verifier.verifyWithAddress( + 'feeTokenBasedStandardGatewayTemplate', + feeTokenBasedStandardGatewayTemplate.address + ) + await l1Verifier.verifyWithAddress( + 'feeTokenBasedCustomGatewayTemplate', + feeTokenBasedCustomGatewayTemplate.address + ) + await l1Verifier.verifyWithAddress( + 'upgradeExecutor', + upgradeExecutor.address, + '', + 20000 + ) + await l1Verifier.verifyWithAddress( + 'l2TokenBridgeFactoryOnL1', + l2TokenBridgeFactoryOnL1.address + ) + await l1Verifier.verifyWithAddress( + 'l2GatewayRouterOnL1', + l2GatewayRouterOnL1.address + ) + await l1Verifier.verifyWithAddress( + 'l2StandardGatewayAddressOnL1', + l2StandardGatewayAddressOnL1.address + ) + await l1Verifier.verifyWithAddress( + 'l2CustomGatewayAddressOnL1', + l2CustomGatewayAddressOnL1.address + ) + await l1Verifier.verifyWithAddress( + 'l2WethGatewayAddressOnL1', + l2WethGatewayAddressOnL1.address + ) + await l1Verifier.verifyWithAddress( + 'l2WethAddressOnL1', + l2WethAddressOnL1.address + ) + await l1Verifier.verifyWithAddress( + 'l2MulticallAddressOnL1', + l2MulticallAddressOnL1.address + ) + + await l1Verifier.verifyWithAddress('l1Multicall', l1Multicall.address) + + await new Promise(resolve => setTimeout(resolve, 2000)) + console.log('\n\n Contract verification done \n\n') + } + + return { l1TokenBridgeCreator, retryableSender } +} + +export const getEstimateForDeployingFactory = async ( + l1Deployer: Signer, + l2Provider: ethers.providers.Provider +) => { + //// run retryable estimate for deploying L2 factory + const l1DeployerAddress = await l1Deployer.getAddress() + const l1ToL2MsgGasEstimate = new L1ToL2MessageGasEstimator(l2Provider) + const deployFactoryGasParams = await l1ToL2MsgGasEstimate.estimateAll( + { + from: ethers.Wallet.createRandom().address, + to: ethers.constants.AddressZero, + l2CallValue: BigNumber.from(0), + excessFeeRefundAddress: l1DeployerAddress, + callValueRefundAddress: l1DeployerAddress, + data: L2AtomicTokenBridgeFactory__factory.bytecode, + }, + await getBaseFee(l1Deployer.provider!), + l1Deployer.provider! + ) + + return deployFactoryGasParams +} + +export const getSigner = (provider: JsonRpcProvider, key?: string) => { + if (!key && !provider) + throw new Error('Provide at least one of key or provider.') + if (key) return new Wallet(key).connect(provider) + else return provider.getSigner(0) +} + +export const getParsedLogs = ( + logs: ethers.providers.Log[], + iface: ethers.utils.Interface, + eventName: string +) => { + const eventFragment = iface.getEvent(eventName) + const parsedLogs = logs + .filter( + (curr: any) => curr.topics[0] === iface.getEventTopic(eventFragment) + ) + .map((curr: any) => iface.parseLog(curr)) + return parsedLogs +} + +const _getFeeToken = async ( + inbox: string, + l1Provider: ethers.providers.Provider +) => { + const bridge = await IInbox__factory.connect(inbox, l1Provider).bridge() + + let feeToken = ethers.constants.AddressZero + + try { + feeToken = await IERC20Bridge__factory.connect( + bridge, + l1Provider + ).nativeToken() + } catch {} + + return feeToken +} + +export function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)) +} diff --git a/scripts/contractVerifier.ts b/scripts/contractVerifier.ts new file mode 100644 index 0000000000..d04d0c58ef --- /dev/null +++ b/scripts/contractVerifier.ts @@ -0,0 +1,103 @@ +import { exec } from 'child_process' +import { ethers } from 'ethers' + +export class ContractVerifier { + chainId: number + apiKey: string = '' + + readonly NUM_OF_OPTIMIZATIONS = 100 + readonly COMPILER_VERSION = '0.8.16' + + ///// List of contract addresses and their corresponding source code files + readonly TUP = + 'node_modules/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy' + readonly PROXY_ADMIN = + 'node_modules/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol:ProxyAdmin' + readonly EXECUTOR = + 'node_modules/@offchainlabs/upgrade-executor/src/UpgradeExecutor.sol:UpgradeExecutor' + + readonly contractToSource = { + l1TokenBridgeCreatorProxyAdmin: this.PROXY_ADMIN, + l1TokenBridgeCreatorLogic: + 'contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol:L1AtomicTokenBridgeCreator', + l1TokenBridgeCreatorProxy: this.TUP, + retryableSenderLogic: + 'contracts/tokenbridge/ethereum/L1TokenBridgeRetryableSender.sol:L1TokenBridgeRetryableSender', + retryableSenderProxy: this.TUP, + routerTemplate: + 'contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol:L1GatewayRouter', + standardGatewayTemplate: + 'contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol:L1ERC20Gateway', + customGatewayTemplate: + 'contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol:L1CustomGateway', + wethGatewayTemplate: + 'contracts/tokenbridge/ethereum/gateway/L1WethGateway.sol:L1WethGateway', + feeTokenBasedRouterTemplate: + 'contracts/tokenbridge/ethereum/gateway/L1OrbitGatewayRouter.sol:L1OrbitGatewayRouter', + feeTokenBasedStandardGatewayTemplate: + 'contracts/tokenbridge/ethereum/gateway/L1OrbitERC20Gateway.sol:L1OrbitERC20Gateway', + feeTokenBasedCustomGatewayTemplate: + 'contracts/tokenbridge/ethereum/gateway/L1OrbitCustomGateway.sol:L1OrbitCustomGateway', + upgradeExecutor: this.EXECUTOR, + l2TokenBridgeFactoryOnL1: + 'contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol:L2AtomicTokenBridgeFactory', + l2GatewayRouterOnL1: + 'contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol:L2GatewayRouter', + l2StandardGatewayAddressOnL1: + 'contracts/tokenbridge/arbitrum/gateway/L2ERC20Gateway.sol:L2ERC20Gateway', + l2CustomGatewayAddressOnL1: + 'contracts/tokenbridge/arbitrum/gateway/L2CustomGateway.sol:L2CustomGateway', + l2WethGatewayAddressOnL1: + 'contracts/tokenbridge/arbitrum/gateway/L2WethGateway.sol:L2WethGateway', + l2WethAddressOnL1: 'contracts/tokenbridge/libraries/aeWETH.sol:aeWETH', + l2MulticallAddressOnL1: 'contracts/rpc-utils/MulticallV2.sol:ArbMulticall2', + l1Multicall: 'contracts/rpc-utils/MulticallV2.sol:Multicall2', + } + + constructor(chainId: number, apiKey: string) { + this.chainId = chainId + if (apiKey) { + this.apiKey = apiKey + } + } + + async verifyWithAddress( + name: string, + contractAddress: string, + constructorArgs?: string, + _numOfOptimization?: number + ) { + // avoid rate limiting + await new Promise(resolve => setTimeout(resolve, 1000)) + + let command = `forge verify-contract --chain-id ${this.chainId} --compiler-version ${this.COMPILER_VERSION}` + + if (_numOfOptimization !== undefined) { + command = `${command} --num-of-optimizations ${_numOfOptimization}` + } else { + command = `${command} --num-of-optimizations ${this.NUM_OF_OPTIMIZATIONS}` + } + + const sourceFile = + this.contractToSource[name as keyof typeof this.contractToSource] + + if (constructorArgs) { + command = `${command} --constructor-args ${constructorArgs}` + } + command = `${command} ${contractAddress} ${sourceFile} --etherscan-api-key ${this.apiKey}` + + exec(command, (err: Error | null, stdout: string, stderr: string) => { + console.log('-----------------') + console.log(command) + if (err) { + console.log( + 'Failed to submit for verification', + contractAddress, + stderr + ) + } else { + console.log('Successfully submitted for verification', contractAddress) + } + }) + } +} diff --git a/scripts/goerli-deployment/createTokenBridge.ts b/scripts/goerli-deployment/createTokenBridge.ts new file mode 100644 index 0000000000..b2a6039300 --- /dev/null +++ b/scripts/goerli-deployment/createTokenBridge.ts @@ -0,0 +1,182 @@ +import { JsonRpcProvider } from '@ethersproject/providers' +import { L1Network, L2Network, addCustomNetwork } from '@arbitrum/sdk' +import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory' +import { createTokenBridge, getSigner } from '../atomicTokenBridgeDeployer' +import dotenv from 'dotenv' +import { L1AtomicTokenBridgeCreator__factory } from '../../build/types' +import * as fs from 'fs' +import { env } from 'process' + +dotenv.config() + +export const envVars = { + rollupAddress: process.env['ROLLUP_ADDRESS'] as string, + rollupOwner: process.env['ROLLUP_OWNER'] as string, + l1TokenBridgeCreator: process.env['L1_TOKEN_BRIDGE_CREATOR'] as string, + baseChainRpc: process.env['BASECHAIN_RPC'] as string, + baseChainDeployerKey: process.env['BASECHAIN_DEPLOYER_KEY'] as string, + childChainRpc: process.env['ORBIT_RPC'] as string, +} + +/** + * Steps: + * - read network info from local container and register networks + * - deploy L1 bridge creator and set templates + * - do single TX deployment of token bridge + * - populate network objects with new addresses and return it + * + * @param l1Deployer + * @param l2Deployer + * @param l1Url + * @param l2Url + * @returns + */ +export const createTokenBridgeOnGoerli = async () => { + if (envVars.rollupAddress == undefined) + throw new Error('Missing ROLLUP_ADDRESS in env vars') + if (envVars.rollupOwner == undefined) + throw new Error('Missing ROLLUP_OWNER in env vars') + if (envVars.l1TokenBridgeCreator == undefined) + throw new Error('Missing L1_TOKEN_BRIDGE_CREATOR in env vars') + if (envVars.baseChainRpc == undefined) + throw new Error('Missing BASECHAIN_RPC in env vars') + if (envVars.baseChainDeployerKey == undefined) + throw new Error('Missing BASECHAIN_DEPLOYER_KEY in env vars') + if (envVars.childChainRpc == undefined) + throw new Error('Missing ORBIT_RPC in env vars') + + console.log('Creating token bridge for rollup', envVars.rollupAddress) + + const l1Provider = new JsonRpcProvider(envVars.baseChainRpc) + const l1Deployer = getSigner(l1Provider, envVars.baseChainDeployerKey) + const l2Provider = new JsonRpcProvider(envVars.childChainRpc) + + const { l1Network, l2Network: corel2Network } = await registerGoerliNetworks( + l1Provider, + l2Provider, + envVars.rollupAddress + ) + + const l1TokenBridgeCreator = L1AtomicTokenBridgeCreator__factory.connect( + envVars.l1TokenBridgeCreator, + l1Deployer + ) + + // create token bridge + const deployedContracts = await createTokenBridge( + l1Deployer, + l2Provider, + l1TokenBridgeCreator, + envVars.rollupAddress, + envVars.rollupOwner + ) + + const l2Network = { + ...corel2Network, + tokenBridge: { + l1CustomGateway: deployedContracts.l1CustomGateway, + l1ERC20Gateway: deployedContracts.l1StandardGateway, + l1GatewayRouter: deployedContracts.l1Router, + l1MultiCall: '', + l1ProxyAdmin: deployedContracts.l1ProxyAdmin, + l1Weth: deployedContracts.l1Weth, + l1WethGateway: deployedContracts.l1WethGateway, + + l2CustomGateway: deployedContracts.l2CustomGateway, + l2ERC20Gateway: deployedContracts.l2StandardGateway, + l2GatewayRouter: deployedContracts.l2Router, + l2Multicall: '', + l2ProxyAdmin: deployedContracts.l2ProxyAdmin, + l2Weth: deployedContracts.l2Weth, + l2WethGateway: deployedContracts.l2WethGateway, + }, + } + + return { + l1Network, + l2Network, + } +} + +const registerGoerliNetworks = async ( + l1Provider: JsonRpcProvider, + l2Provider: JsonRpcProvider, + rollupAddress: string +): Promise<{ + l1Network: L1Network + l2Network: Omit +}> => { + const l1NetworkInfo = await l1Provider.getNetwork() + const l2NetworkInfo = await l2Provider.getNetwork() + + const l1Network: L1Network = { + blockTime: 10, + chainID: l1NetworkInfo.chainId, + explorerUrl: '', + isCustom: true, + name: l1NetworkInfo.name, + partnerChainIDs: [l2NetworkInfo.chainId], + isArbitrum: false, + } + + const rollup = RollupAdminLogic__factory.connect(rollupAddress, l1Provider) + const l2Network: L2Network = { + chainID: l2NetworkInfo.chainId, + confirmPeriodBlocks: (await rollup.confirmPeriodBlocks()).toNumber(), + ethBridge: { + bridge: await rollup.bridge(), + inbox: await rollup.inbox(), + outbox: await rollup.outbox(), + rollup: rollup.address, + sequencerInbox: await rollup.sequencerInbox(), + }, + explorerUrl: '', + isArbitrum: true, + isCustom: true, + name: 'OrbitChain', + partnerChainID: l1NetworkInfo.chainId, + retryableLifetimeSeconds: 7 * 24 * 60 * 60, + nitroGenesisBlock: 0, + nitroGenesisL1Block: 0, + depositTimeout: 900000, + tokenBridge: { + l1CustomGateway: '', + l1ERC20Gateway: '', + l1GatewayRouter: '', + l1MultiCall: '', + l1ProxyAdmin: '', + l1Weth: '', + l1WethGateway: '', + l2CustomGateway: '', + l2ERC20Gateway: '', + l2GatewayRouter: '', + l2Multicall: '', + l2ProxyAdmin: '', + l2Weth: '', + l2WethGateway: '', + }, + } + + // register - needed for retryables + addCustomNetwork({ + customL1Network: l1Network, + customL2Network: l2Network, + }) + + return { + l1Network, + l2Network, + } +} + +async function main() { + const { l1Network, l2Network } = await createTokenBridgeOnGoerli() + const NETWORK_FILE = 'network.json' + fs.writeFileSync( + NETWORK_FILE, + JSON.stringify({ l1Network, l2Network }, null, 2) + ) + console.log(NETWORK_FILE + ' updated') +} + +main().then(() => console.log('Done.')) diff --git a/scripts/goerli-deployment/deployTokenBridgeCreator.ts b/scripts/goerli-deployment/deployTokenBridgeCreator.ts new file mode 100644 index 0000000000..c5a17a01e7 --- /dev/null +++ b/scripts/goerli-deployment/deployTokenBridgeCreator.ts @@ -0,0 +1,136 @@ +import { JsonRpcProvider } from '@ethersproject/providers' +import { L1Network, L2Network, addCustomNetwork } from '@arbitrum/sdk' +import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory' +import { + deployL1TokenBridgeCreator, + getSigner, +} from '../atomicTokenBridgeDeployer' +import dotenv from 'dotenv' + +dotenv.config() + +export const envVars = { + baseChainRpc: process.env['BASECHAIN_RPC'] as string, + baseChainDeployerKey: process.env['BASECHAIN_DEPLOYER_KEY'] as string, + childChainRpc: process.env['ORBIT_RPC'] as string, +} + +const ARB_GOERLI_WETH = '0xEe01c0CD76354C383B8c7B4e65EA88D00B06f36f' + +/** + * Steps: + * - read network info from local container and register networks + * - deploy L1 bridge creator and set templates + * - do single TX deployment of token bridge + * - populate network objects with new addresses and return it + * + * @param l1Deployer + * @param l2Deployer + * @param l1Url + * @param l2Url + * @returns + */ +export const deployTokenBridgeCreator = async (rollupAddress: string) => { + if (envVars.baseChainRpc == undefined) + throw new Error('Missing BASECHAIN_RPC in env vars') + if (envVars.baseChainDeployerKey == undefined) + throw new Error('Missing BASECHAIN_DEPLOYER_KEY in env vars') + if (envVars.childChainRpc == undefined) + throw new Error('Missing ORBIT_RPC in env vars') + + const l1Provider = new JsonRpcProvider(envVars.baseChainRpc) + const l1Deployer = getSigner(l1Provider, envVars.baseChainDeployerKey) + const l2Provider = new JsonRpcProvider(envVars.childChainRpc) + + await registerGoerliNetworks(l1Provider, l2Provider, rollupAddress) + + // deploy L1 creator and set templates + const { l1TokenBridgeCreator, retryableSender } = + await deployL1TokenBridgeCreator(l1Deployer, l2Provider, ARB_GOERLI_WETH, true) + + return { l1TokenBridgeCreator, retryableSender } +} + +const registerGoerliNetworks = async ( + l1Provider: JsonRpcProvider, + l2Provider: JsonRpcProvider, + rollupAddress: string +): Promise<{ + l1Network: L1Network + l2Network: Omit +}> => { + const l1NetworkInfo = await l1Provider.getNetwork() + const l2NetworkInfo = await l2Provider.getNetwork() + + const l1Network: L1Network = { + blockTime: 10, + chainID: l1NetworkInfo.chainId, + explorerUrl: '', + isCustom: true, + name: l1NetworkInfo.name, + partnerChainIDs: [l2NetworkInfo.chainId], + isArbitrum: false, + } + + const rollup = RollupAdminLogic__factory.connect(rollupAddress, l1Provider) + const l2Network: L2Network = { + chainID: l2NetworkInfo.chainId, + confirmPeriodBlocks: (await rollup.confirmPeriodBlocks()).toNumber(), + ethBridge: { + bridge: await rollup.bridge(), + inbox: await rollup.inbox(), + outbox: await rollup.outbox(), + rollup: rollup.address, + sequencerInbox: await rollup.sequencerInbox(), + }, + explorerUrl: '', + isArbitrum: true, + isCustom: true, + name: 'OrbitChain', + partnerChainID: l1NetworkInfo.chainId, + retryableLifetimeSeconds: 7 * 24 * 60 * 60, + nitroGenesisBlock: 0, + nitroGenesisL1Block: 0, + depositTimeout: 900000, + tokenBridge: { + l1CustomGateway: '', + l1ERC20Gateway: '', + l1GatewayRouter: '', + l1MultiCall: '', + l1ProxyAdmin: '', + l1Weth: '', + l1WethGateway: '', + l2CustomGateway: '', + l2ERC20Gateway: '', + l2GatewayRouter: '', + l2Multicall: '', + l2ProxyAdmin: '', + l2Weth: '', + l2WethGateway: '', + }, + } + + // register - needed for retryables + addCustomNetwork({ + customL1Network: l1Network, + customL2Network: l2Network, + }) + + return { + l1Network, + l2Network, + } +} + +async function main() { + // this is just random Orbit rollup that will be used to estimate gas needed to deploy L2 token bridge factory via retryable + const rollupAddress = '0x8223bd899C6643483872ed2A7b105b2aC9C8aBEc' + const { l1TokenBridgeCreator, retryableSender } = + await deployTokenBridgeCreator(rollupAddress) + + console.log('Token bridge creator deployed!') + console.log('L1TokenBridgeCreator:', l1TokenBridgeCreator.address) + console.log('L1TokenBridgeRetryableSender:', retryableSender.address, '\n') +} + +main().then(() => console.log('Done.')) diff --git a/scripts/local-deployment/deployCreatorAndCreateTokenBridge.ts b/scripts/local-deployment/deployCreatorAndCreateTokenBridge.ts new file mode 100644 index 0000000000..1c18c1ed6e --- /dev/null +++ b/scripts/local-deployment/deployCreatorAndCreateTokenBridge.ts @@ -0,0 +1,229 @@ +import { ethers } from 'ethers' +import { JsonRpcProvider } from '@ethersproject/providers' +import { L1Network, L2Network, addCustomNetwork } from '@arbitrum/sdk' +import { Bridge__factory } from '@arbitrum/sdk/dist/lib/abi/factories/Bridge__factory' +import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory' +import * as fs from 'fs' +import { execSync } from 'child_process' +import { + createTokenBridge, + deployL1TokenBridgeCreator, +} from '../atomicTokenBridgeDeployer' +import { l2Networks } from '@arbitrum/sdk/dist/lib/dataEntities/networks' + +/** + * Steps: + * - read network info from local container and register networks + * - deploy L1 bridge creator and set templates + * - do single TX deployment of token bridge + * - populate network objects with new addresses and return it + * + * @param l1Deployer + * @param l2Deployer + * @param l1Url + * @param l2Url + * @returns + */ +export const setupTokenBridgeInLocalEnv = async () => { + /// setup deployers, load local networks + /// L1 URL = parent chain = L2 + /// L2 URL = child chain = L3 + const config = { + l1Url: 'http://localhost:8547', + l2Url: 'http://localhost:3347', + } + const l1Deployer = new ethers.Wallet( + ethers.utils.sha256(ethers.utils.toUtf8Bytes('user_token_bridge_deployer')), + new ethers.providers.JsonRpcProvider(config.l1Url) + ) + const l2Deployer = new ethers.Wallet( + ethers.utils.sha256(ethers.utils.toUtf8Bytes('user_token_bridge_deployer')), + new ethers.providers.JsonRpcProvider(config.l2Url) + ) + // docker-compose run scripts print-address --account l3owner | tail -n 1 | tr -d '\r\n' + const orbitOwner = '0x863c904166E801527125D8672442D736194A3362' + + const { l1Network, l2Network: coreL2Network } = await getLocalNetworks( + config.l1Url, + config.l2Url + ) + + // register - needed for retryables + const existingL2Network = l2Networks[coreL2Network.chainID.toString()] + if (!existingL2Network) { + addCustomNetwork({ + customL1Network: l1Network, + customL2Network: { + ...coreL2Network, + tokenBridge: { + l1CustomGateway: '', + l1ERC20Gateway: '', + l1GatewayRouter: '', + l1MultiCall: '', + l1ProxyAdmin: '', + l1Weth: '', + l1WethGateway: '', + + l2CustomGateway: '', + l2ERC20Gateway: '', + l2GatewayRouter: '', + l2Multicall: '', + l2ProxyAdmin: '', + l2Weth: '', + l2WethGateway: '', + }, + }, + }) + } + + // prerequisite - deploy L1 creator and set templates + console.log('Deploying L1TokenBridgeCreator') + // a random address for l1Weth + const l1Weth = '0x05EcEffc7CBA4e43a410340E849052AD43815aCA' + const { l1TokenBridgeCreator, retryableSender } = + await deployL1TokenBridgeCreator(l1Deployer, l2Deployer.provider!, l1Weth) + console.log('L1TokenBridgeCreator', l1TokenBridgeCreator.address) + console.log('L1TokenBridgeRetryableSender', retryableSender.address) + + // create token bridge + console.log('Creating token bridge') + const deployedContracts = await createTokenBridge( + l1Deployer, + l2Deployer.provider!, + l1TokenBridgeCreator, + coreL2Network.ethBridge.rollup, + orbitOwner + ) + + const l2Network: L2Network = { + ...coreL2Network, + tokenBridge: { + l1CustomGateway: deployedContracts.l1CustomGateway, + l1ERC20Gateway: deployedContracts.l1StandardGateway, + l1GatewayRouter: deployedContracts.l1Router, + l1MultiCall: '', + l1ProxyAdmin: deployedContracts.l1ProxyAdmin, + l1Weth: deployedContracts.l1Weth, + l1WethGateway: deployedContracts.l1WethGateway, + + l2CustomGateway: deployedContracts.l2CustomGateway, + l2ERC20Gateway: deployedContracts.l2StandardGateway, + l2GatewayRouter: deployedContracts.l2Router, + l2Multicall: '', + l2ProxyAdmin: deployedContracts.l2ProxyAdmin, + l2Weth: deployedContracts.l2Weth, + l2WethGateway: deployedContracts.l2WethGateway, + }, + } + + const l1TokenBridgeCreatorAddress = l1TokenBridgeCreator.address + const retryableSenderAddress = retryableSender.address + + return { + l1Network, + l2Network, + l1TokenBridgeCreatorAddress, + retryableSenderAddress, + } +} + +export const getLocalNetworks = async ( + l1Url: string, + l2Url: string +): Promise<{ + l1Network: L1Network + l2Network: Omit +}> => { + const l1Provider = new JsonRpcProvider(l1Url) + const l2Provider = new JsonRpcProvider(l2Url) + let deploymentData: string + + let sequencerContainer = execSync( + 'docker ps --filter "name=l3node" --format "{{.Names}}"' + ) + .toString() + .trim() + + deploymentData = execSync( + `docker exec ${sequencerContainer} cat /config/l3deployment.json` + ).toString() + + const parsedDeploymentData = JSON.parse(deploymentData) as { + bridge: string + inbox: string + ['sequencer-inbox']: string + rollup: string + } + + const rollup = RollupAdminLogic__factory.connect( + parsedDeploymentData.rollup, + l1Provider + ) + const confirmPeriodBlocks = await rollup.confirmPeriodBlocks() + + const bridge = Bridge__factory.connect( + parsedDeploymentData.bridge, + l1Provider + ) + const outboxAddr = await bridge.allowedOutboxList(0) + + const l1NetworkInfo = await l1Provider.getNetwork() + const l2NetworkInfo = await l2Provider.getNetwork() + + const l1Network: L1Network = { + blockTime: 10, + chainID: l1NetworkInfo.chainId, + explorerUrl: '', + isCustom: true, + name: 'EthLocal', + partnerChainIDs: [l2NetworkInfo.chainId], + isArbitrum: false, + } + + const l2Network: Omit = { + chainID: l2NetworkInfo.chainId, + confirmPeriodBlocks: confirmPeriodBlocks.toNumber(), + ethBridge: { + bridge: parsedDeploymentData.bridge, + inbox: parsedDeploymentData.inbox, + outbox: outboxAddr, + rollup: parsedDeploymentData.rollup, + sequencerInbox: parsedDeploymentData['sequencer-inbox'], + }, + explorerUrl: '', + isArbitrum: true, + isCustom: true, + name: 'ArbLocal', + partnerChainID: l1NetworkInfo.chainId, + retryableLifetimeSeconds: 7 * 24 * 60 * 60, + nitroGenesisBlock: 0, + nitroGenesisL1Block: 0, + depositTimeout: 900000, + } + return { + l1Network, + l2Network, + } +} + +async function main() { + const { + l1Network, + l2Network, + l1TokenBridgeCreatorAddress: l1TokenBridgeCreator, + retryableSenderAddress: retryableSender, + } = await setupTokenBridgeInLocalEnv() + + const NETWORK_FILE = 'network.json' + fs.writeFileSync( + NETWORK_FILE, + JSON.stringify( + { l1Network, l2Network, l1TokenBridgeCreator, retryableSender }, + null, + 2 + ) + ) + console.log(NETWORK_FILE + ' updated') +} + +main().then(() => console.log('Done.')) diff --git a/test-e2e/orbitTokenBridge.ts b/test-e2e/orbitTokenBridge.ts new file mode 100644 index 0000000000..7dcf601d15 --- /dev/null +++ b/test-e2e/orbitTokenBridge.ts @@ -0,0 +1,358 @@ +import { + L1Network, + L1ToL2MessageGasEstimator, + L1ToL2MessageStatus, + L1TransactionReceipt, + L2Network, + L2TransactionReceipt, +} from '@arbitrum/sdk' +import { getBaseFee } from '@arbitrum/sdk/dist/lib/utils/lib' +import { JsonRpcProvider } from '@ethersproject/providers' +import { expect } from 'chai' +// import { ethers, Wallet } from '@arbitrum/sdk/node_modules/ethers' +import { setupTokenBridgeInLocalEnv } from '../scripts/local-deployment/deployCreatorAndCreateTokenBridge' +import { + ERC20, + ERC20__factory, + IERC20Bridge__factory, + IInbox__factory, + L1OrbitERC20Gateway__factory, + L1OrbitGatewayRouter__factory, + L2GatewayRouter__factory, + TestERC20, + TestERC20__factory, +} from '../build/types' +import { defaultAbiCoder } from 'ethers/lib/utils' +import { BigNumber, Wallet, ethers } from 'ethers' + +const config = { + arbUrl: 'http://localhost:8547', + ethUrl: 'http://localhost:8545', +} + +let l1Provider: JsonRpcProvider +let l2Provider: JsonRpcProvider + +let deployerL1Wallet: Wallet +let deployerL2Wallet: Wallet + +let userL1Wallet: Wallet +let userL2Wallet: Wallet + +let _l1Network: L1Network +let _l2Network: L2Network + +let token: TestERC20 +let l2Token: ERC20 +let nativeToken: ERC20 + +describe('orbitTokenBridge', () => { + // configure orbit token bridge + before(async function () { + l1Provider = new ethers.providers.JsonRpcProvider(config.ethUrl) + l2Provider = new ethers.providers.JsonRpcProvider(config.arbUrl) + + const deployerKey = ethers.utils.sha256( + ethers.utils.toUtf8Bytes('user_l1user') + ) + deployerL1Wallet = new ethers.Wallet(deployerKey, l1Provider) + deployerL2Wallet = new ethers.Wallet(deployerKey, l2Provider) + + console.log('setupOrbitTokenBridge') + const { l1Network, l2Network } = await setupTokenBridgeInLocalEnv() + + _l1Network = l1Network + _l2Network = l2Network + + // create user wallets and fund it + const userKey = ethers.utils.sha256(ethers.utils.toUtf8Bytes('user_wallet')) + userL1Wallet = new ethers.Wallet(userKey, l1Provider) + userL2Wallet = new ethers.Wallet(userKey, l2Provider) + await ( + await deployerL1Wallet.sendTransaction({ + to: userL1Wallet.address, + value: ethers.utils.parseEther('10.0'), + }) + ).wait() + }) + + it('should have deployed token bridge contracts', async function () { + // get router as entry point + const l1Router = L1OrbitGatewayRouter__factory.connect( + _l2Network.tokenBridge.l1GatewayRouter, + l1Provider + ) + + expect((await l1Router.defaultGateway()).toLowerCase()).to.be.eq( + _l2Network.tokenBridge.l1ERC20Gateway.toLowerCase() + ) + }) + + it('can deposit token via default gateway', async function () { + // fund user to be able to pay retryable fees + nativeToken = ERC20__factory.connect( + await getFeeToken(_l2Network.ethBridge.inbox, userL1Wallet), + userL1Wallet + ) + await ( + await nativeToken + .connect(deployerL1Wallet) + .transfer(userL1Wallet.address, ethers.utils.parseEther('1000')) + ).wait() + + // create token to be bridged + const tokenFactory = await new TestERC20__factory(userL1Wallet).deploy() + token = await tokenFactory.deployed() + await (await token.mint()).wait() + + // snapshot state before + + const userTokenBalanceBefore = await token.balanceOf(userL1Wallet.address) + const gatewayTokenBalanceBefore = await token.balanceOf( + _l2Network.tokenBridge.l1ERC20Gateway + ) + const userNativeTokenBalanceBefore = await nativeToken.balanceOf( + userL1Wallet.address + ) + const bridgeNativeTokenBalanceBefore = await nativeToken.balanceOf( + _l2Network.ethBridge.bridge + ) + + // approve token + const depositAmount = 350 + await ( + await token.approve(_l2Network.tokenBridge.l1ERC20Gateway, depositAmount) + ).wait() + + // calculate retryable params + const maxSubmissionCost = 0 + const callhook = '0x' + + const gateway = L1OrbitERC20Gateway__factory.connect( + _l2Network.tokenBridge.l1ERC20Gateway, + userL1Wallet + ) + const outboundCalldata = await gateway.getOutboundCalldata( + token.address, + userL1Wallet.address, + userL2Wallet.address, + depositAmount, + callhook + ) + + const l1ToL2MessageGasEstimate = new L1ToL2MessageGasEstimator(l2Provider) + const retryableParams = await l1ToL2MessageGasEstimate.estimateAll( + { + from: userL1Wallet.address, + to: userL2Wallet.address, + l2CallValue: BigNumber.from(0), + excessFeeRefundAddress: userL1Wallet.address, + callValueRefundAddress: userL1Wallet.address, + data: outboundCalldata, + }, + await getBaseFee(l1Provider), + l1Provider + ) + + const gasLimit = retryableParams.gasLimit.mul(40) + const maxFeePerGas = retryableParams.maxFeePerGas + const tokenTotalFeeAmount = gasLimit.mul(maxFeePerGas).mul(2) + + // approve fee amount + await ( + await nativeToken.approve( + _l2Network.tokenBridge.l1ERC20Gateway, + tokenTotalFeeAmount + ) + ).wait() + + // bridge it + const userEncodedData = defaultAbiCoder.encode( + ['uint256', 'bytes', 'uint256'], + [maxSubmissionCost, callhook, tokenTotalFeeAmount] + ) + + const router = L1OrbitGatewayRouter__factory.connect( + _l2Network.tokenBridge.l1GatewayRouter, + userL1Wallet + ) + + const depositTx = await router.outboundTransferCustomRefund( + token.address, + userL1Wallet.address, + userL2Wallet.address, + depositAmount, + gasLimit, + maxFeePerGas, + userEncodedData + ) + + // wait for L2 msg to be executed + await waitOnL2Msg(depositTx) + + ///// checks + + const l2TokenAddress = await router.calculateL2TokenAddress(token.address) + l2Token = ERC20__factory.connect(l2TokenAddress, l2Provider) + expect(await l2Token.balanceOf(userL2Wallet.address)).to.be.eq( + depositAmount + ) + + const userTokenBalanceAfter = await token.balanceOf(userL1Wallet.address) + expect(userTokenBalanceBefore.sub(userTokenBalanceAfter)).to.be.eq( + depositAmount + ) + + const gatewayTokenBalanceAfter = await token.balanceOf( + _l2Network.tokenBridge.l1ERC20Gateway + ) + expect(gatewayTokenBalanceAfter.sub(gatewayTokenBalanceBefore)).to.be.eq( + depositAmount + ) + + const userNativeTokenBalanceAfter = await nativeToken.balanceOf( + userL1Wallet.address + ) + expect( + userNativeTokenBalanceBefore.sub(userNativeTokenBalanceAfter) + ).to.be.eq(tokenTotalFeeAmount) + + const bridgeNativeTokenBalanceAfter = await nativeToken.balanceOf( + _l2Network.ethBridge.bridge + ) + expect( + bridgeNativeTokenBalanceAfter.sub(bridgeNativeTokenBalanceBefore) + ).to.be.eq(tokenTotalFeeAmount) + }) + + it('can withdraw token via default gateway', async function () { + // fund userL2Wallet so it can pay for L2 withdraw TX + await depositNativeToL2() + + // snapshot state before + const userL1TokenBalanceBefore = await token.balanceOf(userL1Wallet.address) + const userL2TokenBalanceBefore = await l2Token.balanceOf( + userL2Wallet.address + ) + const l1GatewayTokenBalanceBefore = await token.balanceOf( + _l2Network.tokenBridge.l1ERC20Gateway + ) + const l2TokenSupplyBefore = await l2Token.totalSupply() + + // start withdrawal + const withdrawalAmount = 250 + const l2Router = L2GatewayRouter__factory.connect( + _l2Network.tokenBridge.l2GatewayRouter, + userL2Wallet + ) + const withdrawTx = await l2Router[ + 'outboundTransfer(address,address,uint256,bytes)' + ](token.address, userL1Wallet.address, withdrawalAmount, '0x') + const withdrawReceipt = await withdrawTx.wait() + const l2Receipt = new L2TransactionReceipt(withdrawReceipt) + + // wait until dispute period passes and withdrawal is ready for execution + await sleep(5 * 1000) + + const messages = await l2Receipt.getL2ToL1Messages(userL1Wallet) + const l2ToL1Msg = messages[0] + const timeToWaitMs = 1000 + await l2ToL1Msg.waitUntilReadyToExecute(l2Provider, timeToWaitMs) + + // execute on L1 + await (await l2ToL1Msg.execute(l2Provider)).wait() + + //// checks + const userL1TokenBalanceAfter = await token.balanceOf(userL1Wallet.address) + expect(userL1TokenBalanceAfter.sub(userL1TokenBalanceBefore)).to.be.eq( + withdrawalAmount + ) + + const userL2TokenBalanceAfter = await l2Token.balanceOf( + userL2Wallet.address + ) + expect(userL2TokenBalanceBefore.sub(userL2TokenBalanceAfter)).to.be.eq( + withdrawalAmount + ) + + const l1GatewayTokenBalanceAfter = await token.balanceOf( + _l2Network.tokenBridge.l1ERC20Gateway + ) + expect( + l1GatewayTokenBalanceBefore.sub(l1GatewayTokenBalanceAfter) + ).to.be.eq(withdrawalAmount) + + const l2TokenSupplyAfter = await l2Token.totalSupply() + expect(l2TokenSupplyBefore.sub(l2TokenSupplyAfter)).to.be.eq( + withdrawalAmount + ) + }) +}) + +/** + * helper function to fund user wallet on L2 + */ +async function depositNativeToL2() { + /// deposit tokens + const amountToDeposit = ethers.utils.parseEther('2.0') + await ( + await nativeToken + .connect(userL1Wallet) + .approve(_l2Network.ethBridge.inbox, amountToDeposit) + ).wait() + + const depositFuncSig = { + name: 'depositERC20', + type: 'function', + stateMutability: 'nonpayable', + inputs: [ + { + name: 'amount', + type: 'uint256', + }, + ], + } + const inbox = new ethers.Contract( + _l2Network.ethBridge.inbox, + [depositFuncSig], + userL1Wallet + ) + + const depositTx = await inbox.depositERC20(amountToDeposit) + + // wait for deposit to be processed + const depositRec = await L1TransactionReceipt.monkeyPatchEthDepositWait( + depositTx + ).wait() + await depositRec.waitForL2(l2Provider) +} + +async function waitOnL2Msg(tx: ethers.ContractTransaction) { + const retryableReceipt = await tx.wait() + const l1TxReceipt = new L1TransactionReceipt(retryableReceipt) + const messages = await l1TxReceipt.getL1ToL2Messages(l2Provider) + + // 1 msg expected + const messageResult = await messages[0].waitForStatus() + const status = messageResult.status + expect(status).to.be.eq(L1ToL2MessageStatus.REDEEMED) +} + +const getFeeToken = async (inbox: string, l1Provider: any) => { + const bridge = await IInbox__factory.connect(inbox, l1Provider).bridge() + + let feeToken = ethers.constants.AddressZero + + try { + feeToken = await IERC20Bridge__factory.connect( + bridge, + l1Provider + ).nativeToken() + } catch {} + + return feeToken +} + +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)) +} diff --git a/test-e2e/tokenBridgeDeploymentTest.ts b/test-e2e/tokenBridgeDeploymentTest.ts new file mode 100644 index 0000000000..9a65708964 --- /dev/null +++ b/test-e2e/tokenBridgeDeploymentTest.ts @@ -0,0 +1,613 @@ +import { JsonRpcProvider, Provider, Filter } from '@ethersproject/providers' +import { + BeaconProxyFactory__factory, + IERC20Bridge__factory, + IInbox__factory, + IOwnable__factory, + IRollupCore__factory, + L1AtomicTokenBridgeCreator__factory, + L1CustomGateway, + L1CustomGateway__factory, + L1ERC20Gateway, + L1ERC20Gateway__factory, + L1GatewayRouter, + L1GatewayRouter__factory, + L1WethGateway, + L1WethGateway__factory, + L2CustomGateway, + L2CustomGateway__factory, + L2ERC20Gateway, + L2ERC20Gateway__factory, + L2GatewayRouter, + L2GatewayRouter__factory, + L2WethGateway, + L2WethGateway__factory, +} from '../build/types' +import { abi as UpgradeExecutorABI } from '@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json' +import { RollupCore__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupCore__factory' +import { applyAlias } from '../test/testhelper' +import path from 'path' +import fs from 'fs' +import { expect } from 'chai' +import { ethers } from 'hardhat' +import { Contract } from 'ethers' + +const config = { + l1Url: process.env.BASECHAIN_RPC || 'http://localhost:8547', + l2Url: process.env.ORBIT_RPC || 'http://localhost:3347', +} + +let l1Provider: JsonRpcProvider +let l2Provider: JsonRpcProvider + +describe('tokenBridge', () => { + it('should have deployed and initialized token bridge contracts', async function () { + l1Provider = new JsonRpcProvider(config.l1Url) + l2Provider = new JsonRpcProvider(config.l2Url) + + /// get rollup, L1 creator and retryable sender as entrypoint, either from env vars or from network.json + let rollupAddress: string + let l1TokenBridgeCreator: string + let l1RetryableSender: string + if (process.env.ROLLUP_ADDRESS && process.env.L1_TOKEN_BRIDGE_CREATOR) { + rollupAddress = process.env.ROLLUP_ADDRESS as string + l1TokenBridgeCreator = process.env.L1_TOKEN_BRIDGE_CREATOR as string + l1RetryableSender = process.env.L1_RETRYABLE_SENDER as string + } else { + const localNetworkFile = path.join(__dirname, '..', 'network.json') + if (fs.existsSync(localNetworkFile)) { + const data = JSON.parse(fs.readFileSync(localNetworkFile).toString()) + rollupAddress = data['l2Network']['ethBridge']['rollup'] + l1TokenBridgeCreator = data['l1TokenBridgeCreator'] + l1RetryableSender = data['retryableSender'] + } else { + throw new Error( + "Can't find rollup address info. Either set ROLLUP_ADDRESS, L1_TOKEN_BRIDGE_CREATOR AND L1_RETRYABLE_SENDER env varS or provide network.json file" + ) + } + } + + /// get addresses + const { l1, l2 } = await _getTokenBridgeAddresses( + rollupAddress, + l1TokenBridgeCreator + ) + + //// L1 checks + + // check that setting of retryable sender was not frontrun + const actualRetryableSender = + await L1AtomicTokenBridgeCreator__factory.connect( + l1TokenBridgeCreator, + l1Provider + ).retryableSender() + expect(actualRetryableSender.toLowerCase()).to.be.eq( + l1RetryableSender.toLowerCase() + ) + + await checkL1RouterInitialization( + L1GatewayRouter__factory.connect(l1.router, l1Provider), + l1, + l2 + ) + + await checkL1StandardGatewayInitialization( + L1ERC20Gateway__factory.connect(l1.standardGateway, l1Provider), + l1, + l2 + ) + + await checkL1CustomGatewayInitialization( + L1CustomGateway__factory.connect(l1.customGateway, l1Provider), + l1, + l2 + ) + + const usingFeeToken = await isUsingFeeToken(l1.inbox, l1Provider) + if (!usingFeeToken) + await checkL1WethGatewayInitialization( + L1WethGateway__factory.connect(l1.wethGateway, l1Provider), + l1, + l2 + ) + + //// L2 checks + + await checkL2RouterInitialization( + L2GatewayRouter__factory.connect(l2.router, l2Provider), + l1, + l2 + ) + + await checkL2StandardGatewayInitialization( + L2ERC20Gateway__factory.connect(l2.standardGateway, l2Provider), + l1, + l2 + ) + + await checkL2CustomGatewayInitialization( + L2CustomGateway__factory.connect(l2.customGateway, l2Provider), + l1, + l2 + ) + + if (!usingFeeToken) { + await checkL2WethGatewayInitialization( + L2WethGateway__factory.connect(l2.wethGateway, l2Provider), + l1, + l2 + ) + } + + const upgExecutor = new ethers.Contract( + l2.upgradeExecutor, + UpgradeExecutorABI, + l2Provider + ) + await checkL2UpgradeExecutorInitialization(upgExecutor, l1) + + await checkL1Ownership(l1) + await checkL2Ownership(l2) + }) +}) + +//// L1 contracts + +async function checkL1RouterInitialization( + l1Router: L1GatewayRouter, + l1: L1, + l2: L2 +) { + console.log('checkL1RouterInitialization') + + expect((await l1Router.defaultGateway()).toLowerCase()).to.be.eq( + l1.standardGateway.toLowerCase() + ) + expect((await l1Router.inbox()).toLowerCase()).to.be.eq( + l1.inbox.toLowerCase() + ) + expect((await l1Router.router()).toLowerCase()).to.be.eq( + ethers.constants.AddressZero + ) + expect((await l1Router.counterpartGateway()).toLowerCase()).to.be.eq( + l2.router.toLowerCase() + ) +} + +async function checkL1StandardGatewayInitialization( + l1ERC20Gateway: L1ERC20Gateway, + l1: L1, + l2: L2 +) { + console.log('checkL1StandardGatewayInitialization') + + expect((await l1ERC20Gateway.counterpartGateway()).toLowerCase()).to.be.eq( + l2.standardGateway.toLowerCase() + ) + expect((await l1ERC20Gateway.router()).toLowerCase()).to.be.eq( + l1.router.toLowerCase() + ) + expect((await l1ERC20Gateway.inbox()).toLowerCase()).to.be.eq( + l1.inbox.toLowerCase() + ) + expect((await l1ERC20Gateway.l2BeaconProxyFactory()).toLowerCase()).to.be.eq( + ( + await L2ERC20Gateway__factory.connect( + await l1ERC20Gateway.counterpartGateway(), + l2Provider + ).beaconProxyFactory() + ).toLowerCase() + ) + expect((await l1ERC20Gateway.cloneableProxyHash()).toLowerCase()).to.be.eq( + ( + await BeaconProxyFactory__factory.connect( + await l1ERC20Gateway.l2BeaconProxyFactory(), + l2Provider + ).cloneableProxyHash() + ).toLowerCase() + ) + expect((await l1ERC20Gateway.whitelist()).toLowerCase()).to.be.eq( + ethers.constants.AddressZero + ) +} + +async function checkL1CustomGatewayInitialization( + l1CustomGateway: L1CustomGateway, + l1: L1, + l2: L2 +) { + console.log('checkL1CustomGatewayInitialization') + + expect((await l1CustomGateway.counterpartGateway()).toLowerCase()).to.be.eq( + l2.customGateway.toLowerCase() + ) + + expect((await l1CustomGateway.router()).toLowerCase()).to.be.eq( + l1.router.toLowerCase() + ) + + expect((await l1CustomGateway.inbox()).toLowerCase()).to.be.eq( + l1.inbox.toLowerCase() + ) + + expect((await l1CustomGateway.whitelist()).toLowerCase()).to.be.eq( + ethers.constants.AddressZero + ) +} + +async function checkL1WethGatewayInitialization( + l1WethGateway: L1WethGateway, + l1: L1, + l2: L2 +) { + console.log('checkL1WethGatewayInitialization') + + expect((await l1WethGateway.counterpartGateway()).toLowerCase()).to.be.eq( + l2.wethGateway.toLowerCase() + ) + + expect((await l1WethGateway.router()).toLowerCase()).to.be.eq( + l1.router.toLowerCase() + ) + + expect((await l1WethGateway.inbox()).toLowerCase()).to.be.eq( + l1.inbox.toLowerCase() + ) + + expect((await l1WethGateway.l1Weth()).toLowerCase()).to.not.be.eq( + ethers.constants.AddressZero + ) + + expect((await l1WethGateway.l2Weth()).toLowerCase()).to.not.be.eq( + ethers.constants.AddressZero + ) +} + +async function checkL2UpgradeExecutorInitialization( + l2Executor: Contract, + l1: L1 +) { + console.log('checkL2UpgradeExecutorInitialization') + + //// check assigned/revoked roles are correctly set + const adminRole = await l2Executor.ADMIN_ROLE() + const executorRole = await l2Executor.EXECUTOR_ROLE() + + expect(await l2Executor.hasRole(adminRole, l2Executor.address)).to.be.true + expect(await l2Executor.hasRole(executorRole, l1.rollupOwner)).to.be.true + const aliasedL1Executor = applyAlias(l1.upgradeExecutor) + expect(await l2Executor.hasRole(executorRole, aliasedL1Executor)).to.be.true +} + +//// L2 contracts + +async function checkL2RouterInitialization( + l2Router: L2GatewayRouter, + l1: L1, + l2: L2 +) { + console.log('checkL2RouterInitialization') + + expect((await l2Router.defaultGateway()).toLowerCase()).to.be.eq( + l2.standardGateway.toLowerCase() + ) + + expect((await l2Router.router()).toLowerCase()).to.be.eq( + ethers.constants.AddressZero + ) + + expect((await l2Router.counterpartGateway()).toLowerCase()).to.be.eq( + l1.router.toLowerCase() + ) +} + +async function checkL2StandardGatewayInitialization( + l2ERC20Gateway: L2ERC20Gateway, + l1: L1, + l2: L2 +) { + console.log('checkL2StandardGatewayInitialization') + + expect((await l2ERC20Gateway.counterpartGateway()).toLowerCase()).to.be.eq( + l1.standardGateway.toLowerCase() + ) + + expect((await l2ERC20Gateway.router()).toLowerCase()).to.be.eq( + l2.router.toLowerCase() + ) + + expect((await l2ERC20Gateway.beaconProxyFactory()).toLowerCase()).to.be.eq( + ( + await L1ERC20Gateway__factory.connect( + await l2ERC20Gateway.counterpartGateway(), + l1Provider + ).l2BeaconProxyFactory() + ).toLowerCase() + ) + + expect((await l2ERC20Gateway.cloneableProxyHash()).toLowerCase()).to.be.eq( + ( + await L1ERC20Gateway__factory.connect( + await l2ERC20Gateway.counterpartGateway(), + l1Provider + ).cloneableProxyHash() + ).toLowerCase() + ) +} + +async function checkL2CustomGatewayInitialization( + l2CustomGateway: L2CustomGateway, + l1: L1, + l2: L2 +) { + console.log('checkL2CustomGatewayInitialization') + + expect((await l2CustomGateway.counterpartGateway()).toLowerCase()).to.be.eq( + l1.customGateway.toLowerCase() + ) + + expect((await l2CustomGateway.router()).toLowerCase()).to.be.eq( + l2.router.toLowerCase() + ) +} + +async function checkL2WethGatewayInitialization( + l2WethGateway: L2WethGateway, + l1: L1, + l2: L2 +) { + console.log('checkL2WethGatewayInitialization') + + expect((await l2WethGateway.counterpartGateway()).toLowerCase()).to.be.eq( + l1.wethGateway.toLowerCase() + ) + + expect((await l2WethGateway.router()).toLowerCase()).to.be.eq( + l2.router.toLowerCase() + ) + + expect((await l2WethGateway.l1Weth()).toLowerCase()).to.not.be.eq( + ethers.constants.AddressZero + ) + + expect((await l2WethGateway.l2Weth()).toLowerCase()).to.not.be.eq( + ethers.constants.AddressZero + ) +} + +async function checkL1Ownership(l1: L1) { + console.log('checkL1Ownership') + + // check proxyAdmins + expect(await _getProxyAdmin(l1.router, l1Provider)).to.be.eq(l1.proxyAdmin) + expect(await _getProxyAdmin(l1.standardGateway, l1Provider)).to.be.eq( + l1.proxyAdmin + ) + expect(await _getProxyAdmin(l1.customGateway, l1Provider)).to.be.eq( + l1.proxyAdmin + ) + if (l1.wethGateway !== ethers.constants.AddressZero) { + expect(await _getProxyAdmin(l1.wethGateway, l1Provider)).to.be.eq( + l1.proxyAdmin + ) + } + expect(await _getProxyAdmin(l1.upgradeExecutor, l1Provider)).to.be.eq( + l1.proxyAdmin + ) + + // check ownables + expect(await _getOwner(l1.proxyAdmin, l1Provider)).to.be.eq( + l1.upgradeExecutor + ) + expect(await _getOwner(l1.router, l1Provider)).to.be.eq(l1.upgradeExecutor) + expect(await _getOwner(l1.customGateway, l1Provider)).to.be.eq( + l1.upgradeExecutor + ) +} + +async function checkL2Ownership(l2: L2) { + console.log('checkL2Ownership') + + const l2ProxyAdmin = await _getProxyAdmin(l2.router, l2Provider) + + // check proxyAdmins + expect(await _getProxyAdmin(l2.router, l2Provider)).to.be.eq(l2ProxyAdmin) + expect(await _getProxyAdmin(l2.standardGateway, l2Provider)).to.be.eq( + l2ProxyAdmin + ) + expect(await _getProxyAdmin(l2.customGateway, l2Provider)).to.be.eq( + l2ProxyAdmin + ) + + if (l2.wethGateway != ethers.constants.AddressZero) { + expect(await _getProxyAdmin(l2.wethGateway, l2Provider)).to.be.eq( + l2ProxyAdmin + ) + } + expect(await _getProxyAdmin(l2.upgradeExecutor, l2Provider)).to.be.eq( + l2ProxyAdmin + ) + + // check ownables + expect(await _getOwner(l2ProxyAdmin, l2Provider)).to.be.eq(l2.upgradeExecutor) +} + +//// utils +async function isUsingFeeToken(inbox: string, l1Provider: JsonRpcProvider) { + const bridge = await IInbox__factory.connect(inbox, l1Provider).bridge() + + try { + await IERC20Bridge__factory.connect(bridge, l1Provider).nativeToken() + } catch { + return false + } + + return true +} + +async function _getTokenBridgeAddresses( + rollupAddress: string, + l1TokenBridgeCreatorAddress: string +) { + const inboxAddress = await RollupCore__factory.connect( + rollupAddress, + l1Provider + ).inbox() + + const l1TokenBridgeCreator = L1AtomicTokenBridgeCreator__factory.connect( + l1TokenBridgeCreatorAddress, + l1Provider + ) + + //// L1 + // find all the events emitted by this address + + const filter: Filter = { + address: l1TokenBridgeCreatorAddress, + topics: [ + ethers.utils.id( + 'OrbitTokenBridgeCreated(address,address,address,address,address,address,address,address)' + ), + ethers.utils.hexZeroPad(inboxAddress, 32), + ], + } + + const currentBlock = await l1Provider.getBlockNumber() + const fromBlock = currentBlock - 100000 // ~last 24h on + const logs = await l1Provider.getLogs({ + ...filter, + fromBlock: fromBlock, + toBlock: 'latest', + }) + + if (logs.length === 0) { + throw new Error( + "Couldn't find any OrbitTokenBridgeCreated events in block range[" + + fromBlock + + ',latest]' + ) + } + + const logData = l1TokenBridgeCreator.interface.parseLog(logs[0]) + + const { + inbox, + owner, + router, + standardGateway, + customGateway, + wethGateway, + proxyAdmin, + upgradeExecutor, + } = logData.args + const l1 = { + inbox: inbox.toLowerCase(), + rollupOwner: owner.toLowerCase(), + router: router.toLowerCase(), + standardGateway: standardGateway.toLowerCase(), + customGateway: customGateway.toLowerCase(), + wethGateway: wethGateway.toLowerCase(), + proxyAdmin: proxyAdmin.toLowerCase(), + upgradeExecutor: upgradeExecutor.toLowerCase(), + } + + const usingFeeToken = await isUsingFeeToken(l1.inbox, l1Provider) + + const chainId = await IRollupCore__factory.connect( + rollupAddress, + l1Provider + ).chainId() + + //// L2 + const l2 = { + router: ( + await l1TokenBridgeCreator.getCanonicalL2RouterAddress(chainId) + ).toLowerCase(), + standardGateway: ( + await l1TokenBridgeCreator.getCanonicalL2StandardGatewayAddress(chainId) + ).toLowerCase(), + customGateway: ( + await l1TokenBridgeCreator.getCanonicalL2CustomGatewayAddress(chainId) + ).toLowerCase(), + wethGateway: (usingFeeToken + ? ethers.constants.AddressZero + : await l1TokenBridgeCreator.getCanonicalL2WethGatewayAddress(chainId) + ).toLowerCase(), + weth: (usingFeeToken + ? ethers.constants.AddressZero + : await l1TokenBridgeCreator.getCanonicalL2WethAddress(chainId) + ).toLowerCase(), + upgradeExecutor: ( + await l1TokenBridgeCreator.getCanonicalL2UpgradeExecutorAddress(chainId) + ).toLowerCase(), + } + + return { + l1, + l2, + } +} + +async function _getProxyAdmin( + contractAddress: string, + provider: Provider +): Promise { + return ( + await _getAddressAtStorageSlot( + contractAddress, + provider, + '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103' + ) + ).toLowerCase() +} + +async function _getOwner( + contractAddress: string, + provider: Provider +): Promise { + return ( + await IOwnable__factory.connect(contractAddress, provider).owner() + ).toLowerCase() +} + +async function _getAddressAtStorageSlot( + contractAddress: string, + provider: Provider, + storageSlotBytes: string +): Promise { + const storageValue = await provider.getStorageAt( + contractAddress, + storageSlotBytes + ) + + if (!storageValue) { + return '' + } + + // remove excess bytes + const formatAddress = + storageValue.substring(0, 2) + storageValue.substring(26) + + // return address as checksum address + return ethers.utils.getAddress(formatAddress) +} + +interface L1 { + inbox: string + rollupOwner: string + router: string + standardGateway: string + customGateway: string + wethGateway: string + proxyAdmin: string + upgradeExecutor: string +} + +interface L2 { + router: string + standardGateway: string + customGateway: string + wethGateway: string + weth: string + upgradeExecutor: string +} diff --git a/test-foundry/GatewayRouter.t.sol b/test-foundry/GatewayRouter.t.sol new file mode 100644 index 0000000000..57d5642143 --- /dev/null +++ b/test-foundry/GatewayRouter.t.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import { GatewayRouter } from "contracts/tokenbridge/libraries/gateway/GatewayRouter.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +abstract contract GatewayRouterTest is Test { + GatewayRouter public router; + address public defaultGateway; + + // retryable params + uint256 public maxSubmissionCost; + uint256 public maxGas = 1000000000; + uint256 public gasPriceBid = 3; + uint256 public retryableCost; + address public creditBackAddress = makeAddr("creditBackAddress"); + + /* solhint-disable func-name-mixedcase */ + function test_getGateway_DefaultGateway(address token) public { + address gateway = router.getGateway(token); + assertEq(gateway, defaultGateway, "Invalid gateway"); + } + + function test_finalizeInboundTransfer() public { + vm.expectRevert("ONLY_OUTBOUND_ROUTER"); + router.finalizeInboundTransfer(address(1), address(2), address(3), 0, ""); + } +} diff --git a/test-foundry/IOwnable.sol b/test-foundry/IOwnable.sol new file mode 100644 index 0000000000..20735f0dd2 --- /dev/null +++ b/test-foundry/IOwnable.sol @@ -0,0 +1,10 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.21 <0.9.0; + +interface IOwnable { + function owner() external view returns (address); +} diff --git a/test-foundry/L1ArbitrumExtendedGateway.t.sol b/test-foundry/L1ArbitrumExtendedGateway.t.sol new file mode 100644 index 0000000000..128e5b86db --- /dev/null +++ b/test-foundry/L1ArbitrumExtendedGateway.t.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import "contracts/tokenbridge/ethereum/gateway/L1ArbitrumExtendedGateway.sol"; +import { TestERC20 } from "contracts/tokenbridge/test/TestERC20.sol"; +import { InboxMock } from "contracts/tokenbridge/test/InboxMock.sol"; + +abstract contract L1ArbitrumExtendedGatewayTest is Test { + IL1ArbitrumGateway public l1Gateway; + IERC20 public token; + + address public l2Gateway = makeAddr("l2Gateway"); + address public router = makeAddr("router"); + address public inbox; + address public user = makeAddr("user"); + + // retryable params + uint256 public maxSubmissionCost; + uint256 public maxGas = 1000000000; + uint256 public gasPriceBid = 3; + uint256 public retryableCost; + address public creditBackAddress = makeAddr("creditBackAddress"); + + // fuzzer behaves weirdly when it picks up this address which is used internally for issuing cheatcodes + address internal constant FOUNDRY_CHEATCODE_ADDRESS = + 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; + + /* solhint-disable func-name-mixedcase */ + function test_encodeWithdrawal(uint256 exitNum, address dest) public { + bytes32 encodedWithdrawal = L1ArbitrumExtendedGateway(address(l1Gateway)).encodeWithdrawal( + exitNum, + dest + ); + bytes32 expectedEncoding = keccak256(abi.encode(exitNum, dest)); + + assertEq(encodedWithdrawal, expectedEncoding, "Invalid encodeWithdrawal"); + } + + function test_finalizeInboundTransfer() public virtual { + // fund gateway with tokens being withdrawn + vm.prank(address(l1Gateway)); + TestERC20(address(token)).mint(); + + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + // withdrawal params + address from = address(3000); + uint256 withdrawalAmount = 25; + uint256 exitNum = 7; + bytes memory callHookData = ""; + bytes memory data = abi.encode(exitNum, callHookData); + + InboxMock(address(inbox)).setL2ToL1Sender(l2Gateway); + + // trigger withdrawal + vm.prank(address(IInbox(l1Gateway.inbox()).bridge())); + l1Gateway.finalizeInboundTransfer(address(token), from, user, withdrawalAmount, data); + + // check tokens are properly released + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceAfter - userBalanceBefore, withdrawalAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceBefore - l1GatewayBalanceAfter, + withdrawalAmount, + "Wrong l1 gateway balance" + ); + } + + function test_finalizeInboundTransfer_revert_NotFromBridge() public { + address notBridge = address(300); + vm.prank(notBridge); + vm.expectRevert("NOT_FROM_BRIDGE"); + l1Gateway.finalizeInboundTransfer(address(token), user, user, 100, ""); + } + + function test_finalizeInboundTransfer_revert_OnlyCounterpartGateway() public { + address notCounterPartGateway = address(400); + InboxMock(address(inbox)).setL2ToL1Sender(notCounterPartGateway); + + // trigger withdrawal + vm.prank(address(IInbox(l1Gateway.inbox()).bridge())); + vm.expectRevert("ONLY_COUNTERPART_GATEWAY"); + l1Gateway.finalizeInboundTransfer(address(token), user, user, 100, ""); + } + + function test_getExternalCall( + uint256 exitNum, + address dest, + bytes memory data + ) public { + (address target, bytes memory extData) = L1ArbitrumExtendedGateway(address(l1Gateway)) + .getExternalCall(exitNum, dest, data); + + assertEq(target, dest, "Invalid dest"); + assertEq(extData, data, "Invalid data"); + + bytes32 exitId = keccak256(abi.encode(exitNum, dest)); + (bool isExit, address newTo, bytes memory newData) = L1ArbitrumExtendedGateway( + address(l1Gateway) + ).redirectedExits(exitId); + assertEq(isExit, false, "Invalid isExit"); + assertEq(newTo, address(0), "Invalid _newTo"); + assertEq(newData.length, 0, "Invalid _newData"); + } + + function test_getExternalCall_Redirected( + uint256 exitNum, + address initialDest, + address newDest + ) public { + // redirect + vm.prank(initialDest); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDest, + newDest, + "", + "" + ); + + // check getExternalCall returns new destination + (address target, bytes memory extData) = L1ArbitrumExtendedGateway(address(l1Gateway)) + .getExternalCall(exitNum, initialDest, ""); + assertEq(target, newDest, "Invalid dest"); + assertEq(extData.length, 0, "Invalid data"); + + // check exit redirection is properly stored + bytes32 exitId = keccak256(abi.encode(exitNum, initialDest)); + (bool isExit, address newTo, bytes memory newData) = L1ArbitrumExtendedGateway( + address(l1Gateway) + ).redirectedExits(exitId); + assertEq(isExit, true, "Invalid isExit"); + assertEq(newTo, newDest, "Invalid _newTo"); + assertEq(newData.length, 0, "Invalid _newData"); + } + + function test_outboundTransferCustomRefund_revert_ExtraDataDisabled() public { + bytes memory callHookData = abi.encodeWithSignature("doSomething()"); + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + vm.prank(router); + vm.expectRevert("EXTRA_DATA_DISABLED"); + l1Gateway.outboundTransferCustomRefund( + address(token), + user, + user, + 400, + 0.1 ether, + 0.01 ether, + routerEncodedData + ); + } + + function test_outboundTransferCustomRefund_revert_L1NotContract() public { + address invalidTokenAddress = address(70); + + vm.prank(router); + vm.expectRevert("L1_NOT_CONTRACT"); + l1Gateway.outboundTransferCustomRefund( + address(invalidTokenAddress), + user, + user, + 400, + 0.1 ether, + 0.01 ether, + buildRouterEncodedData("") + ); + } + + function test_outboundTransferCustomRefund_revert_NotFromRouter() public { + vm.expectRevert("NOT_FROM_ROUTER"); + l1Gateway.outboundTransferCustomRefund( + address(token), + user, + user, + 400, + 0.1 ether, + 0.01 ether, + "" + ); + } + + function test_supportsInterface(bytes4 iface) public { + bool expected = false; + if ( + iface == type(IERC165).interfaceId || + iface == IL1ArbitrumGateway.outboundTransferCustomRefund.selector + ) { + expected = true; + } + + assertEq(l1Gateway.supportsInterface(iface), expected, "Interface shouldn't be supported"); + } + + function test_transferExitAndCall_EmptyData_NotRedirected( + uint256 exitNum, + address initialDestination, + address newDestination + ) public { + bytes memory newData; + bytes memory data; + + // check event + vm.expectEmit(true, true, true, true); + emit WithdrawRedirected(initialDestination, newDestination, exitNum, newData, data, false); + + // do it + vm.prank(initialDestination); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + newDestination, + newData, + data + ); + + // check exit data is properly updated + bytes32 exitId = keccak256(abi.encode(exitNum, initialDestination)); + (bool isExit, address exitTo, bytes memory exitData) = L1ArbitrumExtendedGateway( + address(l1Gateway) + ).redirectedExits(exitId); + assertEq(isExit, true, "Invalid isExit"); + assertEq(exitTo, newDestination, "Invalid exitTo"); + assertEq(exitData.length, 0, "Invalid exitData"); + } + + function test_transferExitAndCall_EmptyData_Redirected( + uint256 exitNum, + address initialDestination + ) public { + bytes memory data; + address intermediateDestination = address(new TestExitReceiver()); + + // transfer exit + vm.prank(initialDestination); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + intermediateDestination, + "", + data + ); + + address finalDestination = address(new TestExitReceiver()); + vm.prank(intermediateDestination); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + finalDestination, + "", + data + ); + + // check exit data is properly updated + bytes32 exitId = keccak256(abi.encode(exitNum, initialDestination)); + (bool isExit, address exitTo, bytes memory exitData) = L1ArbitrumExtendedGateway( + address(l1Gateway) + ).redirectedExits(exitId); + assertEq(isExit, true, "Invalid isExit"); + assertEq(exitTo, finalDestination, "Invalid exitTo"); + assertEq(exitData.length, 0, "Invalid exitData"); + } + + function test_transferExitAndCall_NonEmptyData(uint256 exitNum, address initialDestination) + public + { + bytes memory newData; + bytes memory data = abi.encode("fun()"); + address newDestination = address(new TestExitReceiver()); + + // check events + vm.expectEmit(true, true, true, true); + emit ExitHookTriggered(initialDestination, exitNum, data); + + vm.expectEmit(true, true, true, true); + emit WithdrawRedirected(initialDestination, newDestination, exitNum, newData, data, true); + + // do it + vm.prank(initialDestination); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + newDestination, + newData, + data + ); + + // check exit data is properly updated + bytes32 exitId = keccak256(abi.encode(exitNum, initialDestination)); + (bool isExit, address exitTo, bytes memory exitData) = L1ArbitrumExtendedGateway( + address(l1Gateway) + ).redirectedExits(exitId); + assertEq(isExit, true, "Invalid isExit"); + assertEq(exitTo, newDestination, "Invalid exitTo"); + assertEq(exitData.length, 0, "Invalid exitData"); + } + + function test_transferExitAndCall_NonEmptyData_Redirected( + uint256 exitNum, + address initialDestination + ) public { + bytes memory data = abi.encode("run()"); + address intermediateDestination = address(new TestExitReceiver()); + + // transfer exit + vm.prank(initialDestination); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + intermediateDestination, + "", + data + ); + + address finalDestination = address(new TestExitReceiver()); + vm.prank(intermediateDestination); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + finalDestination, + "", + data + ); + + // check exit data is properly updated + bytes32 exitId = keccak256(abi.encode(exitNum, initialDestination)); + (bool isExit, address exitTo, bytes memory exitData) = L1ArbitrumExtendedGateway( + address(l1Gateway) + ).redirectedExits(exitId); + assertEq(isExit, true, "Invalid isExit"); + assertEq(exitTo, finalDestination, "Invalid exitTo"); + assertEq(exitData.length, 0, "Invalid exitData"); + } + + function test_transferExitAndCall_revert_NotExpectedSender() public { + address nonSender = address(800); + vm.expectRevert("NOT_EXPECTED_SENDER"); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + 4, + nonSender, + address(2), + "", + "" + ); + } + + function test_transferExitAndCall_revert_NoDataAllowed() public { + bytes memory nonEmptyData = bytes("abc"); + vm.prank(address(1)); + vm.expectRevert("NO_DATA_ALLOWED"); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + 4, + address(1), + address(2), + nonEmptyData, + "" + ); + } + + function test_transferExitAndCall_revert_ToNotContract(address initialDestination) public { + bytes memory data = abi.encode("execute()"); + address nonContractNewDestination = address(15); + + vm.prank(initialDestination); + vm.expectRevert("TO_NOT_CONTRACT"); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + 4, + initialDestination, + nonContractNewDestination, + "", + data + ); + } + + function test_transferExitAndCall_revert_TransferHookFail( + uint256 exitNum, + address initialDestination + ) public { + bytes memory data = abi.encode("failIt"); + address newDestination = address(new TestExitReceiver()); + + vm.prank(initialDestination); + vm.expectRevert("TRANSFER_HOOK_FAIL"); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + newDestination, + "", + data + ); + } + + function test_transferExitAndCall_revert_TransferHookFail_Redirected( + uint256 exitNum, + address initialDestination + ) public { + bytes memory data = abi.encode("abc"); + address intermediateDestination = address(new TestExitReceiver()); + + vm.prank(initialDestination); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + intermediateDestination, + "", + data + ); + + bytes memory failData = abi.encode("failIt"); + address finalDestination = address(new TestExitReceiver()); + + vm.prank(intermediateDestination); + vm.expectRevert("TRANSFER_HOOK_FAIL"); + L1ArbitrumExtendedGateway(address(l1Gateway)).transferExitAndCall( + exitNum, + initialDestination, + finalDestination, + "", + failData + ); + } + + //// + // Helper functions + //// + function buildRouterEncodedData(bytes memory callHookData) + internal + view + virtual + returns (bytes memory) + { + bytes memory userEncodedData = abi.encode(maxSubmissionCost, callHookData); + bytes memory routerEncodedData = abi.encode(user, userEncodedData); + + return routerEncodedData; + } + + ///// + /// Event declarations + ///// + event WithdrawRedirected( + address indexed from, + address indexed to, + uint256 indexed exitNum, + bytes newData, + bytes data, + bool madeExternalCall + ); + event ExitHookTriggered(address sender, uint256 exitNum, bytes data); +} + +contract TestExitReceiver is ITradeableExitReceiver { + event ExitHookTriggered(address sender, uint256 exitNum, bytes data); + + function onExitTransfer( + address sender, + uint256 exitNum, + bytes calldata data + ) external override returns (bool) { + emit ExitHookTriggered(sender, exitNum, data); + return keccak256(data) != keccak256(abi.encode("failIt")); + } +} diff --git a/test-foundry/L1CustomGateway.t.sol b/test-foundry/L1CustomGateway.t.sol new file mode 100644 index 0000000000..ca4f94048d --- /dev/null +++ b/test-foundry/L1CustomGateway.t.sol @@ -0,0 +1,524 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1ArbitrumExtendedGatewayTest } from "./L1ArbitrumExtendedGateway.t.sol"; +import { L1CustomGateway, IInbox, ITokenGateway, IERC165, IL1ArbitrumGateway, IERC20 } from "contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol"; +import { L2CustomGateway } from "contracts/tokenbridge/arbitrum/gateway/L2CustomGateway.sol"; +import { TestERC20 } from "contracts/tokenbridge/test/TestERC20.sol"; +import { InboxMock } from "contracts/tokenbridge/test/InboxMock.sol"; + +contract L1CustomGatewayTest is L1ArbitrumExtendedGatewayTest { + // gateway params + address public owner = makeAddr("owner"); + + function setUp() public virtual { + inbox = address(new InboxMock()); + + l1Gateway = new L1CustomGateway(); + L1CustomGateway(address(l1Gateway)).initialize(l2Gateway, router, inbox, owner); + + token = IERC20(address(new TestERC20())); + + maxSubmissionCost = 20; + retryableCost = maxSubmissionCost + gasPriceBid * maxGas; + + // fund user and router + vm.prank(user); + TestERC20(address(token)).mint(); + vm.deal(router, 100 ether); + vm.deal(address(token), 100 ether); + vm.deal(owner, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_calculateL2TokenAddress(address l1Token, address l2Token) public virtual { + vm.assume(l1Token != FOUNDRY_CHEATCODE_ADDRESS && l2Token != FOUNDRY_CHEATCODE_ADDRESS); + vm.deal(l1Token, 100 ether); + + // register token to gateway + vm.mockCall( + address(l1Token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(l1Token)); + L1CustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + l2Token, + maxGas, + gasPriceBid, + maxSubmissionCost, + makeAddr("creditBackAddress") + ); + + assertEq(l1Gateway.calculateL2TokenAddress(l1Token), l2Token, "Invalid L2 token address"); + } + + function test_forceRegisterTokenToL2() public virtual { + address[] memory l1Tokens = new address[](2); + l1Tokens[0] = makeAddr("l1Token1"); + l1Tokens[1] = makeAddr("l1Token2"); + address[] memory l2Tokens = new address[](2); + l2Tokens[0] = makeAddr("l2Token1"); + l2Tokens[1] = makeAddr("l2Token2"); + + // expect events + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Tokens[0], l2Tokens[0]); + + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Tokens[1], l2Tokens[1]); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + abi.encodeWithSelector(L2CustomGateway.registerTokenFromL1.selector, l1Tokens, l2Tokens) + ); + + // register token to gateway + vm.prank(owner); + uint256 seqNum = L1CustomGateway(address(l1Gateway)).forceRegisterTokenToL2{ + value: retryableCost + }(l1Tokens, l2Tokens, maxGas, gasPriceBid, maxSubmissionCost); + + ///// checks + assertEq( + L1CustomGateway(address(l1Gateway)).l1ToL2Token(l1Tokens[0]), + l2Tokens[0], + "Invalid L2 token" + ); + + assertEq( + L1CustomGateway(address(l1Gateway)).l1ToL2Token(l1Tokens[1]), + l2Tokens[1], + "Invalid L2 token" + ); + + assertEq(seqNum, 0, "Invalid seqNum"); + } + + function test_forceRegisterTokenToL2_revert_InvalidLength() public virtual { + vm.prank(owner); + vm.expectRevert("INVALID_LENGTHS"); + L1CustomGateway(address(l1Gateway)).forceRegisterTokenToL2{ value: retryableCost }( + new address[](1), + new address[](2), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + function test_forceRegisterTokenToL2_revert_OnlyOwner() public { + vm.expectRevert("ONLY_OWNER"); + L1CustomGateway(address(l1Gateway)).forceRegisterTokenToL2{ value: retryableCost }( + new address[](1), + new address[](1), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + function test_getOutboundCalldata() public { + bytes memory outboundCalldata = l1Gateway.getOutboundCalldata({ + _token: address(token), + _from: user, + _to: address(800), + _amount: 355, + _data: abi.encode("doStuff()") + }); + + bytes memory expectedCalldata = abi.encodeWithSelector( + ITokenGateway.finalizeInboundTransfer.selector, + address(token), + user, + address(800), + 355, + abi.encode("", abi.encode("doStuff()")) + ); + + assertEq(outboundCalldata, expectedCalldata, "Invalid outboundCalldata"); + } + + function test_initialize() public virtual { + L1CustomGateway gateway = new L1CustomGateway(); + gateway.initialize(l2Gateway, router, inbox, owner); + + assertEq(gateway.counterpartGateway(), l2Gateway, "Invalid counterpartGateway"); + assertEq(gateway.router(), router, "Invalid router"); + assertEq(gateway.inbox(), inbox, "Invalid inbox"); + assertEq(gateway.owner(), owner, "Invalid owner"); + assertEq(gateway.whitelist(), address(0), "Invalid whitelist"); + } + + function test_outboundTransfer() public virtual { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + uint256 depositAmount = 300; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // register token to gateway + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(token)); + uint256 seqNum0 = L1CustomGateway(address(l1Gateway)).registerTokenToL2{ + value: retryableCost + }(makeAddr("tokenL2Address"), maxGas, gasPriceBid, maxSubmissionCost, creditBackAddress); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(user, user); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + l1Gateway.getOutboundCalldata(address(token), user, user, depositAmount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 1, depositAmount); + + // trigger deposit + vm.prank(router); + bytes memory seqNum1 = l1Gateway.outboundTransfer{ value: retryableCost }( + address(token), + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund() public virtual { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + uint256 depositAmount = 450; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // register token to gateway + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(token)); + uint256 seqNum0 = L1CustomGateway(address(l1Gateway)).registerTokenToL2{ + value: retryableCost + }(makeAddr("tokenL2Address"), maxGas, gasPriceBid, maxSubmissionCost, creditBackAddress); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, user); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + l1Gateway.getOutboundCalldata(address(token), user, user, depositAmount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 1, depositAmount); + + // trigger deposit + vm.prank(router); + bytes memory seqNum1 = l1Gateway.outboundTransferCustomRefund{ value: retryableCost }( + address(token), + creditBackAddress, + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund_revert_InsufficientAllowance() public virtual { + uint256 tooManyTokens = 500 ether; + + // register token to gateway + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(token)); + L1CustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + makeAddr("creditBackAddress") + ); + + vm.prank(router); + vm.expectRevert("ERC20: insufficient allowance"); + l1Gateway.outboundTransferCustomRefund{ value: 1 ether }( + address(token), + user, + user, + tooManyTokens, + 0.1 ether, + 0.01 ether, + buildRouterEncodedData("") + ); + } + + function test_registerTokenToL2(address l1Token, address l2Token) public virtual { + vm.assume(l1Token != FOUNDRY_CHEATCODE_ADDRESS && l2Token != FOUNDRY_CHEATCODE_ADDRESS); + vm.deal(l1Token, 100 ether); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Token, l2Token); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(l1Token, l1Token); + + address[] memory l1Tokens = new address[](1); + l1Tokens[0] = address(l1Token); + address[] memory l2Tokens = new address[](1); + l2Tokens[0] = address(l2Token); + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + abi.encodeWithSelector(L2CustomGateway.registerTokenFromL1.selector, l1Tokens, l2Tokens) + ); + + // register token to gateway + vm.mockCall( + address(l1Token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(l1Token)); + L1CustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + l2Token, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + assertEq( + L1CustomGateway(address(l1Gateway)).l1ToL2Token(l1Token), + l2Token, + "Invalid L2 token" + ); + } + + function test_registerTokenToL2_CustomRefund(address l1Token, address l2Token) public virtual { + vm.assume(l1Token != FOUNDRY_CHEATCODE_ADDRESS && l2Token != FOUNDRY_CHEATCODE_ADDRESS); + vm.deal(l1Token, 100 ether); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Token, l2Token); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, creditBackAddress); + + address[] memory l1Tokens = new address[](1); + l1Tokens[0] = address(l1Token); + address[] memory l2Tokens = new address[](1); + l2Tokens[0] = address(l2Token); + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + abi.encodeWithSelector(L2CustomGateway.registerTokenFromL1.selector, l1Tokens, l2Tokens) + ); + + // register token to gateway + vm.mockCall( + address(l1Token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(l1Token)); + L1CustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + l2Token, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + + assertEq( + L1CustomGateway(address(l1Gateway)).l1ToL2Token(l1Token), + l2Token, + "Invalid L2 token" + ); + } + + function test_registerTokenToL2_revert_NotArbEnabled() public virtual { + // wrong answer + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xdd)) + ); + + vm.prank(address(token)); + vm.expectRevert("NOT_ARB_ENABLED"); + L1CustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + address(102), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + } + + function test_registerTokenToL2_revert_NoUpdateToDifferentAddress() public virtual { + // register token to gateway + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // set initial address + address initialL2TokenAddress = makeAddr("initial"); + vm.prank(address(token)); + L1CustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + initialL2TokenAddress, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + assertEq( + L1CustomGateway(address(l1Gateway)).l1ToL2Token(address(token)), + initialL2TokenAddress + ); + + // try to set different one + address differentL2TokenAddress = makeAddr("different"); + vm.prank(address(token)); + vm.expectRevert("NO_UPDATE_TO_DIFFERENT_ADDR"); + L1CustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + differentL2TokenAddress, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + function test_setOwner(address newOwner) public { + vm.assume(newOwner != address(0)); + + vm.prank(owner); + L1CustomGateway(address(l1Gateway)).setOwner(newOwner); + + assertEq(L1CustomGateway(address(l1Gateway)).owner(), newOwner, "Invalid owner"); + } + + function test_setOwner_revert_InvalidOwner() public { + address invalidOwner = address(0); + + vm.prank(owner); + vm.expectRevert("INVALID_OWNER"); + L1CustomGateway(address(l1Gateway)).setOwner(invalidOwner); + } + + function test_setOwner_revert_OnlyOwner() public { + address nonOwner = address(250); + + vm.prank(nonOwner); + vm.expectRevert("ONLY_OWNER"); + L1CustomGateway(address(l1Gateway)).setOwner(address(300)); + } + + //// + // Event declarations + //// + event TokenSet(address indexed l1Address, address indexed l2Address); + + event DepositInitiated( + address l1Token, + address indexed _from, + address indexed _to, + uint256 indexed _sequenceNumber, + uint256 _amount + ); + event TicketData(uint256 maxSubmissionCost); + event RefundAddresses(address excessFeeRefundAddress, address callValueRefundAddress); + event InboxRetryableTicket(address from, address to, uint256 value, uint256 maxGas, bytes data); +} diff --git a/test-foundry/L1ERC20Gateway.t.sol b/test-foundry/L1ERC20Gateway.t.sol new file mode 100644 index 0000000000..c6bfb0f7a5 --- /dev/null +++ b/test-foundry/L1ERC20Gateway.t.sol @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1ArbitrumExtendedGatewayTest, InboxMock, TestERC20 } from "./L1ArbitrumExtendedGateway.t.sol"; +import "contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract L1ERC20GatewayTest is L1ArbitrumExtendedGatewayTest { + // gateway params + address public l2BeaconProxyFactory = makeAddr("l2BeaconProxyFactory"); + bytes32 public cloneableProxyHash = + 0x0000000000000000000000000000000000000000000000000000000000000001; + + function setUp() public virtual { + inbox = address(new InboxMock()); + + l1Gateway = new L1ERC20Gateway(); + L1ERC20Gateway(address(l1Gateway)).initialize( + l2Gateway, + router, + inbox, + cloneableProxyHash, + l2BeaconProxyFactory + ); + + token = IERC20(address(new TestERC20())); + + maxSubmissionCost = 70; + retryableCost = maxSubmissionCost + gasPriceBid * maxGas; + + // fund user and router + vm.prank(user); + TestERC20(address(token)).mint(); + vm.deal(router, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_initialize() public virtual { + L1ERC20Gateway gateway = new L1ERC20Gateway(); + gateway.initialize(l2Gateway, router, inbox, cloneableProxyHash, l2BeaconProxyFactory); + + assertEq(gateway.counterpartGateway(), l2Gateway, "Invalid counterpartGateway"); + assertEq(gateway.router(), router, "Invalid router"); + assertEq(gateway.inbox(), inbox, "Invalid inbox"); + assertEq(gateway.l2BeaconProxyFactory(), l2BeaconProxyFactory, "Invalid beacon"); + assertEq(gateway.whitelist(), address(0), "Invalid whitelist"); + } + + function test_initialize_revert_InvalidProxyHash() public { + L1ERC20Gateway gateway = new L1ERC20Gateway(); + bytes32 invalidProxyHash = bytes32(0); + + vm.expectRevert("INVALID_PROXYHASH"); + gateway.initialize(l2Gateway, router, inbox, invalidProxyHash, l2BeaconProxyFactory); + } + + function test_initialize_revert_InvalidBeacon() public { + L1ERC20Gateway gateway = new L1ERC20Gateway(); + address invalidBeaconProxyFactory = address(0); + + vm.expectRevert("INVALID_BEACON"); + gateway.initialize(l2Gateway, router, inbox, cloneableProxyHash, invalidBeaconProxyFactory); + } + + function test_outboundTransfer() public virtual { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + // retryable params + uint256 depositAmount = 300; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(user, user); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + l1Gateway.getOutboundCalldata(address(token), user, user, depositAmount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 0, depositAmount); + + // trigger deposit + vm.prank(router); + l1Gateway.outboundTransfer{ value: retryableCost }( + address(token), + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + } + + function test_outboundTransferCustomRefund() public virtual { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + // retryable params + uint256 depositAmount = 450; + address refundTo = address(2000); + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(refundTo, user); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + l1Gateway.getOutboundCalldata(address(token), user, user, depositAmount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 0, depositAmount); + + // trigger deposit + vm.prank(router); + l1Gateway.outboundTransferCustomRefund{ value: retryableCost }( + address(token), + refundTo, + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + } + + function test_outboundTransferCustomRefund_revert_InsufficientAllowance() public { + uint256 tooManyTokens = 500 ether; + + vm.prank(router); + vm.expectRevert("ERC20: insufficient allowance"); + l1Gateway.outboundTransferCustomRefund( + address(token), + user, + user, + tooManyTokens, + 0.1 ether, + 0.01 ether, + buildRouterEncodedData("") + ); + } + + function test_getOutboundCalldata() public { + bytes memory outboundCalldata = l1Gateway.getOutboundCalldata({ + _token: address(token), + _from: user, + _to: address(800), + _amount: 355, + _data: abi.encode("doStuff()") + }); + + bytes memory expectedCalldata = abi.encodeWithSelector( + ITokenGateway.finalizeInboundTransfer.selector, + address(token), + user, + address(800), + 355, + abi.encode( + abi.encode(abi.encode("IntArbTestToken"), abi.encode("IARB"), abi.encode(18)), + abi.encode("doStuff()") + ) + ); + + assertEq(outboundCalldata, expectedCalldata, "Invalid outboundCalldata"); + } + + function test_calculateL2TokenAddress(address tokenAddress) public { + address l2TokenAddress = l1Gateway.calculateL2TokenAddress(tokenAddress); + + address expectedL2TokenAddress = Create2.computeAddress( + keccak256(abi.encode(l2Gateway, keccak256(abi.encode(tokenAddress)))), + cloneableProxyHash, + l2BeaconProxyFactory + ); + + assertEq(l2TokenAddress, expectedL2TokenAddress, "Invalid calculateL2TokenAddress"); + } + + //// + // Event declarations + //// + event DepositInitiated( + address l1Token, + address indexed _from, + address indexed _to, + uint256 indexed _sequenceNumber, + uint256 _amount + ); + event TicketData(uint256 maxSubmissionCost); + event RefundAddresses(address excessFeeRefundAddress, address callValueRefundAddress); + event InboxRetryableTicket(address from, address to, uint256 value, uint256 maxGas, bytes data); +} diff --git a/test-foundry/L1GatewayRouter.t.sol b/test-foundry/L1GatewayRouter.t.sol new file mode 100644 index 0000000000..ad53629525 --- /dev/null +++ b/test-foundry/L1GatewayRouter.t.sol @@ -0,0 +1,825 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { GatewayRouterTest } from "./GatewayRouter.t.sol"; +import { L1GatewayRouter } from "contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol"; +import { L2GatewayRouter } from "contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol"; +import { L1ERC20Gateway } from "contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol"; +import { L1CustomGateway } from "contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol"; +import { InboxMock } from "contracts/tokenbridge/test/InboxMock.sol"; +import { IERC165 } from "contracts/tokenbridge/libraries/IERC165.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20PresetMinterPauser } from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; + +contract L1GatewayRouterTest is GatewayRouterTest { + L1GatewayRouter public l1Router; + + address public owner = makeAddr("owner"); + address public user = makeAddr("user"); + address public counterpartGateway = makeAddr("counterpartGateway"); + address public inbox; + + function setUp() public virtual { + inbox = address(new InboxMock()); + defaultGateway = address(new L1ERC20Gateway()); + + router = new L1GatewayRouter(); + l1Router = L1GatewayRouter(address(router)); + l1Router.initialize(owner, defaultGateway, address(0), counterpartGateway, inbox); + + maxSubmissionCost = 50000; + retryableCost = maxSubmissionCost + maxGas * gasPriceBid; + + vm.deal(owner, 100 ether); + vm.deal(user, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_initialize() public { + L1GatewayRouter router = new L1GatewayRouter(); + + router.initialize(owner, defaultGateway, address(0), counterpartGateway, inbox); + + assertEq(router.router(), address(0), "Invalid router"); + assertEq(router.counterpartGateway(), counterpartGateway, "Invalid counterpartGateway"); + assertEq(router.defaultGateway(), defaultGateway, "Invalid defaultGateway"); + assertEq(router.owner(), owner, "Invalid owner"); + assertEq(router.whitelist(), address(0), "Invalid whitelist"); + assertEq(router.inbox(), inbox, "Invalid inbox"); + } + + function test_initialize_revert_AlreadyInit() public { + L1GatewayRouter router = new L1GatewayRouter(); + router.initialize(owner, defaultGateway, address(0), counterpartGateway, inbox); + vm.expectRevert("ALREADY_INIT"); + router.initialize(owner, defaultGateway, address(0), counterpartGateway, inbox); + } + + function test_initialize_revert_InvalidCounterPart() public { + L1GatewayRouter router = new L1GatewayRouter(); + address invalidCounterpart = address(0); + vm.expectRevert("INVALID_COUNTERPART"); + router.initialize(owner, defaultGateway, address(0), invalidCounterpart, inbox); + } + + function test_postUpgradeInit_revert_NotFromAdmin() public { + vm.expectRevert("NOT_FROM_ADMIN"); + l1Router.postUpgradeInit(); + } + + function test_getGateway_DisabledGateway() public virtual { + address token = makeAddr("some token"); + + address[] memory tokens = new address[](1); + tokens[0] = token; + address[] memory gateways = new address[](1); + gateways[0] = address(1); + + vm.prank(owner); + l1Router.setGateways{ value: retryableCost }( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + address gateway = router.getGateway(token); + assertEq(gateway, address(0), "Invalid gateway"); + } + + function test_getGateway_CustomGateway() public virtual { + address token = makeAddr("some token"); + + address[] memory tokens = new address[](1); + tokens[0] = token; + address[] memory gateways = new address[](1); + gateways[0] = address(new L1ERC20Gateway()); + + vm.prank(owner); + l1Router.setGateways{ value: retryableCost }( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + address gateway = router.getGateway(token); + assertEq(gateway, gateways[0], "Invalid gateway"); + } + + function test_setDefaultGateway() public virtual { + L1ERC20Gateway newL1DefaultGateway = new L1ERC20Gateway(); + address newDefaultGatewayCounterpart = makeAddr("newDefaultGatewayCounterpart"); + newL1DefaultGateway.initialize( + newDefaultGatewayCounterpart, + address(l1Router), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // event checkers + vm.expectEmit(true, true, true, true); + emit DefaultGatewayUpdated(address(newL1DefaultGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Router), + counterpartGateway, + 0, + maxGas, + abi.encodeWithSelector( + L2GatewayRouter.setDefaultGateway.selector, + newDefaultGatewayCounterpart + ) + ); + + // set it + vm.prank(owner); + uint256 seqNum = l1Router.setDefaultGateway{ value: retryableCost }( + address(newL1DefaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + /// checks + assertEq( + l1Router.defaultGateway(), + address(newL1DefaultGateway), + "Invalid newL1DefaultGateway" + ); + + assertEq(seqNum, 0, "Invalid seqNum"); + } + + function test_setDefaultGateway_AddressZero() public virtual { + address newL1DefaultGateway = address(0); + + // event checkers + vm.expectEmit(true, true, true, true); + emit DefaultGatewayUpdated(address(newL1DefaultGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Router), + counterpartGateway, + 0, + maxGas, + abi.encodeWithSelector(L2GatewayRouter.setDefaultGateway.selector, address(0)) + ); + + // set it + vm.prank(owner); + uint256 seqNum = l1Router.setDefaultGateway{ value: retryableCost }( + newL1DefaultGateway, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + /// checks + assertEq( + l1Router.defaultGateway(), + address(newL1DefaultGateway), + "Invalid newL1DefaultGateway" + ); + + assertEq(seqNum, 0, "Invalid seqNum"); + } + + function test_setGateway() public virtual { + // create gateway + L1CustomGateway customGateway = new L1CustomGateway(); + address l2Counterpart = makeAddr("l2Counterpart"); + customGateway.initialize(l2Counterpart, address(l1Router), address(inbox), owner); + + // create token + ERC20 customToken = new ERC20("X", "Y"); + vm.deal(address(customToken), 100 ether); + vm.mockCall( + address(customToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // register token to gateway + vm.prank(address(customToken)); + customGateway.registerTokenToL2{ value: retryableCost }( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + makeAddr("creditBackAddress") + ); + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(address(customToken), address(customGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(address(customToken), address(customToken)); + + vm.expectEmit(true, true, true, true); + address[] memory _tokenArr = new address[](1); + _tokenArr[0] = address(customToken); + address[] memory _gatewayArr = new address[](1); + _gatewayArr[0] = l2Counterpart; + emit InboxRetryableTicket( + address(l1Router), + counterpartGateway, + 0, + maxGas, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, _tokenArr, _gatewayArr) + ); + + // set gateway + vm.prank(address(customToken)); + uint256 seqNum = l1Router.setGateway{ value: retryableCost }( + address(customGateway), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + ///// checks + + assertEq( + l1Router.l1TokenToGateway(address(customToken)), + address(customGateway), + "Gateway not set" + ); + + assertEq(seqNum, 1, "Invalid seqNum"); + } + + function test_setGateway_CustomCreditback() public virtual { + // create gateway + L1CustomGateway customGateway = new L1CustomGateway(); + address l2Counterpart = makeAddr("l2Counterpart"); + customGateway.initialize(l2Counterpart, address(l1Router), address(inbox), owner); + + // create token + ERC20 customToken = new ERC20("X", "Y"); + vm.deal(address(customToken), 100 ether); + vm.mockCall( + address(customToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // register token to gateway + vm.prank(address(customToken)); + customGateway.registerTokenToL2{ value: retryableCost }( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(address(customToken), address(customGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, creditBackAddress); + + vm.expectEmit(true, true, true, true); + address[] memory _tokenArr = new address[](1); + _tokenArr[0] = address(customToken); + address[] memory _gatewayArr = new address[](1); + _gatewayArr[0] = l2Counterpart; + emit InboxRetryableTicket( + address(l1Router), + counterpartGateway, + 0, + maxGas, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, _tokenArr, _gatewayArr) + ); + + // set gateway + vm.prank(address(customToken)); + uint256 seqNum = l1Router.setGateway{ value: retryableCost }( + address(customGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + + ///// checks + + assertEq( + l1Router.l1TokenToGateway(address(customToken)), + address(customGateway), + "Gateway not set" + ); + + assertEq(seqNum, 1, "Invalid seqNum"); + } + + function test_setGateway_revert_NotArbEnabled() public virtual { + address nonArbEnabledToken = address(new ERC20("X", "Y")); + vm.deal(nonArbEnabledToken, 100 ether); + vm.mockCall( + nonArbEnabledToken, + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb2)) + ); + + vm.prank(nonArbEnabledToken); + vm.expectRevert("NOT_ARB_ENABLED"); + l1Router.setGateway{ value: 400000 }( + makeAddr("gateway"), + 100000, + 3, + 200, + makeAddr("creditback") + ); + } + + function test_setGateway_revert_NotToContract() public virtual { + address token = address(new ERC20("X", "Y")); + vm.deal(token, 100 ether); + vm.mockCall(token, abi.encodeWithSignature("isArbitrumEnabled()"), abi.encode(uint8(0xb1))); + + address gatewayNotContract = makeAddr("not contract"); + + vm.prank(token); + vm.expectRevert("NOT_TO_CONTRACT"); + l1Router.setGateway{ value: retryableCost }( + gatewayNotContract, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + } + + function test_setGateway_revert_NoUpdateToDifferentAddress() public virtual { + // create gateway + address initialGateway = address(new L1CustomGateway()); + address l2Counterpart = makeAddr("l2Counterpart"); + L1CustomGateway(initialGateway).initialize( + l2Counterpart, + address(l1Router), + address(inbox), + owner + ); + + // create token + address token = address(new ERC20("X", "Y")); + vm.deal(address(token), 100 ether); + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // register token to gateway + vm.prank(token); + L1CustomGateway(initialGateway).registerTokenToL2{ value: retryableCost }( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + + // initially set gateway for token + vm.prank(address(token)); + l1Router.setGateway{ value: retryableCost }( + initialGateway, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + assertEq(l1Router.l1TokenToGateway(token), initialGateway, "Initial gateway not set"); + + //// now try setting different gateway + address newGateway = address(new L1CustomGateway()); + + vm.prank(token); + vm.expectRevert("NO_UPDATE_TO_DIFFERENT_ADDR"); + l1Router.setGateway{ value: retryableCost }( + newGateway, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + } + + function test_setGateway_revert_TokenNotHandledByGateway() public virtual { + // create gateway + L1CustomGateway gateway = new L1CustomGateway(); + + // create token + address token = address(new ERC20("X", "Y")); + vm.deal(token, 100 ether); + vm.mockCall(token, abi.encodeWithSignature("isArbitrumEnabled()"), abi.encode(uint8(0xb1))); + + vm.prank(token); + vm.expectRevert("TOKEN_NOT_HANDLED_BY_GATEWAY"); + l1Router.setGateway{ value: retryableCost }( + address(gateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + } + + function test_setGateways() public virtual { + // create tokens and gateways + address[] memory tokens = new address[](2); + tokens[0] = address(new ERC20("1", "1")); + tokens[1] = address(new ERC20("2", "2")); + address[] memory gateways = new address[](2); + gateways[0] = address(new L1CustomGateway()); + gateways[1] = address(new L1CustomGateway()); + + address l2Counterpart = makeAddr("l2Counterpart"); + + /// init all + for (uint256 i = 0; i < 2; i++) { + L1CustomGateway(gateways[i]).initialize( + l2Counterpart, + address(l1Router), + address(inbox), + owner + ); + + vm.mockCall( + tokens[i], + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // register tokens to gateways + vm.deal(tokens[i], 100 ether); + vm.prank(tokens[i]); + L1CustomGateway(gateways[i]).registerTokenToL2{ value: retryableCost }( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + makeAddr("creditBackAddress") + ); + } + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(tokens[0], gateways[0]); + vm.expectEmit(true, true, true, true); + emit GatewaySet(tokens[1], gateways[1]); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + address[] memory _gatewayArr = new address[](2); + _gatewayArr[0] = l2Counterpart; + _gatewayArr[1] = l2Counterpart; + emit InboxRetryableTicket( + address(l1Router), + counterpartGateway, + 0, + maxGas, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, tokens, _gatewayArr) + ); + + /// set gateways + vm.prank(owner); + uint256 seqNum = l1Router.setGateways{ value: retryableCost }( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + ///// checks + + assertEq(l1Router.l1TokenToGateway(tokens[0]), gateways[0], "Gateway[0] not set"); + assertEq(l1Router.l1TokenToGateway(tokens[1]), gateways[1], "Gateway[1] not set"); + assertEq(seqNum, 2, "Invalid seqNum"); + } + + function test_setGateways_revert_WrongLength() public virtual { + address[] memory tokens = new address[](2); + tokens[0] = address(new ERC20("1", "1")); + tokens[1] = address(new ERC20("2", "2")); + address[] memory gateways = new address[](1); + gateways[0] = address(new L1CustomGateway()); + + /// set gateways + vm.prank(owner); + vm.expectRevert("WRONG_LENGTH"); + l1Router.setGateways{ value: retryableCost }( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + function test_setGateways_SetZeroAddr() public virtual { + // create gateway + address initialGateway = address(new L1CustomGateway()); + address l2Counterpart = makeAddr("l2Counterpart"); + L1CustomGateway(initialGateway).initialize( + l2Counterpart, + address(l1Router), + address(inbox), + owner + ); + + // create token + address token = address(new ERC20("X", "Y")); + vm.deal(address(token), 100 ether); + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // register token to gateway + vm.prank(token); + L1CustomGateway(initialGateway).registerTokenToL2{ value: retryableCost }( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + + // initially set gateway for token + vm.prank(address(token)); + l1Router.setGateway{ value: retryableCost }( + initialGateway, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + assertEq(l1Router.l1TokenToGateway(token), initialGateway, "Initial gateway not set"); + + //// now set to zero addr + address newGateway = address(0); + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(token, newGateway); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + address[] memory _tokenArr = new address[](1); + _tokenArr[0] = token; + address[] memory _gatewayArr = new address[](1); + _gatewayArr[0] = newGateway; + emit InboxRetryableTicket( + address(l1Router), + counterpartGateway, + 0, + maxGas, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, _tokenArr, _gatewayArr) + ); + + /// set gateways + vm.prank(owner); + uint256 seqNum = l1Router.setGateways{ value: retryableCost }( + _tokenArr, + _gatewayArr, + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + ///// checks + + assertEq(l1Router.l1TokenToGateway(token), address(0), "Custom gateway not cleared"); + assertEq(seqNum, 2, "Invalid seqNum"); + } + + function test_setGateways_revert_notOwner() public { + vm.expectRevert("ONLY_OWNER"); + l1Router.setGateways{ value: 1000 }(new address[](1), new address[](1), 100, 8, 10); + } + + function test_setOwner(address newOwner) public { + vm.assume(newOwner != address(0)); + + vm.prank(owner); + l1Router.setOwner(newOwner); + + assertEq(l1Router.owner(), newOwner, "Invalid owner"); + } + + function test_setOwner_revert_InvalidOwner() public { + address invalidOwner = address(0); + + vm.prank(owner); + vm.expectRevert("INVALID_OWNER"); + l1Router.setOwner(invalidOwner); + } + + function test_setOwner_revert_OnlyOwner() public { + address nonOwner = address(250); + + vm.prank(nonOwner); + vm.expectRevert("ONLY_OWNER"); + l1Router.setOwner(address(300)); + } + + function test_supportsInterface(bytes4 iface) public { + bool expected = false; + if ( + iface == type(IERC165).interfaceId || + iface == L1GatewayRouter.outboundTransferCustomRefund.selector + ) { + expected = true; + } + + assertEq(l1Router.supportsInterface(iface), expected, "Interface shouldn't be supported"); + } + + function test_outboundTransfer() public virtual { + // init default gateway + L1ERC20Gateway(defaultGateway).initialize( + makeAddr("defaultGatewayCounterpart"), + address(l1Router), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // set default gateway + vm.prank(owner); + l1Router.setDefaultGateway{ value: retryableCost }( + address(defaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + // create token + ERC20PresetMinterPauser token = new ERC20PresetMinterPauser("X", "Y"); + token.mint(user, 10000); + vm.prank(user); + token.approve(defaultGateway, 103); + + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(defaultGateway)); + + /// deposit data + address to = address(401); + uint256 amount = 103; + bytes memory userEncodedData = abi.encode(maxSubmissionCost, ""); + + // expect event + vm.expectEmit(true, true, true, true); + emit TransferRouted(address(token), user, to, address(defaultGateway)); + + /// deposit it + vm.prank(user); + l1Router.outboundTransfer{ value: retryableCost }( + address(token), + to, + amount, + maxGas, + gasPriceBid, + userEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(defaultGateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + amount, + "Wrong defaultGateway balance" + ); + } + + function test_outboundTransferCustomRefund() public virtual { + // init default gateway + L1ERC20Gateway(defaultGateway).initialize( + makeAddr("defaultGatewayCounterpart"), + address(l1Router), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // set default gateway + vm.prank(owner); + l1Router.setDefaultGateway{ value: retryableCost }( + address(defaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + + // create token + ERC20PresetMinterPauser token = new ERC20PresetMinterPauser("X", "Y"); + token.mint(user, 10000); + vm.prank(user); + token.approve(defaultGateway, 103); + + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(defaultGateway)); + + /// deposit data + address refundTo = address(400); + address to = address(401); + uint256 amount = 103; + bytes memory userEncodedData = abi.encode(maxSubmissionCost, ""); + + // expect event + vm.expectEmit(true, true, true, true); + emit TransferRouted(address(token), user, to, address(defaultGateway)); + + /// deposit it + vm.prank(user); + l1Router.outboundTransferCustomRefund{ value: retryableCost }( + address(token), + refundTo, + to, + amount, + maxGas, + gasPriceBid, + userEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(defaultGateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + amount, + "Wrong defaultGateway balance" + ); + } + + //// + // Event declarations + //// + event TransferRouted( + address indexed token, + address indexed _userFrom, + address indexed _userTo, + address gateway + ); + event GatewaySet(address indexed l1Token, address indexed gateway); + event DefaultGatewayUpdated(address newDefaultGateway); + + event DepositInitiated( + address l1Token, + address indexed _from, + address indexed _to, + uint256 indexed _sequenceNumber, + uint256 _amount + ); + event TicketData(uint256 maxSubmissionCost); + event RefundAddresses(address excessFeeRefundAddress, address callValueRefundAddress); + event InboxRetryableTicket(address from, address to, uint256 value, uint256 maxGas, bytes data); +} diff --git a/test-foundry/L1OrbitCustomGateway.t.sol b/test-foundry/L1OrbitCustomGateway.t.sol new file mode 100644 index 0000000000..20093a8db6 --- /dev/null +++ b/test-foundry/L1OrbitCustomGateway.t.sol @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1CustomGatewayTest, IERC20, L2CustomGateway } from "./L1CustomGateway.t.sol"; +import { L1OrbitCustomGateway } from "contracts/tokenbridge/ethereum/gateway/L1OrbitCustomGateway.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20PresetMinterPauser } from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; +import { TestERC20 } from "contracts/tokenbridge/test/TestERC20.sol"; +import { ERC20InboxMock } from "contracts/tokenbridge/test/InboxMock.sol"; + +contract L1OrbitCustomGatewayTest is L1CustomGatewayTest { + ERC20 public nativeToken; + uint256 public nativeTokenTotalFee; + + function setUp() public virtual override { + inbox = address(new ERC20InboxMock()); + nativeToken = ERC20(address(new ERC20PresetMinterPauser("X", "Y"))); + ERC20PresetMinterPauser(address(nativeToken)).mint(user, 1_000_000 ether); + ERC20PresetMinterPauser(address(nativeToken)).mint(owner, 1_000_000 ether); + ERC20InboxMock(inbox).setMockNativeToken(address(nativeToken)); + + l1Gateway = new L1OrbitCustomGateway(); + L1OrbitCustomGateway(address(l1Gateway)).initialize(l2Gateway, router, inbox, owner); + + token = IERC20(address(new TestERC20())); + + maxSubmissionCost = 0; + nativeTokenTotalFee = maxGas * gasPriceBid; + + // fund user and router + vm.prank(user); + TestERC20(address(token)).mint(); + vm.deal(router, 100 ether); + vm.deal(address(token), 100 ether); + vm.deal(owner, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_calculateL2TokenAddress(address l1Token, address l2Token) public override { + vm.assume( + l1Token != FOUNDRY_CHEATCODE_ADDRESS && + l2Token != FOUNDRY_CHEATCODE_ADDRESS && + l1Token != address(0) && + l1Token != router + ); + vm.deal(l1Token, 100 ether); + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint(address(l1Token), nativeTokenTotalFee); + vm.prank(address(l1Token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // register token to gateway + vm.mockCall( + address(l1Token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(l1Token)); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + l2Token, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + assertEq(l1Gateway.calculateL2TokenAddress(l1Token), l2Token, "Invalid L2 token address"); + } + + function test_forceRegisterTokenToL2() public override { + address[] memory l1Tokens = new address[](2); + l1Tokens[0] = makeAddr("l1Token1"); + l1Tokens[1] = makeAddr("l1Token2"); + address[] memory l2Tokens = new address[](2); + l2Tokens[0] = makeAddr("l2Token1"); + l2Tokens[1] = makeAddr("l2Token2"); + + // approve fees + vm.prank(owner); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // expect events + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Tokens[0], l2Tokens[0]); + + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Tokens[1], l2Tokens[1]); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2CustomGateway.registerTokenFromL1.selector, l1Tokens, l2Tokens) + ); + + // register token to gateway + vm.prank(owner); + uint256 seqNum = L1OrbitCustomGateway(address(l1Gateway)).forceRegisterTokenToL2( + l1Tokens, + l2Tokens, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + ///// checks + assertEq( + L1OrbitCustomGateway(address(l1Gateway)).l1ToL2Token(l1Tokens[0]), + l2Tokens[0], + "Invalid L2 token" + ); + + assertEq( + L1OrbitCustomGateway(address(l1Gateway)).l1ToL2Token(l1Tokens[1]), + l2Tokens[1], + "Invalid L2 token" + ); + + assertEq(seqNum, 0, "Invalid seqNum"); + } + + function test_forceRegisterTokenToL2_revert_InvalidLength() public override { + vm.prank(owner); + vm.expectRevert("INVALID_LENGTHS"); + L1OrbitCustomGateway(address(l1Gateway)).forceRegisterTokenToL2( + new address[](1), + new address[](2), + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + } + + function test_forceRegisterTokenToL2_revert_NotSupportedInOrbit() public { + // register token to gateway + vm.prank(owner); + vm.expectRevert("NOT_SUPPORTED_IN_ORBIT"); + L1OrbitCustomGateway(address(l1Gateway)).forceRegisterTokenToL2( + new address[](1), + new address[](1), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + function test_outboundTransfer() public virtual override { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + uint256 depositAmount = 300; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // register token to gateway + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + vm.prank(address(token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(token)); + uint256 seqNum0 = L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // approve fees + vm.prank(user); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(user, user); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + l1Gateway.getOutboundCalldata(address(token), user, user, depositAmount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 1, depositAmount); + + // trigger deposit + vm.prank(router); + bytes memory seqNum1 = l1Gateway.outboundTransfer( + address(token), + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund() public virtual override { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + uint256 depositAmount = 450; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // register token to gateway + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + vm.prank(address(token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(token)); + uint256 seqNum0 = L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // approve fees + vm.prank(user); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, user); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + l1Gateway.getOutboundCalldata(address(token), user, user, depositAmount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 1, depositAmount); + + // trigger deposit + vm.prank(router); + bytes memory seqNum1 = l1Gateway.outboundTransferCustomRefund( + address(token), + creditBackAddress, + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund_revert_InsufficientAllowance() + public + virtual + override + { + uint256 tooManyTokens = 500 ether; + + // register token to gateway + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + vm.prank(address(token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(token)); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + vm.prank(router); + vm.expectRevert("ERC20: insufficient allowance"); + l1Gateway.outboundTransferCustomRefund( + address(token), + user, + user, + tooManyTokens, + 0.1 ether, + 0.01 ether, + buildRouterEncodedData("") + ); + } + + function test_registerTokenToL2(address l1Token, address l2Token) public override { + vm.assume( + l1Token != FOUNDRY_CHEATCODE_ADDRESS && + l2Token != FOUNDRY_CHEATCODE_ADDRESS && + l1Token != address(0) + ); + vm.deal(l1Token, 100 ether); + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint(address(l1Token), nativeTokenTotalFee); + vm.prank(address(l1Token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Token, l2Token); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(l1Token, l1Token); + + address[] memory l1Tokens = new address[](1); + l1Tokens[0] = address(l1Token); + address[] memory l2Tokens = new address[](1); + l2Tokens[0] = address(l2Token); + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2CustomGateway.registerTokenFromL1.selector, l1Tokens, l2Tokens) + ); + + // register token to gateway + vm.mockCall( + address(l1Token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(l1Token)); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + l2Token, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + assertEq( + L1OrbitCustomGateway(address(l1Gateway)).l1ToL2Token(l1Token), + l2Token, + "Invalid L2 token" + ); + } + + function test_registerTokenToL2_CustomRefund(address l1Token, address l2Token) public override { + vm.assume( + l1Token != FOUNDRY_CHEATCODE_ADDRESS && + l2Token != FOUNDRY_CHEATCODE_ADDRESS && + l1Token != address(0) && + l1Token != router && + l1Token != creditBackAddress + ); + vm.deal(l1Token, 100 ether); + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint(address(l1Token), nativeTokenTotalFee); + vm.prank(address(l1Token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TokenSet(l1Token, l2Token); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, creditBackAddress); + + address[] memory l1Tokens = new address[](1); + l1Tokens[0] = address(l1Token); + address[] memory l2Tokens = new address[](1); + l2Tokens[0] = address(l2Token); + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2CustomGateway.registerTokenFromL1.selector, l1Tokens, l2Tokens) + ); + + // register token to gateway + vm.mockCall( + address(l1Token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(l1Token)); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + l2Token, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + assertEq( + L1OrbitCustomGateway(address(l1Gateway)).l1ToL2Token(l1Token), + l2Token, + "Invalid L2 token" + ); + } + + function test_registerTokenToL2_revert_NotArbEnabled() public override { + // wrong answer + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xdd)) + ); + + vm.prank(address(token)); + vm.expectRevert("NOT_ARB_ENABLED"); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + address(102), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + } + + function test_registerTokenToL2_revert_NoUpdateToDifferentAddress() public override { + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + + // register token to gateway + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // set initial address + address initialL2TokenAddress = makeAddr("initial"); + vm.startPrank(address(token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + initialL2TokenAddress, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + vm.stopPrank(); + assertEq( + L1OrbitCustomGateway(address(l1Gateway)).l1ToL2Token(address(token)), + initialL2TokenAddress + ); + + // try to set different one + address differentL2TokenAddress = makeAddr("different"); + vm.startPrank(address(token)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + vm.expectRevert("NO_UPDATE_TO_DIFFERENT_ADDR"); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + differentL2TokenAddress, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + } + + function test_registerTokenToL2_revert_NotSupportedInOrbit() public { + vm.expectRevert("NOT_SUPPORTED_IN_ORBIT"); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + address(100), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + function test_registerTokenToL2_revert_CustomRefund_NotSupportedInOrbit() public { + vm.expectRevert("NOT_SUPPORTED_IN_ORBIT"); + L1OrbitCustomGateway(address(l1Gateway)).registerTokenToL2( + address(100), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + } + + /// + // Helper functions + /// + function buildRouterEncodedData(bytes memory callHookData) + internal + view + override + returns (bytes memory) + { + bytes memory userEncodedData = abi.encode( + maxSubmissionCost, + callHookData, + nativeTokenTotalFee + ); + bytes memory routerEncodedData = abi.encode(user, userEncodedData); + + return routerEncodedData; + } + + event ERC20InboxRetryableTicket( + address from, + address to, + uint256 l2CallValue, + uint256 maxGas, + uint256 gasPriceBid, + uint256 tokenTotalFeeAmount, + bytes data + ); +} diff --git a/test-foundry/L1OrbitERC20Gateway.t.sol b/test-foundry/L1OrbitERC20Gateway.t.sol new file mode 100644 index 0000000000..ecd7a78291 --- /dev/null +++ b/test-foundry/L1OrbitERC20Gateway.t.sol @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1ERC20GatewayTest } from "./L1ERC20Gateway.t.sol"; +import "contracts/tokenbridge/ethereum/gateway/L1OrbitERC20Gateway.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20PresetMinterPauser } from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; +import { TestERC20 } from "contracts/tokenbridge/test/TestERC20.sol"; +import { ERC20InboxMock } from "contracts/tokenbridge/test/InboxMock.sol"; + +contract L1OrbitERC20GatewayTest is L1ERC20GatewayTest { + ERC20 public nativeToken; + uint256 public nativeTokenTotalFee; + + function setUp() public override { + inbox = address(new ERC20InboxMock()); + nativeToken = ERC20(address(new ERC20PresetMinterPauser("X", "Y"))); + ERC20PresetMinterPauser(address(nativeToken)).mint(user, 1_000_000 ether); + ERC20InboxMock(inbox).setMockNativeToken(address(nativeToken)); + + l1Gateway = new L1OrbitERC20Gateway(); + L1OrbitERC20Gateway(address(l1Gateway)).initialize( + l2Gateway, + router, + inbox, + cloneableProxyHash, + l2BeaconProxyFactory + ); + + token = IERC20(address(new TestERC20())); + maxSubmissionCost = 0; + nativeTokenTotalFee = maxGas * gasPriceBid; + + // fund user and router + vm.prank(user); + TestERC20(address(token)).mint(); + vm.deal(router, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_initialize() public override { + L1ERC20Gateway gateway = new L1OrbitERC20Gateway(); + gateway.initialize(l2Gateway, router, inbox, cloneableProxyHash, l2BeaconProxyFactory); + + assertEq(gateway.counterpartGateway(), l2Gateway, "Invalid counterpartGateway"); + assertEq(gateway.router(), router, "Invalid router"); + assertEq(gateway.inbox(), inbox, "Invalid inbox"); + assertEq(gateway.l2BeaconProxyFactory(), l2BeaconProxyFactory, "Invalid beacon"); + assertEq(gateway.whitelist(), address(0), "Invalid whitelist"); + } + + function test_outboundTransfer() public override { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + // retryable params + uint256 depositAmount = 300; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // approve fees + vm.prank(user); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // expect events + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(user, user); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + l1Gateway.getOutboundCalldata(address(token), user, user, 300, "") + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 0, depositAmount); + + // trigger deposit + vm.prank(router); + l1Gateway.outboundTransfer( + address(token), + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + } + + function test_outboundTransfer_revert_NotAllowedToBridgeFeeToken() public { + // trigger deposit + vm.prank(router); + vm.expectRevert("NOT_ALLOWED_TO_BRIDGE_FEE_TOKEN"); + l1Gateway.outboundTransfer(address(nativeToken), user, 100, maxGas, gasPriceBid, ""); + } + + function test_outboundTransferCustomRefund() public override { + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(l1Gateway)); + + // retryable params + uint256 depositAmount = 700; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // approve fees + vm.prank(user); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // approve token + vm.prank(user); + token.approve(address(l1Gateway), depositAmount); + + // expect events + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, user); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + l1Gateway.getOutboundCalldata(address(token), user, user, 700, "") + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(token), user, user, 0, depositAmount); + + // trigger deposit + vm.prank(router); + l1Gateway.outboundTransferCustomRefund( + address(token), + creditBackAddress, + user, + depositAmount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, depositAmount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(l1Gateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + depositAmount, + "Wrong l1 gateway balance" + ); + } + + function test_outboundTransferCustomRefund_revert_NotAllowedToBridgeFeeToken() public { + // trigger deposit + vm.prank(router); + vm.expectRevert("NOT_ALLOWED_TO_BRIDGE_FEE_TOKEN"); + l1Gateway.outboundTransferCustomRefund( + address(nativeToken), + creditBackAddress, + user, + 100, + maxGas, + gasPriceBid, + "" + ); + } + + //// + // Helper functions + //// + function buildRouterEncodedData(bytes memory callHookData) + internal + view + override + returns (bytes memory) + { + bytes memory userEncodedData = abi.encode( + maxSubmissionCost, + callHookData, + nativeTokenTotalFee + ); + bytes memory routerEncodedData = abi.encode(user, userEncodedData); + + return routerEncodedData; + } + + event ERC20InboxRetryableTicket( + address from, + address to, + uint256 l2CallValue, + uint256 maxGas, + uint256 gasPriceBid, + uint256 tokenTotalFeeAmount, + bytes data + ); +} diff --git a/test-foundry/L1OrbitGatewayRouter.t.sol b/test-foundry/L1OrbitGatewayRouter.t.sol new file mode 100644 index 0000000000..a263ebb543 --- /dev/null +++ b/test-foundry/L1OrbitGatewayRouter.t.sol @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1GatewayRouterTest } from "./L1GatewayRouter.t.sol"; +import { ERC20InboxMock } from "contracts/tokenbridge/test/InboxMock.sol"; +import { L1OrbitERC20Gateway } from "contracts/tokenbridge/ethereum/gateway/L1OrbitERC20Gateway.sol"; +import { L1OrbitGatewayRouter } from "contracts/tokenbridge/ethereum/gateway/L1OrbitGatewayRouter.sol"; +import { L2GatewayRouter } from "contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol"; +import { L1GatewayRouter } from "contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol"; +import { L1OrbitCustomGateway } from "contracts/tokenbridge/ethereum/gateway/L1OrbitCustomGateway.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20PresetMinterPauser } from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; + +import "forge-std/console.sol"; + +contract L1OrbitGatewayRouterTest is L1GatewayRouterTest { + L1OrbitGatewayRouter public l1OrbitRouter; + ERC20 public nativeToken; + uint256 public nativeTokenTotalFee; + + function setUp() public override { + inbox = address(new ERC20InboxMock()); + nativeToken = ERC20(address(new ERC20PresetMinterPauser("X", "Y"))); + ERC20PresetMinterPauser(address(nativeToken)).mint(user, 1_000_000 ether); + ERC20PresetMinterPauser(address(nativeToken)).mint(owner, 1_000_000 ether); + ERC20InboxMock(inbox).setMockNativeToken(address(nativeToken)); + + defaultGateway = address(new L1OrbitERC20Gateway()); + + router = new L1OrbitGatewayRouter(); + l1Router = L1GatewayRouter(address(router)); + l1OrbitRouter = L1OrbitGatewayRouter(address(router)); + l1OrbitRouter.initialize(owner, defaultGateway, address(0), counterpartGateway, inbox); + + maxSubmissionCost = 0; + nativeTokenTotalFee = gasPriceBid * maxGas; + + vm.deal(owner, 100 ether); + vm.deal(user, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_getGateway_CustomGateway() public override { + address token = makeAddr("some token"); + + address[] memory tokens = new address[](1); + tokens[0] = token; + address[] memory gateways = new address[](1); + gateways[0] = address(new L1OrbitERC20Gateway()); + + vm.startPrank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + l1OrbitRouter.setGateways( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + address gateway = router.getGateway(token); + assertEq(gateway, gateways[0], "Invalid gateway"); + } + + function test_getGateway_DisabledGateway() public override { + address token = makeAddr("some token"); + + address[] memory tokens = new address[](1); + tokens[0] = token; + address[] memory gateways = new address[](1); + gateways[0] = address(1); + + vm.startPrank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + l1OrbitRouter.setGateways( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + address gateway = router.getGateway(token); + assertEq(gateway, address(0), "Invalid gateway"); + } + + function test_outboundTransfer() public override { + // init default gateway + L1OrbitERC20Gateway(defaultGateway).initialize( + makeAddr("defaultGatewayCounterpart"), + address(l1Router), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // set default gateway + vm.startPrank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + l1OrbitRouter.setDefaultGateway( + address(defaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + vm.stopPrank(); + + // create token + ERC20PresetMinterPauser token = new ERC20PresetMinterPauser("X", "Y"); + token.mint(user, 10000); + + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(defaultGateway)); + uint256 userNativeTokenBalanceBefore = nativeToken.balanceOf(user); + + /// deposit data + uint256 amount = 103; + address to = address(401); + bytes memory userEncodedData = abi.encode(maxSubmissionCost, "", nativeTokenTotalFee); + + /// approve tokens + vm.prank(user); + token.approve(address(defaultGateway), amount); + + // approve fees + vm.prank(user); + nativeToken.approve(address(defaultGateway), nativeTokenTotalFee); + + // expect event + vm.expectEmit(true, true, true, true); + emit TransferRouted(address(token), user, to, address(defaultGateway)); + + /// deposit it + vm.prank(user); + l1Router.outboundTransfer(address(token), to, amount, maxGas, gasPriceBid, userEncodedData); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(defaultGateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + amount, + "Wrong defaultGateway balance" + ); + + uint256 userNativeTokenBalanceAfter = nativeToken.balanceOf(user); + assertEq( + userNativeTokenBalanceBefore - userNativeTokenBalanceAfter, + nativeTokenTotalFee, + "Wrong user native token balance" + ); + } + + function test_outboundTransfer_revert_NotAllowedToBridgeFeeToken() public { + // init default gateway + L1OrbitERC20Gateway(defaultGateway).initialize( + makeAddr("defaultGatewayCounterpart"), + address(l1Router), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // set default gateway + vm.startPrank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + l1OrbitRouter.setDefaultGateway( + address(defaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + vm.stopPrank(); + + /// deposit it + vm.prank(user); + vm.expectRevert("NOT_ALLOWED_TO_BRIDGE_FEE_TOKEN"); + l1Router.outboundTransfer(address(nativeToken), user, 100, maxGas, gasPriceBid, ""); + } + + function test_outboundTransferCustomRefund() public override { + // init default gateway + L1OrbitERC20Gateway(defaultGateway).initialize( + makeAddr("defaultGatewayCounterpart"), + address(l1Router), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // set default gateway + vm.startPrank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + l1OrbitRouter.setDefaultGateway( + address(defaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + vm.stopPrank(); + + // create token + ERC20PresetMinterPauser token = new ERC20PresetMinterPauser("X", "Y"); + token.mint(user, 10000); + + // snapshot state before + uint256 userBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(defaultGateway)); + uint256 userNativeTokenBalanceBefore = nativeToken.balanceOf(user); + + /// deposit data + address refundTo = address(400); + address to = address(401); + uint256 amount = 103; + bytes memory userEncodedData = abi.encode(maxSubmissionCost, "", nativeTokenTotalFee); + + // approve fees + vm.prank(user); + nativeToken.approve(defaultGateway, nativeTokenTotalFee); + + // approve tokens + vm.prank(user); + token.approve(defaultGateway, amount); + + // expect event + vm.expectEmit(true, true, true, true); + emit TransferRouted(address(token), user, to, address(defaultGateway)); + + /// deposit it + vm.prank(user); + l1Router.outboundTransferCustomRefund( + address(token), + refundTo, + to, + amount, + maxGas, + gasPriceBid, + userEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = token.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + uint256 l1GatewayBalanceAfter = token.balanceOf(address(defaultGateway)); + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + amount, + "Wrong defaultGateway balance" + ); + + uint256 userNativeTokenBalanceAfter = nativeToken.balanceOf(user); + assertEq( + userNativeTokenBalanceBefore - userNativeTokenBalanceAfter, + nativeTokenTotalFee, + "Wrong user native token balance" + ); + } + + function test_outboundTransferCustomRefund_revert_NotAllowedToBridgeFeeToken() public { + // init default gateway + L1OrbitERC20Gateway(defaultGateway).initialize( + makeAddr("defaultGatewayCounterpart"), + address(l1Router), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // set default gateway + vm.startPrank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + l1OrbitRouter.setDefaultGateway( + address(defaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + vm.stopPrank(); + + /// deposit it + vm.prank(user); + vm.expectRevert("NOT_ALLOWED_TO_BRIDGE_FEE_TOKEN"); + l1Router.outboundTransferCustomRefund( + address(nativeToken), + user, + user, + 100, + maxGas, + gasPriceBid, + "" + ); + } + + function test_setDefaultGateway() public override { + L1OrbitERC20Gateway newL1DefaultGateway = new L1OrbitERC20Gateway(); + address newDefaultGatewayCounterpart = makeAddr("newDefaultGatewayCounterpart"); + newL1DefaultGateway.initialize( + newDefaultGatewayCounterpart, + address(l1OrbitRouter), + inbox, + 0x0000000000000000000000000000000000000000000000000000000000000001, + makeAddr("l2BeaconProxyFactory") + ); + + // approve fees + vm.prank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit DefaultGatewayUpdated(address(newL1DefaultGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1OrbitRouter), + counterpartGateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector( + L2GatewayRouter.setDefaultGateway.selector, + newDefaultGatewayCounterpart + ) + ); + + // set it + vm.prank(owner); + uint256 seqNum = l1OrbitRouter.setDefaultGateway( + address(newL1DefaultGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + /// checks + assertEq( + l1OrbitRouter.defaultGateway(), + address(newL1DefaultGateway), + "Invalid newL1DefaultGateway" + ); + + assertEq(seqNum, 0, "Invalid seqNum"); + } + + function test_setDefaultGateway_AddressZero() public override { + address newL1DefaultGateway = address(0); + + // approve fees + vm.prank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit DefaultGatewayUpdated(address(newL1DefaultGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1OrbitRouter), + counterpartGateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2GatewayRouter.setDefaultGateway.selector, address(0)) + ); + + // set it + vm.prank(owner); + uint256 seqNum = l1OrbitRouter.setDefaultGateway( + newL1DefaultGateway, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + /// checks + assertEq( + l1OrbitRouter.defaultGateway(), + address(newL1DefaultGateway), + "Invalid newL1DefaultGateway" + ); + + assertEq(seqNum, 0, "Invalid seqNum"); + } + + function test_setDefaultGateway_revert_NotSupportedInOrbit() public { + vm.prank(owner); + vm.expectRevert("NOT_SUPPORTED_IN_ORBIT"); + l1OrbitRouter.setDefaultGateway{ value: retryableCost }( + address(5), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + function test_setGateway() public override { + // create gateway + L1OrbitCustomGateway customGateway = new L1OrbitCustomGateway(); + address l2Counterpart = makeAddr("l2Counterpart"); + customGateway.initialize(l2Counterpart, address(l1Router), address(inbox), owner); + + // create token + ERC20 customToken = new ERC20("X", "Y"); + vm.deal(address(customToken), 100 ether); + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint( + address(customToken), + nativeTokenTotalFee + ); + vm.prank(address(customToken)); + nativeToken.approve(address(customGateway), nativeTokenTotalFee); + + // register token to gateway + vm.mockCall( + address(customToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(customToken)); + customGateway.registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + ERC20PresetMinterPauser(address(nativeToken)).mint( + address(customToken), + nativeTokenTotalFee + ); + + // snapshot state before + uint256 senderNativeTokenBalanceBefore = nativeToken.balanceOf(address(customToken)); + + // approve fees + vm.prank(address(customToken)); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(address(customToken), address(customGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(address(customToken), address(customToken)); + + vm.expectEmit(true, true, true, true); + address[] memory _tokenArr = new address[](1); + _tokenArr[0] = address(customToken); + address[] memory _gatewayArr = new address[](1); + _gatewayArr[0] = l2Counterpart; + emit ERC20InboxRetryableTicket( + address(l1OrbitRouter), + counterpartGateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, _tokenArr, _gatewayArr) + ); + + // set gateway + vm.prank(address(customToken)); + uint256 seqNum = l1OrbitRouter.setGateway( + address(customGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + ///// checks + + assertEq( + l1OrbitRouter.l1TokenToGateway(address(customToken)), + address(customGateway), + "Gateway not set" + ); + + uint256 senderNativeTokenBalanceAfter = nativeToken.balanceOf(address(customToken)); + assertEq( + senderNativeTokenBalanceBefore - senderNativeTokenBalanceAfter, + nativeTokenTotalFee, + "Wrong sender native token balance" + ); + + assertEq(seqNum, 1, "Invalid seqNum"); + } + + function test_setGateway_CustomCreditback() public override { + // create gateway + L1OrbitCustomGateway customGateway = new L1OrbitCustomGateway(); + address l2Counterpart = makeAddr("l2Counterpart"); + customGateway.initialize(l2Counterpart, address(l1Router), address(inbox), owner); + + // create token + ERC20 customToken = new ERC20("X", "Y"); + vm.deal(address(customToken), 100 ether); + + // register token to gateway + ERC20PresetMinterPauser(address(nativeToken)).mint( + address(customToken), + nativeTokenTotalFee + ); + vm.prank(address(customToken)); + nativeToken.approve(address(customGateway), nativeTokenTotalFee); + + vm.mockCall( + address(customToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(address(customToken)); + customGateway.registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint( + address(customToken), + nativeTokenTotalFee + ); + vm.prank(address(customToken)); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(address(customToken), address(customGateway)); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, creditBackAddress); + + vm.expectEmit(true, true, true, true); + address[] memory _tokenArr = new address[](1); + _tokenArr[0] = address(customToken); + address[] memory _gatewayArr = new address[](1); + _gatewayArr[0] = l2Counterpart; + emit ERC20InboxRetryableTicket( + address(l1OrbitRouter), + counterpartGateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, _tokenArr, _gatewayArr) + ); + + // set gateway + vm.prank(address(customToken)); + uint256 seqNum = l1OrbitRouter.setGateway( + address(customGateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + ///// checks + + assertEq( + l1OrbitRouter.l1TokenToGateway(address(customToken)), + address(customGateway), + "Gateway not set" + ); + + assertEq(seqNum, 1, "Invalid seqNum"); + } + + function test_setGateway_revert_NoUpdateToDifferentAddress() public override { + // create gateway + address initialGateway = address(new L1OrbitCustomGateway()); + address l2Counterpart = makeAddr("l2Counterpart"); + L1OrbitCustomGateway(initialGateway).initialize( + l2Counterpart, + address(l1Router), + address(inbox), + owner + ); + + // create token + address token = address(new ERC20("X", "Y")); + vm.deal(address(token), 100 ether); + + // register token to gateway + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + vm.prank(token); + nativeToken.approve(address(initialGateway), nativeTokenTotalFee); + + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(token); + L1OrbitCustomGateway(initialGateway).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + // initially set gateway for token + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + vm.prank(address(token)); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + vm.prank(address(token)); + l1OrbitRouter.setGateway( + initialGateway, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + assertEq(l1OrbitRouter.l1TokenToGateway(token), initialGateway, "Initial gateway not set"); + + //// now try setting different gateway + address newGateway = address(new L1OrbitCustomGateway()); + + vm.prank(token); + vm.expectRevert("NO_UPDATE_TO_DIFFERENT_ADDR"); + l1OrbitRouter.setGateway( + newGateway, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + } + + function test_setGateway_revert_NotArbEnabled() public override { + address nonArbEnabledToken = address(new ERC20("X", "Y")); + vm.deal(nonArbEnabledToken, 100 ether); + vm.mockCall( + nonArbEnabledToken, + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb2)) + ); + + vm.prank(nonArbEnabledToken); + vm.expectRevert("NOT_ARB_ENABLED"); + l1OrbitRouter.setGateway( + makeAddr("gateway"), + 100000, + 3, + 200, + makeAddr("creditback"), + nativeTokenTotalFee + ); + } + + function test_setGateway_revert_NotToContract() public override { + address token = address(new ERC20("X", "Y")); + vm.deal(token, 100 ether); + vm.mockCall(token, abi.encodeWithSignature("isArbitrumEnabled()"), abi.encode(uint8(0xb1))); + + address gatewayNotContract = makeAddr("not contract"); + + vm.prank(token); + vm.expectRevert("NOT_TO_CONTRACT"); + l1OrbitRouter.setGateway( + gatewayNotContract, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + } + + function test_setGateway_revert_NotSupportedInOrbit() public { + vm.expectRevert("NOT_SUPPORTED_IN_ORBIT"); + l1OrbitRouter.setGateway(address(102), maxGas, gasPriceBid, maxSubmissionCost); + } + + function test_setGateway_revert_CustomCreaditbackNotSupportedInOrbit() public { + vm.expectRevert("NOT_SUPPORTED_IN_ORBIT"); + l1OrbitRouter.setGateway( + address(103), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress + ); + } + + function test_setGateway_revert_TokenNotHandledByGateway() public override { + // create gateway + L1OrbitCustomGateway gateway = new L1OrbitCustomGateway(); + + // create token + address token = address(new ERC20("X", "Y")); + vm.deal(token, 100 ether); + vm.mockCall(token, abi.encodeWithSignature("isArbitrumEnabled()"), abi.encode(uint8(0xb1))); + + vm.prank(token); + vm.expectRevert("TOKEN_NOT_HANDLED_BY_GATEWAY"); + l1OrbitRouter.setGateway( + address(gateway), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + } + + function test_setGateways() public override { + // create tokens and gateways + address[] memory tokens = new address[](2); + tokens[0] = address(new ERC20("1", "1")); + tokens[1] = address(new ERC20("2", "2")); + address[] memory gateways = new address[](2); + gateways[0] = address(new L1OrbitCustomGateway()); + gateways[1] = address(new L1OrbitCustomGateway()); + + address l2Counterpart = makeAddr("l2Counterpart"); + + /// init all + for (uint256 i = 0; i < 2; i++) { + L1OrbitCustomGateway(gateways[i]).initialize( + l2Counterpart, + address(l1Router), + address(inbox), + owner + ); + + vm.mockCall( + tokens[i], + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + + // register tokens to gateways + ERC20PresetMinterPauser(address(nativeToken)).mint(tokens[i], nativeTokenTotalFee); + vm.prank(tokens[i]); + nativeToken.approve(address(gateways[i]), nativeTokenTotalFee); + + vm.deal(tokens[i], 100 ether); + vm.prank(tokens[i]); + L1OrbitCustomGateway(gateways[i]).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + } + + // approve fees + vm.prank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(tokens[0], gateways[0]); + vm.expectEmit(true, true, true, true); + emit GatewaySet(tokens[1], gateways[1]); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + address[] memory _gatewayArr = new address[](2); + _gatewayArr[0] = l2Counterpart; + _gatewayArr[1] = l2Counterpart; + emit ERC20InboxRetryableTicket( + address(l1OrbitRouter), + counterpartGateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, tokens, _gatewayArr) + ); + + /// set gateways + vm.prank(owner); + uint256 seqNum = l1OrbitRouter.setGateways( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + ///// checks + + assertEq(l1Router.l1TokenToGateway(tokens[0]), gateways[0], "Gateway[0] not set"); + assertEq(l1Router.l1TokenToGateway(tokens[1]), gateways[1], "Gateway[1] not set"); + assertEq(seqNum, 2, "Invalid seqNum"); + } + + function test_setGateways_SetZeroAddr() public override { + // create gateway + address initialGateway = address(new L1OrbitCustomGateway()); + address l2Counterpart = makeAddr("l2Counterpart"); + L1OrbitCustomGateway(initialGateway).initialize( + l2Counterpart, + address(l1Router), + address(inbox), + owner + ); + + // create token + address token = address(new ERC20("X", "Y")); + vm.deal(address(token), 100 ether); + + // register token to gateway + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + vm.prank(address(token)); + nativeToken.approve(initialGateway, nativeTokenTotalFee); + + vm.mockCall( + address(token), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.prank(token); + L1OrbitCustomGateway(initialGateway).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + // initially set gateway for token + ERC20PresetMinterPauser(address(nativeToken)).mint(address(token), nativeTokenTotalFee); + vm.prank(address(token)); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + vm.prank(address(token)); + l1OrbitRouter.setGateway( + initialGateway, + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + assertEq(l1OrbitRouter.l1TokenToGateway(token), initialGateway, "Initial gateway not set"); + + //// now set to zero addr + address newGateway = address(0); + + // approve fees + vm.prank(owner); + nativeToken.approve(address(l1OrbitRouter), nativeTokenTotalFee); + + // expect events + vm.expectEmit(true, true, true, true); + emit GatewaySet(token, newGateway); + + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(owner, owner); + + vm.expectEmit(true, true, true, true); + address[] memory _tokenArr = new address[](1); + _tokenArr[0] = token; + address[] memory _gatewayArr = new address[](1); + _gatewayArr[0] = newGateway; + emit ERC20InboxRetryableTicket( + address(l1OrbitRouter), + counterpartGateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + abi.encodeWithSelector(L2GatewayRouter.setGateway.selector, _tokenArr, _gatewayArr) + ); + + /// set gateways + vm.prank(owner); + uint256 seqNum = l1OrbitRouter.setGateways( + _tokenArr, + _gatewayArr, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + + ///// checks + + assertEq(l1OrbitRouter.l1TokenToGateway(token), address(0), "Custom gateway not cleared"); + assertEq(seqNum, 2, "Invalid seqNum"); + } + + function test_setGateways_revert_WrongLength() public override { + address[] memory tokens = new address[](2); + tokens[0] = address(new ERC20("1", "1")); + tokens[1] = address(new ERC20("2", "2")); + address[] memory gateways = new address[](1); + gateways[0] = address(new L1OrbitCustomGateway()); + + /// set gateways + vm.prank(owner); + vm.expectRevert("WRONG_LENGTH"); + l1OrbitRouter.setGateways( + tokens, + gateways, + maxGas, + gasPriceBid, + maxSubmissionCost, + nativeTokenTotalFee + ); + } + + function test_setGateways_revert_NotSupportedInOrbit() public { + vm.prank(owner); + vm.expectRevert("NOT_SUPPORTED_IN_ORBIT"); + l1OrbitRouter.setGateways( + new address[](2), + new address[](2), + maxGas, + gasPriceBid, + maxSubmissionCost + ); + } + + event ERC20InboxRetryableTicket( + address from, + address to, + uint256 l2CallValue, + uint256 maxGas, + uint256 gasPrice, + uint256 tokenTotalFeeAmount, + bytes data + ); +} diff --git a/test-foundry/L1OrbitIntegration.t.sol b/test-foundry/L1OrbitIntegration.t.sol new file mode 100644 index 0000000000..985856e8c1 --- /dev/null +++ b/test-foundry/L1OrbitIntegration.t.sol @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import { L1GatewayRouterTest } from "./L1GatewayRouter.t.sol"; +import { ERC20InboxMock } from "contracts/tokenbridge/test/InboxMock.sol"; +import { L1OrbitERC20Gateway } from "contracts/tokenbridge/ethereum/gateway/L1OrbitERC20Gateway.sol"; +import { L1OrbitGatewayRouter } from "contracts/tokenbridge/ethereum/gateway/L1OrbitGatewayRouter.sol"; +import { L2GatewayRouter } from "contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol"; +import { L1GatewayRouter } from "contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol"; +import { L1OrbitCustomGateway } from "contracts/tokenbridge/ethereum/gateway/L1OrbitCustomGateway.sol"; +import { ERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20PresetMinterPauser } from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; +import { TestERC20 } from "contracts/tokenbridge/test/TestERC20.sol"; +import { TestOrbitCustomTokenL1 } from "contracts/tokenbridge/test/TestCustomTokenL1.sol"; +import { ERC20Inbox } from "lib/nitro-contracts/src/bridge/ERC20Inbox.sol"; +import { ERC20Bridge } from "lib/nitro-contracts/src/bridge/ERC20Bridge.sol"; +import { ERC20PresetFixedSupply } from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import { IOwnable } from "lib/nitro-contracts/src/bridge/IOwnable.sol"; +import { ISequencerInbox } from "lib/nitro-contracts/src/bridge/ISequencerInbox.sol"; +import "./util/TestUtil.sol"; + +contract IntegrationTest is Test { + address public owner = makeAddr("owner"); + address public user = makeAddr("user"); + address public counterpartGateway = makeAddr("counterpartGateway"); + address public rollup = makeAddr("rollup"); + address public seqInbox = makeAddr("seqInbox"); + address public l2Gateway = makeAddr("l2Gateway"); + bytes32 public cloneableProxyHash = bytes32("123"); + address public l2BeaconProxyFactory = makeAddr("l2BeaconProxyFactory"); + + ERC20PresetFixedSupply public nativeToken; + ERC20Inbox public inbox; + ERC20Bridge public bridge; + L1OrbitERC20Gateway public defaultGateway; + L1OrbitGatewayRouter public router; + + uint256 private maxSubmissionCost = 0; + uint256 private maxGas = 100000; + uint256 private gasPriceBid = 3; + uint256 private nativeTokenTotalFee; + + function setUp() public { + // deploy token, bridge and inbox + nativeToken = new ERC20PresetFixedSupply( + "Appchain Token", + "App", + 1_000_000 ether, + address(this) + ); + inbox = ERC20Inbox(TestUtil.deployProxy(address(new ERC20Inbox()))); + bridge = ERC20Bridge(TestUtil.deployProxy(address(new ERC20Bridge()))); + + // init bridge and inbox + bridge.initialize(IOwnable(rollup), address(nativeToken)); + inbox.initialize(bridge, ISequencerInbox(seqInbox)); + vm.prank(rollup); + bridge.setDelayedInbox(address(inbox), true); + + // create default gateway and router + defaultGateway = L1OrbitERC20Gateway( + TestUtil.deployProxy(address(new L1OrbitERC20Gateway())) + ); + router = L1OrbitGatewayRouter(TestUtil.deployProxy(address(new L1OrbitGatewayRouter()))); + router.initialize( + owner, + address(defaultGateway), + address(0), + counterpartGateway, + address(inbox) + ); + defaultGateway.initialize( + l2Gateway, + address(router), + address(inbox), + cloneableProxyHash, + l2BeaconProxyFactory + ); + + nativeTokenTotalFee = maxGas * gasPriceBid; + } + + /* solhint-disable func-name-mixedcase */ + function test_depositNative(uint256 depositAmount) public { + vm.assume(depositAmount < 1_000_000 ether); + nativeToken.transfer(user, depositAmount); + + // snapshot before + uint256 userNativeTokenBalanceBefore = nativeToken.balanceOf(user); + uint256 bridgeNativeTokenBalanceBefore = nativeToken.balanceOf(address(bridge)); + + vm.prank(user); + nativeToken.approve(address(inbox), depositAmount); + + vm.prank(user); + inbox.depositERC20(depositAmount); + + // snapshot before + uint256 userNativeTokenBalanceAfter = nativeToken.balanceOf(user); + uint256 bridgeNativeTokenBalanceAfter = nativeToken.balanceOf(address(bridge)); + + assertEq( + userNativeTokenBalanceBefore - userNativeTokenBalanceAfter, + depositAmount, + "Invalid user native token balance" + ); + + assertEq( + bridgeNativeTokenBalanceAfter - bridgeNativeTokenBalanceBefore, + depositAmount, + "Invalid bridge token balance" + ); + } + + function test_depositToken_DefaultGateway() public { + uint256 tokenDepositAmount = 250; + + // token to bridge + IERC20 token = IERC20(address(new TestERC20())); + + // fund account + vm.prank(user); + TestERC20(address(token)).mint(); + + // fund user to be able to pay retryable fees + nativeToken.transfer(user, nativeTokenTotalFee); + + // snapshot state before + uint256 userTokenBalanceBefore = token.balanceOf(user); + uint256 l1GatewayBalanceBefore = token.balanceOf(address(defaultGateway)); + uint256 userNativeTokenBalanceBefore = nativeToken.balanceOf(user); + uint256 bridgeNativeTokenBalanceBefore = nativeToken.balanceOf(address(bridge)); + + { + vm.startPrank(user); + + /// approve token + token.approve(address(defaultGateway), tokenDepositAmount); + + // approve fees + nativeToken.approve(address(defaultGateway), nativeTokenTotalFee); + + address refundTo = user; + bytes memory userEncodedData = abi.encode(maxSubmissionCost, "", nativeTokenTotalFee); + router.outboundTransferCustomRefund( + address(token), + refundTo, + user, + tokenDepositAmount, + maxGas, + gasPriceBid, + userEncodedData + ); + + vm.stopPrank(); + } + + /// check token moved user->gateway, and native token user->bridge + { + uint256 userTokenBalanceAfter = token.balanceOf(user); + uint256 l1GatewayBalanceAfter = token.balanceOf(address(defaultGateway)); + uint256 userNativeTokenBalanceAfter = nativeToken.balanceOf(user); + uint256 bridgeNativeTokenBalanceAfter = nativeToken.balanceOf(address(bridge)); + + assertEq( + userTokenBalanceBefore - userTokenBalanceAfter, + tokenDepositAmount, + "Invalid user token balance" + ); + + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + tokenDepositAmount, + "Invalid default gateway token balance" + ); + + assertEq( + userNativeTokenBalanceBefore - userNativeTokenBalanceAfter, + nativeTokenTotalFee, + "Invalid user native token balance" + ); + + assertEq( + bridgeNativeTokenBalanceAfter - bridgeNativeTokenBalanceBefore, + nativeTokenTotalFee, + "Invalid user native token balance" + ); + } + } + + function test_depositToken_CustomGateway() public { + uint256 tokenDepositAmount = 250; + + ///////// + nativeToken.transfer(user, nativeTokenTotalFee * 3); + + // create + init custom gateway + L1OrbitCustomGateway customL1Gateway = new L1OrbitCustomGateway(); + L1OrbitCustomGateway(address(customL1Gateway)).initialize( + makeAddr("l2Gateway"), + address(router), + address(inbox), + owner + ); + + // create token and register it + TestOrbitCustomTokenL1 customToken = new TestOrbitCustomTokenL1( + address(customL1Gateway), + address(router) + ); + + vm.startPrank(user); + nativeToken.approve(address(customToken), nativeTokenTotalFee * 2); + customToken.registerTokenOnL2( + makeAddr("l2CustomTokenAddress"), + maxSubmissionCost, + maxSubmissionCost, + maxGas, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + nativeTokenTotalFee, + makeAddr("creditbackAddr") + ); + assertEq( + router.l1TokenToGateway(address(customToken)), + address(customL1Gateway), + "Invalid custom gateway" + ); + customToken.mint(); + vm.stopPrank(); + + // snapshot state before + uint256 userTokenBalanceBefore = customToken.balanceOf(user); + uint256 l1GatewayBalanceBefore = customToken.balanceOf(address(customL1Gateway)); + uint256 userNativeTokenBalanceBefore = nativeToken.balanceOf(user); + uint256 bridgeNativeTokenBalanceBefore = nativeToken.balanceOf(address(bridge)); + + /// deposit custom token + { + vm.startPrank(user); + + /// approve token + customToken.approve(address(customL1Gateway), tokenDepositAmount); + + // approve fees + nativeToken.transfer(user, nativeTokenTotalFee); + nativeToken.approve(address(customL1Gateway), nativeTokenTotalFee); + + address refundTo = user; + bytes memory userEncodedData = abi.encode(maxSubmissionCost, "", nativeTokenTotalFee); + router.outboundTransferCustomRefund( + address(customToken), + refundTo, + user, + tokenDepositAmount, + maxGas, + gasPriceBid, + userEncodedData + ); + + vm.stopPrank(); + } + + /// check token moved user->gateway, and native token user->bridge + { + uint256 userTokenBalanceAfter = customToken.balanceOf(user); + uint256 l1GatewayBalanceAfter = customToken.balanceOf(address(customL1Gateway)); + uint256 userNativeTokenBalanceAfter = nativeToken.balanceOf(user); + uint256 bridgeNativeTokenBalanceAfter = nativeToken.balanceOf(address(bridge)); + + assertEq( + userTokenBalanceBefore - userTokenBalanceAfter, + tokenDepositAmount, + "Invalid user token balance" + ); + + assertEq( + l1GatewayBalanceAfter - l1GatewayBalanceBefore, + tokenDepositAmount, + "Invalid default gateway token balance" + ); + + assertEq( + userNativeTokenBalanceBefore - userNativeTokenBalanceAfter, + nativeTokenTotalFee, + "Invalid user native token balance" + ); + + assertEq( + bridgeNativeTokenBalanceAfter - bridgeNativeTokenBalanceBefore, + nativeTokenTotalFee, + "Invalid user native token balance" + ); + } + } +} diff --git a/test-foundry/L1OrbitReverseCustomGateway.t.sol b/test-foundry/L1OrbitReverseCustomGateway.t.sol new file mode 100644 index 0000000000..2300b1fb0d --- /dev/null +++ b/test-foundry/L1OrbitReverseCustomGateway.t.sol @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1OrbitCustomGatewayTest, ERC20InboxMock, TestERC20, IERC20, ERC20, ERC20PresetMinterPauser } from "./L1OrbitCustomGateway.t.sol"; +import { L1OrbitReverseCustomGateway } from "contracts/tokenbridge/ethereum/gateway/L1OrbitReverseCustomGateway.sol"; +import { MintableTestCustomTokenL1, ReverseTestCustomTokenL1 } from "contracts/tokenbridge/test/TestCustomTokenL1.sol"; +import { IInbox } from "contracts/tokenbridge/ethereum/L1ArbitrumMessenger.sol"; + +contract L1OrbitReverseCustomGatewayTest is L1OrbitCustomGatewayTest { + function setUp() public override { + inbox = address(new ERC20InboxMock()); + nativeToken = ERC20(address(new ERC20PresetMinterPauser("X", "Y"))); + ERC20PresetMinterPauser(address(nativeToken)).mint(user, 1_000_000 ether); + ERC20PresetMinterPauser(address(nativeToken)).mint(owner, 1_000_000 ether); + ERC20InboxMock(inbox).setMockNativeToken(address(nativeToken)); + + l1Gateway = new L1OrbitReverseCustomGateway(); + L1OrbitReverseCustomGateway(address(l1Gateway)).initialize(l2Gateway, router, inbox, owner); + + token = IERC20(address(new TestERC20())); + + maxSubmissionCost = 0; + nativeTokenTotalFee = maxGas * gasPriceBid; + + // fund user and router + vm.prank(user); + TestERC20(address(token)).mint(); + vm.deal(router, 100 ether); + vm.deal(address(token), 100 ether); + vm.deal(owner, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_finalizeInboundTransfer() public override { + // fund gateway with bridged tokens + MintableTestCustomTokenL1 bridgedToken = new MintableTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(l1Gateway)); + bridgedToken.mint(); + + // snapshot state before + uint256 userBalanceBefore = bridgedToken.balanceOf(user); + + // deposit params + address from = address(3000); + uint256 amount = 25; + uint256 exitNum = 7; + bytes memory callHookData = ""; + bytes memory data = abi.encode(exitNum, callHookData); + + ERC20InboxMock(address(inbox)).setL2ToL1Sender(l2Gateway); + + // trigger deposit + vm.prank(address(IInbox(l1Gateway.inbox()).bridge())); + L1OrbitReverseCustomGateway(address(l1Gateway)).finalizeInboundTransfer( + address(bridgedToken), + from, + user, + amount, + data + ); + + // check tokens are minted + uint256 userBalanceAfter = bridgedToken.balanceOf(user); + assertEq(userBalanceAfter - userBalanceBefore, amount, "Wrong user balance"); + } + + function test_outboundTransfer() public override { + // fund user with tokens + MintableTestCustomTokenL1 bridgedToken = new ReverseTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(user)); + bridgedToken.mint(); + + // snapshot state before + uint256 userBalanceBefore = bridgedToken.balanceOf(user); + + uint256 amount = 300; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint( + address(bridgedToken), + nativeTokenTotalFee + ); + vm.prank(address(bridgedToken)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // register token to gateway + vm.mockCall( + address(bridgedToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.deal(address(bridgedToken), 100 ether); + vm.prank(address(bridgedToken)); + uint256 seqNum0 = L1OrbitReverseCustomGateway(address(l1Gateway)).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + // approve token + vm.prank(user); + bridgedToken.approve(address(l1Gateway), amount); + + // approve fees + vm.prank(user); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(user, user); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + l1Gateway.getOutboundCalldata(address(bridgedToken), user, user, amount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(bridgedToken), user, user, 1, amount); + + // trigger transfer + vm.prank(router); + bytes memory seqNum1 = L1OrbitReverseCustomGateway(address(l1Gateway)).outboundTransfer( + address(bridgedToken), + user, + amount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are burned + uint256 userBalanceAfter = bridgedToken.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund() public override { + // fund user with tokens + MintableTestCustomTokenL1 bridgedToken = new ReverseTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(user)); + bridgedToken.mint(); + + // snapshot state before + uint256 userBalanceBefore = bridgedToken.balanceOf(user); + + uint256 amount = 450; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint( + address(bridgedToken), + nativeTokenTotalFee + ); + vm.prank(address(bridgedToken)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // register token to gateway + vm.mockCall( + address(bridgedToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.deal(address(bridgedToken), 100 ether); + vm.prank(address(bridgedToken)); + uint256 seqNum0 = L1OrbitReverseCustomGateway(address(l1Gateway)).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + // approve token + vm.prank(user); + bridgedToken.approve(address(l1Gateway), amount); + + // approve fees + vm.prank(user); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, user); + + vm.expectEmit(true, true, true, true); + emit ERC20InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + gasPriceBid, + nativeTokenTotalFee, + l1Gateway.getOutboundCalldata(address(bridgedToken), user, user, amount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(bridgedToken), user, user, 1, amount); + + // trigger deposit + vm.prank(router); + bytes memory seqNum1 = L1OrbitReverseCustomGateway(address(l1Gateway)) + .outboundTransferCustomRefund( + address(bridgedToken), + creditBackAddress, + user, + amount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = bridgedToken.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund_revert_InsufficientAllowance() public override { + // fund user with tokens + MintableTestCustomTokenL1 bridgedToken = new ReverseTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(user)); + bridgedToken.mint(); + + uint256 tooManyTokens = 500 ether; + + // approve fees + ERC20PresetMinterPauser(address(nativeToken)).mint( + address(bridgedToken), + nativeTokenTotalFee + ); + vm.prank(address(bridgedToken)); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + // register token to gateway + vm.mockCall( + address(bridgedToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.deal(address(bridgedToken), 100 ether); + vm.prank(address(bridgedToken)); + L1OrbitReverseCustomGateway(address(l1Gateway)).registerTokenToL2( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + creditBackAddress, + nativeTokenTotalFee + ); + + vm.prank(user); + nativeToken.approve(address(l1Gateway), nativeTokenTotalFee); + + vm.prank(router); + vm.expectRevert("ERC20: burn amount exceeds balance"); + l1Gateway.outboundTransferCustomRefund( + address(bridgedToken), + user, + user, + tooManyTokens, + 0.1 ether, + 0.01 ether, + buildRouterEncodedData("") + ); + } +} diff --git a/test-foundry/L1ReverseCustomGateway.t.sol b/test-foundry/L1ReverseCustomGateway.t.sol new file mode 100644 index 0000000000..30dce5bba1 --- /dev/null +++ b/test-foundry/L1ReverseCustomGateway.t.sol @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.0; + +import { L1CustomGatewayTest, InboxMock, IERC20, IInbox, TestERC20 } from "./L1CustomGateway.t.sol"; +import { L1ReverseCustomGateway } from "contracts/tokenbridge/ethereum/gateway/L1ReverseCustomGateway.sol"; +import { MintableTestCustomTokenL1, ReverseTestCustomTokenL1 } from "contracts/tokenbridge/test/TestCustomTokenL1.sol"; + +contract L1ReverseCustomGatewayTest is L1CustomGatewayTest { + function setUp() public virtual override { + inbox = address(new InboxMock()); + + l1Gateway = new L1ReverseCustomGateway(); + L1ReverseCustomGateway(address(l1Gateway)).initialize(l2Gateway, router, inbox, owner); + + token = IERC20(address(new TestERC20())); + + maxSubmissionCost = 20; + retryableCost = maxSubmissionCost + gasPriceBid * maxGas; + + // fund user and router + vm.prank(user); + TestERC20(address(token)).mint(); + vm.deal(router, 100 ether); + vm.deal(address(token), 100 ether); + vm.deal(owner, 100 ether); + } + + /* solhint-disable func-name-mixedcase */ + function test_finalizeInboundTransfer() public override { + // fund gateway with bridged tokens + MintableTestCustomTokenL1 bridgedToken = new MintableTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(l1Gateway)); + bridgedToken.mint(); + + // snapshot state before + uint256 userBalanceBefore = bridgedToken.balanceOf(user); + + // deposit params + address from = address(3000); + uint256 amount = 25; + uint256 exitNum = 7; + bytes memory callHookData = ""; + bytes memory data = abi.encode(exitNum, callHookData); + + InboxMock(address(inbox)).setL2ToL1Sender(l2Gateway); + + // trigger deposit + vm.prank(address(IInbox(l1Gateway.inbox()).bridge())); + l1Gateway.finalizeInboundTransfer(address(bridgedToken), from, user, amount, data); + + // check tokens are minted + uint256 userBalanceAfter = bridgedToken.balanceOf(user); + assertEq(userBalanceAfter - userBalanceBefore, amount, "Wrong user balance"); + } + + function test_outboundTransfer() public override { + // fund user with tokens + MintableTestCustomTokenL1 bridgedToken = new ReverseTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(user)); + bridgedToken.mint(); + + // snapshot state before + uint256 userBalanceBefore = bridgedToken.balanceOf(user); + + uint256 amount = 300; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // register token to gateway + vm.mockCall( + address(bridgedToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.deal(address(bridgedToken), 100 ether); + vm.prank(address(bridgedToken)); + uint256 seqNum0 = L1ReverseCustomGateway(address(l1Gateway)).registerTokenToL2{ + value: retryableCost + }(makeAddr("tokenL2Address"), maxGas, gasPriceBid, maxSubmissionCost, creditBackAddress); + + // approve token + vm.prank(user); + bridgedToken.approve(address(l1Gateway), amount); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(user, user); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + l1Gateway.getOutboundCalldata(address(bridgedToken), user, user, amount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(bridgedToken), user, user, 1, amount); + + // trigger transfer + vm.prank(router); + bytes memory seqNum1 = l1Gateway.outboundTransfer{ value: retryableCost }( + address(bridgedToken), + user, + amount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are burned + uint256 userBalanceAfter = bridgedToken.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund() public override { + // fund user with tokens + MintableTestCustomTokenL1 bridgedToken = new ReverseTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(user)); + bridgedToken.mint(); + + // snapshot state before + uint256 userBalanceBefore = bridgedToken.balanceOf(user); + + uint256 amount = 450; + bytes memory callHookData = ""; + bytes memory routerEncodedData = buildRouterEncodedData(callHookData); + + // register token to gateway + vm.mockCall( + address(bridgedToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.deal(address(bridgedToken), 100 ether); + vm.prank(address(bridgedToken)); + uint256 seqNum0 = L1ReverseCustomGateway(address(l1Gateway)).registerTokenToL2{ + value: retryableCost + }(makeAddr("tokenL2Address"), maxGas, gasPriceBid, maxSubmissionCost, creditBackAddress); + + // approve token + vm.prank(user); + bridgedToken.approve(address(l1Gateway), amount); + + // event checkers + vm.expectEmit(true, true, true, true); + emit TicketData(maxSubmissionCost); + + vm.expectEmit(true, true, true, true); + emit RefundAddresses(creditBackAddress, user); + + vm.expectEmit(true, true, true, true); + emit InboxRetryableTicket( + address(l1Gateway), + l2Gateway, + 0, + maxGas, + l1Gateway.getOutboundCalldata(address(bridgedToken), user, user, amount, callHookData) + ); + + vm.expectEmit(true, true, true, true); + emit DepositInitiated(address(bridgedToken), user, user, 1, amount); + + // trigger deposit + vm.prank(router); + bytes memory seqNum1 = l1Gateway.outboundTransferCustomRefund{ value: retryableCost }( + address(bridgedToken), + creditBackAddress, + user, + amount, + maxGas, + gasPriceBid, + routerEncodedData + ); + + // check tokens are escrowed + uint256 userBalanceAfter = bridgedToken.balanceOf(user); + assertEq(userBalanceBefore - userBalanceAfter, amount, "Wrong user balance"); + + assertEq(seqNum0, 0, "Invalid seqNum0"); + assertEq(seqNum1, abi.encode(1), "Invalid seqNum1"); + } + + function test_outboundTransferCustomRefund_revert_InsufficientAllowance() public override { + // fund user with tokens + MintableTestCustomTokenL1 bridgedToken = new ReverseTestCustomTokenL1( + address(l1Gateway), + router + ); + vm.prank(address(user)); + bridgedToken.mint(); + + uint256 tooManyTokens = 500 ether; + + // register token to gateway + vm.mockCall( + address(bridgedToken), + abi.encodeWithSignature("isArbitrumEnabled()"), + abi.encode(uint8(0xb1)) + ); + vm.deal(address(bridgedToken), 100 ether); + vm.prank(address(bridgedToken)); + L1ReverseCustomGateway(address(l1Gateway)).registerTokenToL2{ value: retryableCost }( + makeAddr("tokenL2Address"), + maxGas, + gasPriceBid, + maxSubmissionCost, + makeAddr("creditBackAddress") + ); + + vm.prank(router); + vm.expectRevert("ERC20: burn amount exceeds balance"); + l1Gateway.outboundTransferCustomRefund{ value: 1 ether }( + address(bridgedToken), + user, + user, + tooManyTokens, + 0.1 ether, + 0.01 ether, + buildRouterEncodedData("") + ); + } +} diff --git a/test-foundry/util/TestUtil.sol b/test-foundry/util/TestUtil.sol new file mode 100644 index 0000000000..27b3265865 --- /dev/null +++ b/test-foundry/util/TestUtil.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.4; + +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +library TestUtil { + function deployProxy(address logic) public returns (address) { + ProxyAdmin pa = new ProxyAdmin(); + return address(new TransparentUpgradeableProxy(address(logic), address(pa), "")); + } +} diff --git a/test/storage/StandardArbERC20.dot b/test/storage/StandardArbERC20.dot index 02345fbb7c..3a9831ac50 100644 --- a/test/storage/StandardArbERC20.dot +++ b/test/storage/StandardArbERC20.dot @@ -5,7 +5,7 @@ arrowhead=open bgcolor="white" edge [color="black"] node [shape=record, style=filled, color="black", fillcolor="gray95", fontcolor="black", fontname="Courier New"] -7 [label="StandardArbERC20 \<\\>\n | {{ slot | 0 | 1-50 | 51 | 52 | 53 | 54 | 55 | 56 | 57-100 | 101 | 102 | 103-152 | 153 | 154 | 155-203 | 204 | 205 | 206} | { type: \.variable (bytes) | { unallocated (30) | bool: Initializable._initializing (1) | bool: Initializable._initialized (1) } | { <8> uint256[50]: ContextUpgradeable.__gap (1600) } | { mapping\(address=\>uint256\): ERC20Upgradeable._balances (32) } | { mapping\(address=\>mapping\(address=\>uint256\)\): ERC20Upgradeable._allowances (32) } | { uint256: ERC20Upgradeable._totalSupply (32) } | { string: ERC20Upgradeable._name (32) } | { string: ERC20Upgradeable._symbol (32) } | { unallocated (31) | uint8: ERC20Upgradeable._decimals (1) } | { <20> uint256[44]: ERC20Upgradeable.__gap (1408) } | { bytes32: EIP712Upgradeable._HASHED_NAME (32) } | { bytes32: EIP712Upgradeable._HASHED_VERSION (32) } | { <28> uint256[50]: EIP712Upgradeable.__gap (1600) } | { <30> mapping\(address=\>CountersUpgradeable.Counter\): ERC20PermitUpgradeable._nonces (32) } | { bytes32: ERC20PermitUpgradeable._PERMIT_TYPEHASH (32) } | { <37> uint256[49]: ERC20PermitUpgradeable.__gap (1568) } | { unallocated (12) | address: L2GatewayToken.l2Gateway (20) } | { unallocated (11) | bool: Cloneable.isMasterCopy (1) | address: L2GatewayToken.l1Address (20) } | { <44> ERC20Getters: availableGetters (32) }}}"] +7 [label="StandardArbERC20 \<\\>\n | {{ slot | 0 | 1-50 | 51 | 52 | 53 | 54 | 55 | 56 | 57-100 | 101 | 102 | 103-152 | 153 | 154 | 155-203 | 204 | 205 | 206} | { type: \.variable (bytes) | { unallocated (30) | bool: Initializable._initializing (1) | uint8: Initializable._initialized (1) } | { <8> uint256[50]: ContextUpgradeable.__gap (1600) } | { mapping\(address=\>uint256\): ERC20Upgradeable._balances (32) } | { mapping\(address=\>mapping\(address=\>uint256\)\): ERC20Upgradeable._allowances (32) } | { uint256: ERC20Upgradeable._totalSupply (32) } | { string: ERC20Upgradeable._name (32) } | { string: ERC20Upgradeable._symbol (32) } | { unallocated (31) | uint8: ERC20Upgradeable._decimals (1) } | { <20> uint256[44]: ERC20Upgradeable.__gap (1408) } | { bytes32: EIP712Upgradeable._HASHED_NAME (32) } | { bytes32: EIP712Upgradeable._HASHED_VERSION (32) } | { <28> uint256[50]: EIP712Upgradeable.__gap (1600) } | { <30> mapping\(address=\>CountersUpgradeable.Counter\): ERC20PermitUpgradeable._nonces (32) } | { bytes32: ERC20PermitUpgradeable._PERMIT_TYPEHASH_DEPRECATED_SLOT (32) } | { <37> uint256[49]: ERC20PermitUpgradeable.__gap (1568) } | { unallocated (12) | address: L2GatewayToken.l2Gateway (20) } | { unallocated (11) | bool: Cloneable.isMasterCopy (1) | address: L2GatewayToken.l1Address (20) } | { <44> ERC20Getters: availableGetters (32) }}}"] 1 [label="uint256[50]: __gap \<\\>\n | {{ slot | 1 | 2 | 3-48 | 49 | 50} | { type: variable (bytes) | { uint256 (32) } | { uint256 (32) } | { ---- (1472) } | { uint256 (32) } | { uint256 (32) }}}"] diff --git a/yarn.lock b/yarn.lock index 35d0f745c6..bc1e836c0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,19 +2,36 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@aduh95/viz.js@^3.7.0": version "3.7.0" resolved "https://registry.yarnpkg.com/@aduh95/viz.js/-/viz.js-3.7.0.tgz#a20d86c5fc8f6abebdc39b96a4326e10375d77c0" integrity sha512-20Pk2Z98fbPLkECcrZSJszKos/OgtvJJR3NcbVfgCJ6EQjDNzW2P1BKqImOz3tJ952dvO2DWEhcLhQ1Wz1e9ng== -"@arbitrum/nitro-contracts@1.0.0-beta.8": - version "1.0.0-beta.8" - resolved "https://registry.yarnpkg.com/@arbitrum/nitro-contracts/-/nitro-contracts-1.0.0-beta.8.tgz#56554091b466ea1539c11691c60835625f6675e5" - integrity sha512-idzrJ/yGbcVUaqm45kFzV157B7V8W05G0cyMZazNhkWs39zO/moVwjMUCJpQ/SGW4OlOQggI8Xuw4xfocno7Xg== +"@arbitrum/nitro-contracts@^1.0.0-beta.8": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@arbitrum/nitro-contracts/-/nitro-contracts-1.0.2.tgz#c73dce72b8f969a5909d5aaef6da80681c667475" + integrity sha512-Y+cXIQNsy9UNANnFrDGKhHzNmOWttxpXP0/uJFTRmS+rgS4ozlr81/UmBo3tX6uWjziDtquhYRuG3wx17talOQ== dependencies: "@openzeppelin/contracts" "4.5.0" "@openzeppelin/contracts-upgradeable" "4.5.2" - hardhat "^2.6.6" + patch-package "^6.4.7" + optionalDependencies: + sol2uml "2.2.0" + +"@arbitrum/sdk@^3.1.3": + version "3.1.9" + resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-3.1.9.tgz#a511bc70cdd0a947445e4e27833c242ccb77ddf5" + integrity sha512-7Rf75cKmQ8nutTV+2JAOXcI6DKG4D7QCJz1JL2nq6hUpRuw4jyKn+irLqJtcIExssylLWt3t/pKV6fYseCYKNg== + dependencies: + "@ethersproject/address" "^5.0.8" + "@ethersproject/bignumber" "^5.1.1" + "@ethersproject/bytes" "^5.0.8" + ethers "^5.1.0" "@babel/code-frame@7.12.11": version "7.12.11" @@ -24,26 +41,68 @@ "@babel/highlight" "^7.10.4" "@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== + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3" + integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA== dependencies: - "@babel/highlight" "^7.18.6" + "@babel/highlight" "^7.22.10" + chalk "^2.4.2" -"@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-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== -"@babel/highlight@^7.10.4", "@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== +"@babel/highlight@^7.10.4", "@babel/highlight@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7" + integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ== dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.4.2" js-tokens "^4.0.0" +"@chainsafe/as-sha256@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz#3639df0e1435cab03f4d9870cc3ac079e57a6fc9" + integrity sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg== + +"@chainsafe/persistent-merkle-tree@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz#4c9ee80cc57cd3be7208d98c40014ad38f36f7ff" + integrity sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + +"@chainsafe/persistent-merkle-tree@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz#2b4a62c9489a5739dedd197250d8d2f5427e9f63" + integrity sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + +"@chainsafe/ssz@^0.10.0": + version "0.10.2" + resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.10.2.tgz#c782929e1bb25fec66ba72e75934b31fd087579e" + integrity sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + "@chainsafe/persistent-merkle-tree" "^0.5.0" + +"@chainsafe/ssz@^0.9.2": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.9.4.tgz#696a8db46d6975b600f8309ad3a12f7c0e310497" + integrity sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + "@chainsafe/persistent-merkle-tree" "^0.4.2" + case "^1.6.3" + +"@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== + "@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" @@ -67,6 +126,13 @@ resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89" integrity sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA== +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -135,31 +201,15 @@ patch-package "^6.2.2" postinstall-postinstall "^2.1.0" -"@ethereumjs/block@^3.5.0", "@ethereumjs/block@^3.6.2", "@ethereumjs/block@^3.6.3": - version "3.6.3" - resolved "https://registry.yarnpkg.com/@ethereumjs/block/-/block-3.6.3.tgz#d96cbd7af38b92ebb3424223dbf773f5ccd27f84" - integrity sha512-CegDeryc2DVKnDkg5COQrE0bJfw/p0v3GBk2W5/Dj5dOVfEmb50Ux0GLnSPypooLnfqjwFaorGuT9FokWB3GRg== - dependencies: - "@ethereumjs/common" "^2.6.5" - "@ethereumjs/tx" "^3.5.2" - ethereumjs-util "^7.1.5" - merkle-patricia-tree "^4.2.4" - -"@ethereumjs/blockchain@^5.5.2", "@ethereumjs/blockchain@^5.5.3": - version "5.5.3" - resolved "https://registry.yarnpkg.com/@ethereumjs/blockchain/-/blockchain-5.5.3.tgz#aa49a6a04789da6b66b5bcbb0d0b98efc369f640" - integrity sha512-bi0wuNJ1gw4ByNCV56H0Z4Q7D+SxUbwyG12Wxzbvqc89PXLRNR20LBcSUZRKpN0+YCPo6m0XZL/JLio3B52LTw== +"@ethereumjs/common@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.5.0.tgz#ec61551b31bef7a69d1dc634d8932468866a4268" + integrity sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg== dependencies: - "@ethereumjs/block" "^3.6.2" - "@ethereumjs/common" "^2.6.4" - "@ethereumjs/ethash" "^1.1.0" - debug "^4.3.3" - ethereumjs-util "^7.1.5" - level-mem "^5.0.1" - lru-cache "^5.1.1" - semaphore-async-await "^1.5.1" + crc-32 "^1.2.0" + ethereumjs-util "^7.1.1" -"@ethereumjs/common@^2.5.0", "@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": +"@ethereumjs/common@^2.5.0", "@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== @@ -167,18 +217,20 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.5" -"@ethereumjs/ethash@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/ethash/-/ethash-1.1.0.tgz#7c5918ffcaa9cb9c1dc7d12f77ef038c11fb83fb" - integrity sha512-/U7UOKW6BzpA+Vt+kISAoeDie1vAvY4Zy2KF5JJb+So7+1yKmJeJEHOGSnQIj330e9Zyl3L5Nae6VZyh2TJnAA== +"@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== + +"@ethereumjs/tx@3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.2.tgz#348d4624bf248aaab6c44fec2ae67265efe3db00" + integrity sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog== dependencies: - "@ethereumjs/block" "^3.5.0" - "@types/levelup" "^4.3.0" - buffer-xor "^2.0.1" - ethereumjs-util "^7.1.1" - miller-rabin "^4.0.0" + "@ethereumjs/common" "^2.5.0" + ethereumjs-util "^7.1.2" -"@ethereumjs/tx@^3.3.2", "@ethereumjs/tx@^3.5.1", "@ethereumjs/tx@^3.5.2": +"@ethereumjs/tx@^3.3.2": version "3.5.2" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== @@ -186,23 +238,14 @@ "@ethereumjs/common" "^2.6.4" ethereumjs-util "^7.1.5" -"@ethereumjs/vm@^5.9.0": - version "5.9.3" - resolved "https://registry.yarnpkg.com/@ethereumjs/vm/-/vm-5.9.3.tgz#6d69202e4c132a4a1e1628ac246e92062e230823" - integrity sha512-Ha04TeF8goEglr8eL7hkkYyjhzdZS0PsoRURzYlTF6I0VVId5KjKb0N7MrA8GMgheN+UeTncfTgYx52D/WhEmg== +"@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/block" "^3.6.3" - "@ethereumjs/blockchain" "^5.5.3" - "@ethereumjs/common" "^2.6.5" - "@ethereumjs/tx" "^3.5.2" - async-eventemitter "^0.2.4" - core-js-pure "^3.0.1" - debug "^4.3.3" - ethereumjs-util "^7.1.5" - functional-red-black-tree "^1.0.1" - mcl-wasm "^0.7.1" - merkle-patricia-tree "^4.2.4" - rustbn.js "~0.2.0" + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" "@ethersproject/abi@5.0.0-beta.153": version "5.0.0-beta.153" @@ -258,7 +301,7 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/address@5.7.0", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.4.0", "@ethersproject/address@^5.7.0": +"@ethersproject/address@5.7.0", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.0.8", "@ethersproject/address@^5.4.0", "@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== @@ -284,7 +327,7 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.4.1", "@ethersproject/bignumber@^5.7.0": +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.1.1", "@ethersproject/bignumber@^5.4.1", "@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== @@ -293,7 +336,7 @@ "@ethersproject/logger" "^5.7.0" bn.js "^5.2.1" -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.4.0", "@ethersproject/bytes@^5.7.0": +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.0.8", "@ethersproject/bytes@^5.4.0", "@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== @@ -410,33 +453,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.1", "@ethersproject/providers@^5.4.4": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.1.tgz#b0799b616d5579cd1067a8ebf1fc1ec74c1e122c" - integrity sha512-vZveG/DLyo+wk4Ga1yx6jSEHrLPgmTt+dFv0dv8URpVCRf0jVhalps1jq/emN/oXnMRsC7cQgAF32DcXLL7BPQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/providers@5.7.2": +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.4.4", "@ethersproject/providers@^5.7.1", "@ethersproject/providers@^5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -602,14 +619,14 @@ integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -630,20 +647,32 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" -"@noble/hashes@1.1.2": - 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.1.0", "@noble/curves@~1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" + integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== + dependencies: + "@noble/hashes" "1.3.1" -"@noble/hashes@~1.1.1": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.3.tgz#360afc77610e0a61f3417e497dcf36862e4f8111" - integrity sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A== +"@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/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.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== + +"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + +"@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" @@ -666,29 +695,31 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/ethereumjs-block@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz#fdd5c045e7baa5169abeed0e1202bf94e4481c49" - integrity sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA== - dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-tx" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" +"@nomicfoundation/ethereumjs-block@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz#13a7968f5964f1697da941281b7f7943b0465d04" + integrity sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" ethereum-cryptography "0.1.3" + ethers "^5.7.1" -"@nomicfoundation/ethereumjs-blockchain@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.0.0.tgz#1a8c243a46d4d3691631f139bfb3a4a157187b0c" - integrity sha512-pLFEoea6MWd81QQYSReLlLfH7N9v7lH66JC/NMPN848ySPPQA5renWnE7wPByfQFzNrPBuDDRFFULMDmj1C0xw== - dependencies: - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-ethash" "^2.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" +"@nomicfoundation/ethereumjs-blockchain@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz#45323b673b3d2fab6b5008535340d1b8fea7d446" + integrity sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-ethash" "3.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" abstract-level "^1.0.3" debug "^4.3.3" ethereum-cryptography "0.1.3" @@ -696,105 +727,105 @@ lru-cache "^5.1.1" memory-level "^1.0.0" -"@nomicfoundation/ethereumjs-common@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-3.0.0.tgz#f6bcc7753994555e49ab3aa517fc8bcf89c280b9" - integrity sha512-WS7qSshQfxoZOpHG/XqlHEGRG1zmyjYrvmATvc4c62+gZXgre1ymYP8ZNgx/3FyZY0TWe9OjFlKOfLqmgOeYwA== +"@nomicfoundation/ethereumjs-common@4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz#a15d1651ca36757588fdaf2a7d381a150662a3c3" + integrity sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg== dependencies: - "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@nomicfoundation/ethereumjs-util" "9.0.2" crc-32 "^1.2.0" -"@nomicfoundation/ethereumjs-ethash@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-2.0.0.tgz#11539c32fe0990e1122ff987d1b84cfa34774e81" - integrity sha512-WpDvnRncfDUuXdsAXlI4lXbqUDOA+adYRQaEezIkxqDkc+LDyYDbd/xairmY98GnQzo1zIqsIL6GB5MoMSJDew== +"@nomicfoundation/ethereumjs-ethash@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz#da77147f806401ee996bfddfa6487500118addca" + integrity sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg== dependencies: - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" abstract-level "^1.0.3" bigint-crypto-utils "^3.0.23" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-evm@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-1.0.0.tgz#99cd173c03b59107c156a69c5e215409098a370b" - integrity sha512-hVS6qRo3V1PLKCO210UfcEQHvlG7GqR8iFzp0yyjTg2TmJQizcChKgWo8KFsdMw6AyoLgLhHGHw4HdlP8a4i+Q== +"@nomicfoundation/ethereumjs-evm@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz#4c2f4b84c056047102a4fa41c127454e3f0cfcf6" + integrity sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ== dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - "@types/async-eventemitter" "^0.2.1" - async-eventemitter "^0.2.4" + "@ethersproject/providers" "^5.7.1" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" debug "^4.3.3" ethereum-cryptography "0.1.3" mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/ethereumjs-rlp@^4.0.0", "@nomicfoundation/ethereumjs-rlp@^4.0.0-beta.2": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-4.0.0.tgz#d9a9c5f0f10310c8849b6525101de455a53e771d" - integrity sha512-GaSOGk5QbUk4eBP5qFbpXoZoZUj/NrW7MRa0tKY4Ew4c2HAS0GXArEMAamtFrkazp0BO4K5p2ZCG3b2FmbShmw== +"@nomicfoundation/ethereumjs-rlp@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz#4fee8dc58a53ac6ae87fb1fca7c15dc06c6b5dea" + integrity sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA== -"@nomicfoundation/ethereumjs-statemanager@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-1.0.0.tgz#14a9d4e1c828230368f7ab520c144c34d8721e4b" - integrity sha512-jCtqFjcd2QejtuAMjQzbil/4NHf5aAWxUc+CvS0JclQpl+7M0bxMofR2AJdtz+P3u0ke2euhYREDiE7iSO31vQ== +"@nomicfoundation/ethereumjs-statemanager@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz#3ba4253b29b1211cafe4f9265fee5a0d780976e0" + integrity sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA== dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" debug "^4.3.3" ethereum-cryptography "0.1.3" - functional-red-black-tree "^1.0.1" + ethers "^5.7.1" + js-sdsl "^4.1.4" -"@nomicfoundation/ethereumjs-trie@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-5.0.0.tgz#dcfbe3be53a94bc061c9767a396c16702bc2f5b7" - integrity sha512-LIj5XdE+s+t6WSuq/ttegJzZ1vliwg6wlb+Y9f4RlBpuK35B9K02bO7xU+E6Rgg9RGptkWd6TVLdedTI4eNc2A== +"@nomicfoundation/ethereumjs-trie@6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz#9a6dbd28482dca1bc162d12b3733acab8cd12835" + integrity sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ== dependencies: - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" + "@types/readable-stream" "^2.3.13" ethereum-cryptography "0.1.3" readable-stream "^3.6.0" -"@nomicfoundation/ethereumjs-tx@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-4.0.0.tgz#59dc7452b0862b30342966f7052ab9a1f7802f52" - integrity sha512-Gg3Lir2lNUck43Kp/3x6TfBNwcWC9Z1wYue9Nz3v4xjdcv6oDW9QSMJxqsKw9QEGoBBZ+gqwpW7+F05/rs/g1w== - dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" +"@nomicfoundation/ethereumjs-tx@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz#117813b69c0fdc14dd0446698a64be6df71d7e56" + integrity sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g== + dependencies: + "@chainsafe/ssz" "^0.9.2" + "@ethersproject/providers" "^5.7.2" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-util@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-8.0.0.tgz#deb2b15d2c308a731e82977aefc4e61ca0ece6c5" - integrity sha512-2emi0NJ/HmTG+CGY58fa+DQuAoroFeSH9gKu9O6JnwTtlzJtgfTixuoOqLEgyyzZVvwfIpRueuePb8TonL1y+A== +"@nomicfoundation/ethereumjs-util@9.0.2": + version "9.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz#16bdc1bb36f333b8a3559bbb4b17dac805ce904d" + integrity sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ== dependencies: - "@nomicfoundation/ethereumjs-rlp" "^4.0.0-beta.2" + "@chainsafe/ssz" "^0.10.0" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-vm@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-6.0.0.tgz#2bb50d332bf41790b01a3767ffec3987585d1de6" - integrity sha512-JMPxvPQ3fzD063Sg3Tp+UdwUkVxMoo1uML6KSzFhMH3hoQi/LMuXBoEHAoW83/vyNS9BxEe6jm6LmT5xdeEJ6w== - dependencies: - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-evm" "^1.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-tx" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - "@types/async-eventemitter" "^0.2.1" - async-eventemitter "^0.2.4" +"@nomicfoundation/ethereumjs-vm@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz#3b0852cb3584df0e18c182d0672a3596c9ca95e6" + integrity sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-blockchain" "7.0.2" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-evm" "2.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-statemanager" "2.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" debug "^4.3.3" ethereum-cryptography "0.1.3" - functional-red-black-tree "^1.0.1" mcl-wasm "^0.7.1" rustbn.js "~0.2.0" @@ -865,66 +896,82 @@ "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.0" "@nomiclabs/hardhat-ethers@^2.0.1", "@nomiclabs/hardhat-ethers@^2.0.2": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.0.tgz#f55ace2752d0effcf583e754960e9fa89fbe12cd" - integrity sha512-kKCW7xawuD/lw69Yr1yqUUrF0IKmnLNGf+pTVbJ/ctHaRcPrwKI0EPkO1RNXBHlOOZkv6v4DK2PPvq0lL2ykig== + version "2.2.3" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz#b41053e360c31a32c2640c9a45ee981a7e603fe0" + integrity sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg== "@nomiclabs/hardhat-etherscan@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.1.tgz#471590f25c8c12cd84ae80a4f4c92551eb249667" - integrity sha512-a6+fJlHTiPjzUYnvwkcduJN0rAKWagQsQNoHJP/9mJ1CZjIkGysGtvVAjNpnrYWocj/Hbi36XmZ0H2aIKlol7A== + version "3.1.7" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.7.tgz#72e3d5bd5d0ceb695e097a7f6f5ff6fcbf062b9a" + integrity sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ== dependencies: "@ethersproject/abi" "^5.1.2" "@ethersproject/address" "^5.0.2" - cbor "^5.0.2" + cbor "^8.1.0" chalk "^2.4.2" debug "^4.1.1" fs-extra "^7.0.1" lodash "^4.17.11" semver "^6.3.0" table "^6.8.0" - undici "^5.4.0" + undici "^5.14.0" "@nomiclabs/hardhat-waffle@^2.0.1": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.3.tgz#9c538a09c5ed89f68f5fd2dc3f78f16ed1d6e0b1" - integrity sha512-049PHSnI1CZq6+XTbrMbMv5NaL7cednTfPenx02k3cEh8wBMLa6ys++dBETJa6JjfwgA9nBhhHQ173LJv6k2Pg== - dependencies: - "@types/sinon-chai" "^3.2.3" - "@types/web3" "1.0.19" + version "2.0.6" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.6.tgz#d11cb063a5f61a77806053e54009c40ddee49a54" + integrity sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg== -"@openzeppelin/contracts-upgradeable@3.4.2": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-3.4.2.tgz#2c2a1b0fa748235a1f495b6489349776365c51b3" - integrity sha512-mDlBS17ymb2wpaLcrqRYdnBAmP1EwqhOXMvqWk2c5Q1N1pm5TkiCtXM9Xzznh4bYsQBq0aIWEkFFE2+iLSN1Tw== +"@offchainlabs/upgrade-executor@1.1.0-beta.0": + version "1.1.0-beta.0" + resolved "https://registry.yarnpkg.com/@offchainlabs/upgrade-executor/-/upgrade-executor-1.1.0-beta.0.tgz#c4b1375176546a18aaef01a43956abfb58250e0a" + integrity sha512-mpn6PHjH/KDDjNX0pXHEKdyv8m6DVGQiI2nGzQn0JbM1nOSHJpWx6fvfjtH7YxHJ6zBZTcsKkqGkFKDtCfoSLw== + dependencies: + "@openzeppelin/contracts" "4.7.3" + "@openzeppelin/contracts-upgradeable" "4.7.3" "@openzeppelin/contracts-upgradeable@4.5.2": version "4.5.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.5.2.tgz#90d9e47bacfd8693bfad0ac8a394645575528d05" integrity sha512-xgWZYaPlrEOQo3cBj97Ufiuv79SPd8Brh4GcFYhPgb6WvAq4ppz8dWKL6h+jLAK01rUqMRp/TS9AdXgAeNvCLA== -"@openzeppelin/contracts@3.4.2": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" - integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== +"@openzeppelin/contracts-upgradeable@4.7.3": + version "4.7.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.7.3.tgz#f1d606e2827d409053f3e908ba4eb8adb1dd6995" + integrity sha512-+wuegAMaLcZnLCJIvrVUDzA9z/Wp93f0Dla/4jJvIhijRrPabjQbZe6fWiECLaJyfn5ci9fqf9vTw3xpQOad2A== + +"@openzeppelin/contracts-upgradeable@4.8.3": + version "4.8.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.8.3.tgz#6b076a7b751811b90fe3a172a7faeaa603e13a3f" + integrity sha512-SXDRl7HKpl2WDoJpn7CK/M9U4Z8gNXDHHChAKh0Iz+Wew3wu6CmFYBeie3je8V0GSXZAIYYwUktSrnW/kwVPtg== "@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== -"@openzeppelin/upgrades-core@^1.7.6": - version "1.20.1" - resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.20.1.tgz#6734770e50796b941736f5a77394f5b73d3978e6" - integrity sha512-GXvqLkMNY1dGj9BAIXiqYjdj/qgpoeTed+pH2OL4UOqMlxIh8yIYdkLE9wOWiUVVr0rhUGqaoaJ9NeFLlVzBQQ== +"@openzeppelin/contracts@4.7.3": + version "4.7.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.7.3.tgz#939534757a81f8d69cc854c7692805684ff3111e" + integrity sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw== + +"@openzeppelin/contracts@4.8.3": + version "4.8.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.8.3.tgz#cbef3146bfc570849405f59cba18235da95a252a" + integrity sha512-bQHV8R9Me8IaJoJ2vPG4rXcL7seB7YVuskr4f+f5RyOStSZetwzkWtoqDMl5erkBJy0lDRUnIR2WIkPiC0GJlg== + +"@openzeppelin/upgrades-core@^1.24.1": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.28.0.tgz#19405f272dc09e766c756d9d149cbd680168aef7" + integrity sha512-8RKlyg98Adv+46GxDaR0awL3R8bVCcQ27DcSEwrgWOp6siHh8sZg4a2l+2dhPl1510S6uBfhHSydMH5VX2BV5g== dependencies: - cbor "^8.0.0" + cbor "^9.0.0" chalk "^4.1.0" - compare-versions "^5.0.0" + compare-versions "^6.0.0" debug "^4.1.1" ethereumjs-util "^7.0.3" + minimist "^1.2.7" proper-lockfile "^4.1.1" - solidity-ast "^0.4.15" + solidity-ast "^0.4.26" "@resolver-engine/core@^0.3.3": version "0.3.3" @@ -968,21 +1015,38 @@ 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== +"@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: - "@noble/hashes" "~1.1.1" - "@noble/secp256k1" "~1.6.0" + "@noble/hashes" "~1.2.0" + "@noble/secp256k1" "~1.7.0" "@scure/base" "~1.1.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== +"@scure/bip32@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.1.tgz#7248aea723667f98160f593d621c47e208ccbb10" + integrity sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A== + dependencies: + "@noble/curves" "~1.1.0" + "@noble/hashes" "~1.3.1" + "@scure/base" "~1.1.0" + +"@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: - "@noble/hashes" "~1.1.1" + "@noble/hashes" "~1.2.0" + "@scure/base" "~1.1.0" + +"@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" "@sentry/core@5.30.0": @@ -1058,7 +1122,7 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/is@^4.0.0": +"@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.6.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== @@ -1070,14 +1134,14 @@ dependencies: antlr4ts "^0.5.0-alpha.4" -"@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.1", "@solidity-parser/parser@^0.14.3": - version "0.14.3" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.3.tgz#0d627427b35a40d8521aaa933cc3df7d07bfa36f" - integrity sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw== +"@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.3": + 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" -"@solidity-parser/parser@^0.16.1": +"@solidity-parser/parser@^0.16.0", "@solidity-parser/parser@^0.16.1": version "0.16.1" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.16.1.tgz#f7c8a686974e1536da0105466c4db6727311253c" integrity sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw== @@ -1098,27 +1162,34 @@ dependencies: defer-to-connect "^2.0.0" +"@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: + defer-to-connect "^2.0.1" + "@truffle/error@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@truffle/error/-/error-0.1.1.tgz#e52026ac8ca7180d83443dca73c03e07ace2a301" integrity sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA== -"@truffle/interface-adapter@^0.5.23": - version "0.5.23" - resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.5.23.tgz#a4103270e3c73746089b9e5807aaa1359f4725bb" - integrity sha512-nU8kChKgcUP+tELId1PMgHnmd2KcBdBer59TxfVqAZXRmt6blm2tpBbGYtKzTIdZlf6kMqVbZXdB6u1CJDqfxg== +"@truffle/interface-adapter@^0.5.25": + version "0.5.35" + resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.5.35.tgz#f0eb1c4a2803190ca249143f545029a8b641fe96" + integrity sha512-B5gtJnvsum5j2do393n0UfCT8MklrlAZxuqvEFBeMM9UKnreYct0/D368FVMlZwWo1N50HgGeZ0hlpSJqR/nvg== dependencies: bn.js "^5.1.3" ethers "^4.0.32" - web3 "1.7.4" + web3 "1.10.0" "@truffle/provider@^0.2.24": - version "0.2.61" - resolved "https://registry.yarnpkg.com/@truffle/provider/-/provider-0.2.61.tgz#c20b891d77eca3c8907fa096f8f23bac7a180e8b" - integrity sha512-/aa4Xy+ag4zohfPWytA+u5QDDDvSdml6p/+zo5eN1nkmJ7hF6noxBlBHG+rEC3Pl+NNNQrbGZMzvlpfsOrNhMw== + version "0.2.64" + resolved "https://registry.yarnpkg.com/@truffle/provider/-/provider-0.2.64.tgz#7dd55117307fd019dcf81d08db5dc2bc5728f51c" + integrity sha512-ZwPsofw4EsCq/2h0t73SPnnFezu4YQWBmK4FxFaOUX0F+o8NsZuHKyfJzuZwyZbiktYmefM3yD9rM0Dj4BhNbw== dependencies: "@truffle/error" "^0.1.1" - "@truffle/interface-adapter" "^0.5.23" + "@truffle/interface-adapter" "^0.5.25" debug "^4.3.1" web3 "1.7.4" @@ -1138,9 +1209,9 @@ integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@typechain/ethers-v5@^2.0.0": version "2.0.0" @@ -1164,23 +1235,6 @@ dependencies: fs-extra "^9.1.0" -"@types/abstract-leveldown@*": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#f055979a99f7654e84d6b8e6267419e9c4cfff87" - integrity sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ== - -"@types/async-eventemitter@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz#f8e6280e87e8c60b2b938624b0a3530fb3e24712" - integrity sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg== - -"@types/bn.js@*", "@types/bn.js@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" - integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== - dependencies: - "@types/node" "*" - "@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" @@ -1188,20 +1242,27 @@ dependencies: "@types/node" "*" -"@types/cacheable-request@^6.0.1": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9" - integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA== +"@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" + integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== + dependencies: + "@types/node" "*" + +"@types/cacheable-request@^6.0.1", "@types/cacheable-request@^6.0.2": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== dependencies: "@types/http-cache-semantics" "*" - "@types/keyv" "*" + "@types/keyv" "^3.1.4" "@types/node" "*" - "@types/responselike" "*" + "@types/responselike" "^1.0.0" -"@types/chai@*", "@types/chai@^4.2.15": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.3.tgz#3c90752792660c4b562ad73b3fbd68bf3bc7ae07" - integrity sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g== +"@types/chai@^4.2.15": + version "4.3.5" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.5.tgz#ae69bcbb1bebb68c4ac0b11e9d8ed04526b3562b" + integrity sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng== "@types/concat-stream@^1.6.0": version "1.6.1" @@ -1238,29 +1299,15 @@ integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== -"@types/keyv@*": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-4.2.0.tgz#65b97868ab757906f2dbb653590d7167ad023fa0" - integrity sha512-xoBtGl5R9jeKUhc8ZqeYaRDx04qqJ10yhhXYGmJ4Jr8qKpvMsDQQrNUvF/wUJ4klOtmJeJM+p2Xo3zp9uaC3tw== +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== dependencies: - keyv "*" - -"@types/level-errors@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/level-errors/-/level-errors-3.0.0.tgz#15c1f4915a5ef763b51651b15e90f6dc081b96a8" - integrity sha512-/lMtoq/Cf/2DVOm6zE6ORyOM+3ZVm/BvzEZVxUhf6bgh8ZHglXlBqxbxSlJeVp8FCbD3IVvk/VbsaNmDjrQvqQ== - -"@types/levelup@^4.3.0": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@types/levelup/-/levelup-4.3.3.tgz#4dc2b77db079b1cf855562ad52321aa4241b8ef4" - integrity sha512-K+OTIjJcZHVlZQN1HmU64VtrC0jC3dXWQozuEIR9zVvltIk90zaGPM2AgT+fIkChpzHhFE3YnvFLCbLtzAmexA== - dependencies: - "@types/abstract-leveldown" "*" - "@types/level-errors" "*" "@types/node" "*" "@types/lru-cache@^5.1.0": @@ -1291,17 +1338,17 @@ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node-fetch@^2.5.5": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" - integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== + version "2.6.4" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" + integrity sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg== dependencies: "@types/node" "*" form-data "^3.0.0" "@types/node@*": - version "18.11.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.2.tgz#c59b7641832531264fda3f1ba610362dc9a7dfc8" - integrity sha512-BWN3M23gLO2jVG8g/XHIRFWiiV4/GckeFIqbU/C4V3xpoBBWSMk4OZomouN0wCkfQFPqgZikyLr7DOYDysIkkw== + version "20.5.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.6.tgz#5e9aaa86be03a09decafd61b128d6cec64a5fe40" + integrity sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ== "@types/node@^10.0.3": version "10.17.60" @@ -1314,9 +1361,9 @@ integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== "@types/node@^14.14.28": - version "14.18.32" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.32.tgz#8074f7106731f1a12ba993fe8bad86ee73905014" - integrity sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow== + version "14.18.56" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.56.tgz#09e092d684cd8cfbdb3c5e5802672712242f2600" + integrity sha512-+k+57NVS9opgrEn5l9c0gvD1r6C+PtyhVE4BTnMMRwiEA8ZO8uFcs6Yy2sXIy0eC95ZurBtRSvhZiHXBysbl6w== "@types/node@^8.0.0": version "8.10.66" @@ -1331,22 +1378,31 @@ "@types/node" "*" "@types/prettier@^2.1.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.1.tgz#dfd20e2dc35f027cdd6c1908e80a5ddc7499670e" - integrity sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow== + version "2.7.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== "@types/prompts@^2.0.14": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.1.tgz#d47adcb608a0afcd48121ff7c75244694a3a04c5" - integrity sha512-1Mqzhzi9W5KlooNE4o0JwSXGUDeQXKldbGn9NO4tpxwZbHXYd+WcKpCksG2lbhH7U9I9LigfsdVsP2QAY0lNPA== + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.4.tgz#dd5a1d41cb1bcd0fc4464bf44a0c8354f36ea735" + integrity sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A== dependencies: "@types/node" "*" + kleur "^3.0.3" "@types/qs@^6.2.31", "@types/qs@^6.9.7": 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/readable-stream@^2.3.13": + version "2.3.15" + resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-2.3.15.tgz#3d79c9ceb1b6a57d5f6e6976f489b9b5384321ae" + integrity sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ== + dependencies: + "@types/node" "*" + safe-buffer "~5.1.1" + "@types/resolve@^0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -1354,7 +1410,7 @@ dependencies: "@types/node" "*" -"@types/responselike@*", "@types/responselike@^1.0.0": +"@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== @@ -1369,42 +1425,9 @@ "@types/node" "*" "@types/semver@^7.3.12": - version "7.3.12" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.12.tgz#920447fdd78d76b19de0438b7f60df3c4a80bf1c" - integrity sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A== - -"@types/sinon-chai@^3.2.3": - version "3.2.8" - resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.8.tgz#5871d09ab50d671d8e6dd72e9073f8e738ac61dc" - integrity sha512-d4ImIQbT/rKMG8+AXpmcan5T2/PNeSjrYhvkwet6z0p8kzYtfgA32xzOBlbU0yqJfq+/0Ml805iFoODO0LP5/g== - dependencies: - "@types/chai" "*" - "@types/sinon" "*" - -"@types/sinon@*": - version "10.0.13" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.13.tgz#60a7a87a70d9372d0b7b38cc03e825f46981fb83" - integrity sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ== - dependencies: - "@types/sinonjs__fake-timers" "*" - -"@types/sinonjs__fake-timers@*": - version "8.1.2" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz#bf2e02a3dbd4aecaf95942ecd99b7402e03fad5e" - integrity sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA== - -"@types/underscore@*": - version "1.11.4" - resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.11.4.tgz#62e393f8bc4bd8a06154d110c7d042a93751def3" - integrity sha512-uO4CD2ELOjw8tasUrAhvnn2W4A0ZECOvMjCivJr4gA9pGgjv+qxKWY9GLTMVEK8ej85BxQOocUyE7hImmSQYcg== - -"@types/web3@1.0.19": - version "1.0.19" - resolved "https://registry.yarnpkg.com/@types/web3/-/web3-1.0.19.tgz#46b85d91d398ded9ab7c85a5dd57cb33ac558924" - integrity sha512-fhZ9DyvDYDwHZUp5/STa9XW2re0E8GxoioYJ4pEUZ13YHpApSagixj7IAdoYH5uAK+UalGq6Ml8LYzmgRA/q+A== - dependencies: - "@types/bn.js" "*" - "@types/underscore" "*" + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== "@types/yauzl@^2.9.1": version "2.10.0" @@ -1414,12 +1437,11 @@ "@types/node" "*" "@typescript-eslint/eslint-plugin-tslint@^5.30.6": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin-tslint/-/eslint-plugin-tslint-5.40.1.tgz#5cfdf20110a21092c401b7997812907b37bb7fac" - integrity sha512-OrcFPu0E7QdjxkUgCX8+lYZJWq2xLMDPXM4B3MlJxGYYbSmJhGszL7Yp4cdQyX3wn+Kv9JwPxUnjzAu8u6fX6Q== + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin-tslint/-/eslint-plugin-tslint-5.62.0.tgz#220242dcd23711c400d4f5d5d876d5107cea4be0" + integrity sha512-qsYLld1+xed2lVwHbCxkCWdhRcByLNOjpccxK6HHlem724PbMcL1/dmH7jMQaqIpbfPAGkIypyyk3q5nUgtkhA== dependencies: - "@typescript-eslint/utils" "5.40.1" - lodash "^4.17.21" + "@typescript-eslint/utils" "5.62.0" "@typescript-eslint/eslint-plugin@^4.29.0": version "4.33.0" @@ -1465,23 +1487,23 @@ "@typescript-eslint/types" "4.33.0" "@typescript-eslint/visitor-keys" "4.33.0" -"@typescript-eslint/scope-manager@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz#a7a5197dfd234622a2421ea590ee0ccc02e18dfe" - integrity sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg== +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== dependencies: - "@typescript-eslint/types" "5.40.1" - "@typescript-eslint/visitor-keys" "5.40.1" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" "@typescript-eslint/types@4.33.0": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/types@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.40.1.tgz#de37f4f64de731ee454bb2085d71030aa832f749" - integrity sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw== +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== "@typescript-eslint/typescript-estree@4.33.0": version "4.33.0" @@ -1496,31 +1518,31 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz#9a7d25492f02c69882ce5e0cd1857b0c55645d72" - integrity sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA== +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== dependencies: - "@typescript-eslint/types" "5.40.1" - "@typescript-eslint/visitor-keys" "5.40.1" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.40.1.tgz#3204fb73a559d3b7bab7dc9d3c44487c2734a9ca" - integrity sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw== +"@typescript-eslint/utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== dependencies: + "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.40.1" - "@typescript-eslint/types" "5.40.1" - "@typescript-eslint/typescript-estree" "5.40.1" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" eslint-scope "^5.1.1" - eslint-utils "^3.0.0" semver "^7.3.7" "@typescript-eslint/visitor-keys@4.33.0": @@ -1531,19 +1553,14 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz#f3d2bf5af192f4432b84cec6fdcb387193518754" - integrity sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw== +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== dependencies: - "@typescript-eslint/types" "5.40.1" + "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -1559,12 +1576,10 @@ abbrev@1.0.x: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== -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" +abortcontroller-polyfill@^1.7.3: + version "1.7.5" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" + integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: version "1.0.3" @@ -1600,17 +1615,6 @@ abstract-leveldown@^5.0.0, abstract-leveldown@~5.0.0: dependencies: xtend "~4.0.0" -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" @@ -1618,17 +1622,6 @@ abstract-leveldown@~2.6.0: dependencies: xtend "~4.0.0" -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" - accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -1637,7 +1630,7 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-jsx@^5.0.0, acorn-jsx@^5.3.1: +acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -1647,25 +1640,20 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -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@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== acorn@^8.4.1: - version "8.8.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" - integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== address@^1.0.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/address/-/address-1.2.1.tgz#25bb61095b7522d65b357baa11bc05492d4c8acd" - integrity sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA== + version "1.2.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" + integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== adm-zip@^0.4.16: version "0.4.16" @@ -1697,7 +1685,7 @@ aggregate-error@^3.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.10.0, ajv@^6.12.3, 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== @@ -1708,9 +1696,9 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.6.1, ajv@^6.9.1: uri-js "^4.2.2" ajv@^8.0.1: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -1737,11 +1725,6 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -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== - ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -1788,10 +1771,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -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: + version "4.13.0" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.0.tgz#25c0b17f0d9216de114303d38bafd6f181d5447f" + integrity sha512-zooUbt+UscjnWyOrsuY/tVFL4rwrAGwOivpQmvmUDE22hy/lUA467Rc1rcixyRwcRUIXFYBwv7+dClDSHdmmew== antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" @@ -1799,9 +1782,9 @@ antlr4ts@^0.5.0-alpha.4: integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== anymatch@~3.1.1, anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + 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" @@ -1859,6 +1842,14 @@ array-back@^2.0.0: dependencies: typical "^2.6.1" +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -1879,17 +1870,40 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== -array.prototype.reduce@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz#8167e80089f78bff70a99e20bd4201d4663b0a6f" - integrity sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw== +array.prototype.findlast@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.2.tgz#134ef6b7215f131a8884fafe6af46846a032c518" + integrity sha512-p1YDNPNqA+P6cPX9ATsxg7DKir7gOmJ+jh5dEP3LlumMNYVC1F2Jgnyh6oI3n/qD9FeIkqR2jXfd73G68ImYUQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.1.3" + +array.prototype.reduce@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz#6b20b0daa9d9734dd6bc7ea66b5bbce395471eac" + integrity sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" es-array-method-boxes-properly "^1.0.0" is-string "^1.0.7" +arraybuffer.prototype.slice@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz#9b5ea3868a6eebc30273da577eb888381c0044bb" + integrity sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -1927,22 +1941,17 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== -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== - 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-eventemitter@^0.2.2, 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== @@ -1999,9 +2008,9 @@ aws-sign2@~0.7.0: integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== 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== + version "1.12.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" + integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== axios-debug-log@^1.0.0: version "1.0.0" @@ -2018,10 +2027,18 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + axios@^1.3.4: - version "1.5.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267" - integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ== + version "1.4.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -2596,21 +2613,14 @@ bech32@1.1.4: integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== bigint-crypto-utils@^3.0.23: - version "3.1.7" - resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.1.7.tgz#c4c1b537c7c1ab7aadfaecf3edfd45416bf2c651" - integrity sha512-zpCQpIE2Oy5WIQpjC9iYZf8Uh9QqoS51ZCooAcNvzv1AQ3VWdT52D0ksr1+/faeK8HVIej1bxXcP75YcqH3KPA== - dependencies: - bigint-mod-arith "^3.1.0" - -bigint-mod-arith@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz#658e416bc593a463d97b59766226d0a3021a76b1" - integrity sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ== + version "3.3.0" + resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz#72ad00ae91062cf07f2b1def9594006c279c1d77" + integrity sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg== -bignumber.js@^9.0.0, bignumber.js@^9.0.1: - version "9.1.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.0.tgz#8d340146107fe3a6cb8d40699643c302e8773b62" - integrity sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A== +bignumber.js@^9.0.0: + version "9.1.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" + integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== binary-extensions@^2.0.0: version "2.2.0" @@ -2662,7 +2672,7 @@ 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, bn.js@^5.2 resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -body-parser@1.20.1, body-parser@^1.16.0: +body-parser@1.20.1: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== @@ -2680,6 +2690,24 @@ body-parser@1.20.1, body-parser@^1.16.0: type-is "~1.6.18" unpipe "1.0.0" +body-parser@^1.16.0: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -2923,6 +2951,11 @@ cacheable-lookup@^5.0.3: resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== +cacheable-lookup@^6.0.4: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz#0330a543471c61faa4e9035db583aad753b36385" + integrity sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww== + cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -2937,9 +2970,9 @@ cacheable-request@^6.0.0: responselike "^1.0.2" cacheable-request@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" - integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== dependencies: clone-response "^1.0.2" get-stream "^5.1.0" @@ -2965,25 +2998,6 @@ call-bind@^1.0.0, call-bind@^1.0.2, call-bind@~1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.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== - dependencies: - callsites "^2.0.0" - -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== - 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== - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -3005,9 +3019,14 @@ camelcase@^6.0.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30000844: - version "1.0.30001422" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001422.tgz#f2d7c6202c49a8359e6e35add894d88ef93edba1" - integrity sha512-hSesn02u1QacQHhaxl/kNMZwqVG35Sz/8DgvmgedxSH8z9UUpcDYSPYgsj3x5dQNRcNp6BwpSfQfVzYUTm+fog== + version "1.0.30001523" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001523.tgz#b838f70b1a98c556776b998fafb47d2b64146d4f" + integrity sha512-I5q5cisATTPZ1mc588Z//pj/Ox80ERYDfR71YnvY7raS/NOk8xXlZcB0sF7JdqaV//kOaa6aus7lRfpdnt1eBA== + +case@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" + integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== caseless@^0.12.0, caseless@~0.12.0: version "0.12.0" @@ -3019,29 +3038,28 @@ catering@^2.1.0, catering@^2.1.1: resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== -cbor@^5.0.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c" - integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A== - dependencies: - bignumber.js "^9.0.1" - nofilter "^1.0.4" - -cbor@^8.0.0: +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: nofilter "^3.1.0" +cbor@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-9.0.1.tgz#b16e393d4948d44758cd54ac6151379d443b37ae" + integrity sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ== + dependencies: + nofilter "^3.1.0" + chai@^4.2.0: - version "4.3.6" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" - integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== + version "4.3.8" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.8.tgz#40c59718ad6928da6629c70496fe990b2bb5b17c" + integrity sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ== dependencies: assertion-error "^1.1.0" check-error "^1.0.2" - deep-eql "^3.0.1" + deep-eql "^4.1.2" get-func-name "^2.0.0" loupe "^2.3.1" pathval "^1.1.1" @@ -3058,7 +3076,7 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.3.0, chalk@^2.4.1, 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== @@ -3075,11 +3093,6 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.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== - "charenc@>= 0.0.1": version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -3197,14 +3210,14 @@ class-utils@^0.3.5: static-extend "^0.1.1" classic-level@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.2.0.tgz#2d52bdec8e7a27f534e67fdeb890abef3e643c27" - integrity sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg== + version "1.3.0" + resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.3.0.tgz#5e36680e01dc6b271775c093f2150844c5edd5c8" + integrity sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg== dependencies: abstract-level "^1.0.2" catering "^2.1.0" module-error "^1.0.1" - napi-macros "~2.0.0" + napi-macros "^2.2.2" node-gyp-build "^4.3.0" clean-stack@^2.0.0: @@ -3223,13 +3236,6 @@ cli-color@^2.0.3: memoizee "^0.4.15" timers-ext "^0.1.7" -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== - dependencies: - restore-cursor "^2.0.0" - cli-table3@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" @@ -3240,10 +3246,14 @@ cli-table3@^0.5.0: optionalDependencies: colors "^1.1.2" -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== +cli-table3@^0.6.0: + version "0.6.3" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" + integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" cliui@^3.2.0: version "3.2.0" @@ -3347,16 +3357,16 @@ command-line-args@^4.0.7: find-replace "^1.0.3" typical "^2.6.1" -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== - commander@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +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== + commander@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" @@ -3367,15 +3377,15 @@ commander@^2.12.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^9.2.0: +commander@^9.2.0, commander@^9.4.0: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== -compare-versions@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-5.0.1.tgz#14c6008436d994c3787aba38d4087fabe858555e" - integrity sha512-v8Au3l0b+Nwkp4G142JcgJFh1/TUhdxut7wzD1Nq1dyp5oa3tXaqb03EXOAB6jS4gMlalkjAUPZBMiAfKUixHQ== +compare-versions@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" + integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== component-emitter@^1.2.1: version "1.3.0" @@ -3413,10 +3423,10 @@ content-hash@^2.5.2: 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== +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== convert-source-map@^1.5.1: version "1.9.0" @@ -3463,9 +3473,9 @@ cookie@^0.4.1: 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== + version "2.1.4" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" + integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== copy-descriptor@^0.1.0: version "0.1.1" @@ -3473,9 +3483,9 @@ copy-descriptor@^0.1.0: integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== core-js-pure@^3.0.1: - version "3.25.5" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.25.5.tgz#79716ba54240c6aa9ceba6eee08cf79471ba184d" - integrity sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg== + version "3.32.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.32.1.tgz#5775b88f9062885f67b6d7edce59984e89d276f3" + integrity sha512-f52QZwkFVDPf7UEQZGHKx6NYxsxmVGJe5DIvbzOdRMJlmT6yv0KDjR8rmy3ngr/t5wU54c7Sp/qIJH0ppbhVpQ== core-js@^2.4.0, core-js@^2.5.0: version "2.6.12" @@ -3500,15 +3510,15 @@ cors@^2.8.1: 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== +cosmiconfig@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd" + integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ== dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" crc-32@^1.2.0: version "1.2.2" @@ -3566,6 +3576,13 @@ cross-fetch@^2.1.0, cross-fetch@^2.1.1: node-fetch "^2.6.7" whatwg-fetch "^2.0.4" +cross-fetch@^3.1.4: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + 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" @@ -3665,13 +3682,6 @@ debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1, de dependencies: ms "2.1.2" -debug@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - debug@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -3690,9 +3700,9 @@ decamelize@^4.0.0: integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== 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 sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== decompress-response@^3.3.0: version "3.3.0" @@ -3708,10 +3718,10 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== +deep-eql@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== dependencies: type-detect "^4.0.0" @@ -3737,7 +3747,7 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== -defer-to-connect@^2.0.0: +defer-to-connect@^2.0.0, 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== @@ -3757,18 +3767,10 @@ deferred-leveldown@~4.0.0: abstract-leveldown "~5.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" - -define-properties@^1.1.2, define-properties@^1.1.3, 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.1.2, define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== dependencies: has-property-descriptors "^1.0.0" object-keys "^1.1.1" @@ -3795,7 +3797,7 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -defined@~1.0.0: +defined@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== @@ -3811,9 +3813,9 @@ depd@2.0.0: integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 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== + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== dependencies: inherits "^2.0.1" minimalistic-assert "^1.0.0" @@ -3952,9 +3954,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.3.47: - version "1.4.284" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" - integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== + version "1.4.502" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.502.tgz#531cda8774813d97d6cfa2fb9d8ee3e2c75851fa" + integrity sha512-xqeGw3Gr6o3uyHy/yKjdnDQHY2RQvXcGC2cfHjccK1IGkH6cX1WQBN8EeC/YpwPhGkBaikDTecJ8+ssxSVRQlw== elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" @@ -3969,11 +3971,6 @@ 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" -emoji-regex@^10.1.0: - version "10.2.1" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f" - integrity sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA== - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -4005,16 +4002,6 @@ encoding-down@5.0.4, encoding-down@~5.0.0: level-errors "^2.0.0" xtend "^4.0.1" -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.11: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -4030,11 +4017,12 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: once "^1.4.0" enquirer@^2.3.0, enquirer@^2.3.5, enquirer@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== dependencies: ansi-colors "^4.1.1" + strip-ansi "^6.0.1" entities@^4.2.0, entities@^4.4.0: version "4.5.0" @@ -4060,41 +4048,72 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.19.0, es-abstract@^1.19.2, es-abstract@^1.19.5, es-abstract@^1.20.0, es-abstract@^1.20.1: - version "1.20.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861" - integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA== +es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2: + version "1.22.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" + integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.1" + available-typed-arrays "^1.0.5" call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.1" get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" has "^1.0.3" has-property-descriptors "^1.0.0" + has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" is-shared-array-buffer "^1.0.2" is-string "^1.0.7" + is-typed-array "^1.1.10" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" + regexp.prototype.flags "^1.5.0" + safe-array-concat "^1.0.0" safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.5" - string.prototype.trimstart "^1.0.5" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" unbox-primitive "^1.0.2" + which-typed-array "^1.1.10" 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-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-shim-unscopables@^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== + dependencies: + has "^1.0.3" + 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" @@ -4122,6 +4141,11 @@ es6-iterator@^2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" +es6-promise@^4.2.8: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + 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" @@ -4173,9 +4197,9 @@ escodegen@1.8.x: source-map "~0.2.0" eslint-config-prettier@^8.3.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" - integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" + integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== eslint-plugin-mocha@^9.0.0: version "9.0.0" @@ -4192,14 +4216,6 @@ eslint-plugin-prettier@^4.0.0: dependencies: prettier-linter-helpers "^1.0.0" -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" - eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -4208,13 +4224,6 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -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.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" @@ -4229,7 +4238,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.3.0: +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.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== @@ -4240,51 +4249,9 @@ eslint-visitor-keys@^2.0.0: 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" + 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@^7.32.0: version "7.32.0" @@ -4332,15 +4299,6 @@ eslint@^7.32.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -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@^7.3.0, espree@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" @@ -4360,14 +4318,14 @@ esprima@^4.0.0: 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.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== 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== @@ -4562,7 +4520,7 @@ ethereum-common@^0.0.18: resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" integrity sha512-EoltVQTRNg2Uy4o84qpa2aXymXDJhxm7eos/ACOg0DG4baAbMjhbdAEsx9GeE8sC3XCxnYvrrzZDH8D8MtA2iQ== -ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.2, 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== @@ -4584,14 +4542,24 @@ ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.2, ethereum-cryptography setimmediate "^1.0.5" ethereum-cryptography@^1.0.3: - 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-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: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz#18fa7108622e56481157a5cb7c01c0c6a672eb67" + integrity sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug== dependencies: - "@noble/hashes" "1.1.2" - "@noble/secp256k1" "1.6.3" - "@scure/bip32" "1.1.0" - "@scure/bip39" "1.1.0" + "@noble/curves" "1.1.0" + "@noble/hashes" "1.3.1" + "@scure/bip32" "1.3.1" + "@scure/bip39" "1.2.1" ethereum-waffle@^3.2.0: version "3.4.4" @@ -4746,7 +4714,7 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum rlp "^2.0.0" safe-buffer "^5.1.1" -ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.2, ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5: +ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.2, ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -4804,64 +4772,28 @@ ethereumjs-wallet@0.6.5: bs58check "^2.1.2" ethereum-cryptography "^0.1.3" ethereumjs-util "^6.0.0" - randombytes "^2.0.6" - safe-buffer "^5.1.2" - scryptsy "^1.2.1" - utf8 "^3.0.0" - uuid "^3.3.2" - -ethers@^4.0.32, ethers@^4.0.40: - version "4.0.49" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" - integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg== - 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.0.1, ethers@^5.0.2, ethers@^5.4.5, ethers@^5.5.2: - version "5.7.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.1.tgz#48c83a44900b5f006eb2f65d3ba6277047fd4f33" - integrity sha512-5krze4dRLITX7FpU8J4WscXqADiKmyeNlylmmDLbS95DaZpBhDe2YSwRQwKXWNyXcox7a3gBgm/MkGXV1O1S/Q== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.1" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" + randombytes "^2.0.6" + safe-buffer "^5.1.2" + scryptsy "^1.2.1" + utf8 "^3.0.0" + uuid "^3.3.2" + +ethers@^4.0.32, ethers@^4.0.40: + version "4.0.49" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" + integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg== + 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.7.2: +ethers@^5.0.1, ethers@^5.0.2, ethers@^5.1.0, ethers@^5.4.5, ethers@^5.5.2, ethers@^5.6.9, ethers@^5.7.1, ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -4921,11 +4853,6 @@ event-emitter@^0.3.5: d "1" es5-ext "~0.10.14" -event-target-shim@^5.0.0: - 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" @@ -5034,15 +4961,6 @@ extend@~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" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -5090,15 +5008,15 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^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-diff@^1.1.2, 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, fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -5117,9 +5035,9 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 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.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== dependencies: reusify "^1.0.4" @@ -5137,20 +5055,6 @@ fetch-ponyfill@^4.0.0: dependencies: node-fetch "~1.7.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" - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -5254,15 +5158,6 @@ find-yarn-workspace-root@^2.0.0: dependencies: micromatch "^4.0.2" -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" @@ -5283,11 +5178,6 @@ flat@^5.0.2: resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -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== - flatted@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" @@ -5305,7 +5195,7 @@ fmix@^0.1.0: dependencies: imul "^1.0.0" -follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.15.0: +follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.14.9, follow-redirects@^1.15.0: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== @@ -5327,6 +5217,11 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== +form-data-encoder@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.1.tgz#ac80660e4f87ee0d3d3c3638b7da8278ddb8ec96" + integrity sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg== + form-data@^2.2.0: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" @@ -5442,7 +5337,7 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.1.0: +fs-extra@^9.0.0, 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== @@ -5475,9 +5370,9 @@ fsevents@~2.1.1: integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== 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" @@ -5499,7 +5394,7 @@ functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== -functions-have-names@^1.2.2: +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== @@ -5565,13 +5460,14 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.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== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== dependencies: function-bind "^1.1.1" has "^1.0.3" + has-proto "^1.0.1" has-symbols "^1.0.3" get-port@^3.1.0: @@ -5598,6 +5494,11 @@ get-stream@^5.1.0: dependencies: pump "^3.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-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" @@ -5680,7 +5581,7 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@~7.2.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.0.1: +glob@^8.0.1, glob@^8.0.3: version "8.1.0" resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== @@ -5715,15 +5616,10 @@ global@~4.4.0: min-document "^2.19.0" process "^0.11.10" -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.6.0, globals@^13.9.0: - version "13.17.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" - integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== + version "13.21.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" + integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== dependencies: type-fest "^0.20.2" @@ -5732,6 +5628,13 @@ globals@^9.18.0: resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + globby@^10.0.1: version "10.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" @@ -5758,6 +5661,32 @@ globby@^11.0.3, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +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@12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-12.1.0.tgz#099f3815305c682be4fd6b0ee0726d8e4c6b0af4" + integrity sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig== + dependencies: + "@sindresorhus/is" "^4.6.0" + "@szmarczak/http-timer" "^5.0.1" + "@types/cacheable-request" "^6.0.2" + "@types/responselike" "^1.0.0" + cacheable-lookup "^6.0.4" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + form-data-encoder "1.7.1" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^2.0.0" + got@9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -5776,9 +5705,9 @@ got@9.6.0: url-parse-lax "^3.0.0" got@^11.8.5: - version "11.8.5" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" - integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== dependencies: "@sindresorhus/is" "^4.0.0" "@szmarczak/http-timer" "^4.0.5" @@ -5793,9 +5722,9 @@ got@^11.8.5: responselike "^2.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + 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== growl@1.10.5: version "1.10.5" @@ -5803,12 +5732,12 @@ growl@1.10.5: integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 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: @@ -5827,6 +5756,15 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" +hardhat-contract-sizer@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/hardhat-contract-sizer/-/hardhat-contract-sizer-2.10.0.tgz#72646f43bfe50e9a5702c9720c9bc3e77d93a2c9" + integrity sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA== + dependencies: + chalk "^4.0.0" + cli-table3 "^0.6.0" + strip-ansi "^6.0.0" + hardhat-deploy@^0.9.1: version "0.9.29" resolved "https://registry.yarnpkg.com/hardhat-deploy/-/hardhat-deploy-0.9.29.tgz#b1177d4f3077f335ad3f50c55825d9417ec75968" @@ -5864,82 +5802,27 @@ hardhat-gas-reporter@^1.0.4: eth-gas-reporter "^0.2.25" sha1 "^1.1.1" -hardhat@2.9.9: - version "2.9.9" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.9.9.tgz#05c1015eb73e0230309534b00deeb080724aace0" - integrity sha512-Qv7SXnRc0zq1kGXruNnSKpP3eFccXMR5Qv6GVX9hBIJ5efN0PflKPq92aQ5Cv3jrjJeRevLznWZVz7bttXhVfw== - dependencies: - "@ethereumjs/block" "^3.6.2" - "@ethereumjs/blockchain" "^5.5.2" - "@ethereumjs/common" "^2.6.4" - "@ethereumjs/tx" "^3.5.1" - "@ethereumjs/vm" "^5.9.0" - "@ethersproject/abi" "^5.1.2" - "@metamask/eth-sig-util" "^4.0.0" - "@sentry/node" "^5.18.1" - "@solidity-parser/parser" "^0.14.1" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "^5.1.0" - abort-controller "^3.0.0" - adm-zip "^0.4.16" - aggregate-error "^3.0.0" - ansi-escapes "^4.3.0" - chalk "^2.4.2" - chokidar "^3.4.0" - ci-info "^2.0.0" - debug "^4.1.1" - enquirer "^2.3.0" - env-paths "^2.2.0" - ethereum-cryptography "^0.1.2" - ethereumjs-abi "^0.6.8" - ethereumjs-util "^7.1.4" - find-up "^2.1.0" - fp-ts "1.19.3" - fs-extra "^7.0.1" - glob "7.2.0" - immutable "^4.0.0-rc.12" - io-ts "1.10.4" - lodash "^4.17.11" - merkle-patricia-tree "^4.2.4" - mnemonist "^0.38.0" - mocha "^9.2.0" - p-map "^4.0.0" - qs "^6.7.0" - raw-body "^2.4.1" - resolve "1.17.0" - semver "^6.3.0" - slash "^3.0.0" - solc "0.7.3" - source-map-support "^0.5.13" - stacktrace-parser "^0.1.10" - "true-case-path" "^2.2.1" - tsort "0.0.1" - undici "^5.4.0" - uuid "^8.3.2" - ws "^7.4.6" - -hardhat@^2.6.6: - version "2.12.0" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.12.0.tgz#51e59f1ff4991bcb66d1a380ea807e6c15fcac34" - integrity sha512-mNJFbVG479HwOzxiaLxobyvED2M1aEAuPPYhEo1+88yicMDSTrU2JIS7vV+V0GSNQKaDoiHCmV6bcKjiljT/dQ== +hardhat@2.17.3: + version "2.17.3" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.17.3.tgz#4cb15f2afdea5f108970ed72e5b81e6e53052cfb" + integrity sha512-SFZoYVXW1bWJZrIIKXOA+IgcctfuKXDwENywiYNT2dM3YQc4fXNaTbuk/vpPzHIF50upByx4zW5EqczKYQubsA== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-evm" "^1.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-tx" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - "@nomicfoundation/ethereumjs-vm" "^6.0.0" + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-blockchain" "7.0.2" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-evm" "2.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-statemanager" "2.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" + "@nomicfoundation/ethereumjs-vm" "7.0.2" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" "@types/bn.js" "^5.1.0" "@types/lru-cache" "^5.1.0" - abort-controller "^3.0.0" adm-zip "^0.4.16" aggregate-error "^3.0.0" ansi-escapes "^4.3.0" @@ -5962,7 +5845,6 @@ hardhat@^2.6.6: mnemonist "^0.38.0" mocha "^10.0.0" p-map "^4.0.0" - qs "^6.7.0" raw-body "^2.4.1" resolve "1.17.0" semver "^6.3.0" @@ -5970,7 +5852,7 @@ hardhat@^2.6.6: source-map-support "^0.5.13" stacktrace-parser "^0.1.10" tsort "0.0.1" - undici "^5.4.0" + undici "^5.14.0" uuid "^8.3.2" ws "^7.4.6" @@ -6008,7 +5890,12 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.0, has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.0, 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== @@ -6136,9 +6023,9 @@ http-basic@^8.1.1: parse-cache-control "^1.0.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== + 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@2.0.0: version "2.0.0" @@ -6180,6 +6067,14 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" +http2-wrapper@^2.1.10: + version "2.2.0" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.0.tgz#b80ad199d216b7d3680195077bd7b9060fa9d7f3" + integrity sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + https-proxy-agent@5.0.1, 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" @@ -6188,7 +6083,7 @@ https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: agent-base "6" debug "4" -iconv-lite@0.4.24, iconv-lite@^0.4.24: +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== @@ -6219,10 +6114,10 @@ ignore@^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, ignore@^5.1.8, ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +ignore@^5.1.1, ignore@^5.1.8, ignore@^5.2.0, ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== immediate@^3.2.3: version "3.3.0" @@ -6235,17 +6130,9 @@ immediate@~3.2.3: integrity sha512-RrGCXRm/fRVqMIhqXrGEX9rRADavPiDFSoMb/k64i9XMk8uH4r/Omi5Ctierj6XzNecwDbO4WuFbDD1zmpl3Tg== immutable@^4.0.0-rc.12: - version "4.1.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" - integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== - -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" + version "4.3.4" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f" + integrity sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" @@ -6288,31 +6175,12 @@ ini@^1.3.5: 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.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== dependencies: - get-intrinsic "^1.1.0" + get-intrinsic "^1.2.0" has "^1.0.3" side-channel "^1.0.4" @@ -6372,6 +6240,15 @@ is-arguments@^1.0.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -6421,10 +6298,10 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-core-module@^2.9.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== +is-core-module@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== dependencies: has "^1.0.3" @@ -6467,11 +6344,6 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" -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-docker@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -6620,16 +6492,12 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.3, is-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67" - integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== +is-typed-array@^1.1.10, is-typed-array@^1.1.3, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.20.0" - for-each "^0.3.3" - has-tostringtag "^1.0.0" + which-typed-array "^1.1.11" is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" @@ -6680,6 +6548,11 @@ isarray@1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +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== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -6707,6 +6580,11 @@ js-graph-algorithms@^1.0.18: resolved "https://registry.yarnpkg.com/js-graph-algorithms/-/js-graph-algorithms-1.0.18.tgz#f96ec87bf194f5c0a31365fa0e1d07b7b962d891" integrity sha512-Gu1wtWzXBzGeye/j9BuyplGHscwqKRZodp/0M1vyBc19RJpblSwKGu099KwwaTx9cRIV+Qupk8xUMfEiGfFqSA== +js-sdsl@^4.1.4: + version "4.4.2" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.2.tgz#2e3c031b1f47d3aca8b775532e3ebb0818e7f847" + integrity sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w== + 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" @@ -6735,7 +6613,7 @@ js-yaml@3.13.1: 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, js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -6743,7 +6621,7 @@ js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -6775,10 +6653,10 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -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-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-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: version "3.8.0" @@ -6825,11 +6703,11 @@ json-stable-stringify-without-jsonify@^1.0.1: 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 sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0" + integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g== dependencies: - jsonify "~0.0.0" + jsonify "^0.0.1" json-stringify-safe@~5.0.1: version "5.0.1" @@ -6864,7 +6742,7 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@~0.0.0: +jsonify@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== @@ -6892,21 +6770,23 @@ keccak@3.0.1: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" -keccak@^3.0.0, keccak@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" - integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== +keccak@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.3.tgz#4bc35ad917be1ef54ff246f904c2bbbf9ac61276" + integrity sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ== dependencies: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" readable-stream "^3.6.0" -keyv@*, keyv@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.0.tgz#dbce9ade79610b6e641a9a65f2f6499ba06b9bc6" - integrity sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA== +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: - json-buffer "3.0.1" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" keyv@^3.0.0: version "3.1.0" @@ -6915,6 +6795,13 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.0.0: + version "4.5.3" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" + integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== + dependencies: + json-buffer "3.0.1" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -6953,7 +6840,7 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" -klaw@^4.1.0: +klaw@^4.0.1, klaw@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/klaw/-/klaw-4.1.0.tgz#5df608067d8cb62bbfb24374f8e5d956323338f3" integrity sha512-1zGZ9MF9H22UnkpVeuaGKOjfA2t6WrfdrJmGjy16ykcjnKQDmHVX+KI477rpbGevz/5FD4MC3xf1oxylBgcaQw== @@ -6989,11 +6876,6 @@ level-codec@~7.0.0: resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== -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== - level-errors@^1.0.3: version "1.1.2" resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" @@ -7043,15 +6925,6 @@ level-iterator-stream@~3.0.0: readable-stream "^2.3.6" xtend "^4.0.0" -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" - level-mem@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-3.0.1.tgz#7ce8cf256eac40f716eb6489654726247f5a89e5" @@ -7060,22 +6933,6 @@ level-mem@^3.0.1: level-packager "~4.0.0" memdown "~3.0.0" -level-mem@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-5.0.1.tgz#c345126b74f5b8aa376dc77d36813a177ef8251d" - integrity sha512-qd+qUJHXsGSFoHTziptAKXoLX87QjR7v2KMbqncDXPxQuCdsQlzmyX+gwrEHhlzn08vkf8TyipYyMmiC6Gobzg== - dependencies: - level-packager "^5.0.3" - memdown "^5.0.0" - -level-packager@^5.0.3: - 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== - dependencies: - encoding-down "^6.3.0" - levelup "^4.3.2" - level-packager@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-4.0.1.tgz#7e7d3016af005be0869bc5fa8de93d2a7f56ffe6" @@ -7112,13 +6969,6 @@ level-supports@^4.0.0: resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== -level-supports@~1.0.0: - 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" - level-transcoder@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" @@ -7144,15 +6994,6 @@ level-ws@^1.0.0: readable-stream "^2.2.8" xtend "^4.0.1" -level-ws@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" - integrity sha512-1iv7VXx0G9ec1isqQZ7y5LmoZo/ewAsyDHNA8EFDW5hqH2Kqovm33nSFkSdnLLAK+I5FlT+lo5Cw9itGe+CpQA== - dependencies: - inherits "^2.0.3" - readable-stream "^3.1.0" - xtend "^4.0.1" - level@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" @@ -7184,18 +7025,15 @@ levelup@^1.2.1: semver "~5.4.1" xtend "~4.0.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== +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: - 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" + prelude-ls "^1.2.1" + type-check "~0.4.0" -levn@^0.3.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 sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== @@ -7203,13 +7041,10 @@ levn@^0.3.0, levn@~0.3.0: 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" +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== load-json-file@^1.0.0: version "1.1.0" @@ -7282,7 +7117,7 @@ lodash@4.17.20: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4: +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7320,9 +7155,9 @@ loose-envify@^1.0.0: js-tokens "^3.0.0 || ^4.0.0" loupe@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" - integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== + version "2.3.6" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== dependencies: get-func-name "^2.0.0" @@ -7336,6 +7171,11 @@ lowercase-keys@^2.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +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@5.1.1, lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -7453,18 +7293,6 @@ memdown@^1.0.0: ltgt "~2.2.0" safe-buffer "~5.1.1" -memdown@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb" - integrity sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw== - dependencies: - abstract-leveldown "~6.2.1" - functional-red-black-tree "~1.0.1" - immediate "~3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.2.0" - memdown@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/memdown/-/memdown-3.0.0.tgz#93aca055d743b20efc37492e9e399784f2958309" @@ -7542,23 +7370,16 @@ merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: rlp "^2.0.0" semaphore ">=1.0.1" -merkle-patricia-tree@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-4.2.4.tgz#ff988d045e2bf3dfa2239f7fabe2d59618d57413" - integrity sha512-eHbf/BG6eGNsqqfbLED9rIqbsF4+sykEaBn6OLNs71tjclbMcMOk1tEPmJKcNcNCLkvbpY/lwyOlizWsqPNo8w== - dependencies: - "@types/levelup" "^4.3.0" - ethereumjs-util "^7.1.4" - level-mem "^5.0.1" - level-ws "^2.0.0" - readable-stream "^3.6.0" - semaphore-async-await "^1.5.1" - methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +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@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -7611,11 +7432,6 @@ mime@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.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -7648,7 +7464,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.1.1: +"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -7662,13 +7478,6 @@ minimatch@3.0.4: dependencies: brace-expansion "^1.1.7" -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== - dependencies: - brace-expansion "^1.1.7" - minimatch@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" @@ -7683,10 +7492,10 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7, minimist@~1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" @@ -7723,10 +7532,10 @@ mkdirp-promise@^5.0.1: 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@*: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== mkdirp@0.5.5: version "0.5.5" @@ -7742,6 +7551,11 @@ mkdirp@0.5.x, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5: dependencies: minimist "^1.2.6" +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mnemonist@^0.38.0: version "0.38.5" resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" @@ -7750,9 +7564,9 @@ mnemonist@^0.38.0: obliterator "^2.0.0" mocha@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" - integrity sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg== + version "10.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== dependencies: ansi-colors "4.1.1" browser-stdout "1.3.1" @@ -7806,36 +7620,6 @@ mocha@^7.1.1: yargs-parser "13.1.2" yargs-unparser "1.6.0" -mocha@^9.2.0: - version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" - integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "4.2.1" - ms "2.1.3" - nanoid "3.3.1" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - mock-fs@^4.1.0: version "4.14.0" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" @@ -7915,21 +7699,11 @@ murmur-128@^0.2.1: fmix "^0.1.0" imul "^1.0.0" -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== - 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 sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew== -nanoid@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - nanoid@3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" @@ -7952,10 +7726,10 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -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== +napi-macros@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" + integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== natural-compare@^1.4.0: version "1.4.0" @@ -7967,7 +7741,7 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -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== @@ -8002,13 +7776,20 @@ node-environment-flags@1.0.6: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" -node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7: +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-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-fetch@~1.7.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -8018,14 +7799,9 @@ node-fetch@~1.7.1: is-stream "^1.0.1" node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" - integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== - -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== + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== nofilter@^3.1.0: version "3.1.0" @@ -8110,10 +7886,10 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.12.2, object-inspect@^1.9.0, 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-inspect@^1.12.3, object-inspect@^1.9.0, object-inspect@~1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== object-is@^1.0.1: version "1.1.5" @@ -8160,15 +7936,16 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz#7965e6437a57278b587383831a9b829455a4bc37" - integrity sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ== +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz#5e5c384dd209fa4efffead39e3a0512770ccc312" + integrity sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ== dependencies: - array.prototype.reduce "^1.0.4" + array.prototype.reduce "^1.0.5" call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.1" + define-properties "^1.2.0" + es-abstract "^1.21.2" + safe-array-concat "^1.0.0" object.pick@^1.3.0: version "1.3.0" @@ -8210,13 +7987,6 @@ once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== - dependencies: - mimic-fn "^1.0.0" - open@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" @@ -8225,7 +7995,7 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" -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== @@ -8238,16 +8008,16 @@ optionator@^0.8.1, optionator@^0.8.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== + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" os-homedir@^1.0.0: version "1.0.2" @@ -8285,6 +8055,11 @@ p-cancelable@^2.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -8401,13 +8176,15 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" -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.0.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" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" parse5-htmlparser2-tree-adapter@^7.0.0: version "7.0.0" @@ -8452,24 +8229,25 @@ patch-package@6.2.2: slash "^2.0.0" tmp "^0.0.33" -patch-package@^6.2.2: - version "6.4.7" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" - integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ== +patch-package@^6.2.2, patch-package@^6.4.7: + version "6.5.1" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.5.1.tgz#3e5d00c16997e6160291fee06a521c42ac99b621" + integrity sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA== dependencies: "@yarnpkg/lockfile" "^1.1.0" - chalk "^2.4.2" + chalk "^4.1.2" cross-spawn "^6.0.5" find-yarn-workspace-root "^2.0.0" - fs-extra "^7.0.1" + fs-extra "^9.0.0" is-ci "^2.0.0" klaw-sync "^6.0.0" - minimist "^1.2.0" + minimist "^1.2.6" open "^7.4.2" rimraf "^2.6.3" semver "^5.6.0" slash "^2.0.0" tmp "^0.0.33" + yaml "^1.10.2" path-browserify@^1.0.0: version "1.0.1" @@ -8498,11 +8276,6 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -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-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" @@ -8597,6 +8370,11 @@ pkg-dir@4.2.0: dependencies: find-up "^4.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== + pollock@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/pollock/-/pollock-0.2.1.tgz#01273ae3542511492d07f1c10fa53f149b37c6ad" @@ -8640,26 +8418,18 @@ prettier-linter-helpers@^1.0.0: fast-diff "^1.1.2" prettier-plugin-solidity@^1.0.0-beta.17: - version "1.0.0-beta.24" - resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.24.tgz#67573ca87098c14f7ccff3639ddd8a4cab2a87eb" - integrity sha512-6JlV5BBTWzmDSq4kZ9PTXc3eLOX7DF5HpbqmmaF+kloyUwOZbJ12hIYsUaZh2fVgZdV2t0vWcvY6qhILhlzgqg== + version "1.1.3" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz#9a35124f578404caf617634a8cab80862d726cba" + integrity sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg== dependencies: - "@solidity-parser/parser" "^0.14.3" - emoji-regex "^10.1.0" - escape-string-regexp "^4.0.0" - semver "^7.3.7" + "@solidity-parser/parser" "^0.16.0" + semver "^7.3.8" solidity-comments-extractor "^0.0.7" - string-width "^4.2.3" - -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, prettier@^2.3.2: - version "2.7.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +prettier@^2.1.2, prettier@^2.3.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== private@^0.1.6, private@^0.1.8: version "0.1.8" @@ -8690,9 +8460,9 @@ promise-to-callback@^1.0.0: set-immediate-shim "^1.0.1" promise@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/promise/-/promise-8.2.0.tgz#a1f6280ab67457fbfc8aad2b198c9497e9e5c806" - integrity sha512-+CMAlLHqwRYwBMXKCP+o8ns7DN+xHDUiI+0nArsiJ9y+kJVPLFxEaSw6Ha9s9H0tftxg2Yzl25wqj9G7m5wLZg== + version "8.3.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" + integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== dependencies: asap "~2.0.6" @@ -8790,9 +8560,9 @@ pull-pushable@^2.0.0: integrity sha512-M7dp95enQ2kaHvfCt2+DJfyzgCSpWVR2h2kWYnVsW6ZpxQBx5wOu0QWOvQPVoPnBLUZYitYP2y7HyHkLQNeGXg== pull-stream@^3.2.3, pull-stream@^3.4.0, pull-stream@^3.6.8: - version "3.6.14" - resolved "https://registry.yarnpkg.com/pull-stream/-/pull-stream-3.6.14.tgz#529dbd5b86131f4a5ed636fdf7f6af00781357ee" - integrity sha512-KIqdvpqHHaTUA2mCYcLG1ibEbu/LCKoJZsBWyv9lSYtPkJPBq8m3Hxa103xHi6D2thj5YXa0TqK3L3GUkwgnew== + version "3.7.0" + resolved "https://registry.yarnpkg.com/pull-stream/-/pull-stream-3.7.0.tgz#85de0e44ff38a4d2ad08cc43fc458e1922f9bf0b" + integrity sha512-Eco+/R004UaCK2qEDE8vGklcTG2OeZSVm1kTUQNrykEjDwcFXDZhygFDsW49DbXyJMEhHeRL3z5cRVqPAhXlIw== pull-window@^2.1.4: version "2.1.4" @@ -8809,20 +8579,20 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== - punycode@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA== +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + 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== + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== puppeteer@^13.7.0: version "13.7.0" @@ -8842,13 +8612,20 @@ puppeteer@^13.7.0: unbzip2-stream "1.4.3" ws "8.5.0" -qs@6.11.0, qs@^6.4.0, qs@^6.7.0, qs@^6.9.4: +qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" +qs@^6.11.0, qs@^6.4.0, qs@^6.9.4: + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" @@ -8863,11 +8640,6 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== - queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -8903,7 +8675,7 @@ range-parser@~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.5.1, raw-body@^2.4.1: +raw-body@2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== @@ -8913,6 +8685,16 @@ raw-body@2.5.1, raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" +raw-body@2.5.2, 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 "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -8941,9 +8723,9 @@ readable-stream@^1.0.33: string_decoder "~0.10.x" readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.6, readable-stream@~2.3.6: - 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== + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -8953,16 +8735,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.1.0, 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== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@^3.1.1: +readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.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== @@ -9003,11 +8776,11 @@ rechoir@^0.6.2: 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== + 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: - minimatch "3.0.4" + minimatch "^3.0.5" regenerate@^1.2.1: version "1.4.2" @@ -9036,19 +8809,14 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0, 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== +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" + integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.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== + define-properties "^1.2.0" + functions-have-names "^1.2.3" regexpp@^3.1.0: version "3.2.0" @@ -9174,7 +8942,7 @@ require-main-filename@^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== -resolve-alpn@^1.0.0: +resolve-alpn@^1.0.0, 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== @@ -9207,11 +8975,11 @@ resolve@1.17.0: path-parse "^1.0.6" resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1, 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== + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -9229,14 +8997,6 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.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 sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - resumer@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" @@ -9259,13 +9019,6 @@ reusify@^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@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -9295,11 +9048,6 @@ rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3, rlp@^2.2.4: dependencies: bn.js "^5.2.0" -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-limit@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" @@ -9319,12 +9067,15 @@ rustbn.js@~0.2.0: resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== -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== +safe-array-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060" + integrity sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ== dependencies: - tslib "^1.9.0" + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + has-symbols "^1.0.3" + 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: version "5.2.1" @@ -9415,30 +9166,25 @@ seedrandom@3.0.1: resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.1.tgz#eb3dde015bcf55df05a233514e5df44ef9dce083" integrity sha512-1/02Y/rUeU1CJBAGLebiC5Lbo5FnB22gQbIFFYTLkwvp1xdABZJH1sn4ZT1MzXmPpzv+Rf/Lu2NcsLJiK4rcDg== -semaphore-async-await@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz#857bef5e3644601ca4b9570b87e9df5ca12974fa" - integrity sha512-b/ptP11hETwYWpeilHXXQiV5UJNJl7ZWWooKRE5eBIYWoom6dZ0SluCIdCtKycsMtZgKWE01/qAw6jblw1YVhg== - semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== 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== + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== +semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" @@ -9626,15 +9372,6 @@ slash@^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== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -9674,10 +9411,25 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +sol2uml@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/sol2uml/-/sol2uml-2.2.0.tgz#145b1b85cc2c5d466d596f3426aae4dd4dc946f2" + integrity sha512-JMBvn3ZMT/1egoZjheM4Mh9gQudrlVjFZ1VS0gjQ/eluITT08U6V438Jyku28OuXz42aXNbGS80JuRZo0J7pLg== + dependencies: + "@aduh95/viz.js" "^3.7.0" + "@solidity-parser/parser" "^0.14.3" + axios "^0.27.2" + commander "^9.4.0" + convert-svg-to-png "^0.6.4" + debug "^4.3.4" + ethers "^5.6.9" + js-graph-algorithms "^1.0.18" + klaw "^4.0.1" + sol2uml@^2.5.4: - version "2.5.14" - resolved "https://registry.yarnpkg.com/sol2uml/-/sol2uml-2.5.14.tgz#335104d34c9c9a3d5e3d0aabc6ff7675c76c8513" - integrity sha512-TK5b3iozvyIecFyKaMnRWG2Op4u+bsjGlxlLJoMAJIfq4ptC8F/vh1xEOkzwfiA77if7hWqhQBinlxaWVumvBA== + version "2.5.13" + resolved "https://registry.yarnpkg.com/sol2uml/-/sol2uml-2.5.13.tgz#095f34e7ab0e7e62e0680b7eb2dcb32bcf408bc7" + integrity sha512-ACfGQzfciKuCZw7//P2URj1bRHoX/KnJweuPKNcctzalSZGsjNdw8uRzLl1ph00F9xqu4z9wpDGWJ0GSzox2SQ== dependencies: "@aduh95/viz.js" "^3.7.0" "@solidity-parser/parser" "^0.16.1" @@ -9740,31 +9492,36 @@ solhint-plugin-prettier@^0.0.5: prettier-linter-helpers "^1.0.0" solhint@^3.2.0: - 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 "^1.14.3" + prettier "^2.8.3" -solidity-ast@^0.4.15: - version "0.4.35" - resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.35.tgz#82e064b14dc989338123264bde2235cad751f128" - integrity sha512-F5bTDLh3rmDxRmLSrs3qt3nvxJprWSEkS7h2KmuXDx7XTfJ6ZKVTV1rtPIYCqJAuPsU/qa8YUeFn7jdOAZcTPA== +solidity-ast@^0.4.26: + version "0.4.52" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.52.tgz#9f1a9abc7e5ba28bbf91146ecd07aec7e70f3c85" + integrity sha512-iOya9BSiB9jhM8Vf40n8lGELGzwrUc57rl5BhfNtJ5cvAaMvRcNlHeAMNvqJJyjoUnczqRbHqdivEqK89du3Cw== + dependencies: + array.prototype.findlast "^1.2.2" solidity-comments-extractor@^0.0.7: version "0.0.7" @@ -9853,9 +9610,9 @@ source-map@~0.2.0: amdefine ">=0.0.4" spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" @@ -9874,9 +9631,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.12" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz#69077835abe2710b65f03969898b6637b505a779" - integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA== + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -9957,7 +9714,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -9983,32 +9740,32 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.trim@~1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.6.tgz#824960787db37a9e24711802ed0c1d1c0254f83e" - integrity sha512-8lMR2m+U0VJTPp6JjvJTtGyc4FIGq9CdRt7O9p6T0e6K4vjU+OP+SQJpbe/SBmRcCUIvNUnjsbmY6lnMp8MhsQ== +string.prototype.trim@^1.2.7, string.prototype.trim@~1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" -string.prototype.trimend@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" - integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== +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== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" -string.prototype.trimstart@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" - integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== +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== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" string_decoder@^1.1.1: version "1.3.0" @@ -10076,7 +9833,7 @@ strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed "1.0.0" -strip-json-comments@2.0.1, 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 sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== @@ -10164,20 +9921,10 @@ sync-rpc@^1.2.1: dependencies: get-port "^3.1.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== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -table@^6.0.9, table@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" - integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== +table@^6.0.9, table@^6.8.0, table@^6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -10186,24 +9933,24 @@ table@^6.0.9, table@^6.8.0: strip-ansi "^6.0.1" tape@^4.6.3: - version "4.16.1" - resolved "https://registry.yarnpkg.com/tape/-/tape-4.16.1.tgz#8d511b3a0be1a30441885972047c1dac822fd9be" - integrity sha512-U4DWOikL5gBYUrlzx+J0oaRedm2vKLFbtA/+BRAXboGWpXO7bMP8ddxlq3Cse2bvXFQ0jZMOj6kk3546mvCdFg== + version "4.16.2" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.16.2.tgz#7565e6af20426565557266e9dda7215869b297b6" + integrity sha512-TUChV+q0GxBBCEbfCYkGLkv8hDJYjMdSWdE0/Lr331sB389dsvFUHNV9ph5iQqKzt8Ss9drzcda/YeexclBFqg== dependencies: call-bind "~1.0.2" deep-equal "~1.1.1" - defined "~1.0.0" + defined "~1.0.1" dotignore "~0.1.2" for-each "~0.3.3" glob "~7.2.3" has "~1.0.3" inherits "~2.0.4" is-regex "~1.1.4" - minimist "~1.2.6" - object-inspect "~1.12.2" + minimist "~1.2.7" + object-inspect "~1.12.3" resolve "~1.22.1" resumer "~0.0.0" - string.prototype.trim "~1.2.6" + string.prototype.trim "~1.2.7" through "~2.3.8" tar-fs@2.1.1: @@ -10283,7 +10030,7 @@ through2@^2.0.3: readable-stream "~2.3.6" xtend "~4.0.1" -through@^2.3.6, through@^2.3.8, through@~2.3.4, through@~2.3.8: +through@^2.3.8, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -10387,11 +10134,6 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== -"true-case-path@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-2.2.1.tgz#c5bf04a5bbec3fd118be4084461b3a27c4d796bf" - integrity sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q== - ts-essentials@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a" @@ -10441,7 +10183,7 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.13.0, tslib@^1.8.1, 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== @@ -10587,6 +10329,45 @@ typechain@^5.1.2: prettier "^2.1.2" ts-essentials "^7.0.1" +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + 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" @@ -10600,9 +10381,9 @@ typedarray@^0.0.6: integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typescript@^4.2.2: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== typewise-core@^1.2, typewise-core@^1.2.0: version "1.2.0" @@ -10627,9 +10408,9 @@ typical@^2.6.0, typical@^2.6.1: integrity sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg== uglify-js@^3.1.4: - version "3.17.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.3.tgz#f0feedf019c4510f164099e8d7e72ff2d7304377" - integrity sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg== + version "3.17.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" + integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== ultron@~1.1.0: version "1.1.1" @@ -10659,10 +10440,10 @@ underscore@1.9.1: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== -undici@^5.4.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.11.0.tgz#1db25f285821828fc09d3804b9e2e934ae86fc13" - integrity sha512-oWjWJHzFet0Ow4YZBkyiJwiK5vWqEYoH7BINzJAJOLedZ++JpAlCbUktW2GQ2DS2FpKmxD/JMtWUUWl1BtghGw== +undici@^5.14.0: + version "5.23.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.23.0.tgz#e7bdb0ed42cebe7b7aca87ced53e6eaafb8f8ca0" + integrity sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg== dependencies: busboy "^1.6.0" @@ -10729,12 +10510,12 @@ url-set-query@^1.0.0: integrity sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg== url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== + version "0.11.1" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.1.tgz#26f90f615427eca1b9f4d6a28288c147e2302a32" + integrity sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA== dependencies: - punycode "1.3.2" - querystring "0.2.0" + punycode "^1.4.1" + qs "^6.11.0" use@^3.1.0: version "3.1.1" @@ -10759,17 +10540,19 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== util.promisify@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.1.tgz#77832f57ced2c9478174149cae9b96e9918cd54b" - integrity sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw== + version "1.1.2" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.2.tgz#02b3dbadbb80071eee4c43aed58747afdfc516db" + integrity sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA== dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" + call-bind "^1.0.2" + define-properties "^1.2.0" for-each "^0.3.3" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.1" + has-proto "^1.0.1" + has-symbols "^1.0.3" + object.getownpropertydescriptors "^2.1.6" + safe-array-concat "^1.0.0" -util@^0.12.0: +util@^0.12.0, util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== @@ -10805,15 +10588,20 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + 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== v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" + integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== validate-npm-package-license@^3.0.1: version "3.0.4" @@ -10842,6 +10630,15 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +web3-bzz@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.10.0.tgz#ac74bc71cdf294c7080a79091079192f05c5baed" + integrity sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA== + dependencies: + "@types/node" "^12.12.6" + got "12.1.0" + swarm-js "^0.1.40" + web3-bzz@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.11.tgz#41bc19a77444bd5365744596d778b811880f707f" @@ -10861,6 +10658,14 @@ web3-bzz@1.7.4: got "9.6.0" swarm-js "^0.1.40" +web3-core-helpers@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.10.0.tgz#1016534c51a5df77ed4f94d1fcce31de4af37fad" + integrity sha512-pIxAzFDS5vnbXvfvLSpaA1tfRykAe9adw43YCKsEYQwH0gCLL0kMLkaCX3q+Q8EVmAh+e1jWL/nl9U0de1+++g== + dependencies: + web3-eth-iban "1.10.0" + web3-utils "1.10.0" + web3-core-helpers@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.11.tgz#84c681ed0b942c0203f3b324a245a127e8c67a99" @@ -10878,6 +10683,17 @@ web3-core-helpers@1.7.4: web3-eth-iban "1.7.4" web3-utils "1.7.4" +web3-core-method@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.10.0.tgz#82668197fa086e8cc8066742e35a9d72535e3412" + integrity sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA== + dependencies: + "@ethersproject/transactions" "^5.6.2" + web3-core-helpers "1.10.0" + web3-core-promievent "1.10.0" + web3-core-subscriptions "1.10.0" + web3-utils "1.10.0" + web3-core-method@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.11.tgz#f880137d1507a0124912bf052534f168b8d8fbb6" @@ -10901,6 +10717,13 @@ web3-core-method@1.7.4: web3-core-subscriptions "1.7.4" web3-utils "1.7.4" +web3-core-promievent@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.10.0.tgz#cbb5b3a76b888df45ed3a8d4d8d4f54ccb66a37b" + integrity sha512-68N7k5LWL5R38xRaKFrTFT2pm2jBNFaM4GioS00YjAKXRQ3KjmhijOMG3TICz6Aa5+6GDWYelDNx21YAeZ4YTg== + dependencies: + eventemitter3 "4.0.4" + web3-core-promievent@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.11.tgz#51fe97ca0ddec2f99bf8c3306a7a8e4b094ea3cf" @@ -10915,6 +10738,17 @@ web3-core-promievent@1.7.4: dependencies: eventemitter3 "4.0.4" +web3-core-requestmanager@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz#4b34f6e05837e67c70ff6f6993652afc0d54c340" + integrity sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ== + dependencies: + util "^0.12.5" + web3-core-helpers "1.10.0" + web3-providers-http "1.10.0" + web3-providers-ipc "1.10.0" + web3-providers-ws "1.10.0" + web3-core-requestmanager@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.11.tgz#fe6eb603fbaee18530293a91f8cf26d8ae28c45a" @@ -10937,6 +10771,14 @@ web3-core-requestmanager@1.7.4: web3-providers-ipc "1.7.4" web3-providers-ws "1.7.4" +web3-core-subscriptions@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz#b534592ee1611788fc0cb0b95963b9b9b6eacb7c" + integrity sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.0" + web3-core-subscriptions@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.11.tgz#beca908fbfcb050c16f45f3f0f4c205e8505accd" @@ -10954,6 +10796,19 @@ web3-core-subscriptions@1.7.4: eventemitter3 "4.0.4" web3-core-helpers "1.7.4" +web3-core@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.10.0.tgz#9aa07c5deb478cf356c5d3b5b35afafa5fa8e633" + integrity sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ== + dependencies: + "@types/bn.js" "^5.1.1" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-core-requestmanager "1.10.0" + web3-utils "1.10.0" + web3-core@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.11.tgz#1043cacc1becb80638453cc5b2a14be9050288a7" @@ -10980,6 +10835,14 @@ web3-core@1.7.4: web3-core-requestmanager "1.7.4" web3-utils "1.7.4" +web3-eth-abi@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz#53a7a2c95a571e205e27fd9e664df4919483cce1" + integrity sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg== + dependencies: + "@ethersproject/abi" "^5.6.3" + web3-utils "1.10.0" + web3-eth-abi@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.11.tgz#a887494e5d447c2926d557a3834edd66e17af9b0" @@ -10997,6 +10860,22 @@ web3-eth-abi@1.7.4: "@ethersproject/abi" "^5.6.3" web3-utils "1.7.4" +web3-eth-accounts@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz#2942beca0a4291455f32cf09de10457a19a48117" + integrity sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q== + dependencies: + "@ethereumjs/common" "2.5.0" + "@ethereumjs/tx" "3.3.2" + eth-lib "0.2.8" + ethereumjs-util "^7.1.5" + scrypt-js "^3.0.1" + uuid "^9.0.0" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-utils "1.10.0" + web3-eth-accounts@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.11.tgz#a9e3044da442d31903a7ce035a86d8fa33f90520" @@ -11031,6 +10910,20 @@ web3-eth-accounts@1.7.4: web3-core-method "1.7.4" web3-utils "1.7.4" +web3-eth-contract@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz#8e68c7654576773ec3c91903f08e49d0242c503a" + integrity sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w== + dependencies: + "@types/bn.js" "^5.1.1" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-core-promievent "1.10.0" + web3-core-subscriptions "1.10.0" + web3-eth-abi "1.10.0" + web3-utils "1.10.0" + web3-eth-contract@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.11.tgz#917065902bc27ce89da9a1da26e62ef663663b90" @@ -11060,6 +10953,20 @@ web3-eth-contract@1.7.4: web3-eth-abi "1.7.4" web3-utils "1.7.4" +web3-eth-ens@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz#96a676524e0b580c87913f557a13ed810cf91cd9" + integrity sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g== + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-promievent "1.10.0" + web3-eth-abi "1.10.0" + web3-eth-contract "1.10.0" + web3-utils "1.10.0" + web3-eth-ens@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.11.tgz#26d4d7f16d6cbcfff918e39832b939edc3162532" @@ -11089,6 +10996,14 @@ web3-eth-ens@1.7.4: web3-eth-contract "1.7.4" web3-utils "1.7.4" +web3-eth-iban@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.10.0.tgz#5a46646401965b0f09a4f58e7248c8a8cd22538a" + integrity sha512-0l+SP3IGhInw7Q20LY3IVafYEuufo4Dn75jAHT7c2aDJsIolvf2Lc6ugHkBajlwUneGfbRQs/ccYPQ9JeMUbrg== + dependencies: + bn.js "^5.2.1" + web3-utils "1.10.0" + web3-eth-iban@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.11.tgz#f5f73298305bc7392e2f188bf38a7362b42144ef" @@ -11105,6 +11020,18 @@ web3-eth-iban@1.7.4: bn.js "^5.2.1" web3-utils "1.7.4" +web3-eth-personal@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz#94d525f7a29050a0c2a12032df150ac5ea633071" + integrity sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg== + dependencies: + "@types/node" "^12.12.6" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-net "1.10.0" + web3-utils "1.10.0" + web3-eth-personal@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.11.tgz#a38b3942a1d87a62070ce0622a941553c3d5aa70" @@ -11129,6 +11056,24 @@ web3-eth-personal@1.7.4: web3-net "1.7.4" web3-utils "1.7.4" +web3-eth@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.10.0.tgz#38b905e2759697c9624ab080cfcf4e6c60b3a6cf" + integrity sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA== + dependencies: + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-core-subscriptions "1.10.0" + web3-eth-abi "1.10.0" + web3-eth-accounts "1.10.0" + web3-eth-contract "1.10.0" + web3-eth-ens "1.10.0" + web3-eth-iban "1.10.0" + web3-eth-personal "1.10.0" + web3-net "1.10.0" + web3-utils "1.10.0" + web3-eth@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.11.tgz#4c81fcb6285b8caf544058fba3ae802968fdc793" @@ -11166,6 +11111,15 @@ web3-eth@1.7.4: web3-net "1.7.4" web3-utils "1.7.4" +web3-net@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.10.0.tgz#be53e7f5dafd55e7c9013d49c505448b92c9c97b" + integrity sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA== + dependencies: + web3-core "1.10.0" + web3-core-method "1.10.0" + web3-utils "1.10.0" + web3-net@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.11.tgz#eda68ef25e5cdb64c96c39085cdb74669aabbe1b" @@ -11210,6 +11164,16 @@ web3-provider-engine@14.2.1: xhr "^2.2.0" xtend "^4.0.1" +web3-providers-http@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.10.0.tgz#864fa48675e7918c9a4374e5f664b32c09d0151b" + integrity sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA== + dependencies: + abortcontroller-polyfill "^1.7.3" + cross-fetch "^3.1.4" + es6-promise "^4.2.8" + web3-core-helpers "1.10.0" + web3-providers-http@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.11.tgz#1cd03442c61670572d40e4dcdf1faff8bd91e7c6" @@ -11226,6 +11190,14 @@ web3-providers-http@1.7.4: web3-core-helpers "1.7.4" xhr2-cookies "1.1.0" +web3-providers-ipc@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz#9747c7a6aee96a51488e32fa7c636c3460b39889" + integrity sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA== + dependencies: + oboe "2.1.5" + web3-core-helpers "1.10.0" + web3-providers-ipc@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.11.tgz#d16d6c9be1be6e0b4f4536c4acc16b0f4f27ef21" @@ -11243,6 +11215,15 @@ web3-providers-ipc@1.7.4: oboe "2.1.5" web3-core-helpers "1.7.4" +web3-providers-ws@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz#cb0b87b94c4df965cdf486af3a8cd26daf3975e5" + integrity sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.0" + websocket "^1.0.32" + web3-providers-ws@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.11.tgz#a1dfd6d9778d840561d9ec13dd453046451a96bb" @@ -11262,6 +11243,16 @@ web3-providers-ws@1.7.4: web3-core-helpers "1.7.4" websocket "^1.0.32" +web3-shh@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.10.0.tgz#c2979b87e0f67a7fef2ce9ee853bd7bfbe9b79a8" + integrity sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg== + dependencies: + web3-core "1.10.0" + web3-core-method "1.10.0" + web3-core-subscriptions "1.10.0" + web3-net "1.10.0" + web3-shh@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.11.tgz#f5d086f9621c9a47e98d438010385b5f059fd88f" @@ -11282,6 +11273,19 @@ web3-shh@1.7.4: web3-core-subscriptions "1.7.4" web3-net "1.7.4" +web3-utils@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.0.tgz#ca4c1b431a765c14ac7f773e92e0fd9377ccf578" + integrity sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg== + dependencies: + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereumjs-util "^7.1.0" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + web3-utils@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.11.tgz#af1942aead3fb166ae851a985bed8ef2c2d95a82" @@ -11310,18 +11314,32 @@ web3-utils@1.7.4: utf8 "3.0.0" web3-utils@^1.0.0-beta.31, web3-utils@^1.3.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.8.0.tgz#0a506f8c6af9a2ad6ba79689892662769534fc03" - integrity sha512-7nUIl7UWpLVka2f09CMbKOSEvorvHnaugIabU4mj7zfMvm0tSByLcEu3eyV9qgS11qxxLuOkzBIwCstTflhmpQ== + version "1.10.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.1.tgz#97532130d85358628bc0ff14d94b7e9449786983" + integrity sha512-r6iUUw/uMnNcWXjhRv33Nyrhxq3VGOPBXeSzxhOXIci4SvC/LPTpROY0uTrMX7ztKyODYrHp8WhTkEf+ZnHssw== 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.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.10.0.tgz#2fde0009f59aa756c93e07ea2a7f3ab971091274" + integrity sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng== + dependencies: + web3-bzz "1.10.0" + web3-core "1.10.0" + web3-eth "1.10.0" + web3-eth-personal "1.10.0" + web3-net "1.10.0" + web3-shh "1.10.0" + web3-utils "1.10.0" + web3@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.11.tgz#50f458b2e8b11aa37302071c170ed61cff332975" @@ -11407,21 +11425,20 @@ which-module@^1.0.0: integrity sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ== which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.2: - version "1.1.8" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.8.tgz#0cfd53401a6f334d90ed1125754a42ed663eb01f" - integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== +which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.2: + version "1.1.11" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" - es-abstract "^1.20.0" for-each "^0.3.3" + gopd "^1.0.1" has-tostringtag "^1.0.0" - is-typed-array "^1.1.9" which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: version "1.3.1" @@ -11430,7 +11447,7 @@ which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: dependencies: isexe "^2.0.0" -which@2.0.2, which@^2.0.1: +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== @@ -11449,21 +11466,16 @@ window-size@^0.2.0: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" integrity sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw== -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.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 sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== - workerpool@6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" @@ -11500,13 +11512,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -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" @@ -11580,7 +11585,7 @@ xmlhttprequest@1.8.0: resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA== -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== @@ -11622,6 +11627,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"