diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..03ec1e3 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,27 @@ +# +# This action checks PRs to see if any CHANGELOG* files were updated. +# If none were, it will add a message to the PR asking if it would make sense to do so. +# +name: Changelog + +on: pull_request + +jobs: + changelog: + name: Changelog checker + runs-on: ubuntu-latest + steps: + - name: Check for changed files + id: changedfiles + uses: futuratrepadeira/changed-files@186b5b30b1f5e44ed655a59652746c3ce00d53ef # Version v3.1.1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + pattern: '^CHANGELOG.*$' + - name: Make a comment + uses: unsplash/comment-on-pr@d1a1d5dd1eb1bb657a01f4d92dd5e4d5bb7857d3 # Version v1.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: contains(steps.changedfiles.outputs.files_updated, 'CHANGELOG') != true && contains(steps.changedfiles.outputs.files_created, 'CHANGELOG') != true + with: + msg: "I see that you haven't updated any CHANGELOG files. Would it make sense to do so?" + check_for_duplicate_msg: false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..cfe510c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,37 @@ +name: Main + +on: + push: + branches: + - master + pull_request: ~ + +jobs: + run-basic-checks: + name: Run linters and unit tests + runs-on: [self-hosted] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '14.x' + - run: npm install -g yarn + - run: yarn install + - run: yarn setup + - run: yarn lint + - run: yarn test + run-integration: + name: Setup and run integration tests + needs: [run-basic-checks] + runs-on: [self-hosted] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '14.x' + - run: npm install -g yarn + - run: yarn install + - run: yarn setup + - name: Setup Optimism L2 local network + run: yarn script:oe:up + - run: yarn test --network optimism diff --git a/.gitignore b/.gitignore index 903160c..5ada970 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ coverage.json # Misc .DS_STORE + +# Optimism monorepo used for integration tests +/optimism diff --git a/.prettierrc.js b/.prettierrc.js index 4b87aa2..3e9464b 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,7 +1,7 @@ module.exports = { semi: false, singleQuote: true, - printWidth: 120, + printWidth: 100, endOfLine: 'auto', trailingComma: 'all', } diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..3ae7268 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +node 14.16.0 +yarn 1.22.4 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 81523d4..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -dist: trusty -language: node_js -sudo: required -node_js: - - '12' - -env: - - CXX=g++-4.8 - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - build-essential - - g++-4.8 - -before_install: - - export CXX="g++-4.8" - - npm install -g npm@latest - -install: - - yarn install - -script: - - yarn setup - - yarn test diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..111c04c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog LinkToken + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] - Apr 2021 + +### Added + +- Optimism L2 bridge support +- Access controlled mintable & burnable LinkToken, for use on sidechains and L2 networks. + +### Changed + +- Migrated to Hardhat and Waffle + +### Fixed + +### Removed + +- Truffle framework and tests dependencies + +## [1.1.0] - Mar 2021 + +Initial @chainlink/token release! + +### Added + +- Solidity 0.6 support +- Simple token swapping contract + +## [1.0.6] - Sep 2018 + +Initial link_token release! diff --git a/README.md b/README.md index 37c4ad6..a8d89a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# LINK Token Contracts [![Build Status](https://travis-ci.org/smartcontractkit/LinkToken.svg?branch=master)](https://travis-ci.org/smartcontractkit/LinkToken) +# LINK Token Contracts The LINK token is an [EIP20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md) token with additional [ERC677](https://github.com/ethereum/EIPs/issues/677) functionality. @@ -6,36 +6,68 @@ The total supply of the token is 1,000,000,000, and each token is divisible up t To prevent accidental burns, the token does not allow transfers to the contract itself and to 0x0. -Security audit for [v0.4 version of the contracts](./contracts/v0.4/) is available [here](https://gist.github.com/Arachnid/4aa88041bd6e34835b8c0fd051245e79). +Security audit for [0.4 version of the contracts](./contracts/v0.4/) is available [here](https://gist.github.com/Arachnid/4aa88041bd6e34835b8c0fd051245e79). ## Details - Deployments: - - Ethereum Mainnet [LinkToken v0.4](./flat/v0.4/LinkToken.sol): [0x514910771AF9Ca656af840dff83E8264EcF986CA](https://etherscan.io/address/0x514910771af9ca656af840dff83e8264ecf986ca) + - Ethereum Mainnet [LinkToken 0.4](./flat/v0.4/LinkToken.sol): [0x514910771AF9Ca656af840dff83E8264EcF986CA](https://etherscan.io/address/0x514910771af9ca656af840dff83e8264ecf986ca) - Decimals: 18 - Name: ChainLink Token - Symbol: LINK -## Installation +## Setup -The project contains [v0.4 contracts](./contracts/v0.4/) that were used for LINK Ethereum Mainnet deployment in 2017. For deployments moving forward, we use the updated [v0.6 contracts](./contracts/v0.6/) which use a more recent version of solc and the OpenZeppelin token standards. These updates include a minor ABI change around approval/allowance naming. +The project contains [0.4 contracts](./contracts/v0.4/) that were used for LINK Ethereum Mainnet deployment in 2017. For deployments moving forward, we use the updated [0.6 contracts](./contracts/v0.6/) which use a more recent version of solc and the OpenZeppelin token standards. These updates include a minor ABI change around approval/allowance naming. ```bash yarn install ``` -## Testing - Setup contracts: ```bash yarn setup ``` +This will compile all versions of the contracts. + +## Testing + Run tests: ```bash yarn test ``` -This will test both v0.4 and v0.6 versions of the contracts. +This will run unit tests for all versions of the contracts. + +## Integration testing + +Integration tests are currently setup for Optimism bridge contracts, and to run them make sure you have a local network running first. + +The network can be started using a helpful script, which will clone the [Optimism monorepo](https://github.com/ethereum-optimism/optimism), build the : + +```bash +yarn script:oe:up +``` + +Run tests: + +```bash +yarn test --network optimism +``` + +This will run unit tests for all versions of the contracts, plus supported integration tests against the local L1 & L2 networks. + +The network can be stopped using another script: + +```bash +yarn script:oe:down +``` + +Or use the clean script, which will also delete all the images: + +```bash +yarn script:oe:clean +``` diff --git a/contracts/v0.7/README.md b/contracts/v0.7/README.md new file mode 100644 index 0000000..ed5d076 --- /dev/null +++ b/contracts/v0.7/README.md @@ -0,0 +1,5 @@ +# LINK Token Contracts v0.7 + +## Token bridge contracts + +LinkToken bridge contracts can be found in the [./bridge](./bridge) directory. diff --git a/contracts/v0.7/bridge/README.md b/contracts/v0.7/bridge/README.md new file mode 100644 index 0000000..467f650 --- /dev/null +++ b/contracts/v0.7/bridge/README.md @@ -0,0 +1,15 @@ +# LINK Token Bridge v0.7 + +- `./LinkTokenChild.sol`: A mintable & burnable child LinkToken contract to be used on child networks. + +## Optimism L2 bridge + +The Optimistic Virtual Machine (OVM) is a scalable form of the EVM. Optimistic Rollup, by [Optimism](https://optimism.io), is the core scaling solution which enables the off-chain OVM to achieve cheap, instant transactions that still inherit L1 security. The OVM is an EVM-based VM which supports optimistically executing EVM smart contracts on a layer 1 blockchain like Ethereum. It is structured in such a way that it is possible to verify individual steps of its computation on Ethereum mainnet. This allows the mainnet to enforce validity of state roots with fraud proofs in the layer 2 Optimistic Rollup chain. For more information consult the [Optimism developer documentation](https://community.optimism.io/docs/). + +The set of contracts needed for the Optimism L2 LinkToken bridge can be found in the [./optimism](./optimism) dir. + +- `./optimism/OVM_EOACodeHashSet.sol`: Abstract helper contract used to keep track of OVM EOA contract set (OVM specific) +- `./optimism/OVM_L1ERC20Gateway.sol`: Contract which stores deposited L1 funds that are in use on L2, and unlocks/transfers L1 funds on withdrawal. It synchronizes a corresponding L2 ERC20 Gateway, informing it of deposits, and listening to it for newly finalized withdrawals. (delegate proxy deployment) +- `./optimism/OVM_L2ERC20Gateway.sol`: Contract which mints deposited L2 funds that are locked on L1, and burns L2 funds on withdrawal. It synchronizes a corresponding L1 ERC20 Gateway, informing it of withdrawals, and listening to it for newly finalized deposits. (delegate proxy deployment) + +These contracts are an implementation of [abstracts bridge contracts provided by Optimism](https://github.com/ethereum-optimism/optimism/tree/master/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/tokens). diff --git a/contracts/v0.7/bridge/mocks/ERC677CallerMock.sol b/contracts/v0.7/bridge/mocks/ERC677CallerMock.sol new file mode 100644 index 0000000..287c413 --- /dev/null +++ b/contracts/v0.7/bridge/mocks/ERC677CallerMock.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; + +/* Interface Imports */ +import { ERC677 } from "../../../v0.6/token/ERC677.sol"; + +contract ERC677CallerMock { + /// @dev Forward transferAndCall to destination contract + function callTransferAndCall( + address destintion, + address to, + uint value, + bytes memory data + ) + external + { + ERC677(destintion).transferAndCall(to, value, data); + } +} diff --git a/contracts/v0.7/bridge/optimism/OVM_EOACodeHashSet.sol b/contracts/v0.7/bridge/optimism/OVM_EOACodeHashSet.sol new file mode 100644 index 0000000..9d6f91b --- /dev/null +++ b/contracts/v0.7/bridge/optimism/OVM_EOACodeHashSet.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; + +/* Library Imports */ +import { EnumerableSet } from "@openzeppelin/contracts/utils/EnumerableSet.sol"; + +/* Contract Imports */ +import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol"; +import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +/** + * @dev Abstract helper contract used to keep track of OVM EOA contract set (OVM specific) + * + * The OVM implements a basic form of account abstraction. In effect, this means + * that the only type of account is a smart contract (no EOAs), and all user wallets + * are in fact smart contract wallets. So to check for EOA, we need to actually check if + * the sender is an OVM_ProxyEOA contract, which gets deployed by the ovmCREATEEOA opcode. + * + * As the OVM_ProxyEOA.sol contract source could potentially change in the future (i.e., due to a fork), + * here we actually track a set of possible EOA proxy contracts. + */ +abstract contract OVM_EOACodeHashSet is /* Initializable, */ OwnableUpgradeable { + // Add the EnumerableSet library + using EnumerableSet for EnumerableSet.Bytes32Set; + + // Declare a Bytes32Set of code hashes + EnumerableSet.Bytes32Set private s_codeHasheSet; + + // Declare the genesis OVM_ProxyEOA.sol EXTCODEHASH + bytes32 constant OVM_EOA_CODE_HASH_V0 = 0x93bb081a7dd92bde63b4d0aa9b8612352b2ec585176a80efc0a2a277ecfc010e; + bytes32 constant OVM_EOA_CODE_HASH_V1 = 0x8b4ea2cb36c232a7bab9d385b7054ff04752ec4c0fad5dc2ed4b1c18d982154c; + bytes32 constant OVM_EOA_CODE_HASH_V2 = 0xb6268ee2707994607682cc0e3b288cdd71acc63df8de0e6baa39a31a2b91d0ad; + bytes32 constant OVM_EOA_CODE_HASH_V3 = 0x93fae832274ff6aa942fa0c287fc0d8fe180f26b36c92e83d9be7e39309d3464; + + function __OVM_EOACodeHashSet_init() + internal + initializer() + { + __Context_init_unchained(); + __Ownable_init_unchained(); + __OVM_EOACodeHashSet_init_unchained(); + } + + /// @notice Adds genesis OVM_ProxyEOA.sol EXTCODEHASH to the default set. + function __OVM_EOACodeHashSet_init_unchained() + internal + initializer() + { + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V0); + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V1); + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V2); + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V3); + } + + /// @notice Reverts if called by anyone other than whitelisted EOA contracts. + modifier onlyEOAContract() { + require(_isEOAContract(msg.sender), "Only callable by whitelisted EOA"); + _; + } + + /** + * @dev Returns true if the EOA contract code hash value is in the set. O(1). + * + * @param value EOA contract code hash to check + */ + function containsEOACodeHash( + bytes32 value + ) + public + view + returns (bool) + { + return s_codeHasheSet.contains(value); + } + + /** + * @dev Adds a EOA contract code hash value to the set. O(1). + * + * Returns true if the value was added to the set, that is if it was not already present. + * @param value EOA contract code hash to add + */ + function addEOACodeHash( + bytes32 value + ) + public + onlyOwner() + returns (bool) + { + return s_codeHasheSet.add(value); + } + + /** + * @dev Removes a EOA contract code hash value from the set. O(1). + * + * Returns true if the value was removed from the set, that is if it was present. + * @param value EOA contract code hash to remove + */ + function removeEOACodeHash( + bytes32 value + ) + public + onlyOwner() + returns (bool) + { + return s_codeHasheSet.remove(value); + } + + /** + * @dev Returns true if `account` is a whitelisted EOA contract. + * @param account Address to check + */ + function _isEOAContract( + address account + ) + internal + view + returns (bool) + { + bytes32 codehash; + // solhint-disable-next-line no-inline-assembly + assembly { codehash := extcodehash(account) } + return s_codeHasheSet.contains(codehash); + } +} diff --git a/contracts/v0.7/bridge/optimism/OVM_L1ERC20Gateway.sol b/contracts/v0.7/bridge/optimism/OVM_L1ERC20Gateway.sol new file mode 100644 index 0000000..c675b26 --- /dev/null +++ b/contracts/v0.7/bridge/optimism/OVM_L1ERC20Gateway.sol @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT +// @unsupported: ovm +pragma solidity >0.6.0 <0.8.0; +pragma experimental ABIEncoderV2; + +/* Interface Imports */ +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ERC677Receiver } from "../../../v0.6/token/ERC677Receiver.sol"; + +/* Library Imports */ +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; + +/* Contract Imports */ +import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol"; +import { Abs_L1TokenGateway } from "@eth-optimism/contracts/OVM/bridge/tokens/Abs_L1TokenGateway.sol"; + +/** + * @title OVM_L1ERC20Gateway + * @dev The L1 ERC20 Gateway is a contract which stores deposited L1 funds that are in use on L2. + * It synchronizes a corresponding L2 ERC20 Gateway, informing it of deposits, and listening to it + * for newly finalized withdrawals. + * + * NOTE: This contract extends Abs_L1TokenGateway, which is where we + * takes care of most of the initialization and the cross-chain logic. + * If you are looking to implement your own deposit/withdrawal contracts, you + * may also want to extend the abstract contract in a similar manner. + * + * Compiler used: solc + * Runtime target: EVM + */ +contract OVM_L1ERC20Gateway is ERC677Receiver, Initializable, Abs_L1TokenGateway { + // L1 token we are bridging to L2 + IERC20 public s_l1ERC20; + + /// @dev This contract lives behind a proxy, so the constructor parameters will go unused. + constructor() + Abs_L1TokenGateway( + address(0), // _l2DepositedToken + address(0) // _l1messenger + ) + public + {} + + /** + * @param l2ERC20Gateway L2 Gateway address on the chain being deposited into + * @param l1Messenger Cross-domain messenger used by this contract. + * @param l1ERC20 L1 ERC20 address this contract stores deposits for + */ + function initialize( + address l2ERC20Gateway, + address l1Messenger, + address l1ERC20 + ) + public + virtual + initializer() + { + __OVM_L1ERC20Gateway_init(l2ERC20Gateway, l1Messenger, l1ERC20); + } + + /** + * @param l2ERC20Gateway L2 Gateway address on the chain being deposited into + * @param l1Messenger Cross-domain messenger used by this contract. + * @param l1ERC20 L1 ERC20 address this contract stores deposits for + */ + function __OVM_L1ERC20Gateway_init( + address l2ERC20Gateway, + address l1Messenger, + address l1ERC20 + ) + internal + initializer() + { + // Init parent contracts + require(l2ERC20Gateway != address(0), "Init to zero address"); + require(l1Messenger != address(0), "Init to zero address"); + + l2DepositedToken = l2ERC20Gateway; + messenger = l1Messenger; + + __OVM_L1ERC20Gateway_init_unchained(l1ERC20); + } + + /** + * @param l1ERC20 L1 ERC20 address this contract stores deposits for + */ + function __OVM_L1ERC20Gateway_init_unchained( + address l1ERC20 + ) + internal + initializer() + { + require(l1ERC20 != address(0), "Init to zero address"); + s_l1ERC20 = IERC20(l1ERC20); + } + + /// @dev Modifier requiring the contract to be initialized + modifier onlyInitialized() { + require(address(l2DepositedToken) != address(0), "Contract not initialized"); + _; + } + + /// @dev Modifier requiring sender to be EOA + modifier onlyEOA(address acc) { + // Used to stop withdrawals to contracts (avoid accidentally lost tokens) + require(!Address.isContract(acc), "Account not EOA"); + _; + } + + /// @dev Returns L2 ERC20 Gateway address (AKA l2DepositedToken). + function l2ERC20Gateway() + public + view + returns (address) + { + // Default Optimism ERC20 bridge implemenation combines the L2 gateway and token + // into a single OVM_L2DepositedERC20 contract. From the perspective of L1 gateway, + // this should be just an implementation detail, so here we expose an address in a + // different more general name "l2ERC20Gateway". + return l2DepositedToken; + } + + /** + * @dev Hook on successful token transfer that initializes deposit + * @notice Avoids two step approve/transferFrom, only accessible by EOA sender via ERC677 transferAndCall. + * @inheritdoc ERC677Receiver + */ + function onTokenTransfer( + address _sender, + uint _value, + bytes memory /* _data */ + ) + external + override + onlyEOA(_sender) + { + require(msg.sender == address(s_l1ERC20), "onTokenTransfer sender not valid"); + _initiateDeposit(_sender, _sender, _value); + } + + /** + * @notice Only accessible by EOA sender. + * @inheritdoc Abs_L1TokenGateway + */ + function deposit( + uint _amount + ) + external + override + onlyEOA(msg.sender) + { + _initiateDeposit(msg.sender, msg.sender, _amount); + } + + /** + * @notice Recipient account must be EOA. + * @inheritdoc Abs_L1TokenGateway + */ + function depositTo( + address _to, + uint _amount + ) + external + override + onlyEOA(_to) + { + _initiateDeposit(msg.sender, _to, _amount); + } + + /** + * @dev deposit an amount of ERC20 to a recipients's balance on L2 + * WARNING: This is a potentially unsafe operation that could end up with lost tokens, + * if tokens are sent to a contract. Be careful! + * + * @param _to L2 address to credit the withdrawal to + * @param _amount Amount of the ERC20 to deposit + */ + function depositToUnsafe( + address _to, + uint _amount + ) + external + { + _initiateDeposit(msg.sender, _to, _amount); + } + + /** + * @dev When a deposit is initiated on L1, the L1 Gateway + * transfers the funds to itself for future withdrawals + * + * @param _from L1 address ERC20 is being deposited from + * @param _to L2 address that the ERC20 is being deposited to + * @param _amount Amount of ERC20 to send + */ + function _handleInitiateDeposit( + address _from, + address _to, + uint256 _amount + ) + internal + override + onlyInitialized() + { + // Funds already transfered via trasferAndCall (skipping) + if (msg.sender == address(s_l1ERC20)) return; + + // Hold on to the newly deposited funds (must be approved) + s_l1ERC20.transferFrom( + _from, + address(this), + _amount + ); + } + + /** + * @dev When a withdrawal is finalized on L1, the L1 Gateway + * transfers the funds to the withdrawer + * + * @param _to L1 address that the ERC20 is being withdrawn to + * @param _amount Amount of ERC20 to send + */ + function _handleFinalizeWithdrawal( + address _to, + uint _amount + ) + internal + override + onlyInitialized() + { + // Transfer withdrawn funds out to withdrawer + s_l1ERC20.transfer(_to, _amount); + } +} diff --git a/contracts/v0.7/bridge/optimism/OVM_L2ERC20Gateway.sol b/contracts/v0.7/bridge/optimism/OVM_L2ERC20Gateway.sol new file mode 100644 index 0000000..c22134f --- /dev/null +++ b/contracts/v0.7/bridge/optimism/OVM_L2ERC20Gateway.sol @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; +pragma experimental ABIEncoderV2; + +/* Interface Imports */ +import { IERC20Child } from "../token/IERC20Child.sol"; +import { ERC677Receiver } from "../../../v0.6/token/ERC677Receiver.sol"; + +/* Library Imports */ +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; + +/* Contract Imports */ +import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol"; +import { iOVM_L1TokenGateway } from "@eth-optimism/contracts/iOVM/bridge/tokens/iOVM_L1TokenGateway.sol"; +import { Abs_L2DepositedToken } from "@eth-optimism/contracts/OVM/bridge/tokens/Abs_L2DepositedToken.sol"; +import { OVM_EOACodeHashSet } from "./OVM_EOACodeHashSet.sol"; + +/** + * @title OVM_L2ERC20Gateway + * @dev The L2 Deposited LinkToken is an token implementation which represents L1 assets deposited into L2. + * This contract mints new tokens when it hears about deposits into the L1 token gateway. + * This contract also burns the tokens intended for withdrawal, informing the L1 gateway to release L1 funds. + * + * Compiler used: optimistic-solc + * Runtime target: OVM + */ +contract OVM_L2ERC20Gateway is ERC677Receiver, /* Initializable, */ OVM_EOACodeHashSet, Abs_L2DepositedToken { + // Bridged L2 token + IERC20Child public s_l2ERC20; + + /// @dev This contract lives behind a proxy, so the constructor parameters will go unused. + constructor() + Abs_L2DepositedToken( + address(0) // _l2CrossDomainMessenger + ) + public + {} + + /** + * @param l1ERC20Gateway L1 Gateway address on the chain being withdrawn into + * @param l2Messenger Cross-domain messenger used by this contract. + * @param l2ERC20 L2 ERC20 address this contract deposits for + */ + function initialize( + address l1ERC20Gateway, + address l2Messenger, + address l2ERC20 + ) + public + virtual + initializer() + { + __OVM_L2ERC20Gateway_init(l1ERC20Gateway, l2Messenger, l2ERC20); + } + + /** + * @param l1ERC20Gateway L1 Gateway address on the chain being withdrawn into + * @param l2Messenger Cross-domain messenger used by this contract. + * @param l2ERC20 L2 ERC20 address this contract deposits for + */ + function __OVM_L2ERC20Gateway_init( + address l1ERC20Gateway, + address l2Messenger, + address l2ERC20 + ) + internal + initializer() + { + __Context_init_unchained(); + __Ownable_init_unchained(); + + // Init parent contracts + require(l1ERC20Gateway != address(0), "Init to zero address"); + require(l2Messenger != address(0), "Init to zero address"); + // Abs_L2DepositedToken + init(iOVM_L1TokenGateway(l1ERC20Gateway)); + // OVM_CrossDomainEnabled + messenger = l2Messenger; + + __OVM_EOACodeHashSet_init_unchained(); + __OVM_L2ERC20Gateway_init_unchained(l2ERC20); + } + + /** + * @param l2ERC20 L2 ERC20 address this contract deposits for + */ + function __OVM_L2ERC20Gateway_init_unchained( + address l2ERC20 + ) + internal + initializer() + { + require(l2ERC20 != address(0), "Init to zero address"); + s_l2ERC20 = IERC20Child(l2ERC20); + } + + /// @dev Modifier requiring sender to be EOA + modifier onlyEOA(address acc) { + // Used to stop withdrawals to contracts (avoid accidentally lost tokens) + require(!Address.isContract(acc) || _isEOAContract(acc), "Account not EOA"); + _; + } + + /** + * @dev Hook on successful token transfer that initializes withdrawal + * @notice Avoids two step approve/transferFrom, only accessible by EOA sender via ERC677 transferAndCall. + * @inheritdoc ERC677Receiver + */ + function onTokenTransfer( + address _sender, + uint _value, + bytes memory /* _data */ + ) + external + override + onlyEOA(_sender) + { + require(msg.sender == address(s_l2ERC20), "onTokenTransfer sender not valid"); + _initiateWithdrawal(_sender, _value); + } + + /** + * @notice Only accessible by EOA sender. + * @inheritdoc Abs_L2DepositedToken + */ + function withdraw( + uint _amount + ) + external + override + onlyEOA(msg.sender) + { + _initiateWithdrawal(msg.sender, _amount); + } + + /** + * @notice Recipient account must be EOA. + * @inheritdoc Abs_L2DepositedToken + */ + function withdrawTo( + address _to, + uint _amount + ) + external + override + onlyEOA(_to) + { + _initiateWithdrawal(_to, _amount); + } + + /** + * @dev initiate a withdraw of some token to a recipient's account on L1 + * WARNING: This is a potentially unsafe operation that could end up with lost tokens, + * if tokens are sent to a contract. Be careful! + * + * @param _to L1 adress to credit the withdrawal to + * @param _amount Amount of the token to withdraw + */ + function withdrawToUnsafe( + address _to, + uint _amount + ) + external + { + _initiateWithdrawal(_to, _amount); + } + + /** + * @dev When a withdrawal is initiated, we burn the funds to prevent subsequent L2 usage. + * @inheritdoc Abs_L2DepositedToken + */ + function _handleInitiateWithdrawal( + address _to, + uint _amount + ) + internal + override + onlyInitialized() + { + // Check if funds already transfered via trasferAndCall (skipping) + if (msg.sender != address(s_l2ERC20)) { + // Take the newly deposited funds (must be approved) + s_l2ERC20.transferFrom( + msg.sender, + address(this), + _amount + ); + } + + // And withdraw them to L1 + s_l2ERC20.withdraw(_amount); + } + + /** + * @dev When a deposit is finalized, we credit the account on L2 with the same amount of tokens. + * @inheritdoc Abs_L2DepositedToken + */ + function _handleFinalizeDeposit( + address _to, + uint _amount + ) + internal + override + onlyInitialized() + { + s_l2ERC20.deposit(_to, _amount); + } +} diff --git a/contracts/v0.7/bridge/token/IERC20Child.sol b/contracts/v0.7/bridge/token/IERC20Child.sol new file mode 100644 index 0000000..27bcc67 --- /dev/null +++ b/contracts/v0.7/bridge/token/IERC20Child.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; + +/* Interface Imports */ +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/// @dev Interface of the child ERC20 token, for use on sidechains and L2 networks. +interface IERC20Child is IERC20 { + /** + * @notice called by bridge gateway when tokens are deposited on root chain + * Should handle deposits by minting the required amount for the recipient + * + * @param recipient an address for whom deposit is being done + * @param amount total amount to deposit/mint + */ + function deposit(address recipient, uint256 amount) external; + + /** + * @notice called by bridge gateway when tokens are withdrawn back to root chain + * @dev Should burn recipient's tokens. + * + * @param amount total amount to withdraw/burn + */ + function withdraw(uint256 amount) external; +} diff --git a/contracts/v0.7/bridge/token/LinkTokenChild.sol b/contracts/v0.7/bridge/token/LinkTokenChild.sol new file mode 100644 index 0000000..f5c2b79 --- /dev/null +++ b/contracts/v0.7/bridge/token/LinkTokenChild.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; + +/* Interface Imports */ +import { IERC20Child } from "./IERC20Child.sol"; + +/* Contract Imports */ +import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol"; +import { LinkToken } from "../../../v0.6/LinkToken.sol"; + +/// @dev Access controlled mintable & burnable LinkToken, for use on sidechains and L2 networks. +contract LinkTokenChild is IERC20Child, AccessControl, LinkToken { + + // Using this role the bridge gateway can deposit/withdraw (mint/burn) + bytes32 public constant BRIDGE_GATEWAY_ROLE = keccak256("BRIDGE_GATEWAY_ROLE"); + + /** + * @dev Overrides parent contract so no tokens are minted on deployment. + * @inheritdoc LinkToken + */ + function _onCreate() + internal + override + { + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + } + + /** + * @dev Modifier to check access by role. + * + * @param role the required role + */ + modifier onlyRole( + bytes32 role + ) { + require(hasRole(role, _msgSender()), "LinkTokenChild: missing role"); + _; + } + + /** + * @dev Only callable by account with BRIDGE_GATEWAY_ROLE + * @inheritdoc IERC20Child + */ + function deposit( + address recipient, + uint256 amount + ) + external + override + virtual + onlyRole(BRIDGE_GATEWAY_ROLE) + { + _mint(recipient, amount); + } + + /** + * @dev Only callable by account with BRIDGE_GATEWAY_ROLE + * @inheritdoc IERC20Child + */ + function withdraw( + uint256 amount + ) + external + override + virtual + onlyRole(BRIDGE_GATEWAY_ROLE) + { + _burn(_msgSender(), amount); + } +} diff --git a/contracts/v0.7/mocks/bridge/optimism/OVM_CrossDomainMessengerMock.sol b/contracts/v0.7/mocks/bridge/optimism/OVM_CrossDomainMessengerMock.sol new file mode 100644 index 0000000..0166681 --- /dev/null +++ b/contracts/v0.7/mocks/bridge/optimism/OVM_CrossDomainMessengerMock.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; + +/** + * @title OVM_CrossDomainMessengerMock + * + * Compiler used: optimistic-solc + * Runtime target: OVM + */ +contract OVM_CrossDomainMessengerMock { + + /** + * Sends a cross domain message to the target messenger. + * @param _target Target contract address. + * @param _message Message to send to the target. + * @param _gasLimit Gas limit for the provided message. + */ + function sendMessage( + address _target, + bytes memory _message, + uint32 _gasLimit + ) + public + { + // noop + } +} diff --git a/contracts/v0.7/vendor/@openzeppelin/proxy/ProxyAdmin.sol b/contracts/v0.7/vendor/@openzeppelin/proxy/ProxyAdmin.sol new file mode 100644 index 0000000..8dc9a67 --- /dev/null +++ b/contracts/v0.7/vendor/@openzeppelin/proxy/ProxyAdmin.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; + +import { ProxyAdmin as OZ_ProxyAdmin } from "@openzeppelin/contracts/proxy/ProxyAdmin.sol"; + +/** + * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. + * + * We force the toolchain to compile an external contract, by bringing in into our codebase like this. + * For more information see the parent OZ {ProxyAdmin} contract. + */ +contract ProxyAdmin is OZ_ProxyAdmin {} diff --git a/contracts/v0.7/vendor/@openzeppelin/proxy/TransparentUpgradeableProxy.sol b/contracts/v0.7/vendor/@openzeppelin/proxy/TransparentUpgradeableProxy.sol new file mode 100644 index 0000000..fb34d6a --- /dev/null +++ b/contracts/v0.7/vendor/@openzeppelin/proxy/TransparentUpgradeableProxy.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.6.0 <0.8.0; + +import { TransparentUpgradeableProxy as OZ_TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol"; + +/** + * @dev This contract implements a proxy that is upgradeable by an admin. + * + * We force the toolchain to compile an external contract, by bringing in into our codebase like this. + * For more information see the parent OZ {TransparentUpgradeableProxy} contract. + */ +contract TransparentUpgradeableProxy is OZ_TransparentUpgradeableProxy { + + /** + * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and + * optionally initialized with `_data` as explained in {UpgradeableProxy-constructor}. + */ + constructor( + address _logic, + address _admin, + bytes memory _data + ) + public + payable + OZ_TransparentUpgradeableProxy(_logic, _admin, _data) + {} +} diff --git a/env/.env.kovan b/env/.env.kovan new file mode 100644 index 0000000..340f2c9 --- /dev/null +++ b/env/.env.kovan @@ -0,0 +1,12 @@ +### KOVAN +# make sure this private key has Kovan ETH! +PRIVATE_KEY= +L1_WEB3_URL=https://kovan.infura.io/v3/API_KEY +L2_WEB3_URL=https://kovan.optimism.io + +# optional, will be deployed for us if unset +L1_ERC20_ADDRESS= +# optional, will be deployed for us if unset +L1_ERC20_GATEWAY_ADDRESS= +# optional, will be deployed for us if unset (and L1_ERC20_GATEWAY_ADDRESS unset) +L2_ERC20_ADDRESS= diff --git a/env/.env.local b/env/.env.local new file mode 100644 index 0000000..7b4dfec --- /dev/null +++ b/env/.env.local @@ -0,0 +1,11 @@ +### LOCAL (optimism-integration repo) +PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +L1_WEB3_URL=http://127.0.0.1:9545 +L2_WEB3_URL=http://127.0.0.1:8545 + +# optional, will be deployed for us if unset +L1_ERC20_ADDRESS= +# optional, will be deployed for us if unset +L1_ERC20_GATEWAY_ADDRESS= +# optional, will be deployed for us if unset (and L1_ERC20_GATEWAY_ADDRESS unset) +L2_ERC20_ADDRESS= diff --git a/hardhat.config.ts b/hardhat.config.ts index cfd3c58..9de9830 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,55 +1,75 @@ // hardhat.config.ts import { HardhatUserConfig, SolcConfig } from 'hardhat/types' -import { hardhat } from './src' - +import { task } from 'hardhat/config' +import { TASK_COMPILE } from 'hardhat/builtin-tasks/task-names' +import { hardhat, Networks, Versions } from './src' +// plugins import '@nomiclabs/hardhat-waffle' import '@typechain/hardhat' +import '@eth-optimism/hardhat-ovm' -const DEFAULT_VERSION = 'v0.6' +const DEFAULT_NETWORK = Networks.HARDHAT +const DEFAULT_VERSION = Versions.v0_6 -const optimizer = { - runs: 200, - enabled: true, -} +// Override compile task to add custom param +task(TASK_COMPILE) + .addOptionalParam('contracts', 'The contracts version to compile.', DEFAULT_VERSION) + .setAction(async (_args, _hre, runSuper) => runSuper(_args)) -const settings = { - optimizer, +const _settings = (runs: number) => ({ + optimizer: { + runs, + enabled: true, + }, metadata: { // To support Go code generation from build artifacts // we need to remove the metadata from the compiled bytecode. bytecodeHash: 'none', }, -} +}) -const versions: Record = { - 'v0.4': { version: '0.4.16', settings }, - 'v0.6': { version: '0.6.12', settings }, - 'v0.7': { version: '0.7.6', settings }, +const versions: Record = { + [Versions.v0_4]: { version: '0.4.16', settings: _settings(200) }, + [Versions.v0_6]: { version: '0.6.12', settings: _settings(200) }, + [Versions.v0_7]: { version: '0.7.6', settings: _settings(1_000_000) }, } // Require version exists -const versionLabel = process.env.VERSION || DEFAULT_VERSION -const compiler = versions[versionLabel] +const versionLabel = hardhat.argv.contracts || DEFAULT_VERSION +const versionDir = `v${versionLabel}` +const compiler = versions[versionLabel as Versions] if (!compiler) throw Error(`Compiler for ${versionLabel} could not be found!`) +// Setup networks +const networks: { [key: string]: any } = { + [Networks.OPTIMISM]: { + url: 'http://127.0.0.1:8545', + ovm: true, // ensures contracts will be compiled to OVM target. + }, +} +const targetNetwork = hardhat.argv.network || DEFAULT_NETWORK +const typesDir = networks[targetNetwork]?.ovm ? `types-ovm` : 'types' + const config: HardhatUserConfig = { + defaultNetwork: DEFAULT_NETWORK, + networks, paths: { - sources: `./contracts/${versionLabel}`, + sources: `./contracts/${versionDir}`, cache: './build/cache', artifacts: './build/artifacts', }, solidity: { compilers: Object.values(versions), overrides: { - ...hardhat.generateOverrides(`./contracts/${versionLabel}/**/*.sol`, {}, compiler), + ...hardhat.generateOverrides(`./contracts/${versionDir}/**/*.sol`, {}, compiler), }, }, typechain: { - outDir: `build/types/${versionLabel}`, + outDir: `./build/${typesDir}/${versionDir}`, target: 'ethers-v5', }, mocha: { - timeout: 10000, + timeout: 5000, }, } diff --git a/package.json b/package.json index 47d550c..55fba23 100644 --- a/package.json +++ b/package.json @@ -11,39 +11,59 @@ "build/**/*.js", "build/contracts/*", "build/artifacts/**/*.json", + "build/artifacts-ovm/**/*.json", "build/types/**/*.ts", + "build/types-ovm/**/*.ts", "contracts/*" ], "scripts": { + "prepack": "yarn setup", "clean": "tsc -b --clean tsconfig.json && rm -rf build/", - "setup": "yarn build:contracts", - "build:contracts": "yarn build:contracts:v0.4 && yarn build:contracts:v0.6", - "build:contracts:v0.4": "VERSION=v0.4 hardhat compile --show-stack-traces", - "build:contracts:v0.6": "VERSION=v0.6 hardhat compile --show-stack-traces", - "test": "hardhat test --show-stack-traces" + "setup": "yarn build:contracts && yarn build", + "lint": "echo \"Please set up linter\"", + "build": "tsc -p tsconfig.json", + "build:contracts": "yarn build:contracts:0.4 && yarn build:contracts:0.6 && yarn build:contracts:0.7 && yarn build:contracts:0.7:ovm", + "build:contracts:0.4": "hardhat compile --contracts 0.4 --show-stack-traces", + "build:contracts:0.6": "hardhat compile --contracts 0.6 --show-stack-traces", + "build:contracts:0.7": "hardhat compile --contracts 0.7 --show-stack-traces", + "build:contracts:0.7:ovm": "hardhat compile --contracts 0.7 --network optimism --show-stack-traces", + "test": "hardhat test --no-compile --show-stack-traces", + "script:oe:up": "./node_modules/@chainlink/optimism-utils/scripts/run-ci.sh", + "script:oe:down": "cd optimism/ops && docker-compose down -v", + "script:oe:clean": "cd optimism/ops && docker-compose down -v --remove-orphan --rmi all", + "script:oe:deposit-withdraw": "ts-node scripts/deposit-withdraw.ts" }, "dependencies": { "@chainlink/contracts": "^0.1.6", - "@openzeppelin/contracts": "^3.4.0" + "@chainlink/optimism-utils": "https://github.com/smartcontractkit/optimism-utils.git", + "@eth-optimism/contracts": "^0.2.7", + "@ethersproject/bignumber": "^5.1.1", + "@ethersproject/units": "^5.1.0", + "@openzeppelin/contracts": "3.4.0", + "@openzeppelin/contracts-upgradeable": "3.4.0", + "dotenv": "^8.2.0", + "ethers": "^5.1.3", + "glob": "^7.1.6", + "hardhat": "^2.2.0", + "lodash": "^4.17.21", + "yargs": "^16.2.0" }, "devDependencies": { + "@eth-optimism/hardhat-ovm": "^0.0.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-waffle": "^2.0.1", "@typechain/ethers-v5": "^6.0.5", "@typechain/hardhat": "^1.0.1", "@types/chai": "^4.2.16", "@types/glob": "^7.1.3", + "@types/lodash": "^4.14.168", "@types/mocha": "^8.2.2", "@types/node": "^14.14.37", - "@types/semver": "^7.3.4", + "@types/yargs": "^16.0.1", "chai": "^4.3.4", "ethereum-waffle": "^3.3.0", - "ethers": "^5.1.0", - "glob": "^7.1.6", - "hardhat": "^2.1.2", "moment": "^2.15.2", "prettier": "^2.2.1", - "semver": "^7.3.5", "ts-generator": "^0.1.1", "ts-node": "^9.1.1", "typechain": "^4.0.3", diff --git a/scripts/deposit-withdraw.ts b/scripts/deposit-withdraw.ts new file mode 100644 index 0000000..491acdc --- /dev/null +++ b/scripts/deposit-withdraw.ts @@ -0,0 +1,223 @@ +import { Wallet, Contract } from 'ethers' +import { BigNumberish } from '@ethersproject/bignumber' +import { parseEther } from '@ethersproject/units' +import { Direction, waitForXDomainTransaction } from '@chainlink/optimism-utils/dist/watcher-utils' +import { hardhat, getContractFactory, deploy, optimism, Targets, Versions } from '../src' + +export type ConfiguredBridge = { + l1ERC20: Contract + l1ERC20Gateway: Contract + l2ERC20: Contract + l2ERC20Gateway: Contract +} + +export const setupOrRetrieveBridge = async ( + l1Wallet: Wallet, + l2Wallet: Wallet, + l1MessengerAddr: string, + l2MessengerAddr: string, + l1ERC20Addr?: string, + l2ERC20Addr?: string, + l1ERC20GatewayAddr?: string, +): Promise => { + // Deploy or retrieve L1 ERC20 + let l1ERC20: Contract + const l1ERC20__Factory = getContractFactory('LinkToken', l1Wallet, Versions.v0_6, Targets.EVM) + if (!l1ERC20Addr) { + console.log('No L1 ERC20 specified - deploying a new test L1 ERC20 (LinkToken).') + l1ERC20 = await deploy(l1ERC20__Factory, 'LinkToken (L1 ERC20)') + } else { + console.log('Connecting to an existing L1 ERC20 at:', l1ERC20Addr) + l1ERC20 = l1ERC20__Factory.attach(l1ERC20Addr) + } + + // Deploy or retrieve L2 ERC20 + let l2ERC20: Contract + const l2ERC20_Factory = getContractFactory('LinkTokenChild', l2Wallet, Versions.v0_7, Targets.OVM) + if (!l2ERC20Addr) { + console.log('No L2 ERC20 specified - deploying a new test L2 ERC20 (LinkTokenChild).') + l2ERC20 = await deploy(l2ERC20_Factory, 'LinkTokenChild (L2 ERC20)') + } else { + console.log('Connecting to an existing L2 ERC20 at:', l2ERC20Addr) + l2ERC20 = l2ERC20_Factory.attach(l2ERC20Addr) + } + + // Get the required gateway role + const gatewayRole = await l2ERC20.BRIDGE_GATEWAY_ROLE() + + let l1ERC20Gateway: Contract + let l2ERC20Gateway: Contract + if (!l1ERC20GatewayAddr) { + console.log('No L1 gateway specified, deploying a new L1-L2 bridge...') + ;({ l1ERC20Gateway, l2ERC20Gateway } = await optimism.deployGateways( + l1Wallet, + l2Wallet, + l1ERC20.address, + l2ERC20.address, + l1MessengerAddr, + l2MessengerAddr, + )) + // Grant the required gateway role + await optimism.grantRole(l2ERC20, l2ERC20Gateway) + } else { + // Use the specified OVM_L1ERC20Gateway address to construct L1-L2 bridge + l1ERC20Gateway = getContractFactory( + 'OVM_L1ERC20Gateway', + l1Wallet, + Versions.v0_7, + Targets.EVM, + ).attach(l1ERC20GatewayAddr) + + const l2ERC20GatewayAddr = await l1ERC20Gateway.l2ERC20Gateway() + l2ERC20Gateway = getContractFactory( + 'OVM_L2ERC20Gateway', + l2Wallet, + Versions.v0_7, + Targets.OVM, + ).attach(l2ERC20GatewayAddr) + // TODO: check l2ERC20.address matches + + // Check role + const hasGatewayRole = await l2ERC20.hasRole(gatewayRole, l2ERC20Gateway.address) + if (!hasGatewayRole) { + throw Error(`OVM_L2ERC20Gateway should have l2ERC20.BRIDGE_GATEWAY_ROLE role`) + } + } + + // Configured bridge + const bridge = { + l1ERC20, + l1ERC20Gateway, + l2ERC20, + l2ERC20Gateway, + } + logBridge(bridge) + return bridge +} + +export type CheckBalances = ( + l1Wallet: Wallet, + l1ERC20: Contract, + l2Wallet: Wallet, + l2ERC20: Contract, +) => Promise + +export const depositAndWithdraw = async ( + oe: optimism.env.OptimismEnv, + checkBalances: CheckBalances, + amount: BigNumberish = 1, + transferAndCall: boolean = false, +) => { + // Grab existing addresses if specified + const l1ERC20Addr = process.env.L1_ERC20_ADDRESS + const l2ERC20Addr = process.env.L2_ERC20_ADDRESS + const l1ERC20GatewayAddr = process.env.L1_ERC20_GATEWAY_ADDRESS + + const bridge = await setupOrRetrieveBridge( + oe.l1Wallet, + oe.l2Wallet, + oe.l1Messenger.address, + oe.l2Messenger.address, + l1ERC20Addr, + l2ERC20Addr, + l1ERC20GatewayAddr, + ) + + const _approve = transferAndCall + ? () => {} // no approve when using transferAndCall + : async (_token: Contract, _spenderAddr: string, _amount: BigNumberish) => { + console.log(`Approving spender: ${_spenderAddr} for ${_amount}`) + const approveTx = await _token.approve(_spenderAddr, _amount) + await approveTx.wait() + console.log('Approved: https://kovan.etherscan.io/tx/' + approveTx.hash) + console.log() + } + + const _checkBalances = () => + checkBalances(oe.l1Wallet, bridge.l1ERC20, oe.l2Wallet, bridge.l2ERC20) + + const { watcher } = oe + + await _checkBalances() + + // Approve L1 Gateway + await _approve(bridge.l1ERC20, bridge.l1ERC20Gateway.address, amount) + + // Deposit to L1 Gateway + console.log('Depositing into L1 gateway contract...') + const depositTx = transferAndCall + ? bridge.l1ERC20.transferAndCall(bridge.l1ERC20Gateway.address, amount, Buffer.from('')) + : bridge.l1ERC20Gateway.deposit(amount) + const receiptsDepositTx = await waitForXDomainTransaction(watcher, depositTx, Direction.L1ToL2) + console.log('Deposited: https://kovan.etherscan.io/tx/' + receiptsDepositTx.tx.hash) + console.log('Completed Deposit! L2 tx hash:', receiptsDepositTx.remoteTx.hash) + + await _checkBalances() + + // Approve L2 Gateway + await _approve(bridge.l2ERC20, bridge.l2ERC20Gateway.address, amount) + + // Withdraw from L2 Gateway + console.log('Withdrawing from L2 gateway contract...') + const withdrawTx = transferAndCall + ? bridge.l2ERC20.transferAndCall(bridge.l2ERC20Gateway.address, amount, Buffer.from('')) + : bridge.l2ERC20Gateway.withdraw(amount) + const receiptsWithdrawTx = await waitForXDomainTransaction(watcher, withdrawTx, Direction.L2ToL1) + console.log('Withdrawal tx hash:' + receiptsWithdrawTx.tx.hash) + console.log('Completed Withdrawal! L1 tx hash:', receiptsWithdrawTx.remoteTx.hash) + + await _checkBalances() +} + +const logBalances: CheckBalances = async (l1Wallet, l1ERC20, l2Wallet, l2ERC20) => { + console.log() + console.log('Checking balances: ') + console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~') + if (l1ERC20) { + const l1Balance = await l1ERC20.balanceOf(l1Wallet.address) + console.log('L1 balance of', l1Wallet.address, 'is', l1Balance.toString()) + } else { + console.log('L1 ERC20 NOT configured') + } + if (l2ERC20) { + const l2Balance = await l2ERC20.balanceOf(l2Wallet.address) + console.log('L2 balance of', l2Wallet.address, 'is', l2Balance.toString()) + } else { + console.log('L2 ERC20 NOT configured') + } + console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~') + console.log() +} + +const logBridge = async (bridge: ConfiguredBridge) => { + console.log() + console.log('Full L1-L2 configured bridge: ') + console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~') + console.log('L1 ERC20: ', bridge.l1ERC20.address) + console.log('L1 ERC20 Gateway: ', bridge.l1ERC20Gateway.address) + console.log('L2 ERC20: ', bridge.l2ERC20.address) + console.log('L2 ERC20 Gateway: ', bridge.l2ERC20Gateway.address) + console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~') + console.log() +} + +const _run = async () => { + // Load CLI arguments + const { argv } = hardhat.yargs + .env(false) + .string('network') + .number('amount') + .boolean('transferAndCall') + // Load the configuration from environment + const targetNetwork = argv.network || 'local' + const oe = await optimism.loadEnv(targetNetwork) + // Fund L2 wallet + await oe.depositL2(parseEther('1') as BigNumberish) + // Start scripts + await depositAndWithdraw(oe, logBalances, argv.amount || 1, argv.transferAndCall) +} + +if (require.main === module) { + console.log('Running depositAndWithdraw script...') + _run().catch(console.error).finally(process.exit) +} diff --git a/src/contract-defs.ts b/src/contract-defs.ts index 7890e1a..1f328ab 100644 --- a/src/contract-defs.ts +++ b/src/contract-defs.ts @@ -1,32 +1,102 @@ import * as path from 'path' import * as glob from 'glob' -import { ethers, ContractFactory, Signer } from 'ethers' +import { uniqBy } from 'lodash' +import { ethers, ContractFactory, Signer, Contract } from 'ethers' import { Interface } from 'ethers/lib/utils' +import { Targets, Versions } from '.' -export const getContractDefinition = (name: string, version?: string): any => { +export const getContractDefinition = ( + name: string, + version?: Versions, + target: Targets = Targets.EVM, +): any => { const match = glob.sync( - path.resolve(__dirname, `../build/artifacts/contracts${version ? `/${version}` : ''}`) + + path.resolve(__dirname, '../build') + + `/artifacts${target ? `-${target}` : ''}` + + `/contracts${version ? `/v${version}` : ''}` + `/**/${name}.json`, ) - if (match.length > 0) { - return require(match[0]) - } else { - throw new Error(`Unable to find artifact for contract: ${name}`) - } + if (match.length === 0) throw new Error(`Unable to find artifact for contract: ${name}`) + + // We return only one match for now + return require(match[0]) } -export const getContractInterface = (name: string, version?: string): Interface => { - const definition = getContractDefinition(name, version) +export const getContractInterface = ( + name: string, + version?: Versions, + target: Targets = Targets.EVM, +): Interface => { + const definition = getContractDefinition(name, version, target) return new ethers.utils.Interface(definition.abi) } export const getContractFactory = ( name: string, signer?: Signer, - version?: string, + version?: Versions, + target: Targets = Targets.EVM, ): ContractFactory => { - const definition = getContractDefinition(name, version) - const contractInterface = getContractInterface(name, version) + const definition = getContractDefinition(name, version, target) + const contractInterface = getContractInterface(name, version, target) return new ContractFactory(contractInterface, definition.bytecode, signer) } + +const CONTRACT_PROXY = 'TransparentUpgradeableProxy' +const CONTRACT_PROXY_ADMIN = 'ProxyAdmin' + +export const deployProxy = async ( + signer: Signer, + target: Targets = Targets.EVM, + logic: Contract, + admin: string | undefined = undefined, + data: Buffer = Buffer.from(''), +) => { + console.log() + if (!admin) { + console.log('Admin not specified, deploying ProxyAdmin helper contract...') + const proxyAdmin = await deploy( + getContractFactory(CONTRACT_PROXY_ADMIN, signer, Versions.v0_7, target), + CONTRACT_PROXY_ADMIN, + ) + admin = proxyAdmin.address + } + + const proxyFactory = getContractFactory(CONTRACT_PROXY, signer, Versions.v0_7, target) + // Merge proxy + logic ABI + const abi = uniqBy([...proxyFactory.interface.fragments, ...logic.interface.fragments], 'name') + + const payload = [logic.address, admin, data] + return { + admin, + proxy: await deploy( + new ContractFactory(abi, proxyFactory.bytecode, signer), + CONTRACT_PROXY, + payload, + ), + } +} + +export const deploy = async ( + factory: ContractFactory, + name: string, + payload: any[] = [], +): Promise => { + const contract = await factory.deploy(...payload) + await contract.deployTransaction.wait() + await assertDeployed(contract) + console.log(`${contract.address} - '${name}' deployed with payload:`, payload) + return contract +} + +// To assert if contract is successfully deployed on OVM, we need to check +// if there is code for reported contract address. This check is necessary +// because Optimism Sequencer doesn't flag failed deployments as a failure. +export const assertDeployed = async (contract: Contract) => { + await contract.deployed() + + const code = await contract.provider.getCode(contract.address) + if (code && code.length > 2) return + throw Error(`Error: Deployment unsuccessful - no code at ${contract.address}`) +} diff --git a/src/hardhat/index.ts b/src/hardhat/index.ts index e2fbe9b..42c1e5a 100644 --- a/src/hardhat/index.ts +++ b/src/hardhat/index.ts @@ -1,6 +1,15 @@ import * as glob from 'glob' import { SolcConfig } from 'hardhat/types' +import _yargs from 'yargs/yargs' +import { hideBin } from 'yargs/helpers' +// Parse CLI arguments +export const yargs = _yargs(hideBin(process.argv)) + +// Load defult CLI arguments +export const { argv } = yargs.env(false).string('contracts').string('network') + +// Glob files matching the pattern and generate Hardhat overrides for them export const generateOverrides = ( pattern: string, options = {}, @@ -10,6 +19,6 @@ export const generateOverrides = ( const files = glob.sync(pattern, options) console.log('Generating Hardhat overrides for: ') console.dir({ files, compiler }, { depth: null, colors: true }) - files.forEach(f => (overrides[f] = compiler)) + files.forEach((f) => (overrides[f] = compiler)) return overrides } diff --git a/src/index.ts b/src/index.ts index faeb7b6..c8ed70a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,20 @@ export * as hardhat from './hardhat' +export * as optimism from './optimism' export * from './contract-defs' + +export const enum Versions { + v0_4 = '0.4', + v0_6 = '0.6', + v0_7 = '0.7', +} + +export const enum Targets { + EVM = '', // default target + OVM = 'ovm', +} + +export const enum Networks { + HARDHAT = 'hardhat', + OPTIMISM = 'optimism', // AKA 'hardhat-optimism' + KOVAN_OPTIMISM = 'kovan-optimism', +} diff --git a/src/optimism/index.ts b/src/optimism/index.ts new file mode 100644 index 0000000..f8ebe90 --- /dev/null +++ b/src/optimism/index.ts @@ -0,0 +1,115 @@ +import * as dotenv from 'dotenv' +import * as optimism from '@chainlink/optimism-utils' +import { Wallet, Contract, providers, Signer, utils } from 'ethers' +import { getContractFactory, Targets, Versions } from '../' +import { deploy, deployProxy } from '../contract-defs' + +export * from '@chainlink/optimism-utils' + +export const loadEnv = async (envName: string = 'local'): Promise => { + // Load env configuration by name + dotenv.config({ path: __dirname + `/../../env/.env.${envName}` }) + + // Predefined AddressManager addresses + const addressManager: { [key: string]: string } = { + local: optimism.utils.LOCAL_ADDRESS_MANAGER_ADDR, + kovan: optimism.utils.KOVAN_ADDRESS_MANAGER_ADDR, + mainnet: optimism.utils.MAINNET_ADDRESS_MANAGER_ADDR, + } + + const addressManagerAddr = process.env.ADDRESS_MANAGER_ADDR || addressManager[envName] + if (!addressManagerAddr) throw Error(`Unknown AddressManager for network: ${envName}`) + + const l1Provider = new providers.JsonRpcProvider(process.env.L1_WEB3_URL) + const l2Provider = new providers.JsonRpcProvider(process.env.L2_WEB3_URL) + + l1Provider.pollingInterval = 10 + l2Provider.pollingInterval = 10 + + // Grab wallets for both chains + const l1Wallet = new Wallet(process.env.PRIVATE_KEY!, l1Provider) + const l2Wallet = l1Wallet.connect(l2Provider) + + return await optimism.env.OptimismEnv.new(addressManagerAddr, l1Wallet, l2Wallet) +} + +// TODO: Fix ERROR { "reason":"cannot estimate gas; transaction may fail or may require manual gas limit","code":"UNPREDICTABLE_GAS_LIMIT" } +export const TX_OVERRIDES_OE_BUG: any = { + gasPrice: utils.parseUnits('1', 'gwei'), + gasLimit: 2_000_000, +} + +export const deployGateways = async ( + l1Wallet: Wallet, + l2Wallet: Wallet, + l1ERC20Address: string, + l2ERC20Address: string, + l1MessengerAddress: string, + l2MessengerAddress: string, + isProxyDeployment = true, +): Promise<{ + l1ERC20Gateway: Contract + l2ERC20Gateway: Contract +}> => { + // Deploy L2 ERC20 Gateway + const l2ERC20Gateway = await deployL2ERC20Gateway(l2Wallet, isProxyDeployment) + + // Deploy & Init L1 ERC20 Gateway + const l1ERC20Gateway = await deployL1ERC20Gateway(l1Wallet, isProxyDeployment) + + const l1InitPayload = [l2ERC20Gateway.address, l1MessengerAddress, l1ERC20Address] + const l1InitTx = await l1ERC20Gateway.initialize(...l1InitPayload) + await l1InitTx.wait() + console.log('OVM_L1ERC20Gateway initialized with:', l1InitPayload) + + // Init L2 ERC20 Gateway + const l2InitPayload = [l1ERC20Gateway.address, l2MessengerAddress, l2ERC20Address] + const l2InitTx = await l2ERC20Gateway.initialize(...l2InitPayload) + await l2InitTx.wait() + console.log('OVM_L2ERC20Gateway initialized with:', l2InitPayload) + + return { + l1ERC20Gateway, + l2ERC20Gateway, + } +} + +export const grantRole = async (l2ERC20: Contract, l2ERC20Gateway: Contract) => { + const message = `Adding LinkTokenChild.BRIDGE_GATEWAY_ROLE to OVM_L2ERC20Gateway at: ${l2ERC20Gateway.address}` + console.log(message) + // Get the required gateway role + const gatewayRole = await l2ERC20.BRIDGE_GATEWAY_ROLE() + const grantRoleTx = await l2ERC20.grantRole(gatewayRole, l2ERC20Gateway.address) + await grantRoleTx.wait() +} + +export const deployL1ERC20Gateway = async (l1Signer: Signer, proxy: boolean = false) => { + // Deploy L1 ERC20 Gateway + const l1ERC20Gateway = await deploy( + getContractFactory('OVM_L1ERC20Gateway', l1Signer, Versions.v0_7, Targets.EVM), + 'OVM_L1ERC20Gateway', + ) + + if (!proxy) return l1ERC20Gateway + + // Deploy L2 ERC20 Gateway Proxy + const logic = l1ERC20Gateway + return (await deployProxy(l1Signer, Targets.EVM, logic)).proxy +} + +export const deployL2ERC20Gateway = async ( + l2Signer: Signer, + isProxyDeployment: boolean = false, +) => { + // Deploy L2 ERC20 Gateway + const l2ERC20Gateway = await deploy( + getContractFactory('OVM_L2ERC20Gateway', l2Signer, Versions.v0_7, Targets.OVM), + 'OVM_L2ERC20Gateway', + ) + + if (!isProxyDeployment) return l2ERC20Gateway + + // Deploy L2 ERC20 Gateway Proxy + const logic = l2ERC20Gateway + return (await deployProxy(l2Signer, Targets.OVM, logic)).proxy +} diff --git a/test/behavior/token/BasicToken.ts b/test/behavior/token/BasicToken.ts index 1287d62..3f2e15a 100644 --- a/test/behavior/token/BasicToken.ts +++ b/test/behavior/token/BasicToken.ts @@ -19,10 +19,8 @@ export const shouldBehaveLikeBasicToken = ( let token: Contract beforeEach(async () => { - token = await getContractFactory('BasicTokenMock', defaultAccount).deploy( - defaultAccount.address, - 100, - ) + const factory = getContractFactory('BasicTokenMock', defaultAccount) + token = await factory.deploy(defaultAccount.address, 100) }) it('should return the correct totalSupply after construction', async () => { @@ -41,7 +39,7 @@ export const shouldBehaveLikeBasicToken = ( expect(secondAccountBalance).to.equal(100) }) - it('should throw an error when trying to transfer more than balance', async function() { + it('should throw an error when trying to transfer more than balance', async function () { await expect( token.connect(defaultAccount).transfer(personas.Carol.address, 101), ).to.be.revertedWith(getReasonStr('ERC20: transfer amount exceeds balance')) diff --git a/test/behavior/token/StandardToken.ts b/test/behavior/token/StandardToken.ts index 2c30b99..aa2ad15 100644 --- a/test/behavior/token/StandardToken.ts +++ b/test/behavior/token/StandardToken.ts @@ -19,10 +19,8 @@ export const shouldBehaveLikeStandardToken = ( let token: Contract beforeEach(async () => { - token = await getContractFactory('StandardTokenMock', defaultAccount).deploy( - personas.Carol.address, - 100, - ) + const factory = getContractFactory('StandardTokenMock', defaultAccount) + token = await factory.deploy(personas.Carol.address, 100) }) it('should return the correct allowance amount after approval', async () => { diff --git a/test/helpers.ts b/test/helpers/index.ts similarity index 50% rename from test/helpers.ts rename to test/helpers/index.ts index 7e93d19..d562041 100644 --- a/test/helpers.ts +++ b/test/helpers/index.ts @@ -1,5 +1,18 @@ import { ethers } from 'ethers' import { assert } from 'chai' +import { hardhat, Networks, Versions } from '../../src' + +export const describes = { + // Only run if Hardhat unit test + HH: !hardhat.argv.network || hardhat.argv.network === Networks.HARDHAT ? describe : describe.skip, + // Only run if OE integration test + OE: hardhat.argv.network === Networks.OPTIMISM ? describe : describe.skip, +} + +export const revertShim = (v?: Versions) => + v && v === Versions.v0_4 // reason string not supported on versions <= 0.4 + ? (_: string) => REVERT_REASON_EMPTY + : (reason: string) => reason export const REVERT_REASON_EMPTY = 'Transaction reverted without a reason' @@ -17,11 +30,10 @@ export const encodeBytes = (bytes: string) => { return length + padded } -export const functionID = (fnSignature: string) => - ethers.utils - .keccak256(ethers.utils.toUtf8Bytes(fnSignature)) - .slice(2) - .slice(0, 8) +export const functionID = (fnSignature: string) => { + const { keccak256, toUtf8Bytes } = ethers.utils + return keccak256(toUtf8Bytes(fnSignature)).slice(2).slice(0, 8) +} /** * Check that a contract's abi exposes the expected interface. @@ -50,3 +62,34 @@ export function publicAbi( assert.isAtLeast(index, 0, `#${method} is expected to be public`) } } + +/** + * Check that an evm transaction fails + * + * @param action The asynchronous action to execute, which should cause an evm revert. + */ +export async function txRevert(action: (() => Promise) | Promise) { + try { + if (typeof action === 'function') { + await action() + } else { + await action + } + } catch (e) { + assert(e.message, 'Expected an error to contain a message') + + const ERROR_MESSAGES = ['transaction failed'] + const hasErrored = ERROR_MESSAGES.some((msg) => e.message.includes(msg)) + + assert( + hasErrored, + `expected following error message to include ${ERROR_MESSAGES.join(' or ')}. Got: "${ + e.message + }"`, + ) + return + } + + const err = undefined + assert.exists(err, 'Expected an error to be raised') +} diff --git a/test/v0.4/ERC677Token.test.ts b/test/v0.4/ERC677Token.test.ts index 8649e59..356ec27 100644 --- a/test/v0.4/ERC677Token.test.ts +++ b/test/v0.4/ERC677Token.test.ts @@ -1,14 +1,11 @@ import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../src' +import { getContractFactory, Versions } from '../../src' import { shouldBehaveLikeERC677Token } from '../behavior/ERC677Token' -import { REVERT_REASON_EMPTY } from '../helpers' +import * as h from '../helpers' -const VERSION = 'v0.4' - -describe(`ERC677Token ${VERSION}`, () => { +h.describes.HH(`ERC677Token ${Versions.v0_4}`, () => { const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(name, signer, VERSION) - const _getReasonStr = (_: string) => REVERT_REASON_EMPTY + getContractFactory(name, signer, Versions.v0_4) - shouldBehaveLikeERC677Token(_getContractFactory, _getReasonStr) + shouldBehaveLikeERC677Token(_getContractFactory, h.revertShim(Versions.v0_4)) }) diff --git a/test/v0.4/LinkToken.test.ts b/test/v0.4/LinkToken.test.ts index e00e8cf..c80e2fd 100644 --- a/test/v0.4/LinkToken.test.ts +++ b/test/v0.4/LinkToken.test.ts @@ -1,17 +1,15 @@ import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../src' +import { getContractFactory, Versions } from '../../src' import { shouldBehaveLikeLinkToken } from '../behavior/LinkToken' -import { REVERT_REASON_EMPTY } from '../helpers' +import * as h from '../helpers' -const VERSION = 'v0.4' const v4_EXTRA_PUBLIC_ABI: string[] = [] -describe(`LinkToken ${VERSION}`, () => { +h.describes.HH(`LinkToken ${Versions.v0_4}`, () => { const overrides: Record = { Token677: 'LinkToken' } const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(overrides[name] || name, signer, VERSION) + getContractFactory(overrides[name] || name, signer, Versions.v0_4) - const _getReasonStr = (_: string) => REVERT_REASON_EMPTY - shouldBehaveLikeLinkToken(_getContractFactory, _getReasonStr, v4_EXTRA_PUBLIC_ABI) + shouldBehaveLikeLinkToken(_getContractFactory, h.revertShim(Versions.v0_4), v4_EXTRA_PUBLIC_ABI) }) diff --git a/test/v0.4/token/BasicToken.test.ts b/test/v0.4/token/BasicToken.test.ts index bed675a..c014681 100644 --- a/test/v0.4/token/BasicToken.test.ts +++ b/test/v0.4/token/BasicToken.test.ts @@ -1,15 +1,12 @@ import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../../src' +import { getContractFactory, Versions } from '../../../src' import { shouldBehaveLikeBasicToken } from '../../behavior/token/BasicToken' -import { REVERT_REASON_EMPTY } from '../../helpers' +import * as h from '../../helpers' -const VERSION = 'v0.4' - -describe(`BasicToken ${VERSION}`, () => { +h.describes.HH(`BasicToken ${Versions.v0_4}`, () => { const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(name, signer, VERSION) - const _getReasonStr = (_: string) => REVERT_REASON_EMPTY + getContractFactory(name, signer, Versions.v0_4) - shouldBehaveLikeBasicToken(_getContractFactory, _getReasonStr) + shouldBehaveLikeBasicToken(_getContractFactory, h.revertShim(Versions.v0_4)) }) diff --git a/test/v0.4/token/StandardToken.test.ts b/test/v0.4/token/StandardToken.test.ts index 79640bb..8184f5b 100644 --- a/test/v0.4/token/StandardToken.test.ts +++ b/test/v0.4/token/StandardToken.test.ts @@ -1,18 +1,15 @@ import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../../src' +import { getContractFactory, Versions } from '../../../src' import { shouldBehaveLikeBasicToken } from '../../behavior/token/BasicToken' import { shouldBehaveLikeStandardToken } from '../../behavior/token/StandardToken' -import { REVERT_REASON_EMPTY } from '../../helpers' +import * as h from '../../helpers' -const VERSION = 'v0.4' - -describe(`StandardToken ${VERSION}`, () => { +h.describes.HH(`StandardToken ${Versions.v0_4}`, () => { const overrides: Record = { BasicTokenMock: 'StandardTokenMock' } const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(overrides[name] || name, signer, VERSION) - const _getReasonStr = (_: string) => REVERT_REASON_EMPTY + getContractFactory(overrides[name] || name, signer, Versions.v0_4) - shouldBehaveLikeBasicToken(_getContractFactory, _getReasonStr) - shouldBehaveLikeStandardToken(_getContractFactory, _getReasonStr) + shouldBehaveLikeBasicToken(_getContractFactory, h.revertShim(Versions.v0_4)) + shouldBehaveLikeStandardToken(_getContractFactory, h.revertShim(Versions.v0_4)) }) diff --git a/test/v0.6/ERC677Token.test.ts b/test/v0.6/ERC677Token.test.ts index de9b233..9e1ea4d 100644 --- a/test/v0.6/ERC677Token.test.ts +++ b/test/v0.6/ERC677Token.test.ts @@ -2,16 +2,14 @@ import { ethers } from 'ethers' ethers.utils.Logger.setLogLevel(ethers.utils.Logger.levels.ERROR) import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../src' +import { getContractFactory, Versions } from '../../src' import { shouldBehaveLikeERC677Token } from '../behavior/ERC677Token' +import * as h from '../helpers' -const VERSION = 'v0.6' - -describe(`ERC677Token ${VERSION}`, () => { +h.describes.HH(`ERC677Token ${Versions.v0_6}`, () => { const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(name, signer, VERSION) - const _getReasonStr = (reason: string) => reason + getContractFactory(name, signer, Versions.v0_6) - shouldBehaveLikeERC677Token(_getContractFactory, _getReasonStr) + shouldBehaveLikeERC677Token(_getContractFactory, h.revertShim()) }) diff --git a/test/v0.6/LinkToken.test.ts b/test/v0.6/LinkToken.test.ts index 97d3156..e3798d3 100644 --- a/test/v0.6/LinkToken.test.ts +++ b/test/v0.6/LinkToken.test.ts @@ -2,18 +2,17 @@ import { ethers } from 'ethers' ethers.utils.Logger.setLogLevel(ethers.utils.Logger.levels.ERROR) import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../src' +import { getContractFactory, Versions } from '../../src' import { shouldBehaveLikeLinkToken } from '../behavior/LinkToken' +import * as h from '../helpers' -const VERSION = 'v0.6' const v6_EXTRA_PUBLIC_ABI = ['decreaseAllowance', 'increaseAllowance'] -describe(`LinkToken ${VERSION}`, () => { +h.describes.HH(`LinkToken ${Versions.v0_6}`, () => { const overrides: Record = { Token677: 'LinkToken' } const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(overrides[name] || name, signer, VERSION) + getContractFactory(overrides[name] || name, signer, Versions.v0_6) - const _getReasonStr = (reason: string) => reason - shouldBehaveLikeLinkToken(_getContractFactory, _getReasonStr, v6_EXTRA_PUBLIC_ABI) + shouldBehaveLikeLinkToken(_getContractFactory, h.revertShim(), v6_EXTRA_PUBLIC_ABI) }) diff --git a/test/v0.6/PegSwap.test.ts b/test/v0.6/PegSwap.test.ts index 8366ef4..593610b 100644 --- a/test/v0.6/PegSwap.test.ts +++ b/test/v0.6/PegSwap.test.ts @@ -9,7 +9,7 @@ import { StandardTokenMock__factory } from '../../build/types/v0.6/factories/Sta import * as h from '../helpers' -describe('ERC677Token', () => { +h.describes.HH('ERC677Token', () => { let swap: Contract, owner: SignerWithAddress, base: Contract, diff --git a/test/v0.6/token/BasicToken.test.ts b/test/v0.6/token/BasicToken.test.ts index 2137682..047a2a2 100644 --- a/test/v0.6/token/BasicToken.test.ts +++ b/test/v0.6/token/BasicToken.test.ts @@ -2,18 +2,15 @@ import { ethers } from 'ethers' ethers.utils.Logger.setLogLevel(ethers.utils.Logger.levels.ERROR) import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../../src' +import { getContractFactory, Versions } from '../../../src' import { shouldBehaveLikeBasicToken } from '../../behavior/token/BasicToken' +import * as h from '../../helpers' -const VERSION = 'v0.6' - -describe(`BasicToken ${VERSION}`, () => { +h.describes.HH(`BasicToken ${Versions.v0_6}`, () => { const overrides: Record = { BasicTokenMock: 'StandardTokenMock' } const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(overrides[name] || name, signer, VERSION) - - const _getReasonStr = (reason: string) => reason + getContractFactory(overrides[name] || name, signer, Versions.v0_6) - shouldBehaveLikeBasicToken(_getContractFactory, _getReasonStr) + shouldBehaveLikeBasicToken(_getContractFactory, h.revertShim()) }) diff --git a/test/v0.6/token/StandardToken.test.ts b/test/v0.6/token/StandardToken.test.ts index 9e70714..b6e2f5d 100644 --- a/test/v0.6/token/StandardToken.test.ts +++ b/test/v0.6/token/StandardToken.test.ts @@ -2,19 +2,17 @@ import { ethers } from 'ethers' ethers.utils.Logger.setLogLevel(ethers.utils.Logger.levels.ERROR) import { Signer } from '@ethersproject/abstract-signer' -import { getContractFactory } from '../../../src' +import { getContractFactory, Versions } from '../../../src' import { shouldBehaveLikeBasicToken } from '../../behavior/token/BasicToken' import { shouldBehaveLikeStandardToken } from '../../behavior/token/StandardToken' +import * as h from '../../helpers' -const VERSION = 'v0.6' - -describe(`StandardToken ${VERSION}`, () => { +h.describes.HH(`StandardToken ${Versions.v0_6}`, () => { const overrides: Record = { BasicTokenMock: 'StandardTokenMock' } const _getContractFactory = (name: string, signer?: Signer) => - getContractFactory(overrides[name] || name, signer, VERSION) - const _getReasonStr = (reason: string) => reason + getContractFactory(overrides[name] || name, signer, Versions.v0_6) - shouldBehaveLikeBasicToken(_getContractFactory, _getReasonStr) - shouldBehaveLikeStandardToken(_getContractFactory, _getReasonStr) + shouldBehaveLikeBasicToken(_getContractFactory, h.revertShim()) + shouldBehaveLikeStandardToken(_getContractFactory, h.revertShim()) }) diff --git a/test/v0.7/bridge/optimism/OVM_L1ERC20Gateway.test.ts b/test/v0.7/bridge/optimism/OVM_L1ERC20Gateway.test.ts new file mode 100644 index 0000000..c422b2f --- /dev/null +++ b/test/v0.7/bridge/optimism/OVM_L1ERC20Gateway.test.ts @@ -0,0 +1,138 @@ +import { ethers } from 'hardhat' +import { expect } from 'chai' +import { Contract } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { Versions, getContractFactory, Targets, optimism } from '../../../../src' +import * as h from '../../../helpers' + +h.describes.HH(`OVM_L1ERC20Gateway ${Versions.v0_7}`, () => { + describe('deposit safety', () => { + let wallet: SignerWithAddress, walletOther: SignerWithAddress + + before(async () => { + ;[wallet, walletOther] = await ethers.getSigners() + }) + + let l1Token: Contract, l1Gateway: Contract + + beforeEach(async () => { + l1Token = await getContractFactory('LinkToken', wallet, Versions.v0_6, Targets.EVM).deploy() + + const messengerMock = await getContractFactory( + 'OVM_CrossDomainMessengerMock', + wallet, + Versions.v0_7, + Targets.EVM, + ).deploy() + const fake_l1CrossDomainMessenger = messengerMock.address + const fake_l2ERC20Gateway = '0x00000000000000000000000000000000000000ff' + + l1Gateway = await optimism.deployL1ERC20Gateway(wallet) + // Init L2 ERC20 Gateways + const l1InitPayload = [fake_l2ERC20Gateway, fake_l1CrossDomainMessenger, l1Token.address] + const l1InitTx = await l1Gateway.initialize(...l1InitPayload) + await l1InitTx.wait() + }) + + it('can deposit (all fn) as EOA contract', async () => { + const totalAmount = '30' + await l1Token.approve(l1Gateway.address, totalAmount) + + const amount = '10' + await l1Gateway.deposit(amount) + await l1Gateway.depositTo(wallet.address, amount) + await l1Gateway.depositToUnsafe(wallet.address, amount) + + const balanceWallet = await l1Token.balanceOf(wallet.address) + expect(balanceWallet).to.equal('999999999999999999999999970') + + const balanceGateway = await l1Token.balanceOf(l1Gateway.address) + expect(balanceGateway).to.equal(totalAmount) + }) + + it('can depositTo other account', async () => { + const totalAmount = '20' + await l1Token.approve(l1Gateway.address, totalAmount) + + const amount = '10' + await l1Gateway.depositTo(walletOther.address, amount) + await l1Gateway.depositToUnsafe(walletOther.address, amount) + + const balanceWallet = await l1Token.balanceOf(wallet.address) + expect(balanceWallet).to.equal('999999999999999999999999980') + + const balanceGateway = await l1Token.balanceOf(l1Gateway.address) + expect(balanceGateway).to.equal(totalAmount) + }) + + it("can't depositTo contract", async () => { + const totalAmount = '10' + await l1Token.approve(l1Gateway.address, totalAmount) + + const contractAddr = l1Token.address + const amount = totalAmount + + await expect(l1Gateway.depositTo(contractAddr, amount)).to.be.revertedWith('Account not EOA') + }) + + it('can depositToUnsafe contract', async () => { + const totalAmount = '10' + await l1Token.approve(l1Gateway.address, totalAmount) + + const contractAddr = l1Token.address + const amount = totalAmount + await l1Gateway.depositToUnsafe(contractAddr, amount) + + const balanceWallet = await l1Token.balanceOf(wallet.address) + expect(balanceWallet).to.equal('999999999999999999999999990') + + const balanceGateway = await l1Token.balanceOf(l1Gateway.address) + expect(balanceGateway).to.equal(totalAmount) + }) + + // TODO: refactor as reusable behavior + describe('ERC677Receiver', () => { + it('can transferAndCall from EOA', async () => { + // Skip approval + const totalAmount = '30' + const amount = '10' + await l1Token.transferAndCall(l1Gateway.address, amount, Buffer.from('')) + await l1Token.transferAndCall(l1Gateway.address, amount, Buffer.from('')) + await l1Token.transferAndCall(l1Gateway.address, amount, Buffer.from('')) + + const balanceWallet = await l1Token.balanceOf(wallet.address) + expect(balanceWallet).to.equal('999999999999999999999999970') + + const balanceGateway = await l1Token.balanceOf(l1Gateway.address) + expect(balanceGateway).to.equal(totalAmount) + }) + + it("can't transferAndCall from contract", async () => { + const erc677CallerMock = await getContractFactory( + 'ERC677CallerMock', + wallet, + Versions.v0_7, + Targets.EVM, + ).deploy() + + // Fund the mock contract + const amount = '10' + await l1Token.transfer(erc677CallerMock.address, amount) + + // Mock contract tries (fails) to transferAndCall to L1 Gateway + const payload = [l1Token.address, l1Gateway.address, amount, Buffer.from('')] + await expect(erc677CallerMock.callTransferAndCall(...payload)).to.be.revertedWith( + 'Account not EOA', + ) + }) + + it("can't call onTokenTransfer directly", async () => { + const amount = '10' + const payload = [wallet.address, amount, Buffer.from('')] + await expect(l1Gateway.onTokenTransfer(...payload)).to.be.revertedWith( + 'onTokenTransfer sender not valid', + ) + }) + }) + }) +}) diff --git a/test/v0.7/bridge/optimism/OVM_L2ERC20Gateway.test.ts b/test/v0.7/bridge/optimism/OVM_L2ERC20Gateway.test.ts new file mode 100644 index 0000000..a7c751e --- /dev/null +++ b/test/v0.7/bridge/optimism/OVM_L2ERC20Gateway.test.ts @@ -0,0 +1,191 @@ +import { expect } from 'chai' +import { Wallet, Contract, BigNumberish } from 'ethers' +import { parseEther } from '@ethersproject/units' +import { getContractFactory, deploy, Targets, Versions, optimism } from '../../../../src' +import * as h from '../../../helpers' + +// short alias +const _getFactory = getContractFactory + +describe(`OVM_L2ERC20Gateway ${Versions.v0_7}`, () => { + h.describes.OE(`@integration`, () => { + describe('withdrawal safety', () => { + let oe: optimism.env.OptimismEnv, l2Token: Contract, l2Gateway: Contract + + before(async function () { + this.timeout(20000) + + // Load the configuration from environment + oe = await optimism.loadEnv() + await oe.depositL2(parseEther('1') as BigNumberish) + + // Deploy LinkTokenChild contract + l2Token = await deploy( + _getFactory('LinkTokenChild', oe.l2Wallet, Versions.v0_7, Targets.OVM), + 'LinkTokenChild', + ) + + // Deploy l2CrossDomainMessenger + const messengerMock = await deploy( + _getFactory('OVM_CrossDomainMessengerMock', oe.l2Wallet, Versions.v0_7, Targets.OVM), + 'OVM_CrossDomainMessengerMock', + ) + const fake_l2CrossDomainMessenger = messengerMock.address + + // Deploy l2Gateway with l2CrossDomainMessenger + l2Gateway = await deploy( + _getFactory('OVM_L2ERC20Gateway', oe.l2Wallet, Versions.v0_7, Targets.OVM), + 'OVM_L2ERC20Gateway', + ) + + // Init L2 ERC20 Gateway + const fake_l1ERC20Gateway = '0x00000000000000000000000000000000000000ff' + const l2InitPayload = [fake_l1ERC20Gateway, fake_l2CrossDomainMessenger, l2Token.address] + const l2InitTx = await l2Gateway.initialize(...l2InitPayload) + await l2InitTx.wait() + + // Grant BRIDGE_GATEWAY_ROLE role + const gatewayRole = await l2Token.BRIDGE_GATEWAY_ROLE() + const grantRoleTx1 = await l2Token.grantRole(gatewayRole, l2Gateway.address) + await grantRoleTx1.wait() + + // Mock deposit $$$ + const grantRoleTx2 = await l2Token.grantRole(gatewayRole, oe.l2Wallet.address) + await grantRoleTx2.wait() + + const depositTx = await l2Token.deposit(oe.l2Wallet.address, '1000000000000000000000000000') + await depositTx.wait() + }) + + it('can withdraw (all fn) as EOA contract', async () => { + const amountTotal = '30' + const approveTx = await l2Token.approve(l2Gateway.address, amountTotal) + await approveTx.wait() + + const amount = '10' + const withdrawTx = await l2Gateway.withdraw(amount) + await withdrawTx.wait() + + const withdrawToTx = await l2Gateway.withdrawTo(oe.l2Wallet.address, amount) + await withdrawToTx.wait() + + const withdrawToUnsafeTx = await l2Gateway.withdrawToUnsafe(oe.l2Wallet.address, amount) + await withdrawToUnsafeTx.wait() + + const balance = await l2Token.balanceOf(oe.l2Wallet.address) + expect(balance).to.equal('999999999999999999999999970') + }).timeout(20000) + + it('can withdrawTo an empty (unseen) account', async () => { + const emptyAccPK = '0x' + '12345678'.repeat(8) + const emptyAccWallet = new Wallet(emptyAccPK, oe.l2Wallet.provider) + + const amountTotal = '20' + const approveTx = await l2Token.approve(l2Gateway.address, amountTotal) + await approveTx.wait() + + const amount = '10' + const withdrawToTx = await l2Gateway.withdrawTo(emptyAccWallet.address, amount) + await withdrawToTx.wait() + + const withdrawToUnsafeTx = await l2Gateway.withdrawToUnsafe(emptyAccWallet.address, amount) + await withdrawToUnsafeTx.wait() + + const balance = await l2Token.balanceOf(oe.l2Wallet.address) + expect(balance).to.equal('999999999999999999999999950') + }).timeout(10000) + + it("can't withdrawTo contract", async () => { + const contractAddr = l2Token.address + + const amount = '10' + const approveTx = await l2Token.approve(l2Gateway.address, amount) + await approveTx.wait() + + const withdrawToTx = await l2Gateway.withdrawTo( + contractAddr, + amount, + optimism.TX_OVERRIDES_OE_BUG, + ) + + // TODO: fetch revert reason + // revert: Account not EOA + await h.txRevert(withdrawToTx.wait()) + }).timeout(10000) + + it('can withdrawToUnsafe contract', async () => { + const contractAddr = l2Token.address + + const amount = '10' + const approveTx = await l2Token.approve(l2Gateway.address, amount) + await approveTx.wait() + + const withdrawToUnsafeTx = await l2Gateway.withdrawToUnsafe(contractAddr, amount) + await withdrawToUnsafeTx.wait() + + const balance = await l2Token.balanceOf(oe.l2Wallet.address) + expect(balance).to.equal('999999999999999999999999940') + }).timeout(10000) + + // TODO: refactor as reusable behavior + describe('ERC677Receiver', () => { + it('can transferAndCall from EOA', async () => { + // Skip approval + const amount = '10' + + const payload = [l2Gateway.address, amount, Buffer.from('')] + const transferAndCallTx1 = await l2Token.transferAndCall(...payload) + await transferAndCallTx1.wait() + + const transferAndCallTx2 = await l2Token.transferAndCall(...payload) + await transferAndCallTx2.wait() + + const transferAndCallTx3 = await l2Token.transferAndCall(...payload) + await transferAndCallTx3.wait() + + const balanceWallet = await l2Token.balanceOf(oe.l2Wallet.address) + expect(balanceWallet).to.equal('999999999999999999999999910') + + const balanceGateway = await l2Token.balanceOf(l2Gateway.address) + expect(balanceGateway).to.equal(0) // all burnt + }).timeout(10000) + + it("can't transferAndCall from contract", async () => { + const erc677CallerMock = await deploy( + _getFactory('ERC677CallerMock', oe.l2Wallet, Versions.v0_7, Targets.OVM), + 'ERC677CallerMock', + ) + + // Fund the mock contract + const amount = '10' + const transferTx = await l2Token.transfer(erc677CallerMock.address, amount) + await transferTx.wait() + + // Mock contract tries (fails) to transferAndCall to L1 Gateway + const payload = [l2Token.address, l2Gateway.address, amount, Buffer.from('')] + const callTransferAndCallTx = await erc677CallerMock.callTransferAndCall( + ...payload, + optimism.TX_OVERRIDES_OE_BUG, + ) + + // TODO: fetch revert reason + // revert: Account not EOA + await h.txRevert(callTransferAndCallTx.wait()) + }) + }).timeout(10000) + + it("can't call onTokenTransfer directly", async () => { + const amount = '10' + const payload = [oe.l2Wallet.address, amount, Buffer.from('')] + const onTokenTransferTx = await l2Gateway.onTokenTransfer( + ...payload, + optimism.TX_OVERRIDES_OE_BUG, + ) + + // TODO: fetch revert reason + // revert: onTokenTransfer sender not valid + await h.txRevert(onTokenTransferTx.wait()) + }) + }) + }) +}) diff --git a/test/v0.7/bridge/optimism/deposit-withdraw.test.ts b/test/v0.7/bridge/optimism/deposit-withdraw.test.ts new file mode 100644 index 0000000..b179bde --- /dev/null +++ b/test/v0.7/bridge/optimism/deposit-withdraw.test.ts @@ -0,0 +1,57 @@ +import { BigNumberish } from '@ethersproject/bignumber' +import { parseEther } from '@ethersproject/units' +import { expect } from 'chai' +import { depositAndWithdraw, CheckBalances } from '../../../../scripts/deposit-withdraw' +import { optimism } from '../../../../src' +import * as h from '../../../helpers' + +h.describes.OE('Optimism deposit-withdraw @integration', () => { + let oe: optimism.env.OptimismEnv + + before(async function () { + this.timeout(10000) + + // Load the configuration from environment + oe = await optimism.loadEnv() + // Fund L2 wallet + await oe.depositL2(parseEther('1') as BigNumberish) + }) + + const checkBalances = (step = 0): CheckBalances => async ( + l1Wallet, + l1ERC20, + l2Wallet, + l2ERC20, + ) => { + const _expect = async (_l1Balance: string, _l2Balance: string) => { + const l1Balance = await l1ERC20.balanceOf(l1Wallet.address) + expect(l1Balance).to.equal(_l1Balance) + + const l2Balance = await l2ERC20.balanceOf(l2Wallet.address) + expect(l2Balance).to.equal(_l2Balance) + } + + switch (step++) { + case 0: + return await _expect('1000000000000000000000000000', '0') + case 1: + return await _expect('999999999999999999999999999', '1') + case 2: + return await _expect('1000000000000000000000000000', '0') + default: + expect(step).to.be.lte(3) + } + } + + describe('deposit L1->L2, withdraw L2->L1', () => { + it('approve/transferFrom ', async () => { + await depositAndWithdraw(oe, checkBalances()) + }).timeout(60000) + + it('transferAndCall', async () => { + const amount = 1 + const transferAndCall = true + await depositAndWithdraw(oe, checkBalances(), amount, transferAndCall) + }).timeout(60000) + }) +}) diff --git a/test/v0.7/bridge/token/LinkTokenChild.test.ts b/test/v0.7/bridge/token/LinkTokenChild.test.ts new file mode 100644 index 0000000..7bdbb35 --- /dev/null +++ b/test/v0.7/bridge/token/LinkTokenChild.test.ts @@ -0,0 +1,77 @@ +import { Contract, ContractFactory, Signer } from 'ethers' +import { getContractFactory, Targets, Versions } from '../../../../src' + +import { shouldBehaveLikeERC677Token } from '../../../behavior/ERC677Token' +import { shouldBehaveLikeLinkToken } from '../../../behavior/LinkToken' +import * as h from '../../../helpers' + +export class LinkTokenChildTest__factory { + readonly signer: Signer + constructor(signer?: Signer) { + this.signer = signer || ({} as Signer) + } + + static new(signer?: Signer): ContractFactory { + return (new LinkTokenChildTest__factory(signer) as unknown) as ContractFactory + } + + deploy(...args: Array): Promise { + const initBalance: number = args[0] || '1000000000000000000000000000' + const _deploy = async () => { + // Deploy LinkTokenChild contract + const token = await getContractFactory( + 'LinkTokenChild', + this.signer, + Versions.v0_7, + Targets.EVM, + ).deploy() + + // Grant BRIDGE_GATEWAY_ROLE role + const signerAddr = await this.signer.getAddress() + const gatewayRole = await token.BRIDGE_GATEWAY_ROLE() + await token.grantRole(gatewayRole, signerAddr) + + // Deposit requested amount + await token.deposit(signerAddr, initBalance) + return token + } + + return _deploy() + } + + connect(signer: Signer): ContractFactory { + return LinkTokenChildTest__factory.new(signer) + } +} + +const OZ_AccessControl_PUBLIC_ABI = ['BRIDGE_GATEWAY_ROLE', 'deposit', 'withdraw'] +const LinkTokenChild_PUBLIC_ABI = [ + 'DEFAULT_ADMIN_ROLE', + 'hasRole', + 'getRoleMemberCount', + 'getRoleMember', + 'getRoleAdmin', + 'grantRole', + 'revokeRole', + 'renounceRole', +] +const EXTRA_PUBLIC_ABI = [ + 'decreaseAllowance', + 'increaseAllowance', + ...OZ_AccessControl_PUBLIC_ABI, + ...LinkTokenChild_PUBLIC_ABI, +] + +h.describes.HH(`LinkTokenChild ${Versions.v0_7}`, () => { + const _getContractFactory = (name: string, signer?: Signer) => { + if (name === 'LinkToken' || name === 'Token677') { + return LinkTokenChildTest__factory.new(signer) + } + return getContractFactory(name, signer, Versions.v0_6) + } + + shouldBehaveLikeERC677Token(_getContractFactory, h.revertShim()) + shouldBehaveLikeLinkToken(_getContractFactory, h.revertShim(), EXTRA_PUBLIC_ABI) + + // TODO: LinkTokenChild specific tests +}) diff --git a/yarn.lock b/yarn.lock index 1e2ce75..d1b46fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,17 @@ "@truffle/contract" "^4.2.29" ethers "^4.0.45" +"@chainlink/optimism-utils@https://github.com/smartcontractkit/optimism-utils.git": + version "0.0.1-alpha" + resolved "https://github.com/smartcontractkit/optimism-utils.git#b1415a2b4067fd757f0730d597bbb0d4f85a300f" + dependencies: + "@eth-optimism/contracts" "^0.2.7" + "@eth-optimism/core-utils" "^0.3.1" + "@ethersproject/bignumber" "^5.1.1" + "@ethersproject/providers" "^5.1.2" + "@ethersproject/units" "^5.1.0" + ethers "^5.1.3" + "@ensdomains/ens@^0.4.4": version "0.4.5" resolved "https://registry.yarnpkg.com/@ensdomains/ens/-/ens-0.4.5.tgz#e0aebc005afdc066447c6e22feb4eda89a5edbfc" @@ -26,6 +37,57 @@ resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89" integrity sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA== +"@eth-optimism/contracts@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@eth-optimism/contracts/-/contracts-0.2.7.tgz#ab3b1f5e30f36d1f5fd4449e9031d8bb9a920ceb" + integrity sha512-hPaMq+cqdzzXFGdaitlAo5vlUVPoui4zTfkqlXC1Rd12gHxObPYeY1Bhva67i6lQ4OQybmXAYi16fEYWdXTDzA== + dependencies: + "@eth-optimism/core-utils" "^0.3.1" + "@eth-optimism/solc" "^0.6.12-alpha.1" + "@ethersproject/abstract-provider" "^5.0.8" + "@ethersproject/contracts" "^5.0.5" + "@openzeppelin/contracts" "^3.3.0" + "@typechain/hardhat" "^1.0.1" + ganache-core "^2.13.2" + glob "^7.1.6" + +"@eth-optimism/core-utils@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.3.1.tgz#c7979e6fddcd16fa4e466b52bdceaf2260106c32" + integrity sha512-0zqbk2xPUB8dzdquYR2jlRML0IMsy7fOWDmUhaUyV7TS8PhSDDx/Yj/edR86jjncV1AMDanDrxtZlnCLPXPXog== + dependencies: + "@ethersproject/abstract-provider" "^5.0.9" + "@sentry/node" "^6.3.0" + "@types/pino-multi-stream" "^5.1.1" + ethers "^5.0.31" + lodash "^4.17.21" + pino "^6.11.1" + pino-multi-stream "^5.3.0" + pino-sentry "^0.7.0" + prom-client "^13.1.0" + +"@eth-optimism/hardhat-ovm@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@eth-optimism/hardhat-ovm/-/hardhat-ovm-0.0.3.tgz#4d9e34e4a466a4750b68785bec73ff76e44f6198" + integrity sha512-J4B+HXjP2DA8FWaKTbZ+7qIULNM3OxQrkXklcfb63WRjvlR3xWNK72BBMMVA4V1W9BwDNx5hgr08hehg6mmV1w== + dependencies: + node-fetch "^2.6.1" + +"@eth-optimism/solc@^0.6.12-alpha.1": + version "0.6.12-alpha.1" + resolved "https://registry.yarnpkg.com/@eth-optimism/solc/-/solc-0.6.12-alpha.1.tgz#041876f83b34c6afe2f19dfe9626568df6ed8590" + integrity sha512-Ky73mo+2iNJs/VTaT751nMeZ7hXns0TBAlffTOxIOsScjAZ/zi/KWsDUo3r89aV2JKXcYAU/bLidxF40MVJeUw== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + follow-redirects "^1.12.1" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + "@ethereum-waffle/chai@^3.3.0": version "3.3.1" resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.3.1.tgz#3f20b810d0fa516f19af93c50c3be1091333fa8e" @@ -79,6 +141,76 @@ patch-package "^6.2.2" postinstall-postinstall "^2.1.0" +"@ethereumjs/block@^3.2.0", "@ethereumjs/block@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/block/-/block-3.2.1.tgz#c24c345e6dd6299efa4bed40979280b7dda96d3a" + integrity sha512-FCxo5KwwULne2A2Yuae4iaGGqSsRjwzXOlDhGalOFiBbLfP3hE04RHaHGw4c8vh1PfOrLauwi0dQNUBkOG3zIA== + dependencies: + "@ethereumjs/common" "^2.2.0" + "@ethereumjs/tx" "^3.1.3" + ethereumjs-util "^7.0.10" + merkle-patricia-tree "^4.1.0" + +"@ethereumjs/blockchain@^5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/blockchain/-/blockchain-5.2.1.tgz#83ed83647667265f1666f111caf065ef9d1e82b5" + integrity sha512-+hshP2qSOOFsiYvZCbaDQFG7jYTWafE8sfBi+pAsdhAHfP7BN7VLyob7qoQISgwS1s7NTR4c4+2t/woU9ahItw== + dependencies: + "@ethereumjs/block" "^3.2.0" + "@ethereumjs/common" "^2.2.0" + "@ethereumjs/ethash" "^1.0.0" + debug "^2.2.0" + ethereumjs-util "^7.0.9" + level-mem "^5.0.1" + lru-cache "^5.1.1" + rlp "^2.2.4" + semaphore-async-await "^1.5.1" + +"@ethereumjs/common@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.2.0.tgz#850a3e3e594ee707ad8d44a11e8152fb62450535" + integrity sha512-PyQiTG00MJtBRkJmv46ChZL8u2XWxNBeAthznAUIUiefxPAXjbkuiCZOuncgJS34/XkMbNc9zMt/PlgKRBElig== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.0.9" + +"@ethereumjs/ethash@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/ethash/-/ethash-1.0.0.tgz#4e77f85b37be1ade5393e8719bdabac3e796ddaa" + integrity sha512-iIqnGG6NMKesyOxv2YctB2guOVX18qMAWlj3QlZyrc+GqfzLqoihti+cVNQnyNxr7eYuPdqwLQOFuPe6g/uKjw== + dependencies: + "@types/levelup" "^4.3.0" + buffer-xor "^2.0.1" + ethereumjs-util "^7.0.7" + miller-rabin "^4.0.0" + +"@ethereumjs/tx@^3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.1.3.tgz#0e4b0ccec2f12b1f0bbbb0e7542dd79d9ec25d87" + integrity sha512-DJBu6cbwYtiPTFeCUR8DF5p+PF0jxs+0rALJZiEcTz2tiRPIEkM72GEbrkGuqzENLCzBrJHT43O0DxSYTqeo+g== + dependencies: + "@ethereumjs/common" "^2.2.0" + ethereumjs-util "^7.0.10" + +"@ethereumjs/vm@^5.3.2": + version "5.3.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/vm/-/vm-5.3.2.tgz#b4d83a3d50a7ad22d6d412cc21bbde221b3e2871" + integrity sha512-QmCUQrW6xbhgEbQh9njue4kAJdM056C+ytBFUTF/kDYa3kNDm4Qxp9HUyTlt1OCSXvDhws0qqlh8+q+pmXpN7g== + dependencies: + "@ethereumjs/block" "^3.2.1" + "@ethereumjs/blockchain" "^5.2.1" + "@ethereumjs/common" "^2.2.0" + "@ethereumjs/tx" "^3.1.3" + async-eventemitter "^0.2.4" + core-js-pure "^3.0.1" + debug "^2.2.0" + ethereumjs-util "^7.0.10" + functional-red-black-tree "^1.0.1" + mcl-wasm "^0.7.1" + merkle-patricia-tree "^4.1.0" + rustbn.js "~0.2.0" + util.promisify "^1.0.1" + "@ethersproject/abi@5.0.0-beta.153": version "5.0.0-beta.153" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" @@ -124,7 +256,22 @@ "@ethersproject/properties" "^5.1.0" "@ethersproject/strings" "^5.1.0" -"@ethersproject/abstract-provider@5.1.0", "@ethersproject/abstract-provider@^5.1.0": +"@ethersproject/abi@5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.1.1.tgz#79525f582338d98660ac709c65b44c3c081ed2fc" + integrity sha512-UNmhRL4ngm1nCWvhJWRd55PvP1JWojGD4BR63JxyiiWZQAszYzaHHeYdRcj+NY3S0kV6SmAS2dZWSBOZPnXbSw== + dependencies: + "@ethersproject/address" "^5.1.0" + "@ethersproject/bignumber" "^5.1.0" + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/constants" "^5.1.0" + "@ethersproject/hash" "^5.1.0" + "@ethersproject/keccak256" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + "@ethersproject/properties" "^5.1.0" + "@ethersproject/strings" "^5.1.0" + +"@ethersproject/abstract-provider@5.1.0", "@ethersproject/abstract-provider@^5.0.8", "@ethersproject/abstract-provider@^5.0.9", "@ethersproject/abstract-provider@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.1.0.tgz#1f24c56cda5524ef4ed3cfc562a01d6b6f8eeb0b" integrity sha512-8dJUnT8VNvPwWhYIau4dwp7qe1g+KgdRm4XTWvjkI9gAT2zZa90WF5ApdZ3vl1r6NDmnn6vUVvyphClRZRteTQ== @@ -183,6 +330,15 @@ "@ethersproject/logger" "^5.1.0" bn.js "^4.4.0" +"@ethersproject/bignumber@5.1.1", "@ethersproject/bignumber@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.1.1.tgz#84812695253ccbc639117f7ac49ee1529b68e637" + integrity sha512-AVz5iqz7+70RIqoQTznsdJ6DOVBYciNlvO+AlQmPTB6ofCvoihI9bQdr6wljsX+d5W7Yc4nyvQvP4JMzg0Agig== + dependencies: + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + bn.js "^4.4.0" + "@ethersproject/bytes@5.1.0", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.1.0.tgz#55dfa9c4c21df1b1b538be3accb50fb76d5facfd" @@ -197,7 +353,7 @@ dependencies: "@ethersproject/bignumber" "^5.1.0" -"@ethersproject/contracts@5.1.0": +"@ethersproject/contracts@5.1.0", "@ethersproject/contracts@^5.0.5": version "5.1.0" resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.1.0.tgz#f7c3451f1af77e029005733ccab3419d07d23f6b" integrity sha512-dvTMs/4XGSc57cYOW0KjgX1NdTujUu7mNb6PQdJWg08m9ULzPyGZuBkFJnijBcp6vTOCQ59RwjboWgNWw393og== @@ -213,6 +369,22 @@ "@ethersproject/properties" "^5.1.0" "@ethersproject/transactions" "^5.1.0" +"@ethersproject/contracts@5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.1.1.tgz#c66cb6d618fcbd73e20a6b808e8f768b2b781d0b" + integrity sha512-6WwktLJ0DFWU8pDkgH4IGttQHhQN4SnwKFu9h+QYVe48VGWtbDu4W8/q/7QA1u/HWlWMrKxqawPiZUJj0UMvOw== + dependencies: + "@ethersproject/abi" "^5.1.0" + "@ethersproject/abstract-provider" "^5.1.0" + "@ethersproject/abstract-signer" "^5.1.0" + "@ethersproject/address" "^5.1.0" + "@ethersproject/bignumber" "^5.1.0" + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/constants" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + "@ethersproject/properties" "^5.1.0" + "@ethersproject/transactions" "^5.1.0" + "@ethersproject/hash@5.1.0", "@ethersproject/hash@>=5.0.0-beta.128", "@ethersproject/hash@^5.0.4", "@ethersproject/hash@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.1.0.tgz#40961d64837d57f580b7b055e0d74174876d891e" @@ -324,6 +496,31 @@ bech32 "1.1.4" ws "7.2.3" +"@ethersproject/providers@5.1.2", "@ethersproject/providers@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.1.2.tgz#4e4459698903f911402fe91aa7544eb07f3921ed" + integrity sha512-GqsS8rd+eyd4eNkcNgzZ4l9IRULBPUZa7JPnv22k4MHflMobUseyhfbVnmoN5bVNNkOxjV1IPTw9i0sV1hwdpg== + dependencies: + "@ethersproject/abstract-provider" "^5.1.0" + "@ethersproject/abstract-signer" "^5.1.0" + "@ethersproject/address" "^5.1.0" + "@ethersproject/basex" "^5.1.0" + "@ethersproject/bignumber" "^5.1.0" + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/constants" "^5.1.0" + "@ethersproject/hash" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + "@ethersproject/networks" "^5.1.0" + "@ethersproject/properties" "^5.1.0" + "@ethersproject/random" "^5.1.0" + "@ethersproject/rlp" "^5.1.0" + "@ethersproject/sha2" "^5.1.0" + "@ethersproject/strings" "^5.1.0" + "@ethersproject/transactions" "^5.1.0" + "@ethersproject/web" "^5.1.0" + bech32 "1.1.4" + ws "7.2.3" + "@ethersproject/random@5.1.0", "@ethersproject/random@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.1.0.tgz#0bdff2554df03ebc5f75689614f2d58ea0d9a71f" @@ -395,7 +592,22 @@ "@ethersproject/rlp" "^5.1.0" "@ethersproject/signing-key" "^5.1.0" -"@ethersproject/units@5.1.0": +"@ethersproject/transactions@5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.1.1.tgz#5a6bbb25fb062c3cc75eb0db12faefcdd3870813" + integrity sha512-Nwgbp09ttIVN0OoUBatCXaHxR7grWPHbozJN8v7AXDLrl6nnOIBEMDh+yJTnosSQlFhcyjfTGGN+Mx6R8HdvMw== + dependencies: + "@ethersproject/address" "^5.1.0" + "@ethersproject/bignumber" "^5.1.0" + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/constants" "^5.1.0" + "@ethersproject/keccak256" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + "@ethersproject/properties" "^5.1.0" + "@ethersproject/rlp" "^5.1.0" + "@ethersproject/signing-key" "^5.1.0" + +"@ethersproject/units@5.1.0", "@ethersproject/units@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.1.0.tgz#b6ab3430ebc22adc3cb4839516496f167bee3ad5" integrity sha512-isvJrx6qG0nKWfxsGORNjmOq/nh175fStfvRTA2xEKrGqx8JNJY83fswu4GkILowfriEM/eYpretfJnfzi7YhA== @@ -447,27 +659,6 @@ "@ethersproject/properties" "^5.1.0" "@ethersproject/strings" "^5.1.0" -"@nomiclabs/ethereumjs-vm@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@nomiclabs/ethereumjs-vm/-/ethereumjs-vm-4.2.2.tgz#2f8817113ca0fb6c44c1b870d0a809f0e026a6cc" - integrity sha512-8WmX94mMcJaZ7/m7yBbyuS6B+wuOul+eF+RY9fBpGhNaUpyMR/vFIcDojqcWQ4Yafe1tMKY5LDu2yfT4NZgV4Q== - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - core-js-pure "^3.0.1" - ethereumjs-account "^3.0.0" - ethereumjs-block "^2.2.2" - ethereumjs-blockchain "^4.0.3" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.2" - ethereumjs-util "^6.2.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "3.0.0" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - util.promisify "^1.0.0" - "@nomiclabs/hardhat-ethers@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.2.tgz#c472abcba0c5185aaa4ad4070146e95213c68511" @@ -481,7 +672,17 @@ "@types/sinon-chai" "^3.2.3" "@types/web3" "1.0.19" -"@openzeppelin/contracts@^3.4.0": +"@openzeppelin/contracts-upgradeable@3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-3.4.0.tgz#7674c73c643a509f1b90c509e3e72fe9aae02aeb" + integrity sha512-7wBcbukDqWZt/B1zjb7zyeWq+AC7rx7nGln7/hPxHdKd8PAiiteXd51Cp2KmGP8qaY0/TXh/fQLsA082LWp8Zw== + +"@openzeppelin/contracts@3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.0.tgz#9a1669ad5f9fdfb6e273bb5a4fed10cb4cc35eb0" + integrity sha512-qh+EiHWzfY/9CORr+eRUkeEUP1WiFUcq3974bLHwyYzLBUtK6HPaMkIUHi74S1rDTZ0sNz42DwPc5A4IJvN3rg== + +"@openzeppelin/contracts@^3.3.0": version "3.4.1" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1.tgz#03c891fec7f93be0ae44ed74e57a122a38732ce7" integrity sha512-cUriqMauq1ylzP2TxePNdPqkwI7Le3Annh4K9rrpvKfSBB/bdW+Iu1ihBaTIABTAAJ85LmKL5SSPPL9ry8d1gQ== @@ -534,6 +735,17 @@ "@sentry/utils" "5.30.0" tslib "^1.9.3" +"@sentry/core@6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.3.1.tgz#5e32ca919c9be30fec0bb3125a556bc711584bdf" + integrity sha512-aVuvVbaehGeN86jZlLDGGkhEtprdOtB6lvYLfGy40Dj1Tkh2mGWE550QsRXAXAqYvQzIYwQR23r6m3o8FujgVg== + dependencies: + "@sentry/hub" "6.3.1" + "@sentry/minimal" "6.3.1" + "@sentry/types" "6.3.1" + "@sentry/utils" "6.3.1" + tslib "^1.9.3" + "@sentry/hub@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.30.0.tgz#2453be9b9cb903404366e198bd30c7ca74cdc100" @@ -543,6 +755,15 @@ "@sentry/utils" "5.30.0" tslib "^1.9.3" +"@sentry/hub@6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.3.1.tgz#dda07888a82d1c48bbefa00205bfa9d035691f07" + integrity sha512-2er+OeVlsdVZkhl9kXQAANwgjwoCdM1etK2iFuhzX8xkMaJlAuZLyQInv2U1BbXBlIfWjvzRM8B95hCWvVrR3Q== + dependencies: + "@sentry/types" "6.3.1" + "@sentry/utils" "6.3.1" + tslib "^1.9.3" + "@sentry/minimal@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.30.0.tgz#ce3d3a6a273428e0084adcb800bc12e72d34637b" @@ -552,6 +773,15 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sentry/minimal@6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.3.1.tgz#38f71c77e8820555effb6e868336d4f5672018cd" + integrity sha512-0eN9S7HvXsCQEjX/qXHTMgvSb3mwrnZEWS9Qz/Bz5ig9pEGXKgJ1om5NTTHVHhXqd3wFCjdvIo6slufLHoCtSw== + dependencies: + "@sentry/hub" "6.3.1" + "@sentry/types" "6.3.1" + tslib "^1.9.3" + "@sentry/node@^5.18.1": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.30.0.tgz#4ca479e799b1021285d7fe12ac0858951c11cd48" @@ -567,6 +797,21 @@ lru_map "^0.3.3" tslib "^1.9.3" +"@sentry/node@^6.2.5", "@sentry/node@^6.3.0": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.3.1.tgz#0f81a0e352fa5b3e36bcc53adb6e26cd214c637d" + integrity sha512-D0r603fdNwUPkwvy0IcQaUSTafl+7lrOytiO5dfdLdlkhtTcwivwENc/n8ER8GOC2zpIvYOEIJvzP4PGL85khw== + dependencies: + "@sentry/core" "6.3.1" + "@sentry/hub" "6.3.1" + "@sentry/tracing" "6.3.1" + "@sentry/types" "6.3.1" + "@sentry/utils" "6.3.1" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + "@sentry/tracing@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.30.0.tgz#501d21f00c3f3be7f7635d8710da70d9419d4e1f" @@ -578,11 +823,27 @@ "@sentry/utils" "5.30.0" tslib "^1.9.3" +"@sentry/tracing@6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.3.1.tgz#3b96aabf4d9cebadfec070c006db79801a68ee24" + integrity sha512-qveDmoWsXy9qLEblZJwJ1OU/zZRlEd/q7Jhd0Hnwlob8Ci96huABEbYyGdJs18BKVHEFU3gSdVfvrikUE/W17g== + dependencies: + "@sentry/hub" "6.3.1" + "@sentry/minimal" "6.3.1" + "@sentry/types" "6.3.1" + "@sentry/utils" "6.3.1" + tslib "^1.9.3" + "@sentry/types@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402" integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== +"@sentry/types@6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.3.1.tgz#af3b54728b29f633f38fbe51b8c10e3834fbc158" + integrity sha512-BEBn8JX1yaooCAuonbaMci9z0RjwwMbQ3Eny/eyDdd+rjXprZCZaStZnCvSThbNBqAJ8YaUqY2YBMnEwJxarAw== + "@sentry/utils@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" @@ -591,6 +852,14 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sentry/utils@6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.3.1.tgz#6d8e691139b5b49d8c655ad1dcaf2cb3ff0d0b03" + integrity sha512-cdtl/QWC9FtinAuW3w8QfvSfh/Q9ui5vwvjzVHiS1ga/U38edi2XX+cttY39ZYwz0SQG99cE10GOIhd1p7/mAA== + dependencies: + "@sentry/types" "6.3.1" + tslib "^1.9.3" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -722,6 +991,11 @@ resolved "https://registry.yarnpkg.com/@typechain/hardhat/-/hardhat-1.0.1.tgz#6e53956c15b2aff073413cfcdb3f5339b0a85f2e" integrity sha512-gRETPlvLdN95PIP3PVktEtQSnSMJMWxaxNKI34KFPYEuW4QLLm6UrUCHWmulhB1eUQ1EhYRAda7kEhcJOQ/M1g== +"@types/abstract-leveldown@*": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz#3c7750d0186b954c7f2d2f6acc8c3c7ba0c3412e" + integrity sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ== + "@types/bn.js@*", "@types/bn.js@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" @@ -749,6 +1023,19 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/levelup@^4.3.0": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@types/levelup/-/levelup-4.3.1.tgz#7a53b9fd510716e11b2065332790fdf5f9b950b9" + integrity sha512-n//PeTpbHLjMLTIgW5B/g06W/6iuTBHuvUka2nFL9APMSVMNe2r4enADfu3CIE9IyV9E+uquf9OEQQqrDeg24A== + dependencies: + "@types/abstract-leveldown" "*" + "@types/node" "*" + +"@types/lodash@^4.14.168": + version "4.14.168" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008" + integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q== + "@types/lru-cache@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03" @@ -801,6 +1088,37 @@ dependencies: "@types/node" "*" +"@types/pino-multi-stream@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/pino-multi-stream/-/pino-multi-stream-5.1.1.tgz#8d5bc607357324621667c8a5613d4a534c075d0f" + integrity sha512-juOdSxwfE5TFKJJlq/VzXxTRyO+9yI9RZoyh/CYnof8MvqM+aUSUP1ZXGTuOZe7qgQnGp8xr8NHU2O/rTrYysA== + dependencies: + "@types/pino" "*" + +"@types/pino-pretty@*": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@types/pino-pretty/-/pino-pretty-4.7.0.tgz#e4a18541f8464d1cc48216f5593cc6a0e62dc2c3" + integrity sha512-fIZ+VXf9gJoJR4tiiM7G+j/bZkPoZEfFGzA4d8tAWCTpTVyvVaBwnmdLs3wEXYpMjw8eXulrOzNCjmGHT3FgHw== + dependencies: + "@types/pino" "*" + +"@types/pino-std-serializers@*": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/pino-std-serializers/-/pino-std-serializers-2.4.1.tgz#f8bd52a209c8b3c97d1533b1ba27f57c816382bf" + integrity sha512-17XcksO47M24IVTVKPeAByWUd3Oez7EbIjXpSbzMPhXVzgjGtrOa49gKBwxH9hb8dKv58OelsWQ+A1G1l9S3wQ== + dependencies: + "@types/node" "*" + +"@types/pino@*": + version "6.3.7" + resolved "https://registry.yarnpkg.com/@types/pino/-/pino-6.3.7.tgz#0ccef98a159230cb3fa2589c7e8b00a7550a69f6" + integrity sha512-v7FdDXVEL0Zx1zcCf0cJZMojChnF+O0ujDKV1UdocsLuUhENjdtNIaanCZK1zRELp35x//bI2/IHtYUK0vmRvw== + dependencies: + "@types/node" "*" + "@types/pino-pretty" "*" + "@types/pino-std-serializers" "*" + "@types/sonic-boom" "*" + "@types/prettier@^2.1.1": version "2.2.3" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.3.tgz#ef65165aea2924c9359205bf748865b8881753c0" @@ -820,11 +1138,6 @@ dependencies: "@types/node" "*" -"@types/semver@^7.3.4": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" - integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ== - "@types/sinon-chai@^3.2.3": version "3.2.5" resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.5.tgz#df21ae57b10757da0b26f512145c065f2ad45c48" @@ -845,6 +1158,13 @@ resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae" integrity sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg== +"@types/sonic-boom@*": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@types/sonic-boom/-/sonic-boom-0.7.0.tgz#38337036293992a1df65dd3161abddf8fb9b7176" + integrity sha512-AfqR0fZMoUXUNwusgXKxcE9DPlHNDHQp6nKYUd4PSRpLobF5CCevSpyTEBcVZreqaWKCnGBr9KI1fHMTttoB7A== + dependencies: + "@types/node" "*" + "@types/underscore@*": version "1.11.0" resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.11.0.tgz#bb33549f8f89957fdf959c16e4c1d0eaa5bf985d" @@ -858,6 +1178,18 @@ "@types/bn.js" "*" "@types/underscore" "*" +"@types/yargs-parser@*": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" + integrity sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA== + +"@types/yargs@^16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.1.tgz#5fc5d41f69762e00fbecbc8d4bf9dea47d8726f4" + integrity sha512-x4HABGLyzr5hKUzBC9dvjciOTm11WVH1NWonNjGgxapnTHu5SWUqyqn0zQ6Re0yQU0lsQ6ztLCoMAKDGZflyxA== + dependencies: + "@types/yargs-parser" "*" + "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -891,6 +1223,17 @@ 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" @@ -898,6 +1241,17 @@ 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.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -981,6 +1335,11 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -993,6 +1352,13 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + anymatch@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" @@ -1094,7 +1460,7 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -async-eventemitter@^0.2.2: +async-eventemitter@^0.2.2, async-eventemitter@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== @@ -1135,6 +1501,11 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + available-typed-arrays@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" @@ -1740,6 +2111,11 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bintrees@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" + integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= + bip39@2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.5.0.tgz#51cbd5179460504a63ea3c000db3f787ca051235" @@ -2215,6 +2591,15 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -2247,11 +2632,23 @@ color-convert@^1.9.0: dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -2278,6 +2675,11 @@ commander@3.0.2: resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -2374,6 +2776,14 @@ cors@^2.8.1: object-assign "^4" vary "^1" +crc-32@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + create-ecdh@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" @@ -2566,6 +2976,14 @@ 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: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -2689,6 +3107,11 @@ domutils@^2.4.3, domutils@^2.4.4: domelementtype "^2.2.0" domhandler "^4.1.0" +dotenv@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + dotignore@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" @@ -2701,6 +3124,16 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= +duplexify@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.1.tgz#7027dc374f157b122a8ae08c2d3ea4d2d953aa61" + integrity sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.0" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -2750,6 +3183,11 @@ emoji-regex@^7.0.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -2766,6 +3204,16 @@ 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" @@ -2773,7 +3221,7 @@ encoding@^0.1.11: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -2873,6 +3321,11 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.3: d "^1.0.1" ext "^1.1.2" +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -3246,7 +3699,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.2: +ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.2, ethereumjs-util@^7.0.7, ethereumjs-util@^7.0.8, ethereumjs-util@^7.0.9: version "7.0.10" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f" integrity sha512-c/xThw6A+EAnej5Xk5kOzFzyoSnw0WX0tSlZ6pAsfGVvQj3TItaDg9b1+Fz1RJXA+y2YksKwQnuzgt1eY6LKzw== @@ -3326,7 +3779,7 @@ ethers@^4.0.32, ethers@^4.0.45: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.2, ethers@^5.1.0: +ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.2, ethers@^5.0.31: version "5.1.0" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.1.0.tgz#8a8758e0b6cbbc19fd4b87f4d551170fa6f1a995" integrity sha512-2L6Ge6wMBw02FlRoCLg4E0Elt3khMNlW6ULawa10mMeeZToYJ5+uCfiuTuB+XZ6om1Y7wuO9ZzezP8FsU2M/+g== @@ -3362,6 +3815,42 @@ ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.2, ethers@^5.1.0: "@ethersproject/web" "5.1.0" "@ethersproject/wordlists" "5.1.0" +ethers@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.1.3.tgz#68eb48742b8a8ca53480bca2e53fb314c23fea7f" + integrity sha512-QAj+LG3z5HsK6UDAOdCjDEthWioZ7sTzAcMWyVrQF+ACioalQ99NrrSxIq5qS0c+hoy3TAIjqpYteHgC2Iqy+w== + dependencies: + "@ethersproject/abi" "5.1.1" + "@ethersproject/abstract-provider" "5.1.0" + "@ethersproject/abstract-signer" "5.1.0" + "@ethersproject/address" "5.1.0" + "@ethersproject/base64" "5.1.0" + "@ethersproject/basex" "5.1.0" + "@ethersproject/bignumber" "5.1.1" + "@ethersproject/bytes" "5.1.0" + "@ethersproject/constants" "5.1.0" + "@ethersproject/contracts" "5.1.1" + "@ethersproject/hash" "5.1.0" + "@ethersproject/hdnode" "5.1.0" + "@ethersproject/json-wallets" "5.1.0" + "@ethersproject/keccak256" "5.1.0" + "@ethersproject/logger" "5.1.0" + "@ethersproject/networks" "5.1.0" + "@ethersproject/pbkdf2" "5.1.0" + "@ethersproject/properties" "5.1.0" + "@ethersproject/providers" "5.1.2" + "@ethersproject/random" "5.1.0" + "@ethersproject/rlp" "5.1.0" + "@ethersproject/sha2" "5.1.0" + "@ethersproject/signing-key" "5.1.0" + "@ethersproject/solidity" "5.1.0" + "@ethersproject/strings" "5.1.0" + "@ethersproject/transactions" "5.1.1" + "@ethersproject/units" "5.1.0" + "@ethersproject/wallet" "5.1.0" + "@ethersproject/web" "5.1.0" + "@ethersproject/wordlists" "5.1.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -3411,6 +3900,11 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -3528,6 +4022,16 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-redact@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.0.tgz#ac2f9e36c9f4976f5db9fb18c6ffbaf308cf316d" + integrity sha512-a/S/Hp6aoIjx7EmugtzLqXmcNsyFszqbt6qQ99BdG61QjBZF6shNis0BYR6TsZOQ1twYc0FN2Xdhwwbv6+KD0w== + +fast-safe-stringify@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== + fetch-ponyfill@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" @@ -3617,6 +4121,11 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" +flatstr@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" + integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw== + flow-stoplight@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" @@ -3797,7 +4306,7 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -3951,15 +4460,19 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" -hardhat@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.1.2.tgz#a2128b71b0fb216ffc978c85a2030835b4e306ea" - integrity sha512-42iOheDsDl6Gr7sBfpA0S+bQUIcXSDEUrrqmnFEcBHx9qBoQad3s212y2ODmmkdLt+PqqTM+Mq8N3bZDTdjoLg== - dependencies: - "@nomiclabs/ethereumjs-vm" "4.2.2" +hardhat@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.2.0.tgz#7d569d29678e5f786a228390b4c0b0cc9fd8ae32" + integrity sha512-3g0qFoQTkR4gfcHDZr59vPfbSH2PiAyxzYblkAAHUNTPBadO5W26z5RWzDv6/lRu8SqZZ9/8AdGZX4IZEa8EDg== + dependencies: + "@ethereumjs/block" "^3.2.1" + "@ethereumjs/blockchain" "^5.2.1" + "@ethereumjs/common" "^2.2.0" + "@ethereumjs/tx" "^3.1.3" + "@ethereumjs/vm" "^5.3.2" "@sentry/node" "^5.18.1" "@solidity-parser/parser" "^0.11.0" - "@types/bn.js" "^4.11.5" + "@types/bn.js" "^5.1.0" "@types/lru-cache" "^5.1.0" abort-controller "^3.0.0" adm-zip "^0.4.16" @@ -3973,11 +4486,7 @@ hardhat@^2.1.2: eth-sig-util "^2.5.2" ethereum-cryptography "^0.1.2" ethereumjs-abi "^0.6.8" - ethereumjs-account "^3.0.0" - ethereumjs-block "^2.2.2" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.2" - ethereumjs-util "^6.2.0" + ethereumjs-util "^7.0.10" find-up "^2.1.0" fp-ts "1.19.3" fs-extra "^7.0.1" @@ -3985,7 +4494,7 @@ hardhat@^2.1.2: immutable "^4.0.0-rc.12" io-ts "1.10.4" lodash "^4.17.11" - merkle-patricia-tree "3.0.0" + merkle-patricia-tree "^4.1.0" mnemonist "^0.38.0" mocha "^7.1.2" node-fetch "^2.6.0" @@ -4438,6 +4947,11 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-function@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" @@ -4814,6 +5328,11 @@ 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" @@ -4863,6 +5382,15 @@ 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" @@ -4871,6 +5399,22 @@ 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" @@ -4902,6 +5446,13 @@ level-sublevel@6.6.4: typewiselite "~1.0.0" xtend "~4.0.0" +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-ws@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" @@ -4919,6 +5470,15 @@ 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" + levelup@3.1.1, levelup@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/levelup/-/levelup-3.1.1.tgz#c2c0b3be2b4dc316647c53b42e2f559e232d2189" @@ -4942,6 +5502,17 @@ 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== + 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" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -5004,7 +5575,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.14, lodash@^4.17.15, lodash@^4.17.4: +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, 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== @@ -5096,6 +5667,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +mcl-wasm@^0.7.1: + version "0.7.6" + resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.6.tgz#c1789ebda5565d49b77d2ee195ff3e4d282f1554" + integrity sha512-cbRl3sUOkBeRY2hsM4t1EIln2TIdQBkSiTOqNTv/4Hu5KOECnMWCgjIf+a9Ebunyn22VKqkMF3zj6ejRzz7YBw== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -5122,6 +5698,18 @@ 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" @@ -5171,6 +5759,19 @@ merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: rlp "^2.0.0" semaphore ">=1.0.1" +merkle-patricia-tree@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-4.1.0.tgz#010636c4cfd68682df33a2e3186b7d0be7b98b9d" + integrity sha512-vmP1J7FwIpprFMVjjSMM1JAwFce85Q+tp0TYIedYv8qaMh2oLUZ3ETXn9wbgi9S6elySzKzGa+Ai6VNKGEwSlg== + dependencies: + "@types/levelup" "^4.3.0" + ethereumjs-util "^7.0.8" + level-mem "^5.0.1" + level-ws "^2.0.0" + readable-stream "^3.6.0" + rlp "^2.2.3" + 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" @@ -5471,7 +6072,7 @@ node-fetch@2.1.2: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U= -node-fetch@^2.6.0: +node-fetch@^2.6.0, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -5918,6 +6519,53 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +pino-multi-stream@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/pino-multi-stream/-/pino-multi-stream-5.3.0.tgz#2816ec4422c7e37e676a210a1705c7155506afd4" + integrity sha512-4fAGCRll18I+JmoAbxDvU9zc5sera/3c+VgTtUdoNMOZ/VSHB+HMAYtixKpeRmZTDHDDdE2rtwjVkuwWB8mYQA== + dependencies: + pino "^6.0.0" + +pino-sentry@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/pino-sentry/-/pino-sentry-0.7.0.tgz#087717d2787ec437627e97454238ca7ce0562a91" + integrity sha512-/rZO1R/oMcMa4mzfIqW6Afap+TGgVHgB8iZfzwjhLdT2PhyuTUNJ3KJT2eIZ0citsQNv26pxRzIPbqgHuQtUAQ== + dependencies: + "@sentry/node" "^6.2.5" + commander "^2.20.0" + pumpify "^2.0.1" + split2 "^3.1.1" + through2 "^3.0.1" + +pino-std-serializers@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" + integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== + +pino@^6.0.0: + version "6.11.3" + resolved "https://registry.yarnpkg.com/pino/-/pino-6.11.3.tgz#0c02eec6029d25e6794fdb6bbea367247d74bc29" + integrity sha512-drPtqkkSf0ufx2gaea3TryFiBHdNIdXKf5LN0hTM82SXI4xVIve2wLwNg92e1MT6m3jASLu6VO7eGY6+mmGeyw== + dependencies: + fast-redact "^3.0.0" + fast-safe-stringify "^2.0.7" + flatstr "^1.0.12" + pino-std-serializers "^3.1.0" + quick-format-unescaped "^4.0.3" + sonic-boom "^1.0.2" + +pino@^6.11.1: + version "6.11.2" + resolved "https://registry.yarnpkg.com/pino/-/pino-6.11.2.tgz#2f3d119c526651aab4ec3d280844785d52d0b690" + integrity sha512-bmzxwbrIPxQUlAuMkF4PWVErUGERU4z37HazlhflKFg08crsNE3fACGN6gPwg5xtKOK47Ux5cZm8YCuLV4wWJg== + dependencies: + fast-redact "^3.0.0" + fast-safe-stringify "^2.0.7" + flatstr "^1.0.12" + pino-std-serializers "^3.1.0" + quick-format-unescaped "4.0.1" + sonic-boom "^1.0.2" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -5948,6 +6596,11 @@ prettier@^2.1.2, prettier@^2.2.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== +printj@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== + private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -5963,6 +6616,13 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= +prom-client@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-13.1.0.tgz#1185caffd8691e28d32e373972e662964e3dba45" + integrity sha512-jT9VccZCWrJWXdyEtQddCDszYsiuWj5T0ekrPszi/WEegj3IZy6Mm09iOOVM86A4IKMWq8hZkT2dD9MaSe+sng== + dependencies: + tdigest "^0.1.1" + promise-to-callback@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" @@ -6062,6 +6722,15 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +pumpify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-2.0.1.tgz#abfc7b5a621307c728b551decbbefb51f0e4aa1e" + integrity sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw== + dependencies: + duplexify "^4.1.1" + inherits "^2.0.3" + pump "^3.0.0" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -6108,6 +6777,16 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= +quick-format-unescaped@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.1.tgz#437a5ea1a0b61deb7605f8ab6a8fd3858dbeb701" + integrity sha512-RyYpQ6Q5/drsJyOhrWHYMWTedvjTIat+FTwv0K4yoUxzvekw2aRHMQJLlnvt8UantkZg2++bEzD9EdxXqkWf4A== + +quick-format-unescaped@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz#6d6b66b8207aa2b35eef12be1421bb24c428f652" + integrity sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -6165,6 +6844,15 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" +"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.0.6, readable-stream@^3.1.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@^1.0.33: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" @@ -6188,15 +6876,6 @@ 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.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@~1.0.15: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" @@ -6471,6 +7150,11 @@ 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 sha1-hXvvXjZEYBykuVcLh+nfXKEpdPo= + 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" @@ -6486,7 +7170,7 @@ semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.4, semver@^7.3.5: +semver@^7.3.4: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -6701,6 +7385,14 @@ solc@^0.6.3: semver "^5.5.0" tmp "0.0.33" +sonic-boom@^1.0.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" + integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg== + dependencies: + atomic-sleep "^1.0.0" + flatstr "^1.0.12" + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -6783,6 +7475,13 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split2@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -6823,6 +7522,11 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + stream-to-pull-stream@^1.7.1: version "1.7.3" resolved "https://registry.yarnpkg.com/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz#4161aa2d2eb9964de60bfa1af7feaf917e874ece" @@ -6862,6 +7566,15 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + string.prototype.trim@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz#6014689baf5efaf106ad031a5fa45157666ed1bd" @@ -6927,6 +7640,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -7026,6 +7746,13 @@ tar@^4.0.2: safe-buffer "^5.1.2" yallist "^3.0.3" +tdigest@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" + integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE= + dependencies: + bintrees "1.0.1" + test-value@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/test-value/-/test-value-2.1.0.tgz#11da6ff670f3471a73b625ca4f3fdcf7bb748291" @@ -7047,6 +7774,14 @@ through2@^2.0.3: readable-stream "~2.3.6" xtend "~4.0.1" +through2@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -7432,7 +8167,7 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util.promisify@^1.0.0: +util.promisify@^1.0.0, util.promisify@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.1.tgz#77832f57ced2c9478174149cae9b96e9918cd54b" integrity sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw== @@ -8345,6 +9080,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8418,7 +9162,7 @@ xmlhttprequest@1.8.0: resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, 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== @@ -8440,6 +9184,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yaeti@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" @@ -8471,6 +9220,11 @@ yargs-parser@^2.4.1: camelcase "^3.0.0" lodash.assign "^4.0.6" +yargs-parser@^20.2.2: + version "20.2.7" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" + integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== + yargs-unparser@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" @@ -8496,6 +9250,19 @@ yargs@13.3.2, yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@^4.7.1: version "4.8.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0"