diff --git a/.github/actions/setup-repo/action.yml b/.github/actions/setup-repo/action.yml new file mode 100644 index 0000000..3c5cc7d --- /dev/null +++ b/.github/actions/setup-repo/action.yml @@ -0,0 +1,35 @@ +name: Setup repo +description: Runs all steps to setup the repo (install node_modules, build, etc...) +inputs: + registry-token: + description: 'PAT to access registries' +runs: + using: 'composite' + steps: + - name: Get yarn cache directory path + id: yarn-cache-dir-path + shell: bash + run: | + echo "::set-output name=dir::$(yarn cache dir)" + echo "::set-output name=version::$(yarn -v)" + + - uses: actions/setup-node@v3 + with: + node-version: '20' + + - uses: actions/cache@v2 + id: yarn-cache + with: + path: | + **/node_modules + ${{ steps.yarn-cache-dir-path.outputs.dir }} + + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependencies + shell: bash + run: echo "//npm.pkg.github.com/:_authToken=$GH_REGISTRY_ACCESS_TOKEN" >> .npmrc && yarn install --frozen-lockfile --verbose && rm -f .npmrc + env: + GH_REGISTRY_ACCESS_TOKEN: ${{ inputs.registry-token }} \ No newline at end of file diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index a75ce1b..f0539f8 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -32,8 +32,10 @@ jobs: node-version: 18 cache: "yarn" - - name: Install dependencies - run: yarn install + - name: Setup repo + uses: ./.github/actions/setup-repo + with: + registry-token: ${{ secrets.GH_REGISTRY_ACCESS_TOKEN }} - name: Run solhint run: yarn lint:check @@ -56,7 +58,12 @@ jobs: version: nightly - name: Compile foundry - run: yarn compile --sizes + run: yarn compile + + - name: Setup repo + uses: ./.github/actions/setup-repo + with: + registry-token: ${{ secrets.GH_REGISTRY_ACCESS_TOKEN }} - name: "Cache the build so that it can be re-used by the other jobs" uses: "actions/cache/save@v3" @@ -65,6 +72,7 @@ jobs: path: | cache-forge out + node_modules - name: "Add build summary" run: | @@ -85,6 +93,7 @@ jobs: path: | cache-forge out + node_modules key: "build-${{ github.sha }}" - name: Install Foundry @@ -92,6 +101,13 @@ jobs: with: version: nightly + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install vyper + run: pip install vyper==0.2.16 + - name: Run Foundry tests run: yarn test:unit env: @@ -119,6 +135,7 @@ jobs: path: | cache-forge out + node_modules key: "build-${{ github.sha }}" - name: Install Foundry @@ -126,6 +143,13 @@ jobs: with: version: nightly + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install vyper + run: pip install vyper==0.2.16 + - name: Run Foundry tests run: yarn test:invariant env: @@ -155,6 +179,7 @@ jobs: path: | cache-forge out + node_modules key: "build-${{ github.sha }}" - name: Install Foundry @@ -162,6 +187,13 @@ jobs: with: version: nightly + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install vyper + run: pip install vyper==0.2.16 + - name: Run Foundry tests run: yarn test:fuzz env: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20fef55..e83e289 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,8 +21,10 @@ jobs: node-version: 18 cache: "yarn" - - name: Install dependencies - run: yarn install + - name: Setup repo + uses: ./.github/actions/setup-repo + with: + registry-token: ${{ secrets.GH_REGISTRY_ACCESS_TOKEN }} - name: Run solhint run: yarn lint:check @@ -44,8 +46,13 @@ jobs: with: version: nightly + - name: Setup repo + uses: ./.github/actions/setup-repo + with: + registry-token: ${{ secrets.GH_REGISTRY_ACCESS_TOKEN }} + - name: Compile foundry - run: yarn compile --sizes + run: yarn compile - name: "Cache the build so that it can be re-used by the other jobs" uses: "actions/cache/save@v3" @@ -54,6 +61,7 @@ jobs: path: | cache-forge out + node_modules - name: "Add build summary" run: | @@ -74,6 +82,7 @@ jobs: path: | cache-forge out + node_modules key: "build-${{ github.sha }}" - name: Install Foundry @@ -81,6 +90,13 @@ jobs: with: version: nightly + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install vyper + run: pip install vyper==0.2.16 + - name: Run Foundry tests run: yarn test:unit env: @@ -108,6 +124,7 @@ jobs: path: | cache-forge out + node_modules key: "build-${{ github.sha }}" - name: Install Foundry @@ -115,6 +132,13 @@ jobs: with: version: nightly + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install vyper + run: pip install vyper==0.2.16 + - name: Run Foundry tests run: yarn test:invariant env: @@ -144,6 +168,7 @@ jobs: path: | cache-forge out + node_modules key: "build-${{ github.sha }}" - name: Install Foundry @@ -151,6 +176,13 @@ jobs: with: version: nightly + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install vyper + run: pip install vyper==0.2.16 + - name: Run Foundry tests run: npm run test:fuzz env: @@ -176,6 +208,18 @@ jobs: - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" + - name: Setup repo + uses: ./.github/actions/setup-repo + with: + registry-token: ${{ secrets.GH_REGISTRY_ACCESS_TOKEN }} + + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install vyper + run: pip install vyper==0.2.16 + - name: "Install lcov" run: "sudo apt-get install lcov" diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..af66bba --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@angleprotocol:registry=https://npm.pkg.github.com diff --git a/.solhint.json b/.solhint.json index 99c3260..d9609eb 100644 --- a/.solhint.json +++ b/.solhint.json @@ -2,7 +2,7 @@ "extends": "solhint:recommended", "plugins": ["prettier"], "rules": { - "max-line-length": ["error", 120], + "max-line-length": ["warn", 120], "avoid-call-value": "warn", "avoid-low-level-calls": "off", "avoid-tx-origin": "warn", @@ -23,6 +23,7 @@ "no-complex-fallback": "off", "reason-string": "off", "func-visibility": ["warn", { "ignoreConstructors": true }], - "explicit-types": ["error","explicit"] + "explicit-types": ["error","explicit"], + "custom-errors": "off" } } diff --git a/.vscode/settings.json b/.vscode/settings.json index e6b354a..ab5d1b9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "solidity.compileUsingRemoteVersion": "0.8.20", + "solidity.compileUsingRemoteVersion": "0.8.22", "[solidity]": { "editor.defaultFormatter": "JuanBlanco.solidity", "editor.formatOnSave": true diff --git a/README.md b/README.md index 07aa577..d5a8393 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # Angle Angle DAO [![CI](https://github.com/AngleProtocol/boilerplate/actions/workflows/ci.yml/badge.svg)](https://github.com/AngleProtocol/boilerplate/actions) -[![Coverage](https://codecov.io/gh/AngleProtocol/boilerplate/branch/main/graph/badge.svg)](https://codecov.io/gh/AngleProtocol/boilerplate) -This repository proposes a template that is based on foundry frameworks. It also provides templates for EVM compatible smart contracts (in `./contracts/example`), tests and deployment scripts. +## Overview + +This repository contains all the contracts related to the Angle DAO including the angle, veANGLE ... etc. ## Starting @@ -119,32 +120,6 @@ yarn hardhat:coverage yarn foundry:coverage ``` -### Simulate - -You can simulate your transaction live or in fork mode. For both option you need to -complete the `scripts/foundry/Simulate.s.sol` with your values: address sending the tx, -address caled and the data to give to this address call. - -For live simulation - -```bash -yarn foundry:simulate -``` - -For fork simulation - -```bash -yarn foundry:fork -yarn foundry:simulate:fork -``` - -For fork simulation at a given block - -```bash -yarn foundry:fork:block ${XXXX} -yarn foundry:simulate:fork -``` - ### Gas report ```bash diff --git a/contracts/dao/veANGLE-old.vy b/contracts/dao/veANGLE-old.vy new file mode 100644 index 0000000..674f991 --- /dev/null +++ b/contracts/dao/veANGLE-old.vy @@ -0,0 +1,710 @@ +# @version 0.2.16 +""" +@title Voting Escrow +@author Angle Protocol +@license MIT +@notice Votes have a weight depending on time, so that users are + committed to the future of (whatever they are voting for) +@dev Vote weight decays linearly over time. Lock time cannot be + more than `MAXTIME` (4 years). +""" + +# Original idea and credit: +# Curve Finance's veCRV +# https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy +# veANGLE is a fork with only one view functions added to it to make veANGLE compatible +# with Compound governance system. The references to the controller have also been removed + +# Voting escrow to have time-weighted votes +# Votes have a weight depending on time, so that users are committed +# to the future of (whatever they are voting for). +# The weight in this implementation is linear, and lock cannot be more than maxtime: +# w ^ +# 1 + / +# | / +# | / +# | / +# |/ +# 0 +--------+------> time +# maxtime (4 years?) + +struct Point: + bias: int128 + slope: int128 # - dweight / dt + ts: uint256 + blk: uint256 # block +# We cannot really do block numbers per se b/c slope is per time, not per block +# and per block could be fairly bad b/c Ethereum changes blocktimes. +# What we can do is to extrapolate ***At functions + +struct LockedBalance: + amount: int128 + end: uint256 + + +interface ERC20: + def decimals() -> uint256: view + def name() -> String[64]: view + def symbol() -> String[32]: view + def transfer(to: address, amount: uint256) -> bool: nonpayable + def transferFrom(spender: address, to: address, amount: uint256) -> bool: nonpayable + + +# Interface for checking whether address belongs to a whitelisted +# type of a smart wallet. +# When new types are added - the whole contract is changed +# The check() method is modifying to be able to use caching +# for individual wallet addresses +interface SmartWalletChecker: + def check(addr: address) -> bool: nonpayable + +DEPOSIT_FOR_TYPE: constant(int128) = 0 +CREATE_LOCK_TYPE: constant(int128) = 1 +INCREASE_LOCK_AMOUNT: constant(int128) = 2 +INCREASE_UNLOCK_TIME: constant(int128) = 3 + + +event CommitOwnership: + admin: address + +event ApplyOwnership: + admin: address + +event Deposit: + provider: indexed(address) + value: uint256 + locktime: indexed(uint256) + type: int128 + ts: uint256 + +event Withdraw: + provider: indexed(address) + value: uint256 + ts: uint256 + +event Supply: + prevSupply: uint256 + supply: uint256 + + +WEEK: constant(uint256) = 7 * 86400 # all future times are rounded by week +MAXTIME: constant(uint256) = 4 * 365 * 86400 # 4 years +MULTIPLIER: constant(uint256) = 10 ** 18 + +token: public(address) +supply: public(uint256) + +locked: public(HashMap[address, LockedBalance]) + +epoch: public(uint256) +point_history: public(Point[100000000000000000000000000000]) # epoch -> unsigned point +user_point_history: public(HashMap[address, Point[1000000000]]) # user -> Point[user_epoch] +user_point_epoch: public(HashMap[address, uint256]) +slope_changes: public(HashMap[uint256, int128]) # time -> signed slope change + +name: public(String[64]) +symbol: public(String[32]) +decimals: public(uint256) + +# Checker for whitelisted (smart contract) wallets which are allowed to deposit +# The goal is to prevent tokenizing the escrow +future_smart_wallet_checker: public(address) +smart_wallet_checker: public(address) + +admin: public(address) # Can and will be a smart contract +future_admin: public(address) + +initialized: public(bool) + + +@external +def __init__(): + """ + @notice Contract constructor + @dev The contract has an initializer to prevent the take over of the implementation + """ + assert self.initialized == False #dev: contract is already initialized + self.initialized = True + +@external +def initialize(_admin: address, token_addr: address, _smart_wallet_checker: address, _name: String[64], _symbol: String[32]): + """ + @notice Contract initializer + @param _admin Future veANGLE admin + @param token_addr `ERC20ANGLE` token address + @param _smart_wallet_checker Future smart wallet checker contract + @param _name Token name + @param _symbol Token symbol + """ + assert self.initialized == False #dev: contract is already initialized + self.initialized = True + assert _admin!= ZERO_ADDRESS #dev: admin cannot be the 0 address + self.admin = _admin + self.token = token_addr + self.smart_wallet_checker = _smart_wallet_checker + self.point_history[0].blk = block.number + self.point_history[0].ts = block.timestamp + + _decimals: uint256 = ERC20(token_addr).decimals() + assert _decimals <= 255 + self.decimals = _decimals + + self.name = _name + self.symbol = _symbol + + +@external +def commit_transfer_ownership(addr: address): + """ + @notice Transfer ownership of VotingEscrow contract to `addr` + @param addr Address to have ownership transferred to + """ + assert msg.sender == self.admin # dev: admin only + assert addr != ZERO_ADDRESS # dev: future admin cannot be the 0 address + self.future_admin = addr + log CommitOwnership(addr) + +@external +def accept_transfer_ownership(): + """ + @notice Accept a pending ownership transfer + """ + _admin: address = self.future_admin + assert msg.sender == _admin # dev: future admin only + + self.admin = _admin + log ApplyOwnership(_admin) + +@external +def apply_transfer_ownership(): + """ + @notice Apply ownership transfer + """ + assert msg.sender == self.admin # dev: admin only + _admin: address = self.future_admin + assert _admin != ZERO_ADDRESS # dev: admin not set + self.admin = _admin + log ApplyOwnership(_admin) + + +@external +def commit_smart_wallet_checker(addr: address): + """ + @notice Set an external contract to check for approved smart contract wallets + @param addr Address of Smart contract checker + """ + assert msg.sender == self.admin + self.future_smart_wallet_checker = addr + + +@external +def apply_smart_wallet_checker(): + """ + @notice Apply setting external contract to check approved smart contract wallets + """ + assert msg.sender == self.admin + self.smart_wallet_checker = self.future_smart_wallet_checker + + +@internal +def assert_not_contract(addr: address): + """ + @notice Check if the call is from a whitelisted smart contract, revert if not + @param addr Address to be checked + """ + if addr != tx.origin: + checker: address = self.smart_wallet_checker + if checker != ZERO_ADDRESS: + if SmartWalletChecker(checker).check(addr): + return + raise "Smart contract depositors not allowed" + + +@external +@view +def get_last_user_slope(addr: address) -> int128: + """ + @notice Get the most recently recorded rate of voting power decrease for `addr` + @param addr Address of the user wallet + @return Value of the slope + """ + uepoch: uint256 = self.user_point_epoch[addr] + return self.user_point_history[addr][uepoch].slope + + +@external +@view +def user_point_history__ts(_addr: address, _idx: uint256) -> uint256: + """ + @notice Get the timestamp for checkpoint `_idx` for `_addr` + @param _addr User wallet address + @param _idx User epoch number + @return Epoch time of the checkpoint + """ + return self.user_point_history[_addr][_idx].ts + + +@external +@view +def locked__end(_addr: address) -> uint256: + """ + @notice Get timestamp when `_addr`'s lock finishes + @param _addr User wallet + @return Epoch time of the lock end + """ + return self.locked[_addr].end + + +@internal +def _checkpoint(addr: address, old_locked: LockedBalance, new_locked: LockedBalance): + """ + @notice Record global and per-user data to checkpoint + @param addr User's wallet address. No user checkpoint if 0x0 + @param old_locked Pevious locked amount / end lock time for the user + @param new_locked New locked amount / end lock time for the user + """ + u_old: Point = empty(Point) + u_new: Point = empty(Point) + old_dslope: int128 = 0 + new_dslope: int128 = 0 + _epoch: uint256 = self.epoch + + if addr != ZERO_ADDRESS: + # Calculate slopes and biases + # Kept at zero when they have to + if old_locked.end > block.timestamp and old_locked.amount > 0: + u_old.slope = old_locked.amount / MAXTIME + u_old.bias = u_old.slope * convert(old_locked.end - block.timestamp, int128) + if new_locked.end > block.timestamp and new_locked.amount > 0: + u_new.slope = new_locked.amount / MAXTIME + u_new.bias = u_new.slope * convert(new_locked.end - block.timestamp, int128) + + # Read values of scheduled changes in the slope + # old_locked.end can be in the past and in the future + # new_locked.end can ONLY by in the FUTURE unless everything expired: than zeros + old_dslope = self.slope_changes[old_locked.end] + if new_locked.end != 0: + if new_locked.end == old_locked.end: + new_dslope = old_dslope + else: + new_dslope = self.slope_changes[new_locked.end] + + last_point: Point = Point({bias: 0, slope: 0, ts: block.timestamp, blk: block.number}) + if _epoch > 0: + last_point = self.point_history[_epoch] + last_checkpoint: uint256 = last_point.ts + # initial_last_point is used for extrapolation to calculate block number + # (approximately, for *At methods) and save them + # as we cannot figure that out exactly from inside the contract + initial_last_point: Point = last_point + block_slope: uint256 = 0 # dblock/dt + if block.timestamp > last_point.ts: + block_slope = MULTIPLIER * (block.number - last_point.blk) / (block.timestamp - last_point.ts) + # If last point is already recorded in this block, slope=0 + # But that's ok b/c we know the block in such case + + # Go over weeks to fill history and calculate what the current point is + t_i: uint256 = (last_checkpoint / WEEK) * WEEK + for i in range(255): + # Hopefully it won't happen that this won't get used in 5 years! + # If it does, users will be able to withdraw but vote weight will be broken + t_i += WEEK + d_slope: int128 = 0 + if t_i > block.timestamp: + t_i = block.timestamp + else: + d_slope = self.slope_changes[t_i] + last_point.bias -= last_point.slope * convert(t_i - last_checkpoint, int128) + last_point.slope += d_slope + if last_point.bias < 0: # This can happen + last_point.bias = 0 + if last_point.slope < 0: # This cannot happen - just in case + last_point.slope = 0 + last_checkpoint = t_i + last_point.ts = t_i + last_point.blk = initial_last_point.blk + block_slope * (t_i - initial_last_point.ts) / MULTIPLIER + _epoch += 1 + if t_i == block.timestamp: + last_point.blk = block.number + break + else: + self.point_history[_epoch] = last_point + + self.epoch = _epoch + # Now point_history is filled until t=now + + if addr != ZERO_ADDRESS: + # If last point was in this block, the slope change has been applied already + # But in such case we have 0 slope(s) + last_point.slope += (u_new.slope - u_old.slope) + last_point.bias += (u_new.bias - u_old.bias) + if last_point.slope < 0: + last_point.slope = 0 + if last_point.bias < 0: + last_point.bias = 0 + + # Record the changed point into history + self.point_history[_epoch] = last_point + + if addr != ZERO_ADDRESS: + # Schedule the slope changes (slope is going down) + # We subtract new_user_slope from [new_locked.end] + # and add old_user_slope to [old_locked.end] + if old_locked.end > block.timestamp: + # old_dslope was - u_old.slope, so we cancel that + old_dslope += u_old.slope + if new_locked.end == old_locked.end: + old_dslope -= u_new.slope # It was a new deposit, not extension + self.slope_changes[old_locked.end] = old_dslope + + if new_locked.end > block.timestamp: + if new_locked.end > old_locked.end: + new_dslope -= u_new.slope # old slope disappeared at this point + self.slope_changes[new_locked.end] = new_dslope + # else: we recorded it already in old_dslope + + # Now handle user history + user_epoch: uint256 = self.user_point_epoch[addr] + 1 + + self.user_point_epoch[addr] = user_epoch + u_new.ts = block.timestamp + u_new.blk = block.number + self.user_point_history[addr][user_epoch] = u_new + + +@internal +def _deposit_for(_addr: address, _value: uint256, unlock_time: uint256, locked_balance: LockedBalance, type: int128, sender: address): + """ + @notice Deposit and lock tokens for a user + @param _addr User's wallet address + @param _value Amount to deposit + @param unlock_time New time when to unlock the tokens, or 0 if unchanged + @param locked_balance Previous locked amount / timestamp + """ + _locked: LockedBalance = locked_balance + supply_before: uint256 = self.supply + + self.supply = supply_before + _value + old_locked: LockedBalance = _locked + # Adding to existing lock, or if a lock is expired - creating a new one + _locked.amount += convert(_value, int128) + if unlock_time != 0: + _locked.end = unlock_time + self.locked[_addr] = _locked + + # Possibilities: + # Both old_locked.end could be current or expired (>/< block.timestamp) + # value == 0 (extend lock) or value > 0 (add to lock or extend lock) + # _locked.end > block.timestamp (always) + self._checkpoint(_addr, old_locked, _locked) + + if _value != 0: + assert ERC20(self.token).transferFrom(sender, self, _value) + + log Deposit(_addr, _value, _locked.end, type, block.timestamp) + log Supply(supply_before, supply_before + _value) + + +@external +def checkpoint(): + """ + @notice Record global data to checkpoint + """ + self._checkpoint(ZERO_ADDRESS, empty(LockedBalance), empty(LockedBalance)) + + +@external +@nonreentrant('lock') +def deposit_for(_addr: address, _value: uint256): + """ + @notice Deposit `_value` tokens for `_addr` and add to the lock + @dev Anyone (even a smart contract) can deposit for someone else, but + cannot extend their locktime and deposit for a brand new user + @param _addr User's wallet address + @param _value Amount to add to user's lock + """ + _locked: LockedBalance = self.locked[_addr] + + assert _value > 0 # dev: need non-zero value + assert _locked.amount > 0, "No existing lock found" + assert _locked.end > block.timestamp, "Cannot add to expired lock. Withdraw" + + self._deposit_for(_addr, _value, 0, self.locked[_addr], DEPOSIT_FOR_TYPE, msg.sender) + + +@external +@nonreentrant('lock') +def create_lock(_value: uint256, _unlock_time: uint256): + """ + @notice Deposit `_value` tokens for `msg.sender` and lock until `_unlock_time` + @param _value Amount to deposit + @param _unlock_time Epoch time when tokens unlock, rounded down to whole weeks + """ + self.assert_not_contract(msg.sender) + unlock_time: uint256 = (_unlock_time / WEEK) * WEEK # Locktime is rounded down to weeks + _locked: LockedBalance = self.locked[msg.sender] + + assert _value > 0 # dev: need non-zero value + assert _locked.amount == 0, "Withdraw old tokens first" + assert unlock_time > block.timestamp, "Can only lock until time in the future" + assert unlock_time <= block.timestamp + MAXTIME, "Voting lock can be 4 years max" + + self._deposit_for(msg.sender, _value, unlock_time, _locked, CREATE_LOCK_TYPE, msg.sender) + + +@external +@nonreentrant('lock') +def increase_amount(_value: uint256): + """ + @notice Deposit `_value` additional tokens for `msg.sender` + without modifying the unlock time + @param _value Amount of tokens to deposit and add to the lock + """ + self.assert_not_contract(msg.sender) + _locked: LockedBalance = self.locked[msg.sender] + + assert _value > 0 # dev: need non-zero value + assert _locked.amount > 0, "No existing lock found" + assert _locked.end > block.timestamp, "Cannot add to expired lock. Withdraw" + + self._deposit_for(msg.sender, _value, 0, _locked, INCREASE_LOCK_AMOUNT, msg.sender) + + +@external +@nonreentrant('lock') +def increase_unlock_time(_unlock_time: uint256): + """ + @notice Extend the unlock time for `msg.sender` to `_unlock_time` + @param _unlock_time New epoch time for unlocking + """ + self.assert_not_contract(msg.sender) + _locked: LockedBalance = self.locked[msg.sender] + unlock_time: uint256 = (_unlock_time / WEEK) * WEEK # Locktime is rounded down to weeks + + assert _locked.end > block.timestamp, "Lock expired" + assert _locked.amount > 0, "Nothing is locked" + assert unlock_time > _locked.end, "Can only increase lock duration" + assert unlock_time <= block.timestamp + MAXTIME, "Voting lock can be 4 years max" + + self._deposit_for(msg.sender, 0, unlock_time, _locked, INCREASE_UNLOCK_TIME, msg.sender) + + +@external +@nonreentrant('lock') +def withdraw(): + """ + @notice Withdraw all tokens for `msg.sender` + @dev Only possible if the lock has expired + """ + _locked: LockedBalance = self.locked[msg.sender] + assert block.timestamp >= _locked.end, "The lock didn't expire" + value: uint256 = convert(_locked.amount, uint256) + + old_locked: LockedBalance = _locked + _locked.end = 0 + _locked.amount = 0 + self.locked[msg.sender] = _locked + supply_before: uint256 = self.supply + self.supply = supply_before - value + + # old_locked can have either expired <= timestamp or zero end + # _locked has only 0 end + # Both can have >= 0 amount + self._checkpoint(msg.sender, old_locked, _locked) + + assert ERC20(self.token).transfer(msg.sender, value) + + log Withdraw(msg.sender, value, block.timestamp) + log Supply(supply_before, supply_before - value) + + +# The following ERC20/minime-compatible methods are not real balanceOf and supply! +# They measure the weights for the purpose of voting, so they don't represent +# real coins. + +@internal +@view +def find_block_epoch(_block: uint256, max_epoch: uint256) -> uint256: + """ + @notice Binary search to estimate timestamp for block number + @param _block Block to find + @param max_epoch Don't go beyond this epoch + @return Approximate timestamp for block + """ + # Binary search + _min: uint256 = 0 + _max: uint256 = max_epoch + for i in range(128): # Will be always enough for 128-bit numbers + if _min >= _max: + break + _mid: uint256 = (_min + _max + 1) / 2 + if self.point_history[_mid].blk <= _block: + _min = _mid + else: + _max = _mid - 1 + return _min + + +@external +@view +def balanceOf(addr: address, _t: uint256 = block.timestamp) -> uint256: + """ + @notice Get the current voting power for `msg.sender` + @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility + @param addr User wallet address + @param _t Epoch time to return voting power at + @return User voting power + """ + _epoch: uint256 = self.user_point_epoch[addr] + if _epoch == 0: + return 0 + else: + last_point: Point = self.user_point_history[addr][_epoch] + last_point.bias -= last_point.slope * convert(_t - last_point.ts, int128) + if last_point.bias < 0: + last_point.bias = 0 + return convert(last_point.bias, uint256) + + +@internal +@view +def _balanceOfAt(addr: address, _block: uint256) -> uint256: + """ + @notice measure voting power of `addr` at block height `_block` + @param addr User's wallet address + @param _block Block to calculate the voting power at + @return Voting power + """ + # Copying and pasting totalSupply code because Vyper cannot pass by + # reference yet + assert _block <= block.number + + # Binary search + _min: uint256 = 0 + _max: uint256 = self.user_point_epoch[addr] + for i in range(128): # Will be always enough for 128-bit numbers + if _min >= _max: + break + _mid: uint256 = (_min + _max + 1) / 2 + if self.user_point_history[addr][_mid].blk <= _block: + _min = _mid + else: + _max = _mid - 1 + + upoint: Point = self.user_point_history[addr][_min] + + max_epoch: uint256 = self.epoch + _epoch: uint256 = self.find_block_epoch(_block, max_epoch) + point_0: Point = self.point_history[_epoch] + d_block: uint256 = 0 + d_t: uint256 = 0 + if _epoch < max_epoch: + point_1: Point = self.point_history[_epoch + 1] + d_block = point_1.blk - point_0.blk + d_t = point_1.ts - point_0.ts + else: + d_block = block.number - point_0.blk + d_t = block.timestamp - point_0.ts + block_time: uint256 = point_0.ts + if d_block != 0: + block_time += d_t * (_block - point_0.blk) / d_block + + upoint.bias -= upoint.slope * convert(block_time - upoint.ts, int128) + if upoint.bias >= 0: + return convert(upoint.bias, uint256) + else: + return 0 + + +@external +@view +def balanceOfAt(addr: address, _block: uint256) -> uint256: + """ + @notice Measure voting power of `addr` at block height `_block` + @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime + @param addr User's wallet address + @param _block Block to calculate the voting power at + @return Voting power + """ + return self._balanceOfAt(addr,_block) + + +@external +@view +def getPastVotes(addr: address, _block: uint256) -> uint256: + """ + @notice Measure voting power of `addr` at block height `_block` + @dev Adheres to ERC20Votes `getPastVotes` interface: @openzeppelin-contracts-upgradeable/blob/master/contracts/token/ERC20/extensions/ERC20VotesCompUpgradeable.sol + @param addr User's wallet address + @param _block Block to calculate the voting power at + @return Voting power + """ + return self._balanceOfAt(addr,_block) + + +@internal +@view +def supply_at(point: Point, t: uint256) -> uint256: + """ + @notice Calculate total voting power at some point in the past + @param point The point (bias/slope) to start search from + @param t Time to calculate the total voting power at + @return Total voting power at that time + """ + last_point: Point = point + t_i: uint256 = (last_point.ts / WEEK) * WEEK + for i in range(255): + t_i += WEEK + d_slope: int128 = 0 + if t_i > t: + t_i = t + else: + d_slope = self.slope_changes[t_i] + last_point.bias -= last_point.slope * convert(t_i - last_point.ts, int128) + if t_i == t: + break + last_point.slope += d_slope + last_point.ts = t_i + + if last_point.bias < 0: + last_point.bias = 0 + return convert(last_point.bias, uint256) + + +@external +@view +def totalSupply(t: uint256 = block.timestamp) -> uint256: + """ + @notice Calculate total voting power + @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility + @return Total voting power + """ + _epoch: uint256 = self.epoch + last_point: Point = self.point_history[_epoch] + return self.supply_at(last_point, t) + + +@external +@view +def totalSupplyAt(_block: uint256) -> uint256: + """ + @notice Calculate total voting power at some point in the past + @param _block Block to calculate the total voting power at + @return Total voting power at `_block` + """ + assert _block <= block.number + _epoch: uint256 = self.epoch + target_epoch: uint256 = self.find_block_epoch(_block, _epoch) + + point: Point = self.point_history[target_epoch] + dt: uint256 = 0 + if target_epoch < _epoch: + point_next: Point = self.point_history[target_epoch + 1] + if point.blk != point_next.blk: + dt = (_block - point.blk) * (point_next.ts - point.ts) / (point_next.blk - point.blk) + else: + if point.blk != block.number: + dt = (_block - point.blk) * (block.timestamp - point.ts) / (block.number - point.blk) + # Now dt contains info on how far are we beyond point + + return self.supply_at(point, point.ts + dt) \ No newline at end of file diff --git a/contracts/dao/veANGLE.vy b/contracts/dao/veANGLE.vy index 674f991..425893b 100644 --- a/contracts/dao/veANGLE.vy +++ b/contracts/dao/veANGLE.vy @@ -116,15 +116,7 @@ future_admin: public(address) initialized: public(bool) - -@external -def __init__(): - """ - @notice Contract constructor - @dev The contract has an initializer to prevent the take over of the implementation - """ - assert self.initialized == False #dev: contract is already initialized - self.initialized = True +emergency_withdrawal: public(bool) @external def initialize(_admin: address, token_addr: address, _smart_wallet_checker: address, _name: String[64], _symbol: String[32]): @@ -186,6 +178,28 @@ def apply_transfer_ownership(): self.admin = _admin log ApplyOwnership(_admin) +@external +def set_emergency_withdrawal(): + assert msg.sender == self.admin + self.emergency_withdrawal = True + +@external +def withdraw_fast(): + """ + @notice withdraw all tokens when in emergency states + """ + assert self.emergency_withdrawal, "Emergency withdrawal not enabled" + + _locked: LockedBalance = self.locked[msg.sender] + value: uint256 = convert(_locked.amount, uint256) + + # remove lock + self.locked[msg.sender].end = 0 + self.locked[msg.sender].amount = 0 + + assert ERC20(self.token).transfer(msg.sender, value) + + log Withdraw(msg.sender, value, block.timestamp) @external def commit_smart_wallet_checker(addr: address): @@ -371,7 +385,6 @@ def _checkpoint(addr: address, old_locked: LockedBalance, new_locked: LockedBala u_new.blk = block.number self.user_point_history[addr][user_epoch] = u_new - @internal def _deposit_for(_addr: address, _value: uint256, unlock_time: uint256, locked_balance: LockedBalance, type: int128, sender: address): """ @@ -410,9 +423,9 @@ def checkpoint(): """ @notice Record global data to checkpoint """ + assert not self.emergency_withdrawal, "Emergency withdrawal enabled" self._checkpoint(ZERO_ADDRESS, empty(LockedBalance), empty(LockedBalance)) - @external @nonreentrant('lock') def deposit_for(_addr: address, _value: uint256): @@ -423,6 +436,7 @@ def deposit_for(_addr: address, _value: uint256): @param _addr User's wallet address @param _value Amount to add to user's lock """ + assert not self.emergency_withdrawal, "Emergency withdrawal enabled" _locked: LockedBalance = self.locked[_addr] assert _value > 0 # dev: need non-zero value @@ -431,7 +445,6 @@ def deposit_for(_addr: address, _value: uint256): self._deposit_for(_addr, _value, 0, self.locked[_addr], DEPOSIT_FOR_TYPE, msg.sender) - @external @nonreentrant('lock') def create_lock(_value: uint256, _unlock_time: uint256): @@ -440,6 +453,7 @@ def create_lock(_value: uint256, _unlock_time: uint256): @param _value Amount to deposit @param _unlock_time Epoch time when tokens unlock, rounded down to whole weeks """ + assert not self.emergency_withdrawal, "Emergency withdrawal enabled" self.assert_not_contract(msg.sender) unlock_time: uint256 = (_unlock_time / WEEK) * WEEK # Locktime is rounded down to weeks _locked: LockedBalance = self.locked[msg.sender] @@ -460,6 +474,7 @@ def increase_amount(_value: uint256): without modifying the unlock time @param _value Amount of tokens to deposit and add to the lock """ + assert not self.emergency_withdrawal, "Emergency withdrawal enabled" self.assert_not_contract(msg.sender) _locked: LockedBalance = self.locked[msg.sender] @@ -477,6 +492,7 @@ def increase_unlock_time(_unlock_time: uint256): @notice Extend the unlock time for `msg.sender` to `_unlock_time` @param _unlock_time New epoch time for unlocking """ + assert not self.emergency_withdrawal, "Emergency withdrawal enabled" self.assert_not_contract(msg.sender) _locked: LockedBalance = self.locked[msg.sender] unlock_time: uint256 = (_unlock_time / WEEK) * WEEK # Locktime is rounded down to weeks @@ -496,6 +512,7 @@ def withdraw(): @notice Withdraw all tokens for `msg.sender` @dev Only possible if the lock has expired """ + assert not self.emergency_withdrawal, "Emergency withdrawal enabled" _locked: LockedBalance = self.locked[msg.sender] assert block.timestamp >= _locked.end, "The lock didn't expire" value: uint256 = convert(_locked.amount, uint256) @@ -544,28 +561,59 @@ def find_block_epoch(_block: uint256, max_epoch: uint256) -> uint256: _max = _mid - 1 return _min +@internal +@view +def _find_user_timestamp_epoch(addr: address, ts: uint256) -> uint256: + """ + @notice Find the epoch for a user's timestamp + @param addr User wallet address + @param ts Epoch time to find + @return User epoch number + """ + minimum_value: uint256 = 0 + maximum_value: uint256 = self.user_point_epoch[addr] + + for i in range(128): # Will be always enough for 128-bit numbers + if minimum_value >= maximum_value: + break + mid: uint256 = (minimum_value + maximum_value + 1) / 2 + if self.user_point_history[addr][mid].ts <= ts: + minimum_value = mid + else: + maximum_value = mid - 1 + return minimum_value @external @view -def balanceOf(addr: address, _t: uint256 = block.timestamp) -> uint256: +def find_user_timestamp_epoch(addr: address, ts: uint256) -> uint256: + """ + @notice Find the epoch for a user's timestamp + @param addr User wallet address + @param ts Epoch time to find + @return User epoch number + """ + return self._find_user_timestamp_epoch(addr, ts) + +@external +@view +def balanceOf(addr: address, ts: uint256 = block.timestamp) -> uint256: """ @notice Get the current voting power for `msg.sender` @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility @param addr User wallet address - @param _t Epoch time to return voting power at + @param ts Epoch time to return voting power at @return User voting power """ - _epoch: uint256 = self.user_point_epoch[addr] + _epoch: uint256 = self._find_user_timestamp_epoch(addr, ts) if _epoch == 0: return 0 else: last_point: Point = self.user_point_history[addr][_epoch] - last_point.bias -= last_point.slope * convert(_t - last_point.ts, int128) + last_point.bias -= last_point.slope * convert(ts - last_point.ts, int128) if last_point.bias < 0: last_point.bias = 0 return convert(last_point.bias, uint256) - @internal @view def _balanceOfAt(addr: address, _block: uint256) -> uint256: diff --git a/contracts/external/FullMath.sol b/contracts/external/FullMath.sol index e8cec2c..58b55a8 100644 --- a/contracts/external/FullMath.sol +++ b/contracts/external/FullMath.sol @@ -8,105 +8,101 @@ pragma solidity >=0.4.0; /// @dev This contract was forked from Uniswap V3's contract `FullMath.sol` available here /// https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/FullMath.sol abstract contract FullMath { - /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 - /// @param a The multiplicand - /// @param b The multiplier - /// @param denominator The divisor - /// @return result The 256-bit result - /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv - /// @dev Contrary to UniswapV3 implementation, this contract doesn't handle `a*b` overflows - /// and will revert if so - function _mulDiv( - uint256 a, - uint256 b, - uint256 denominator - ) internal pure returns (uint256 result) { - // 512-bit multiply [prod1 prod0] = a * b - // Compute the product mod 2**256 and mod 2**256 - 1 - // then use the Chinese Remainder Theorem to reconstruct - // the 512 bit result. The result is stored in two 256 - // variables such that product = prod1 * 2**256 + prod0 - uint256 prod0; // Least significant 256 bits of the product - uint256 prod1; // Most significant 256 bits of the product - assembly { - let mm := mulmod(a, b, not(0)) - prod0 := mul(a, b) - prod1 := sub(sub(mm, prod0), lt(mm, prod0)) - } + /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + /// @param a The multiplicand + /// @param b The multiplier + /// @param denominator The divisor + /// @return result The 256-bit result + /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv + /// @dev Contrary to UniswapV3 implementation, this contract doesn't handle `a*b` overflows + /// and will revert if so + function _mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) { + // 512-bit multiply [prod1 prod0] = a * b + // Compute the product mod 2**256 and mod 2**256 - 1 + // then use the Chinese Remainder Theorem to reconstruct + // the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2**256 + prod0 + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(a, b, not(0)) + prod0 := mul(a, b) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } - // Handle non-overflow cases, 256 by 256 division - if (prod1 == 0) { - require(denominator > 0); - assembly { - result := div(prod0, denominator) - } - return result; - } + // Handle non-overflow cases, 256 by 256 division + if (prod1 == 0) { + require(denominator > 0); + assembly { + result := div(prod0, denominator) + } + return result; + } - // Make sure the result is less than 2**256. - // Also prevents denominator == 0 - require(denominator > prod1); + // Make sure the result is less than 2**256. + // Also prevents denominator == 0 + require(denominator > prod1); - /////////////////////////////////////////////// - // 512 by 256 division. - /////////////////////////////////////////////// + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// - // Make division exact by subtracting the remainder from [prod1 prod0] - // Compute remainder using mulmod - uint256 remainder; - assembly { - remainder := mulmod(a, b, denominator) - } - // Subtract 256 bit number from 512 bit number - assembly { - prod1 := sub(prod1, gt(remainder, prod0)) - prod0 := sub(prod0, remainder) - } + // Make division exact by subtracting the remainder from [prod1 prod0] + // Compute remainder using mulmod + uint256 remainder; + assembly { + remainder := mulmod(a, b, denominator) + } + // Subtract 256 bit number from 512 bit number + assembly { + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } - // Factor powers of two out of denominator - // Compute largest power of two divisor of denominator. - // Always >= 1. - uint256 twos = denominator & (~denominator + 1); - // Divide denominator by power of two - assembly { - denominator := div(denominator, twos) - } + // Factor powers of two out of denominator + // Compute largest power of two divisor of denominator. + // Always >= 1. + uint256 twos = denominator & (~denominator + 1); + // Divide denominator by power of two + assembly { + denominator := div(denominator, twos) + } - // Divide [prod1 prod0] by the factors of two - assembly { - prod0 := div(prod0, twos) - } - // Shift in bits from prod1 into prod0. For this we need - // to flip `twos` such that it is 2**256 / twos. - // If twos is zero, then it becomes one - assembly { - twos := add(div(sub(0, twos), twos), 1) - } - prod0 |= prod1 * twos; + // Divide [prod1 prod0] by the factors of two + assembly { + prod0 := div(prod0, twos) + } + // Shift in bits from prod1 into prod0. For this we need + // to flip `twos` such that it is 2**256 / twos. + // If twos is zero, then it becomes one + assembly { + twos := add(div(sub(0, twos), twos), 1) + } + prod0 |= prod1 * twos; - // Invert denominator mod 2**256 - // Now that denominator is an odd number, it has an inverse - // modulo 2**256 such that denominator * inv = 1 mod 2**256. - // Compute the inverse by starting with a seed that is correct - // correct for four bits. That is, denominator * inv = 1 mod 2**4 - uint256 inv = (3 * denominator) ^ 2; - // Now use Newton-Raphson iteration to improve the precision. - // Thanks to Hensel's lifting lemma, this also works in modular - // arithmetic, doubling the correct bits in each step. - inv *= 2 - denominator * inv; // inverse mod 2**8 - inv *= 2 - denominator * inv; // inverse mod 2**16 - inv *= 2 - denominator * inv; // inverse mod 2**32 - inv *= 2 - denominator * inv; // inverse mod 2**64 - inv *= 2 - denominator * inv; // inverse mod 2**128 - inv *= 2 - denominator * inv; // inverse mod 2**256 + // Invert denominator mod 2**256 + // Now that denominator is an odd number, it has an inverse + // modulo 2**256 such that denominator * inv = 1 mod 2**256. + // Compute the inverse by starting with a seed that is correct + // correct for four bits. That is, denominator * inv = 1 mod 2**4 + uint256 inv = (3 * denominator) ^ 2; + // Now use Newton-Raphson iteration to improve the precision. + // Thanks to Hensel's lifting lemma, this also works in modular + // arithmetic, doubling the correct bits in each step. + inv *= 2 - denominator * inv; // inverse mod 2**8 + inv *= 2 - denominator * inv; // inverse mod 2**16 + inv *= 2 - denominator * inv; // inverse mod 2**32 + inv *= 2 - denominator * inv; // inverse mod 2**64 + inv *= 2 - denominator * inv; // inverse mod 2**128 + inv *= 2 - denominator * inv; // inverse mod 2**256 - // Because the division is now exact we can divide by multiplying - // with the modular inverse of denominator. This will give us the - // correct result modulo 2**256. Since the precoditions guarantee - // that the outcome is less than 2**256, this is the final result. - // We don't need to compute the high bits of the result and prod1 - // is no longer required. - result = prod0 * inv; - return result; - } + // Because the division is now exact we can divide by multiplying + // with the modular inverse of denominator. This will give us the + // correct result modulo 2**256. Since the precoditions guarantee + // that the outcome is less than 2**256, this is the final result. + // We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inv; + return result; + } } diff --git a/contracts/external/SmartWalletChecker.sol b/contracts/external/SmartWalletChecker.sol index 5ad1c41..4bead64 100644 --- a/contracts/external/SmartWalletChecker.sol +++ b/contracts/external/SmartWalletChecker.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.7; /// @notice Interface of the `SmartWalletChecker` contracts of the protocol interface SmartWalletChecker { diff --git a/contracts/external/TransparentUpgradeableProxy.sol b/contracts/external/TransparentUpgradeableProxy.sol index 2bb6caa..36474ca 100644 --- a/contracts/external/TransparentUpgradeableProxy.sol +++ b/contracts/external/TransparentUpgradeableProxy.sol @@ -31,11 +31,7 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. */ - constructor( - address _logic, - address admin_, - bytes memory _data - ) payable ERC1967Proxy(_logic, _data) { + constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) { assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); _changeAdmin(admin_); } diff --git a/contracts/interfaces/IAgToken.sol b/contracts/interfaces/IAgToken.sol index f0d3a18..6409639 100644 --- a/contracts/interfaces/IAgToken.sol +++ b/contracts/interfaces/IAgToken.sol @@ -13,11 +13,7 @@ interface IAgToken is IERC20Upgradeable { // ======================= `StableMaster` functions ============================ function mint(address account, uint256 amount) external; - function burnFrom( - uint256 amount, - address burner, - address sender - ) external; + function burnFrom(uint256 amount, address burner, address sender) external; function burnSelf(uint256 amount, address burner) external; diff --git a/contracts/interfaces/IBondingCurve.sol b/contracts/interfaces/IBondingCurve.sol deleted file mode 100644 index 2662d2f..0000000 --- a/contracts/interfaces/IBondingCurve.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.7; - -import "./IAgToken.sol"; -import "./IOracle.sol"; - -/// @title IBondingCurve -/// @author Angle Core Team -/// @notice Interface for the `BondingCurve` contract -interface IBondingCurve { - // ============================ User Functions ================================= - - function buySoldToken( - IAgToken _agToken, - uint256 targetSoldTokenQuantity, - uint256 maxAmountToPayInAgToken - ) external; - - // ========================== Governance Functions ============================= - - function changeOracle(IAgToken _agToken, IOracle _oracle) external; -} diff --git a/contracts/interfaces/ICollateralSettler.sol b/contracts/interfaces/ICollateralSettler.sol deleted file mode 100644 index 3293462..0000000 --- a/contracts/interfaces/ICollateralSettler.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.7; - -/// @title ICollateralSettler -/// @author Angle Core Team -/// @notice Interface for the collateral settlement contracts -interface ICollateralSettler { - function triggerSettlement( - uint256 _oracleValue, - uint256 _sanRate, - uint256 _stocksUsers - ) external; -} diff --git a/contracts/interfaces/IERC721.sol b/contracts/interfaces/IERC721.sol deleted file mode 100644 index 53d07cf..0000000 --- a/contracts/interfaces/IERC721.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.7; - -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - -interface IERC721 is IERC165 { - function balanceOf(address owner) external view returns (uint256 balance); - - function ownerOf(uint256 tokenId) external view returns (address owner); - - function safeTransferFrom( - address from, - address to, - uint256 tokenId - ) external; - - function transferFrom( - address from, - address to, - uint256 tokenId - ) external; - - function approve(address to, uint256 tokenId) external; - - function getApproved(uint256 tokenId) external view returns (address operator); - - function setApprovalForAll(address operator, bool _approved) external; - - function isApprovedForAll(address owner, address operator) external view returns (bool); - - function safeTransferFrom( - address from, - address to, - uint256 tokenId, - bytes calldata data - ) external; -} - -interface IERC721Metadata is IERC721 { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function tokenURI(uint256 tokenId) external view returns (string memory); -} diff --git a/contracts/interfaces/IFeeDistributor.sol b/contracts/interfaces/IFeeDistributor.sol deleted file mode 100644 index 8d89070..0000000 --- a/contracts/interfaces/IFeeDistributor.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.7; - -/// @title IFeeDistributor -/// @author Interface of the `FeeDistributor` contract -/// @dev This interface is used by the `SurplusConverter` contract to send funds to the `FeeDistributor` -interface IFeeDistributor { - function burn(address token) external; -} - -/// @title IFeeDistributorFront -/// @author Interface for public use of the `FeeDistributor` contract -/// @dev This interface is used for user related function -interface IFeeDistributorFront { - function token() external returns (address); - - function claim(address _addr) external returns (uint256); - - function claim(address[20] memory _addr) external returns (bool); -} \ No newline at end of file diff --git a/contracts/interfaces/IFeeManager.sol b/contracts/interfaces/IFeeManager.sol index afe30cc..adca175 100644 --- a/contracts/interfaces/IFeeManager.sol +++ b/contracts/interfaces/IFeeManager.sol @@ -16,17 +16,9 @@ interface IFeeManagerFunctions is IAccessControl { // ================================= Governance ================================ - function deployCollateral( - address[] memory governorList, - address guardian, - address _perpetualManager - ) external; - - function setFees( - uint256[] memory xArray, - uint64[] memory yArray, - uint8 typeChange - ) external; + function deployCollateral(address[] memory governorList, address guardian, address _perpetualManager) external; + + function setFees(uint256[] memory xArray, uint64[] memory yArray, uint8 typeChange) external; function setHAFees(uint64 _haFeeDeposit, uint64 _haFeeWithdraw) external; } diff --git a/contracts/interfaces/IPerpetualManager.sol b/contracts/interfaces/IPerpetualManager.sol index 6f3f493..3b3e55e 100644 --- a/contracts/interfaces/IPerpetualManager.sol +++ b/contracts/interfaces/IPerpetualManager.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.7; -import "./IERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import "./IFeeManager.sol"; import "./IOracle.sol"; import "./IAccessControl.sol"; @@ -19,19 +19,11 @@ interface IPerpetualManagerFront is IERC721Metadata { uint256 minNetMargin ) external returns (uint256 perpetualID); - function closePerpetual( - uint256 perpetualID, - address to, - uint256 minCashOutAmount - ) external; + function closePerpetual(uint256 perpetualID, address to, uint256 minCashOutAmount) external; function addToPerpetual(uint256 perpetualID, uint256 amount) external; - function removeFromPerpetual( - uint256 perpetualID, - uint256 amount, - address to - ) external; + function removeFromPerpetual(uint256 perpetualID, uint256 amount, address to) external; function liquidatePerpetuals(uint256[] memory perpetualIDs) external; @@ -60,11 +52,7 @@ interface IPerpetualManagerFunctions is IAccessControl { function setFeeManager(IFeeManager feeManager_) external; - function setHAFees( - uint64[] memory _xHAFees, - uint64[] memory _yHAFees, - uint8 deposit - ) external; + function setHAFees(uint64[] memory _xHAFees, uint64[] memory _yHAFees, uint8 deposit) external; function setTargetAndLimitHAHedge(uint64 _targetHAHedge, uint64 _limitHAHedge) external; diff --git a/contracts/interfaces/IPoolManager.sol b/contracts/interfaces/IPoolManager.sol index 2d7757e..8e40854 100644 --- a/contracts/interfaces/IPoolManager.sol +++ b/contracts/interfaces/IPoolManager.sol @@ -40,11 +40,7 @@ interface IPoolManagerFunctions { function debtOutstanding() external view returns (uint256); - function report( - uint256 _gain, - uint256 _loss, - uint256 _debtPayment - ) external; + function report(uint256 _gain, uint256 _loss, uint256 _debtPayment) external; // ============================ Governance ===================================== diff --git a/contracts/interfaces/ISanToken.sol b/contracts/interfaces/ISanToken.sol index 2b85817..613347f 100644 --- a/contracts/interfaces/ISanToken.sol +++ b/contracts/interfaces/ISanToken.sol @@ -13,11 +13,7 @@ interface ISanToken is IERC20Upgradeable { function mint(address account, uint256 amount) external; - function burnFrom( - uint256 amount, - address burner, - address sender - ) external; + function burnFrom(uint256 amount, address burner, address sender) external; function burnSelf(uint256 amount, address burner) external; diff --git a/contracts/interfaces/IStableMaster.sol b/contracts/interfaces/IStableMaster.sol index 10616dc..43b6e26 100644 --- a/contracts/interfaces/IStableMaster.sol +++ b/contracts/interfaces/IStableMaster.sol @@ -74,11 +74,7 @@ struct SLPData { /// @author Angle Core Team /// @notice Interface for the `StableMaster` contract interface IStableMasterFunctions { - function deploy( - address[] memory _governorList, - address _guardian, - address _agToken - ) external; + function deploy(address[] memory _governorList, address _guardian, address _agToken) external; // ============================== Lending ====================================== @@ -96,12 +92,7 @@ interface IStableMasterFunctions { function getCollateralRatio() external returns (uint256); - function setFeeKeeper( - uint64 feeMint, - uint64 feeBurn, - uint64 _slippage, - uint64 _slippageFee - ) external; + function setFeeKeeper(uint64 feeMint, uint64 feeBurn, uint64 _slippage, uint64 _slippageFee) external; // ============================== AgToken ====================================== @@ -125,18 +116,9 @@ interface IStableMasterFunctions { IPoolManager poolManager ) external; - function setIncentivesForSLPs( - uint64 _feesForSLPs, - uint64 _interestsForSLPs, - IPoolManager poolManager - ) external; + function setIncentivesForSLPs(uint64 _feesForSLPs, uint64 _interestsForSLPs, IPoolManager poolManager) external; - function setUserFees( - IPoolManager poolManager, - uint64[] memory _xFee, - uint64[] memory _yFee, - uint8 _mint - ) external; + function setUserFees(IPoolManager poolManager, uint64[] memory _xFee, uint64[] memory _yFee, uint8 _mint) external; function setTargetHAHedge(uint64 _targetHAHedge) external; @@ -151,7 +133,9 @@ interface IStableMasterFunctions { interface IStableMaster is IStableMasterFunctions { function agToken() external view returns (address); - function collateralMap(IPoolManager poolManager) + function collateralMap( + IPoolManager poolManager + ) external view returns ( diff --git a/contracts/interfaces/IStableMasterFront.sol b/contracts/interfaces/IStableMasterFront.sol deleted file mode 100644 index 2728f06..0000000 --- a/contracts/interfaces/IStableMasterFront.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.7; - -import "../interfaces/IPoolManager.sol"; - -/// @title IStableMasterFront -/// @author Angle Core Team -/// @dev Front interface, meaning only user-facing functions -interface IStableMasterFront { - function mint( - uint256 amount, - address user, - IPoolManager poolManager, - uint256 minStableAmount - ) external; - - function burn( - uint256 amount, - address burner, - address dest, - IPoolManager poolManager, - uint256 minCollatAmount - ) external; - - function deposit( - uint256 amount, - address user, - IPoolManager poolManager - ) external; - - function withdraw( - uint256 amount, - address burner, - address dest, - IPoolManager poolManager - ) external; - - function agToken() external view returns (address); -} diff --git a/contracts/interfaces/IStakingRewards.sol b/contracts/interfaces/IStakingRewards.sol index 135097f..560f434 100644 --- a/contracts/interfaces/IStakingRewards.sol +++ b/contracts/interfaces/IStakingRewards.sol @@ -10,11 +10,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IStakingRewardsFunctions { function notifyRewardAmount(uint256 reward) external; - function recoverERC20( - address tokenAddress, - address to, - uint256 tokenAmount - ) external; + function recoverERC20(address tokenAddress, address to, uint256 tokenAmount) external; function setNewRewardsDistribution(address newRewardsDistribution) external; } diff --git a/contracts/interfaces/IVaultManager.sol b/contracts/interfaces/IVaultManager.sol index d16dd77..29ee8dc 100644 --- a/contracts/interfaces/IVaultManager.sol +++ b/contracts/interfaces/IVaultManager.sol @@ -52,8 +52,8 @@ interface IVaultManagerFunctions { /// this function can perform any of the allowed actions in the order of their choice /// @param actions Set of actions to perform /// @param datas Data to be decoded for each action: it can include like the `vaultID` or the - /// @param from Address from which stablecoins will be taken if one action includes burning stablecoins. This address - /// should either be the `msg.sender` or be approved by the latter + /// @param from Address from which stablecoins will be taken if one action includes burning stablecoins. + /// This address should either be the `msg.sender` or be approved by the latter /// @param to Address to which stablecoins and/or collateral will be sent in case of /// @return paymentData Struct containing the final transfers executed /// @dev This function is optimized to reduce gas cost due to payment from or to the user and that expensive calls @@ -69,8 +69,8 @@ interface IVaultManagerFunctions { /// this function can perform any of the allowed actions in the order of their choice /// @param actions Set of actions to perform /// @param datas Data to be decoded for each action: it can include like the `vaultID` or the - /// @param from Address from which stablecoins will be taken if one action includes burning stablecoins. This address - /// should either be the `msg.sender` or be approved by the latter + /// @param from Address from which stablecoins will be taken if one action includes burning stablecoins. + /// This address should either be the `msg.sender` or be approved by the latter /// @param to Address to which stablecoins and/or collateral will be sent in case of /// @param who Address of the contract to handle in case of repayment of stablecoins from received collateral /// @param repayData Data to pass to the repayment contract in case of diff --git a/contracts/interfaces/IVeANGLE.sol b/contracts/interfaces/IVeANGLE.sol index 53e254f..edda05a 100644 --- a/contracts/interfaces/IVeANGLE.sol +++ b/contracts/interfaces/IVeANGLE.sol @@ -1,13 +1,65 @@ // SPDX-License-Identifier: GPL-3.0 +// solhint-disable pragma solidity ^0.8.7; -import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; -/// @title IVeANGLE +/// @title IveANGLE /// @author Angle Core Team /// @notice Interface for the `VeANGLE` contract -interface IVeANGLE { - // solhint-disable-next-line func-name-mixedcase - function deposit_for(address addr, uint256 amount) external; +interface IveANGLE is IERC20MetadataUpgradeable { + struct Point { + int128 bias; + int128 slope; + uint256 ts; + uint256 blk; + } + + struct LockedBalance { + uint128 amount; + uint256 end; + } + + function locked(address addr) external view returns (LockedBalance memory); + + function set_emergency_withdrawal() external; + + function emergency_withdrawal() external view returns (bool); + + function withdraw_fast() external; + + function initialize( + address admin, + address token_addr, + address smart_wallet_checker, + string memory name, + string memory symbol + ) external; + + function checkpoint() external; + + function withdraw() external; + + function deposit_for(address addr, uint256 value) external; + + function admin() external view returns (address); + + function smart_wallet_checker() external view returns (address); + + function create_lock(uint256 value, uint256 unlock_time) external; + + function increase_amount(uint256 value) external; + + function increase_unlock_time(uint256 unlock_time) external; + + function initialized() external view returns (bool); + + function balanceOf(address addr, uint256 ts) external view returns (uint256); + + function find_user_timestamp_epoch(address addr, uint256 ts) external view returns (uint256); + + function locked__end(address addr) external view returns (uint256); + + function user_point_history(address addr, uint256 idx) external view returns (Point memory); } diff --git a/contracts/interfaces/IWETH.sol b/contracts/interfaces/IWETH.sol index 1ca3256..bab53bb 100644 --- a/contracts/interfaces/IWETH.sol +++ b/contracts/interfaces/IWETH.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.5.0; + import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { diff --git a/contracts/interfaces/external/aave/IAave.sol b/contracts/interfaces/external/aave/IAave.sol index 3476753..98ea17a 100644 --- a/contracts/interfaces/external/aave/IAave.sol +++ b/contracts/interfaces/external/aave/IAave.sol @@ -8,22 +8,11 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IAaveIncentivesController { function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256); - function claimRewards( - address[] calldata assets, - uint256 amount, - address to - ) external returns (uint256); + function claimRewards(address[] calldata assets, uint256 amount, address to) external returns (uint256); function getDistributionEnd() external view returns (uint256); - function getAssetData(address asset) - external - view - returns ( - uint256, - uint256, - uint256 - ); + function getAssetData(address asset) external view returns (uint256, uint256, uint256); } interface IAToken is IERC20 { @@ -31,18 +20,9 @@ interface IAToken is IERC20 { } interface ILendingPool { - function deposit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) external; - - function withdraw( - address asset, - uint256 amount, - address to - ) external returns (uint256); + function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external; + + function withdraw(address asset, uint256 amount, address to) external returns (uint256); function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); } @@ -54,7 +34,9 @@ interface ILendingPoolAddressesProvider { interface IProtocolDataProvider { function ADDRESSES_PROVIDER() external view returns (ILendingPoolAddressesProvider); - function getReserveConfigurationData(address asset) + function getReserveConfigurationData( + address asset + ) external view returns ( @@ -70,7 +52,9 @@ interface IProtocolDataProvider { bool isFrozen ); - function getReserveData(address asset) + function getReserveData( + address asset + ) external view returns ( @@ -95,14 +79,7 @@ interface IReserveInterestRateStrategy { uint256 totalVariableDebt, uint256 averageStableBorrowRate, uint256 reserveFactor - ) - external - view - returns ( - uint256 liquidityRate, - uint256 stableBorrowRate, - uint256 variableBorrowRate - ); + ) external view returns (uint256 liquidityRate, uint256 stableBorrowRate, uint256 variableBorrowRate); } interface IStakedAave { diff --git a/contracts/interfaces/external/compound/CTokenI.sol b/contracts/interfaces/external/compound/CTokenI.sol index 54d1941..bc4010d 100644 --- a/contracts/interfaces/external/compound/CTokenI.sol +++ b/contracts/interfaces/external/compound/CTokenI.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; + import "./InterestRateModel.sol"; interface CTokenI { diff --git a/contracts/interfaces/external/compound/IComptroller.sol b/contracts/interfaces/external/compound/IComptroller.sol index 1a7e2bb..1f6013a 100644 --- a/contracts/interfaces/external/compound/IComptroller.sol +++ b/contracts/interfaces/external/compound/IComptroller.sol @@ -7,10 +7,5 @@ import "./CTokenI.sol"; interface IComptroller { function compSupplySpeeds(address cToken) external view returns (uint256); - function claimComp( - address[] memory holders, - CTokenI[] memory cTokens, - bool borrowers, - bool suppliers - ) external; + function claimComp(address[] memory holders, CTokenI[] memory cTokens, bool borrowers, bool suppliers) external; } diff --git a/contracts/interfaces/external/compound/InterestRateModel.sol b/contracts/interfaces/external/compound/InterestRateModel.sol index 42acca1..b14446e 100755 --- a/contracts/interfaces/external/compound/InterestRateModel.sol +++ b/contracts/interfaces/external/compound/InterestRateModel.sol @@ -19,9 +19,5 @@ interface InterestRateModel { ) external view returns (uint256); // Rinkeby function - function getBorrowRate( - uint256 cash, - uint256 borrows, - uint256 _reserves - ) external view returns (uint256, uint256); + function getBorrowRate(uint256 cash, uint256 borrows, uint256 _reserves) external view returns (uint256, uint256); } diff --git a/contracts/interfaces/external/curve/Curve.sol b/contracts/interfaces/external/curve/Curve.sol index 3b267d5..dac6c4c 100644 --- a/contracts/interfaces/external/curve/Curve.sol +++ b/contracts/interfaces/external/curve/Curve.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.7; interface ICurveFi { function get_virtual_price() external view returns (uint256); @@ -27,34 +27,17 @@ interface ICurveFi { function remove_liquidity(uint256 _amount, uint256[4] calldata amounts) external; - function remove_liquidity_one_coin( - uint256 _token_amount, - int128 i, - uint256 min_amount - ) external; + function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_amount) external; - function exchange( - int128 from, - int128 to, - uint256 _from_amount, - uint256 _min_to_amount - ) external payable; + function exchange(int128 from, int128 to, uint256 _from_amount, uint256 _min_to_amount) external payable; function balances(int128) external view returns (uint256); - function get_dy( - int128 from, - int128 to, - uint256 _from_amount - ) external view returns (uint256); + function get_dy(int128 from, int128 to, uint256 _from_amount) external view returns (uint256); function calc_token_amount(uint256[2] calldata amounts, bool is_deposit) external view returns (uint256); } interface Zap { - function remove_liquidity_one_coin( - uint256, - int128, - uint256 - ) external; + function remove_liquidity_one_coin(uint256, int128, uint256) external; } diff --git a/contracts/interfaces/external/lido/ISteth.sol b/contracts/interfaces/external/lido/ISteth.sol index c5e9bde..83d3dc4 100644 --- a/contracts/interfaces/external/lido/ISteth.sol +++ b/contracts/interfaces/external/lido/ISteth.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/interfaces/external/lido/IWStETH.sol b/contracts/interfaces/external/lido/IWStETH.sol index b6f4500..b1171c3 100644 --- a/contracts/interfaces/external/lido/IWStETH.sol +++ b/contracts/interfaces/external/lido/IWStETH.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/staking/AngleDistributor.sol b/contracts/staking/AngleDistributor.sol index 597befc..ffab92e 100644 --- a/contracts/staking/AngleDistributor.sol +++ b/contracts/staking/AngleDistributor.sol @@ -27,7 +27,7 @@ contract AngleDistributor is AngleDistributorEvents, ReentrancyGuardUpgradeable, uint256 public constant RATE_REDUCTION_COEFFICIENT = 1007827884862117171; // 1.5 ^ (1/52) * 10**18 /// @notice Base used for computation - uint256 public constant BASE = 10**18; + uint256 public constant BASE = 10 ** 18; /// @notice Maps the address of a gauge to the last time this gauge received rewards mapping(address => uint256) public lastTimeGaugePaid; @@ -123,8 +123,8 @@ contract AngleDistributor is AngleDistributorEvents, ReentrancyGuardUpgradeable, /// @dev The reason for having an internal function is that it's called by the `distributeReward` and the /// `distributeRewardToMultipleGauges` /// @dev Although they would need to be performed all the time this function is called, this function does not - /// contain checks on whether distribution is on, and on whether rate should be reduced. These are done in each external - /// function calling this function for gas efficiency + /// contain checks on whether distribution is on, and on whether rate should be reduced. These are done in + /// each external function calling this function for gas efficiency function _distributeReward(address gaugeAddr) internal returns (uint256 weeksElapsed, uint256 rewardTally) { // Checking if the gauge has been added or if it still possible to distribute rewards to this gauge int128 gaugeType = IGaugeController(controller).gauge_types(gaugeAddr); @@ -164,8 +164,8 @@ contract AngleDistributor is AngleDistributorEvents, ReentrancyGuardUpgradeable, rewardTally += (weeklyRate * relWeightAtWeek * WEEK) / BASE; // To get the rate of the week prior from the current rate we just have to multiply by the weekly division - // factor - // There may be some precisions error: inferred previous values of the rate may be different to what we would + // factor. There may be some + // precisions error: inferred previous values of the rate may be different to what we would // have had if the rate had been computed correctly in these weeks: we expect from empirical observations // this `weeklyRate` to be inferior to what the `rate` would have been weeklyRate = (weeklyRate * RATE_REDUCTION_COEFFICIENT) / BASE; @@ -290,11 +290,7 @@ contract AngleDistributor is AngleDistributorEvents, ReentrancyGuardUpgradeable, /// @dev Added to support recovering LP Rewards and other mistaken tokens /// from other systems to be distributed to holders /// @dev This function could also be used to recover ANGLE tokens in case the rate got smaller - function recoverERC20( - address tokenAddress, - address to, - uint256 amount - ) external onlyRole(GOVERNOR_ROLE) { + function recoverERC20(address tokenAddress, address to, uint256 amount) external onlyRole(GOVERNOR_ROLE) { // If the token is the ANGLE token, we need to make sure that governance is not going to withdraw // too many tokens and that it'll be able to sustain the weekly distribution forever // This check assumes that `distributeReward` has been called for gauges and that there are no gauges @@ -326,9 +322,10 @@ contract AngleDistributor is AngleDistributorEvents, ReentrancyGuardUpgradeable, /// @param _delegateGauge Address of the new gauge delegate related to `gaugeAddr` /// @param toggleInterface Whether we should toggle the fact that the `_delegateGauge` is built for automation or not /// @dev This function can be used to remove delegating or introduce the pulling of rewards to a given address - /// @dev If `gaugeAddr` is the zero address, this function updates the delegate gauge common to all gauges with type >= 2 - /// @dev The `toggleInterface` parameter has been added for convenience to save one transaction when adding a gauge delegate - /// which supports the `notifyReward` interface + /// @dev If `gaugeAddr` is the zero address, this function updates the delegate gauge common to all gauges + /// with type >= 2 + /// @dev The `toggleInterface` parameter has been added for convenience to save one transaction when adding + /// a gauge delegate which supports the `notifyReward` interface function setDelegateGauge( address gaugeAddr, address _delegateGauge, @@ -349,12 +346,12 @@ contract AngleDistributor is AngleDistributorEvents, ReentrancyGuardUpgradeable, /// @notice Changes the ANGLE emission rate /// @param _newRate New ANGLE emission rate /// @dev It is important to be super wary when calling this function and to make sure that `distributeReward` - /// has been called for all gauges in the past weeks. If not, gauges may get an incorrect distribution of ANGLE rewards - /// for these past weeks based on the new rate and not on the old rate - /// @dev Governance should thus make sure to call this function rarely and when it does to do it after the weekly `distributeReward` - /// calls for all existing gauges - /// @dev As this function assumes that `distributeReward` has been called during the week, it also assumes that the `startEpochSupply` - /// parameter has been put up to date + /// has been called for all gauges in the past weeks. If not, gauges may get an incorrect distribution + /// of ANGLE rewards for these past weeks based on the new rate and not on the old rate + /// @dev Governance should thus make sure to call this function rarely and when it does to do it after the weekly + /// `distributeReward` calls for all existing gauges + /// @dev As this function assumes that `distributeReward` has been called during the week, it also assumes that + /// the `startEpochSupply` parameter has been put up to date function setRate(uint256 _newRate) external onlyRole(GOVERNOR_ROLE) { // Checking if the new rate is compatible with the amount of ANGLE tokens this contract has in balance // This check assumes, like this function, that `distributeReward` has correctly been called before @@ -371,13 +368,13 @@ contract AngleDistributor is AngleDistributorEvents, ReentrancyGuardUpgradeable, /// @param gaugeAddr Gauge to toggle the status of /// @dev It is impossible to kill a gauge in the `GaugeController` contract, for this reason killing of gauges /// takes place in the `AngleDistributor` contract - /// @dev This means that people could vote for a gauge in the gauge controller contract but that rewards are not going - /// to be distributed to it in the end: people would need to remove their weights on the gauge killed to end the diminution - /// in rewards - /// @dev In the case of a gauge being killed, this function resets the timestamps at which this gauge has been approved and - /// disapproves the gauge to spend the token - /// @dev It should be cautiously called by governance as it could result in less ANGLE overall rewards than initially planned - /// if people do not remove their voting weights to the killed gauge + /// @dev This means that people could vote for a gauge in the gauge controller contract but that rewards are + /// not going to be distributed to it in the end: people would need to remove their weights on the gauge killed + /// to end the diminution in rewards + /// @dev In the case of a gauge being killed, this function resets the timestamps at which this gauge has been + /// approved and disapproves the gauge to spend the token + /// @dev It should be cautiously called by governance as it could result in less ANGLE overall rewards than + /// initially planned if people do not remove their voting weights to the killed gauge function toggleGauge(address gaugeAddr) external onlyRole(GOVERNOR_ROLE) { bool gaugeKilledMem = killedGauges[gaugeAddr]; if (!gaugeKilledMem) { diff --git a/contracts/staking/RewardsDistributor.sol b/contracts/staking/RewardsDistributor.sol index df6b97d..e26a32a 100644 --- a/contracts/staking/RewardsDistributor.sol +++ b/contracts/staking/RewardsDistributor.sol @@ -56,11 +56,7 @@ contract RewardsDistributor is RewardsDistributorEvents, IRewardsDistributor, Ac /// @param governorList List of the governor addresses of the protocol /// @param guardian The guardian address, optional /// @param rewardTokenAddress The ERC20 token to distribute - constructor( - address[] memory governorList, - address guardian, - address rewardTokenAddress - ) { + constructor(address[] memory governorList, address guardian, address rewardTokenAddress) { require(rewardTokenAddress != address(0) && guardian != address(0), "0"); require(governorList.length > 0, "47"); rewardToken = IERC20(rewardTokenAddress); @@ -185,11 +181,12 @@ contract RewardsDistributor is RewardsDistributorEvents, IRewardsDistributor, Ac /// @param _stakingContract Address of the staking contract /// @param _duration Time frame during which tokens will be distributed /// @param _incentiveAmount Incentive amount given to keepers calling the update function - /// @param _updateFrequency Frequency when it is possible to call the update function and give tokens to the staking contract + /// @param _updateFrequency Frequency when it is possible to call the update function and give tokens to the + /// staking contract /// @param _amountToDistribute Amount of gov tokens to give to the staking contract across all drips /// @dev Called by governance to activate a contract - /// @dev After setting a new staking contract, everything is as if the contract had already been set for `_updateFrequency` - /// meaning that it is possible to `drip` the staking contract immediately after that + /// @dev After setting a new staking contract, everything is as if the contract had already been set for + /// `_updateFrequency` meaning that it is possible to `drip` the staking contract immediately after that function setStakingContract( address _stakingContract, uint256 _duration, @@ -222,11 +219,10 @@ contract RewardsDistributor is RewardsDistributorEvents, IRewardsDistributor, Ac /// @notice Sets the update frequency /// @param _updateFrequency New update frequency /// @param stakingContract Reference to the staking contract - function setUpdateFrequency(uint256 _updateFrequency, IStakingRewards stakingContract) - external - override - onlyRole(GUARDIAN_ROLE) - { + function setUpdateFrequency( + uint256 _updateFrequency, + IStakingRewards stakingContract + ) external override onlyRole(GUARDIAN_ROLE) { StakingParameters storage stakingParams = stakingContractsMap[stakingContract]; require(stakingParams.duration > 0, "80"); require(stakingParams.duration >= _updateFrequency, "87"); @@ -237,11 +233,10 @@ contract RewardsDistributor is RewardsDistributorEvents, IRewardsDistributor, Ac /// @notice Sets the incentive amount for calling drip /// @param _incentiveAmount New incentive amount /// @param stakingContract Reference to the staking contract - function setIncentiveAmount(uint256 _incentiveAmount, IStakingRewards stakingContract) - external - override - onlyRole(GUARDIAN_ROLE) - { + function setIncentiveAmount( + uint256 _incentiveAmount, + IStakingRewards stakingContract + ) external override onlyRole(GUARDIAN_ROLE) { StakingParameters storage stakingParams = stakingContractsMap[stakingContract]; require(stakingParams.duration > 0, "80"); stakingParams.incentiveAmount = _incentiveAmount; @@ -251,11 +246,10 @@ contract RewardsDistributor is RewardsDistributorEvents, IRewardsDistributor, Ac /// @notice Sets the new amount to distribute to a staking contract /// @param _amountToDistribute New amount to distribute /// @param stakingContract Reference to the staking contract - function setAmountToDistribute(uint256 _amountToDistribute, IStakingRewards stakingContract) - external - override - onlyRole(GUARDIAN_ROLE) - { + function setAmountToDistribute( + uint256 _amountToDistribute, + IStakingRewards stakingContract + ) external override onlyRole(GUARDIAN_ROLE) { StakingParameters storage stakingParams = stakingContractsMap[stakingContract]; require(stakingParams.duration > 0, "80"); require(stakingParams.distributedRewards < _amountToDistribute, "88"); diff --git a/contracts/staking/StakingRewards.sol b/contracts/staking/StakingRewards.sol index ee14dee..6f15faa 100644 --- a/contracts/staking/StakingRewards.sol +++ b/contracts/staking/StakingRewards.sol @@ -71,12 +71,7 @@ contract StakingRewards is StakingRewardsEvents, IStakingRewards, ReentrancyGuar /// @param _rewardToken ERC20 token given as reward /// @param _stakingToken ERC20 token used for staking /// @param _rewardsDuration Duration of the staking contract - constructor( - address _rewardsDistribution, - address _rewardToken, - address _stakingToken, - uint256 _rewardsDuration - ) { + constructor(address _rewardsDistribution, address _rewardToken, address _stakingToken, uint256 _rewardsDuration) { require(_stakingToken != address(0) && _rewardToken != address(0) && _rewardsDistribution != address(0), "0"); // We are not checking the compatibility of the reward token between the distributor and this contract here @@ -87,7 +82,7 @@ contract StakingRewards is StakingRewardsEvents, IStakingRewards, ReentrancyGuar rewardsDuration = _rewardsDuration; rewardsDistribution = _rewardsDistribution; - stakingBase = 10**IERC20Metadata(_stakingToken).decimals(); + stakingBase = 10 ** IERC20Metadata(_stakingToken).decimals(); } // ============================ Modifiers ====================================== @@ -201,12 +196,10 @@ contract StakingRewards is StakingRewardsEvents, IStakingRewards, ReentrancyGuar /// @notice Allows to stake on behalf of another address /// @param amount Amount to stake /// @param onBehalf Address to stake onBehalf of - function stakeOnBehalf(uint256 amount, address onBehalf) - external - nonReentrant - zeroCheck(onBehalf) - updateReward(onBehalf) - { + function stakeOnBehalf( + uint256 amount, + address onBehalf + ) external nonReentrant zeroCheck(onBehalf) updateReward(onBehalf) { _stake(amount, onBehalf); } @@ -227,13 +220,9 @@ contract StakingRewards is StakingRewardsEvents, IStakingRewards, ReentrancyGuar /// @notice Adds rewards to be distributed /// @param reward Amount of reward tokens to distribute /// @dev This reward will be distributed during `rewardsDuration` set previously - function notifyRewardAmount(uint256 reward) - external - override - onlyRewardsDistribution - nonReentrant - updateReward(address(0)) - { + function notifyRewardAmount( + uint256 reward + ) external override onlyRewardsDistribution nonReentrant updateReward(address(0)) { if (block.timestamp >= periodFinish) { // If no reward is currently being distributed, the new rate is just `reward / duration` rewardRate = reward / rewardsDuration; @@ -261,11 +250,7 @@ contract StakingRewards is StakingRewardsEvents, IStakingRewards, ReentrancyGuar /// @param to Address to transfer to /// @param amount Amount to transfer /// @dev A use case would be to claim tokens if the staked tokens accumulate rewards - function recoverERC20( - address tokenAddress, - address to, - uint256 amount - ) external override onlyRewardsDistribution { + function recoverERC20(address tokenAddress, address to, uint256 amount) external override onlyRewardsDistribution { require(tokenAddress != address(stakingToken) && tokenAddress != address(rewardToken), "20"); IERC20(tokenAddress).safeTransfer(to, amount); @@ -275,8 +260,8 @@ contract StakingRewards is StakingRewardsEvents, IStakingRewards, ReentrancyGuar /// @notice Changes the rewards distributor associated to this contract /// @param _rewardsDistribution Address of the new rewards distributor contract /// @dev This function was also added by Angle Core Team - /// @dev A compatibility check of the reward token is already performed in the current `RewardsDistributor` implementation - /// which has right to call this function + /// @dev A compatibility check of the reward token is already performed in the current `RewardsDistributor` + /// implementation which has right to call this function function setNewRewardsDistribution(address _rewardsDistribution) external override onlyRewardsDistribution { rewardsDistribution = _rewardsDistribution; emit RewardsDistributionUpdated(_rewardsDistribution); diff --git a/contracts/utils/VyperDeployer.sol b/contracts/utils/VyperDeployer.sol index 0650a23..2e72418 100644 --- a/contracts/utils/VyperDeployer.sol +++ b/contracts/utils/VyperDeployer.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.13; -pragma solidity ^0.8.7; +// solhint-disable + +//Taken from: https://github.com/0xKitsune/Foundry-Vyper ///@notice This cheat codes interface is named _CheatCodes so you can use the CheatCodes interface in other testing files without errors interface _CheatCodes { @@ -15,14 +18,14 @@ contract VyperDeployer { ///@notice Compiles a Vyper contract and returns the address that the contract was deployeod to ///@notice If deployment fails, an error will be thrown - ///@param fileName - The file name of the Vyper contract. For example, the file name for "SimpleStore.vy" is "SimpleStore" + ///@param filepath - The file name of the Vyper contract. For example, the file name for "SimpleStore.vy" is "SimpleStore" ///@return deployedAddress - The address that the contract was deployed to - function deployContract(string memory fileName) public returns (address) { + function deployContract(string memory filepath) public returns (address) { ///@notice create a list of strings with the commands necessary to compile Vyper contracts string[] memory cmds = new string[](2); cmds[0] = "vyper"; - cmds[1] = string.concat("vyper_contracts/", fileName, ".vy"); + cmds[1] = filepath; ///@notice compile the Vyper contract and return the bytecode bytes memory bytecode = cheatCodes.ffi(cmds); @@ -48,7 +51,7 @@ contract VyperDeployer { ///@notice create a list of strings with the commands necessary to compile Vyper contracts string[] memory cmds = new string[](2); cmds[0] = "vyper"; - cmds[1] = string.concat("vyper_contracts/", fileName, ".vy"); + cmds[1] = string.concat("test/external/", fileName, ".vy"); ///@notice compile the Vyper contract and return the bytecode bytes memory _bytecode = cheatCodes.ffi(cmds); @@ -68,48 +71,4 @@ contract VyperDeployer { ///@notice return the address that the contract was deployed to return deployedAddress; } - - /// @dev Consider listening to the Blueprint if you haven't already - /// @param fileName - The file name of the Blueprint Contract - function deployBlueprint(string memory fileName) public returns (address) { - ///@notice create a list of strings with the commands necessary to compile Vyper contracts - string[] memory cmds = new string[](2); - cmds[0] = "vyper"; - cmds[1] = string.concat("vyper_contracts/", fileName, ".vy"); - - ///@notice compile the Vyper contract and return the bytecode - bytes memory bytecode = cheatCodes.ffi(cmds); - - require(bytecode.length > 0, "Initcodes length must be greater than 0"); - - /// @notice prepend needed items for Blueprint ERC - /// See https://eips.ethereum.org/EIPS/eip-5202 for more details - bytes memory eip_5202_bytecode = bytes.concat( - hex"fe", // EIP_5202_EXECUTION_HALT_BYTE - hex"71", // EIP_5202_BLUEPRINT_IDENTIFIER_BYTE - hex"00", // EIP_5202_VERSION_BYTE - bytecode - ); - - bytes2 len = bytes2(uint16(eip_5202_bytecode.length)); - - /// @notice prepend the deploy preamble - bytes memory deployBytecode = bytes.concat( - hex"61", // DEPLOY_PREAMBLE_INITIAL_BYTE - len, // DEPLOY_PREAMBLE_BYTE_LENGTH - hex"3d81600a3d39f3", // DEPLOY_PREABLE_POST_LENGTH_BYTES - eip_5202_bytecode - ); - - ///@notice check that the deployment was successful - address deployedAddress; - assembly { - deployedAddress := create(0, add(deployBytecode, 0x20), mload(deployBytecode)) - } - - require(deployedAddress != address(0), "VyperDeployer could not deploy contract"); - - ///@notice return the address that the contract was deployed to - return deployedAddress; - } } diff --git a/foundry.toml b/foundry.toml index e314232..3db7807 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,19 +6,20 @@ libs = ["lib"] script = "scripts" cache_path = "cache" gas_reports = ["*"] -via_ir = true sizes = true optimizer = true optimizer_runs = 1000 -solc_version = "0.8.7" +solc_version = "0.8.22" ffi = true +via_ir = true [fuzz] runs = 10000 [invariant] -runs = 1000 -depth = 30 +runs = 10 +depth = 100 +fail_on_revert = true [rpc_endpoints] arbitrum = "${ETH_NODE_URI_ARBITRUM}" @@ -34,16 +35,7 @@ bsc = "${ETH_NODE_URI_BSC}" base = "${ETH_NODE_URI_BASE}" [etherscan] -arbitrum = { key = "${ARBITRUM_ETHERSCAN_API_KEY}" } -gnosis = { key = "${GNOSIS_ETHERSCAN_API_KEY}" , url = "https://api.gnosisscan.io/api"} -mainnet = { key = "${MAINNET_ETHERSCAN_API_KEY}" } -optimism = { key = "${OPTIMISM_ETHERSCAN_API_KEY}" } -polygon = { key = "${POLYGON_ETHERSCAN_API_KEY}" } -avalanche = { key = "${AVALANCHE_ETHERSCAN_API_KEY}" } -celo = { key = "${CELO_ETHERSCAN_API_KEY}", url = "https://api.celoscan.io/api" } -base = { key = "${BASE_ETHERSCAN_API_KEY}", url = "https://api.basescan.org/api" } -polygonzkevm = { key = "${POLYGONZKEVM_ETHERSCAN_API_KEY}", url = "https://api-zkevm.polygonscan.com/api" } -bsc = { key = "${BSC_ETHERSCAN_API_KEY}"} + [profile.dev] optimizer = true @@ -55,9 +47,9 @@ gas_reports = ["*"] runs = 2000 [profile.dev.invariant] -runs = 10 -depth = 1 -fail_on_revert = false +runs = 100 +depth = 10 +fail_on_revert = true [profile.ci] src = "test" @@ -70,4 +62,4 @@ runs = 100 [profile.ci.invariant] runs = 10 depth = 30 -fail_on_revert = false +fail_on_revert = true diff --git a/lib/utils b/lib/utils index 03a279e..41388c6 160000 --- a/lib/utils +++ b/lib/utils @@ -1 +1 @@ -Subproject commit 03a279efc8569b5b6f1a2925effeb5e966a02f03 +Subproject commit 41388c6ea9c45b05b92155356d6e700802fdb566 diff --git a/package.json b/package.json index 4b559c4..8c81d99 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "fork": "bash helpers/fork.sh", "run": "docker run -it --rm -v $(pwd):/app -w /app ghcr.io/foundry-rs/foundry sh", "script:fork": "source .env && forge script --skip test --fork-url fork --broadcast -vvvv", - "test:unit": "forge test -vvv --gas-report --match-path \"test/unit/**/*.sol\"", + "test:unit": "forge test -vvvv --gas-report --match-path \"test/unit/**/*.sol\"", "test:invariant": "forge test -vvv --gas-report --match-path \"test/invariant/**/*.sol\"", "test:fuzz": "forge test -vvv --gas-report --match-path \"test/fuzz/**/*.sol\"", "test": "FOUNDRY_PROFILE=dev forge test -vvv", @@ -38,5 +38,7 @@ "solhint": "^3.5.1", "solhint-plugin-prettier": "^0.0.5" }, - "dependencies": {} + "dependencies": { + "@angleprotocol/sdk": "^0.38.0" + } } diff --git a/remappings.txt b/remappings.txt index 20ce6b6..c9238f4 100644 --- a/remappings.txt +++ b/remappings.txt @@ -2,4 +2,5 @@ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts @openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts -utils/=lib/utils/ \ No newline at end of file +utils/=lib/utils/ +contracts/=contracts/ \ No newline at end of file diff --git a/scripts/BasicScript.s.sol b/scripts/BasicScript.s.sol deleted file mode 100644 index 8c1e77d..0000000 --- a/scripts/BasicScript.s.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; - -import "forge-std/Script.sol"; -import { console } from "forge-std/console.sol"; - -contract MyScript is Script { - function test() external { - vm.startBroadcast(); - - address _sender = address(uint160(uint256(keccak256(abi.encodePacked("sender"))))); - address _receiver = address(uint160(uint256(keccak256(abi.encodePacked("receiver"))))); - - // deal(address(token), _sender, 1 ether); - // vm.prank(_sender); - // token.transfer(_receiver, 1 ether); - - vm.stopBroadcast(); - } -} diff --git a/scripts/DeployVeAngle.s.sol b/scripts/DeployVeAngle.s.sol new file mode 100644 index 0000000..0f5c436 --- /dev/null +++ b/scripts/DeployVeAngle.s.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "forge-std/Script.sol"; +import { console } from "forge-std/console.sol"; +import { VyperDeployer } from "contracts/utils/VyperDeployer.sol"; +import "./Utils.s.sol"; + +contract DeployVeAngleScript is Script, Utils, VyperDeployer { + function run() external { + uint256 deployerPrivateKey = vm.deriveKey(vm.envString("MNEMONIC_MAINNET"), "m/44'/60'/0'/0/", 0); + + address deployer = vm.addr(deployerPrivateKey); + console.log("Deployer address: ", deployer); + + vm.startBroadcast(deployerPrivateKey); + address veANGLE = deployContract("contracts/dao/veANGLE.vy"); + vm.stopBroadcast(); + console.log("veANGLE deployed at: ", veANGLE); + } +} diff --git a/scripts/Simulate.s.sol b/scripts/Simulate.s.sol deleted file mode 100644 index d922378..0000000 --- a/scripts/Simulate.s.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; - -import "forge-std/Script.sol"; -import { console } from "forge-std/console.sol"; - -contract Simulate is Script { - error WrongCall(); - - function run() external { - // TODO replace with your inputs - address sender = address(0x0274a704a6D9129F90A62dDC6f6024b33EcDad36); - address contractAddress = address(0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae); - // remove the 0x - bytes - memory data = hex"71ee95c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000274a704a6d9129f90a62ddc6f6024b33ecdad3600000000000000000000000000000000000000000000000000000000000000010000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000427abf85e5d121ac000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000811e1782af6373843046497b3be2c5b25f13037b02c218c5a1a5be24666434d169ca949b7c3d8c763a566075f024a19b4565aba390e00f197fff97adb2f9ef8b0eee43dfe473f564bbd71b106e37928d4f052afe2abf8a42e5f07aded57af2766943bc7bedecf531200d4ca454185d135e6933aa3cff5c53a55f45033135d3a01aae71a2ff3d1e34342bdb86d6348a9da5c8384085f743bb2451aa846b5f667690ccb7b7b1fe363d3e286addaaff93de4a258308fae35fb008580bc25873284f63b37592378acc9f27d211017550c57ae97d0e9cc944d3f90bf54147a69fedeed81940d2088ad7b84767ae8569a9202e23aa0f8204a30b365916d5cefb60c1dfe"; - - vm.prank(sender); - (bool success, ) = contractAddress.call(data); - if (!success) revert WrongCall(); - } -} diff --git a/test/Fixture.t.sol b/test/Fixture.t.sol new file mode 100644 index 0000000..6524e23 --- /dev/null +++ b/test/Fixture.t.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "forge-std/Test.sol"; +import { IveANGLE } from "contracts/interfaces/IVeANGLE.sol"; +import { VyperDeployer } from "contracts/utils/VyperDeployer.sol"; +import { ANGLE } from "contracts/dao/ANGLE.sol"; +import "utils/src/CommonUtils.sol"; + +contract Fixture is Test, CommonUtils { + VyperDeployer public vyperDeployer; + + IveANGLE public veANGLE; + address public admin; + ANGLE public Angle; + address public checker; + + address public alice; + address public bob; + + function setUp() public virtual { + uint256 CHAIN_SOURCE = CHAIN_ETHEREUM; + + vyperDeployer = new VyperDeployer(); + veANGLE = IveANGLE(vyperDeployer.deployContract("contracts/dao/veANGLE.vy")); + + vm.createSelectFork("mainnet"); + IveANGLE forkedveANGLE = IveANGLE(_chainToContract(CHAIN_SOURCE, ContractType.veANGLE)); + + admin = forkedveANGLE.admin(); + string memory name = forkedveANGLE.name(); + string memory symbol = forkedveANGLE.symbol(); + checker = forkedveANGLE.smart_wallet_checker(); + Angle = ANGLE(_chainToContract(CHAIN_SOURCE, ContractType.Angle)); + + veANGLE.initialize(admin, address(Angle), checker, name, symbol); + + alice = makeAddr("alice"); + bob = makeAddr("bob"); + } +} diff --git a/test/fuzz/.gitkeep b/test/fuzz/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/fuzz/EmergencyWithdrawal.t.sol b/test/fuzz/EmergencyWithdrawal.t.sol new file mode 100644 index 0000000..6080a9b --- /dev/null +++ b/test/fuzz/EmergencyWithdrawal.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import { Fixture, IveANGLE } from "../Fixture.t.sol"; +import { console } from "forge-std/console.sol"; + +contract EmergencyWithdrawalFuzz is Fixture { + function test_emergencyWithdrawalFuzz_Normal(uint256[10] memory balances, uint256[10] memory durations) external { + address[] memory accounts = new address[](balances.length); + for (uint i = 0; i < accounts.length; i++) { + accounts[i] = address(uint160(uint256(keccak256(abi.encodePacked("account", i))))); + } + for (uint i = 0; i < accounts.length; i++) { + durations[i] = bound(durations[i], 1 weeks, 365 days * 4); + balances[i] = bound(balances[i], 1e18, 1e22); + deal(address(Angle), accounts[i], balances[i]); + + vm.startPrank(accounts[i], accounts[i]); + Angle.approve(address(veANGLE), balances[i]); + veANGLE.create_lock(balances[i], block.timestamp + durations[i]); + vm.stopPrank(); + } + + assertEq(veANGLE.emergency_withdrawal(), false); + + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + assertEq(veANGLE.emergency_withdrawal(), true); + + for (uint i = 0; i < accounts.length; i++) { + assertEq(Angle.balanceOf(accounts[i]), 0); + + vm.prank(accounts[i]); + veANGLE.withdraw_fast(); + assertEq(Angle.balanceOf(accounts[i]), balances[i]); + + vm.prank(accounts[i]); + veANGLE.withdraw_fast(); + assertEq(Angle.balanceOf(accounts[i]), balances[i]); + } + } + + function test_emergencyWithdrawalFuzz_WithTimeWraps( + uint256[10] memory balances, + uint256[10] memory durations, + uint256[10] memory timeWraps + ) external { + address[] memory accounts = new address[](balances.length); + for (uint i = 0; i < accounts.length; i++) { + accounts[i] = address(uint160(uint256(keccak256(abi.encodePacked("account", i))))); + } + + for (uint i = 0; i < accounts.length; i++) { + durations[i] = bound(durations[i], 1 weeks, 365 days * 4); + balances[i] = bound(balances[i], 1e18, 1e22); + deal(address(Angle), accounts[i], balances[i]); + vm.startPrank(accounts[i], accounts[i]); + Angle.approve(address(veANGLE), balances[i]); + veANGLE.create_lock(balances[i], block.timestamp + durations[i]); + vm.stopPrank(); + } + + assertEq(veANGLE.emergency_withdrawal(), false); + + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + assertEq(veANGLE.emergency_withdrawal(), true); + + for (uint i = 0; i < accounts.length; i++) { + timeWraps[i] = bound(timeWraps[i], 0, 365 days * 4 + 1); + assertEq(Angle.balanceOf(accounts[i]), 0); + + vm.warp(block.timestamp + timeWraps[i]); + + vm.prank(accounts[i]); + veANGLE.withdraw_fast(); + assertEq(Angle.balanceOf(accounts[i]), balances[i]); + + vm.prank(accounts[i]); + veANGLE.withdraw_fast(); + assertEq(Angle.balanceOf(accounts[i]), balances[i]); + } + } +} diff --git a/test/invariant/.gitkeep b/test/invariant/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/invariant/LocksInvariants.t.sol b/test/invariant/LocksInvariants.t.sol new file mode 100644 index 0000000..24dd623 --- /dev/null +++ b/test/invariant/LocksInvariants.t.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.7; + +import "../Fixture.t.sol"; +import { Locker } from "./actors/Locker.t.sol"; +import { Param } from "./actors/Param.t.sol"; +import { TimestampStore } from "./stores/TimestampStore.t.sol"; +import { LockStore, Lock } from "./stores/LockStore.t.sol"; +import { IERC20 } from "oz/token/ERC20/IERC20.sol"; +import "oz/utils/Strings.sol"; + +//solhint-disable +import { console } from "forge-std/console.sol"; + +contract LocksInvariants is Fixture { + uint256 internal constant _NUM_LOCKERS = 10; + uint256 internal constant _NUM_PARAMS = 1; + + Locker internal _lockerHandler; + Param internal _paramHandler; + TimestampStore internal _timestampStore; + LockStore internal _lockStore; + + modifier useCurrentTimestampBlock() { + vm.warp(_timestampStore.currentTimestamp()); + vm.roll(_timestampStore.currentBlockNumber()); + _; + } + + function concat(string memory a, string memory b) public pure returns (string memory) { + return string(abi.encodePacked(a, b)); + } + + function setUp() public virtual override { + super.setUp(); + _timestampStore = new TimestampStore(); + _lockStore = new LockStore(); + _lockerHandler = new Locker(_NUM_LOCKERS, IERC20(address(Angle)), veANGLE, _timestampStore, _lockStore); + _paramHandler = new Param(_NUM_PARAMS, _timestampStore); + + // Label newly created addresses + for (uint256 i; i < _NUM_LOCKERS; i++) { + vm.label(_lockerHandler.actors(i), concat("Locker ", Strings.toString(i))); + } + vm.label({ account: address(_timestampStore), newLabel: "TimestampStore" }); + vm.label({ account: address(_paramHandler), newLabel: "Param" }); + targetContract(address(_lockerHandler)); + targetContract(address(_paramHandler)); + + { + bytes4[] memory selectors = new bytes4[](4); + selectors[0] = Locker.createLock.selector; + selectors[1] = Locker.withdraw.selector; + selectors[2] = Locker.extendLockTime.selector; + selectors[3] = Locker.extendLockAmount.selector; + targetSelector(FuzzSelector({ addr: address(_lockerHandler), selectors: selectors })); + } + { + bytes4[] memory selectors = new bytes4[](1); + selectors[0] = Param.wrap.selector; + targetSelector(FuzzSelector({ addr: address(_paramHandler), selectors: selectors })); + } + } + + function invariant_RightBalanceAtTimestamp() public useCurrentTimestampBlock { + for (uint256 i = 0; i < _NUM_LOCKERS; i++) { + address locker = _lockerHandler.actors(i); + + Lock[] memory locks = _lockStore.getLocks(locker); + for (uint256 j = 0; j < locks.length; j++) { + Lock memory lock = locks[j]; + if (lock.amount == 0) { + assertEq(veANGLE.balanceOf(locker, lock.timestamp), 0); + continue; + } + + uint256 balance = veANGLE.balanceOf(locker, lock.timestamp); + assertGt(balance, (((lock.amount * (lock.unlockTime - lock.timestamp)) / (365 days * 4)) * 95) / 100); + assertLe(balance, (lock.amount * (lock.unlockTime - lock.timestamp)) / (365 days * 4)); + } + } + } + + function invariant_RightBalanceAfterTimestamp() public useCurrentTimestampBlock { + for (uint256 i = 0; i < _NUM_LOCKERS; i++) { + address locker = _lockerHandler.actors(i); + + Lock[] memory locks = _lockStore.getLocks(locker); + for (uint256 j = 0; j < locks.length; j++) { + Lock memory lock = locks[j]; + if (lock.amount == 0) { + assertEq(veANGLE.balanceOf(locker, lock.timestamp + 1), 0); + continue; + } + + uint256 balance = veANGLE.balanceOf(locker, lock.timestamp + 1); + assertGt( + balance, + (((lock.amount * (lock.unlockTime - lock.timestamp + 1)) / (365 days * 4)) * 95) / 100 + ); + assertLe(balance, (lock.amount * (lock.unlockTime - lock.timestamp + 1)) / (365 days * 4)); + } + } + } +} diff --git a/test/invariant/actors/BaseActor.t.sol b/test/invariant/actors/BaseActor.t.sol new file mode 100644 index 0000000..869cdab --- /dev/null +++ b/test/invariant/actors/BaseActor.t.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.7; + +import { IERC20 } from "oz/token/ERC20/IERC20.sol"; +import { Test, stdMath, StdStorage, stdStorage } from "forge-std/Test.sol"; + +contract BaseActor is Test { + uint256 internal _minWallet = 0; // in base 18 + uint256 internal _maxWallet = 10 ** (18 + 12); // in base 18 + + mapping(bytes32 => uint256) public calls; + mapping(address => uint256) public addressToIndex; + address[] public actors; + uint256 public nbrActor; + address internal _currentActor; + + modifier countCall(bytes32 key) { + calls[key]++; + _; + } + + modifier useActor(uint256 actorIndexSeed) { + _currentActor = actors[bound(actorIndexSeed, 0, actors.length - 1)]; + vm.startPrank(_currentActor, _currentActor); + _; + vm.stopPrank(); + } + + constructor(uint256 _nbrActor, string memory actorType) { + for (uint256 i; i < _nbrActor; ++i) { + address actor = address(uint160(uint256(keccak256(abi.encodePacked("actor", actorType, i))))); + actors.push(actor); + addressToIndex[actor] = i; + } + nbrActor = _nbrActor; + } +} diff --git a/test/invariant/actors/Locker.t.sol b/test/invariant/actors/Locker.t.sol new file mode 100644 index 0000000..593acf9 --- /dev/null +++ b/test/invariant/actors/Locker.t.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.7; + +import "./BaseActor.t.sol"; +import { TimestampStore } from "../stores/TimestampStore.t.sol"; +import { LockStore, Lock } from "../stores/LockStore.t.sol"; +import { IveANGLE } from "../../../contracts/interfaces/IVeANGLE.sol"; +import { console } from "forge-std/console.sol"; + +contract Locker is BaseActor { + IveANGLE public veANGLE; + TimestampStore public timestampStore; + LockStore public lockStore; + IERC20 public angle; + + modifier useCurrentTimestampBlock() { + vm.warp(timestampStore.currentTimestamp()); + vm.roll(timestampStore.currentBlockNumber()); + _; + vm.warp(timestampStore.currentTimestamp()); + vm.roll(timestampStore.currentBlockNumber()); + } + + constructor( + uint256 _nbrActor, + IERC20 _angle, + IveANGLE _veANGLE, + TimestampStore _timestampStore, + LockStore _lockStore + ) BaseActor(_nbrActor, "Locker") { + timestampStore = _timestampStore; + lockStore = _lockStore; + angle = _angle; + veANGLE = _veANGLE; + } + + function createLock( + uint256 actorIndex, + uint256 amount, + uint256 duration + ) public useCurrentTimestampBlock useActor(actorIndex) { + if (veANGLE.locked__end(_currentActor) != 0) { + return; + } + duration = bound(duration, 365 days * 2, 365 days * 4); + amount = bound(amount, 1e18, 100e18); + + deal(address(angle), _currentActor, amount); + angle.approve(address(veANGLE), amount); + + veANGLE.create_lock(amount, block.timestamp + duration); + + IveANGLE.LockedBalance memory locked = veANGLE.locked(_currentActor); + lockStore.addLock(_currentActor, locked.amount, locked.end, block.timestamp); + + // increase timestamp to avoid lock timestamp collision + timestampStore.increaseCurrentTimestamp(10); + } + + function withdraw(uint256 actorIndex) public useCurrentTimestampBlock useActor(actorIndex) { + if (veANGLE.locked__end(_currentActor) != 0 && veANGLE.locked__end(_currentActor) < block.timestamp) { + veANGLE.withdraw(); + lockStore.addLock(_currentActor, 0, 0, block.timestamp); + + // increase timestamp to avoid lock timestamp collision + timestampStore.increaseCurrentTimestamp(10); + } + } + + function extendLockTime(uint256 actorIndex, uint256 duration) public useCurrentTimestampBlock useActor(actorIndex) { + uint256 end = veANGLE.locked__end(_currentActor); + if (end == 0 || end < block.timestamp || end + 365 days * 2 > block.timestamp + 365 days * 4) { + return; + } + + duration = bound(duration, end + 365 days * 2, block.timestamp + 365 days * 4); + veANGLE.increase_unlock_time(duration); + + IveANGLE.LockedBalance memory locked = veANGLE.locked(_currentActor); + + Lock memory lastLock = lockStore.getLatestLock(_currentActor); + lockStore.addLock(_currentActor, lastLock.amount, locked.end, block.timestamp); + + // increase timestamp to avoid lock timestamp collision + timestampStore.increaseCurrentTimestamp(10); + } + + function extendLockAmount(uint256 actorIndex, uint256 amount) public useCurrentTimestampBlock useActor(actorIndex) { + if (veANGLE.balanceOf(_currentActor) == 0) { + return; + } + amount = bound(amount, 1e18, 100e18); + + deal(address(angle), _currentActor, amount); + angle.approve(address(veANGLE), amount); + veANGLE.increase_amount(amount); + + Lock memory lastLock = lockStore.getLatestLock(_currentActor); + lockStore.addLock(_currentActor, lastLock.amount + amount, lastLock.unlockTime, block.timestamp); + + // increase timestamp to avoid lock timestamp collision + timestampStore.increaseCurrentTimestamp(10); + } +} diff --git a/test/invariant/actors/Param.t.sol b/test/invariant/actors/Param.t.sol new file mode 100644 index 0000000..dbabcea --- /dev/null +++ b/test/invariant/actors/Param.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.7; + +import "./BaseActor.t.sol"; +import { TimestampStore } from "../stores/TimestampStore.t.sol"; + +contract Param is BaseActor { + TimestampStore public timestampStore; + + constructor(uint256 _nbrActor, TimestampStore _timestampStore) BaseActor(_nbrActor, "Param") { + timestampStore = _timestampStore; + } + + function wrap(uint256 duration) public { + duration = bound(duration, 0, 365 days * 5); + timestampStore.increaseCurrentTimestamp(duration); + vm.warp(timestampStore.currentTimestamp()); + vm.roll(timestampStore.currentBlockNumber()); + } +} diff --git a/test/invariant/stores/LockStore.t.sol b/test/invariant/stores/LockStore.t.sol new file mode 100644 index 0000000..61c7c87 --- /dev/null +++ b/test/invariant/stores/LockStore.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.7; + +struct Lock { + uint256 amount; + uint256 unlockTime; + uint256 timestamp; +} + +contract LockStore { + mapping(address => Lock[]) public locks; + + constructor() {} + + function addLock(address account, uint256 amount, uint256 unlockTime, uint256 timestamp) external { + locks[account].push(Lock(amount, unlockTime, timestamp)); + } + + function getLatestLock(address account) external view returns (Lock memory) { + return locks[account][locks[account].length - 1]; + } + + function getLocks(address account) external view returns (Lock[] memory) { + return locks[account]; + } +} diff --git a/test/invariant/stores/TimestampStore.t.sol b/test/invariant/stores/TimestampStore.t.sol new file mode 100644 index 0000000..4853212 --- /dev/null +++ b/test/invariant/stores/TimestampStore.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.7; + +/// @dev Because Foundry does not commit the state changes between invariant runs, we need to +/// save the current timestamp in a contract with persistent storage. +contract TimestampStore { + uint256 public currentTimestamp; + uint256 public currentBlockNumber; + + constructor() { + currentTimestamp = block.timestamp; + currentBlockNumber = block.number; + } + + function increaseCurrentTimestamp(uint256 timeJump) external { + currentTimestamp += timeJump; + currentBlockNumber += 1; + } + + function increaseCurrentBlockNumber(uint256 blockJump) external { + currentTimestamp += 1; + currentBlockNumber += blockJump; + } +} diff --git a/test/unit/.gitkeep b/test/unit/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/unit/BalanceOf.t.sol b/test/unit/BalanceOf.t.sol new file mode 100644 index 0000000..e1d1d6f --- /dev/null +++ b/test/unit/BalanceOf.t.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import { Fixture, IveANGLE } from "../Fixture.t.sol"; +import { console } from "forge-std/console.sol"; + +contract BalanceOf is Fixture { + function test_balanceOf_LocksAfterTimestamp() external { + uint256 timestamp = block.timestamp + 365 days * 2; + uint256 oldTimestamp = block.timestamp; + uint256 amount = 10e18; + + deal(address(Angle), alice, amount); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), amount); + veANGLE.create_lock(amount, timestamp); + vm.stopPrank(); + + vm.warp(block.timestamp + 200 days); + + assertEq(veANGLE.balanceOf(alice, oldTimestamp - 1), 0); + } + + function test_balanceOf_ExtendDate() external { + uint256 timestamp = block.timestamp + 365 days * 2; + uint256 oldTimestamp = block.timestamp; + uint256 amount = 10e18; + + deal(address(Angle), alice, amount); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), amount); + veANGLE.create_lock(amount, timestamp); + vm.stopPrank(); + + vm.warp(block.timestamp + 200 days); + + vm.prank(alice, alice); + veANGLE.increase_unlock_time(block.timestamp + 4 * 365 days); + + assertGt(veANGLE.balanceOf(alice, block.timestamp), ((amount * 10000) * 95) / 1000000); + assertLt(veANGLE.balanceOf(alice, block.timestamp), amount); + + assertGt(veANGLE.balanceOf(alice, oldTimestamp), ((amount * 10000) * 47) / 1000000); + assertLt(veANGLE.balanceOf(alice, oldTimestamp), amount); + } + + function test_balanceOf_ExtendAmount() external { + uint256 timestamp = block.timestamp + 365 days * 2; + uint256 oldTimestamp = block.timestamp; + uint256 amount = 10e18; + uint256 amount2 = 10e18; + + deal(address(Angle), alice, amount + amount2); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), amount); + veANGLE.create_lock(amount, timestamp); + vm.stopPrank(); + + vm.warp(block.timestamp + 365 days); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), amount2); + veANGLE.increase_amount(amount2); + vm.stopPrank(); + + assertGt(veANGLE.balanceOf(alice, block.timestamp), (((amount + amount2) * 10000) * 22) / 1000000); + assertLt(veANGLE.balanceOf(alice, block.timestamp), amount + amount2); + + assertGt(veANGLE.balanceOf(alice, oldTimestamp), ((amount * 10000) * 47) / 1000000); + assertLt(veANGLE.balanceOf(alice, oldTimestamp), amount); + } + + function test_balanceOf_LocksBeforeTimestamp() external { + uint256 timestamp = block.timestamp + 365 days * 2; + uint256 oldTimestamp = block.timestamp; + uint256 amount = 10e18; + + deal(address(Angle), alice, amount); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), amount); + veANGLE.create_lock(amount, timestamp); + vm.stopPrank(); + + assertGt(veANGLE.balanceOf(alice, block.timestamp), ((amount * 10000) * 47) / 1000000); + assertLt(veANGLE.balanceOf(alice, block.timestamp), amount); + } + + function test_balanceOf_MultipleLocks() external { + uint256 timestamp = block.timestamp + 365 days * 2; + uint256 oldTimestamp = block.timestamp; + uint256 amount = 10e18; + uint256 amount2 = 100e18; + + deal(address(Angle), alice, amount); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), amount); + veANGLE.create_lock(amount, timestamp); + vm.stopPrank(); + + vm.warp(block.timestamp + 365 days * 2 + 1); + + deal(address(Angle), alice, amount2); + + vm.startPrank(alice, alice); + veANGLE.withdraw(); + Angle.approve(address(veANGLE), amount2); + veANGLE.create_lock(amount2, block.timestamp + 365 days * 2); + vm.stopPrank(); + + assertGt(veANGLE.balanceOf(alice, block.timestamp), ((amount2 * 10000) * 47) / 1000000); + assertLt(veANGLE.balanceOf(alice, block.timestamp), amount2); + + assertGt(veANGLE.balanceOf(alice, oldTimestamp), ((amount * 10000) * 47) / 1000000); + assertLt(veANGLE.balanceOf(alice, oldTimestamp), amount); + } +} diff --git a/test/unit/EmergencyWithdrawal.t.sol b/test/unit/EmergencyWithdrawal.t.sol new file mode 100644 index 0000000..7fcf1dd --- /dev/null +++ b/test/unit/EmergencyWithdrawal.t.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import { Fixture, IveANGLE } from "../Fixture.t.sol"; + +contract EmergencyWithdrawal is Fixture { + function test_emergencyWithdrawal_Normal() external { + assertEq(veANGLE.emergency_withdrawal(), false); + + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + assertEq(veANGLE.emergency_withdrawal(), true); + } + + function test_emergencyWithdrawal_checkpoint() external { + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.expectRevert("Emergency withdrawal enabled"); + veANGLE.checkpoint(); + } + + function test_emergencyWithdrawal_create_lock() external { + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.expectRevert("Emergency withdrawal enabled"); + veANGLE.create_lock(10e18, block.timestamp + 365 days); + } + + function test_emergencyWithdrawal_increase_amount() external { + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.expectRevert("Emergency withdrawal enabled"); + veANGLE.increase_amount(0); + } + + function test_emergencyWithdrawal_increase_unlock_time() external { + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.expectRevert("Emergency withdrawal enabled"); + veANGLE.increase_unlock_time(block.timestamp + 365 days); + } + + function test_emergencyWithdrawal_withdraw() external { + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.expectRevert("Emergency withdrawal enabled"); + veANGLE.withdraw(); + } + + function test_emergencyWithdrawal_deposit_for() external { + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.expectRevert("Emergency withdrawal enabled"); + veANGLE.deposit_for(alice, 10e18); + } + + function test_emergencyWithdrawal_SingleLock() external { + deal(address(Angle), alice, 10e18); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), 10e18); + veANGLE.create_lock(10e18, block.timestamp + 365 days); + vm.stopPrank(); + + assertEq(Angle.balanceOf(alice), 0); + + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.prank(alice, alice); + veANGLE.withdraw_fast(); + + assertEq(Angle.balanceOf(alice), 10e18); + } + + function test_emergencyWithdrawal_AfterLockExpired() external { + deal(address(Angle), alice, 10e18); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), 10e18); + veANGLE.create_lock(10e18, block.timestamp + 365 days); + vm.stopPrank(); + + assertEq(Angle.balanceOf(alice), 0); + + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.warp(block.timestamp + 365 days + 1); + + vm.prank(alice, alice); + veANGLE.withdraw_fast(); + + assertEq(Angle.balanceOf(alice), 10e18); + } + + function test_emergencyWithdrawal_MultipleLocks() external { + deal(address(Angle), alice, 10e18); + deal(address(Angle), bob, 20e18); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), 10e18); + veANGLE.create_lock(10e18, block.timestamp + 365 days * 4); + vm.stopPrank(); + + vm.warp(block.timestamp + 365 days); + + vm.startPrank(bob, bob); + Angle.approve(address(veANGLE), 20e18); + veANGLE.create_lock(20e18, block.timestamp + 365 days * 2); + vm.stopPrank(); + + assertEq(Angle.balanceOf(alice), 0); + assertEq(Angle.balanceOf(bob), 0); + + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.prank(alice, alice); + veANGLE.withdraw_fast(); + + assertEq(Angle.balanceOf(alice), 10e18); + + vm.warp(block.timestamp + 365 days); + + vm.prank(bob, bob); + veANGLE.withdraw_fast(); + + assertEq(Angle.balanceOf(bob), 20e18); + } + + function test_emergencyWithdrawal_CannotWithdrawTwice() external { + deal(address(Angle), alice, 10e18); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), 10e18); + veANGLE.create_lock(10e18, block.timestamp + 365 days); + vm.stopPrank(); + + assertEq(Angle.balanceOf(alice), 0); + + vm.prank(admin); + veANGLE.set_emergency_withdrawal(); + + vm.prank(alice, alice); + veANGLE.withdraw_fast(); + + assertEq(Angle.balanceOf(alice), 10e18); + + vm.prank(alice, alice); + veANGLE.withdraw_fast(); + + assertEq(Angle.balanceOf(alice), 10e18); + } + + function test_emergencyWithdrawal_CannotWithdrawWhenNoEmergency() external { + deal(address(Angle), alice, 20e18); + + vm.startPrank(alice, alice); + Angle.approve(address(veANGLE), 20e18); + veANGLE.create_lock(10e18, block.timestamp + 365 days); + vm.stopPrank(); + + vm.expectRevert("Emergency withdrawal not enabled"); + veANGLE.withdraw_fast(); + } +} diff --git a/yarn.lock b/yarn.lock index 54f44d1..1a6fa94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,44 @@ # yarn lockfile v1 +"@angleprotocol/sdk@^0.38.0": + version "0.38.0" + resolved "https://npm.pkg.github.com/download/@angleprotocol/sdk/0.38.0/c8050577a3f844b3e4713bef2f0628eba7e522fd#c8050577a3f844b3e4713bef2f0628eba7e522fd" + integrity sha512-mufd2bhCSyWKyzf45HsIz6rhw2rS1nyXnp2FyvDDvXpk6xSGYIClF870FleCd9vCVBrf10tz8oDXY7y80V3CMg== + dependencies: + "@apollo/client" "^3.7.17" + "@typechain/ethers-v5" "^10.0.0" + "@types/lodash" "^4.14.180" + ethers "^5.6.4" + graphql "^15.7.1" + graphql-request "^3.6.1" + jsbi "^4.3.0" + keccak256 "^1.0.6" + lodash "^4.17.21" + merkletreejs "^0.3.10" + tiny-invariant "^1.1.0" + typechain "^8.3.2" + +"@apollo/client@^3.7.17": + version "3.9.9" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.9.9.tgz#38f983a1ad24e2687abfced0a9c1c3bef8d32616" + integrity sha512-/sMecU/M0WK9knrguts1lSLV8xFKzIgOMVb4mi6MOxgJXjliDB8PvOtmXhTqh2cVMMR4TzXgOnb+af/690zlQw== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + "@wry/caches" "^1.0.0" + "@wry/equality" "^0.5.6" + "@wry/trie" "^0.5.0" + graphql-tag "^2.12.6" + hoist-non-react-statics "^3.3.2" + optimism "^0.18.0" + prop-types "^15.7.2" + rehackt "0.0.6" + response-iterator "^0.2.6" + symbol-observable "^4.0.0" + ts-invariant "^0.10.3" + tslib "^2.3.0" + zen-observable-ts "^1.2.5" + "@babel/code-frame@^7.0.0": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" @@ -24,6 +62,401 @@ chalk "^2.4.2" js-tokens "^4.0.0" +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@graphql-typed-document-node/core@^3.1.1": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + +"@noble/curves@1.3.0", "@noble/curves@~1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== + dependencies: + "@noble/hashes" "1.3.3" + +"@noble/hashes@1.3.3", "@noble/hashes@~1.3.2": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== + +"@scure/base@~1.1.4": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" + integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== + +"@scure/bip32@1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" + integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== + dependencies: + "@noble/curves" "~1.3.0" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + +"@scure/bip39@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" + integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== + dependencies: + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + "@solidity-parser/parser@^0.16.0": version "0.16.1" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.16.1.tgz#f7c8a686974e1536da0105466c4db6727311253c" @@ -31,6 +464,64 @@ dependencies: antlr4ts "^0.5.0-alpha.4" +"@typechain/ethers-v5@^10.0.0": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz#50241e6957683281ecfa03fb5a6724d8a3ce2391" + integrity sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A== + dependencies: + lodash "^4.17.15" + ts-essentials "^7.0.1" + +"@types/lodash@^4.14.180": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.0.tgz#d774355e41f372d5350a4d0714abb48194a489c3" + integrity sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA== + +"@types/prettier@^2.1.1": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== + +"@wry/caches@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@wry/caches/-/caches-1.0.1.tgz#8641fd3b6e09230b86ce8b93558d44cf1ece7e52" + integrity sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA== + dependencies: + tslib "^2.3.0" + +"@wry/context@^0.7.0": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.7.4.tgz#e32d750fa075955c4ab2cfb8c48095e1d42d5990" + integrity sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ== + dependencies: + tslib "^2.3.0" + +"@wry/equality@^0.5.6": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.7.tgz#72ec1a73760943d439d56b7b1e9985aec5d497bb" + integrity sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.4.3.tgz#077d52c22365871bf3ffcbab8e95cb8bc5689af4" + integrity sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.5.0.tgz#11e783f3a53f6e4cd1d42d2d1323f5bc3fa99c94" + integrity sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA== + dependencies: + tslib "^2.3.0" + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + ajv@^6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -85,6 +576,16 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + ast-parents@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" @@ -95,11 +596,54 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bignumber.js@^9.0.1: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + brace-expansion@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" @@ -107,6 +651,24 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +buffer-reverse@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60" + integrity sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg== + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -121,7 +683,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.2: +chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -153,11 +715,43 @@ color-name@~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.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.1.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + commander@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + cosmiconfig@^8.0.0: version "8.3.6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" @@ -168,6 +762,48 @@ cosmiconfig@^8.0.0: parse-json "^5.2.0" path-type "^4.0.0" +cross-fetch@^3.0.6: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-extend@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -185,6 +821,72 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +ethereum-bloom-filters@^1.0.6: + version "1.0.10" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" + integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== + dependencies: + js-sha3 "^0.8.0" + +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" + integrity sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA== + dependencies: + "@noble/curves" "1.3.0" + "@noble/hashes" "1.3.3" + "@scure/bip32" "1.3.3" + "@scure/bip39" "1.2.2" + +ethers@^5.6.4: + version "5.7.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +extract-files@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" + integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== + fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -200,11 +902,48 @@ 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== +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^8.0.3: version "8.1.0" resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" @@ -216,6 +955,32 @@ glob@^8.0.3: minimatch "^5.0.1" once "^1.3.0" +graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphql-request@^3.6.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.7.0.tgz#c7406e537084f8b9788541e3e6704340ca13055b" + integrity sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ== + dependencies: + cross-fetch "^3.0.6" + extract-files "^9.0.0" + form-data "^3.0.0" + +graphql-tag@^2.12.6: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +graphql@^15.7.1: + version "15.8.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" + integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -226,6 +991,35 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" @@ -247,7 +1041,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -262,7 +1056,17 @@ is-fullwidth-code-point@^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== -js-tokens@^4.0.0: +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + +js-sha3@0.8.0, js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -274,6 +1078,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsbi@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-4.3.0.tgz#b54ee074fb6fcbc00619559305c8f7e912b04741" + integrity sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -289,21 +1098,58 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +keccak256@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/keccak256/-/keccak256-1.0.6.tgz#dd32fb771558fed51ce4e45a035ae7515573da58" + integrity sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw== + dependencies: + bn.js "^5.2.0" + buffer "^6.0.3" + keccak "^3.0.2" + +keccak@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -311,6 +1157,51 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +merkletreejs@^0.3.10: + version "0.3.11" + resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.3.11.tgz#e0de05c3ca1fd368de05a12cb8efb954ef6fc04f" + integrity sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ== + dependencies: + bignumber.js "^9.0.1" + buffer-reverse "^1.0.1" + crypto-js "^4.2.0" + treeify "^1.1.0" + web3-utils "^1.3.4" + +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimatch@^5.0.1: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" @@ -318,6 +1209,46 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + +node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.2.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" + integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -325,6 +1256,16 @@ once@^1.3.0: dependencies: wrappy "1" +optimism@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.18.0.tgz#e7bb38b24715f3fdad8a9a7fc18e999144bbfa63" + integrity sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ== + dependencies: + "@wry/caches" "^1.0.0" + "@wry/context" "^0.7.0" + "@wry/trie" "^0.4.3" + tslib "^2.3.0" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -342,6 +1283,11 @@ parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -368,16 +1314,56 @@ prettier-plugin-solidity@^1.1.3: semver "^7.3.8" solidity-comments-extractor "^0.0.7" -prettier@^2.0.0, prettier@^2.8.3: +prettier@^2.0.0, prettier@^2.3.1, prettier@^2.8.3: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== + +rehackt@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/rehackt/-/rehackt-0.0.6.tgz#7a0a2247f2295e7548915417e44fbbf03bf004f4" + integrity sha512-l3WEzkt4ntlEc/IB3/mF6SRgNHA6zfQR7BlGOgBTOmx7IJJXojDASav+NsgXHFjHn+6RmwqsGPFgZpabWpeOdw== + require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" @@ -388,6 +1374,21 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +response-iterator@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/response-iterator/-/response-iterator-0.2.6.tgz#249005fb14d2e4eeb478a3f735a28fd8b4c9f3da" + integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== + +safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + semver@^7.3.8, semver@^7.5.2: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" @@ -441,6 +1442,11 @@ solidity-comments-extractor@^0.0.7: resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== +string-format@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" + integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== + string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -450,6 +1456,13 @@ string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -457,6 +1470,13 @@ strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -471,6 +1491,21 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + table@^6.8.1: version "6.8.1" resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" @@ -487,6 +1522,79 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tiny-invariant@^1.1.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +treeify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" + integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== + +ts-command-line-args@^2.2.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" + integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw== + dependencies: + chalk "^4.1.0" + command-line-args "^5.1.1" + command-line-usage "^6.1.0" + string-format "^2.0.0" + +ts-essentials@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" + integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== + +ts-invariant@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.10.3.tgz#3e048ff96e91459ffca01304dbc7f61c1f642f6c" + integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== + dependencies: + tslib "^2.1.0" + +tslib@^2.1.0, tslib@^2.3.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +typechain@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.3.2.tgz#1090dd8d9c57b6ef2aed3640a516bdbf01b00d73" + integrity sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q== + dependencies: + "@types/prettier" "^2.1.1" + debug "^4.3.1" + fs-extra "^7.0.0" + glob "7.1.7" + js-sha3 "^0.8.0" + lodash "^4.17.15" + mkdirp "^1.0.4" + prettier "^2.3.1" + ts-command-line-args "^2.2.0" + ts-essentials "^7.0.1" + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -494,12 +1602,74 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +utf8@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +web3-utils@^1.3.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" + integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== + dependencies: + "@ethereumjs/util" "^8.1.0" + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereum-cryptography "^2.1.2" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +zen-observable-ts@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz#6c6d9ea3d3a842812c6e9519209365a122ba8b58" + integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== + dependencies: + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==