diff --git a/.env.example b/.env.example index 1a93ecc..f386fde 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,3 @@ -THIS_IS_AN_EXAMPLE_FILE=!!! - ARB_ETHERSCAN_API_KEY= ARB_MAINNET_RPC= diff --git a/.gitignore b/.gitignore index dedbbbf..0e19620 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,4 @@ deployments/anvil/ docs/ # Dotenv file -.env - -lib/ \ No newline at end of file +.env \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 4b4c42b..4bcc3d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/ds-test"] path = lib/ds-test url = https://github.com/dapphub/ds-test +[submodule "lib/aave-debt-swap"] + path = lib/aave-debt-swap + url = https://github.com/aave/aave-debt-swap diff --git a/foundry.toml b/foundry.toml index b1afa9b..02b212a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -13,6 +13,7 @@ auto_detect_solc = true src = "src" out = "out" libs = ["lib"] +ffi = true [rpc_endpoints] mainnet = "${ARB_MAINNET_RPC}" diff --git a/lib/aave-debt-swap b/lib/aave-debt-swap new file mode 160000 index 0000000..7ae5938 --- /dev/null +++ b/lib/aave-debt-swap @@ -0,0 +1 @@ +Subproject commit 7ae5938a333e55a3de36d7489cf4d85acdabc4c7 diff --git a/lib/ds-test b/lib/ds-test new file mode 160000 index 0000000..e282159 --- /dev/null +++ b/lib/ds-test @@ -0,0 +1 @@ +Subproject commit e282159d5170298eb2455a6c05280ab5a73a4ef0 diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 0000000..6e05729 --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 6e05729b76f1ae0d437e74951aef1ca987788ab3 diff --git a/package.json b/package.json index 1b5533f..1b76053 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,14 @@ "test:coverage": "forge coverage --report lcov && lcov --ignore-errors unused --remove lcov.info 'node_modules/*' 'script/*' 'test/*' 'src/contracts/for-test/*' 'src/libraries/*' -o lcov.info.pruned && mv lcov.info.pruned lcov.info && genhtml -o coverage-report lcov.info" }, "dependencies": { - "@opendollar/contracts": "0.0.0-e31c2151", + "@opendollar/contracts": "0.0.0-984c17c2", + "@openzeppelin-contracts-3.4.2-solc-0.7": "yarn:@openzeppelin/contracts@^3.4.2", "@openzeppelin/contracts": "4.9.6", - "@paraswap/sdk": "^6.7.0" + "@paraswap/sdk": "^6.7.0", + "axios": "^1.7.2", + "dotenv": "^16.4.5", + "ethers": "^5.7.2", + "object-hash": "^3.0.0" }, "devDependencies": { "cross-env": "^7.0.3", diff --git a/remappings.txt b/remappings.txt index 17dcb78..dc7389c 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,6 +1,13 @@ +@aave-core-v3/=lib/aave-debt-swap/lib/aave-v3-core/ +@aave-address-book/=lib/aave-debt-swap/lib/aave-address-book/src/ +@aave-debt-swap/=lib/aave-debt-swap/src/contracts/ +@aave-debt-swap-test/=lib/aave-debt-swap/src/tests/ @openzeppelin/=node_modules/@openzeppelin/contracts/ @openzeppelin-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/ +@openzeppelin-sol7/=node_modules/@openzeppelin-contracts-3.4.2-solc-0.7/ +@openzeppelin-upgradeable/=node_modules/@openzeppelin/ @defi-wonderland/solidity-utils/=node_modules/@defi-wonderland/solidity-utils/solidity/ +solidity-utils/=lib/aave-debt-swap/lib/solidity-utils/src/ @opendollar/contracts/=node_modules/@opendollar/contracts/src/contracts/ @opendollar/interfaces/=node_modules/@opendollar/contracts/src/interfaces/ diff --git a/script/Registry.s.sol b/script/Registry.s.sol index b580299..d1fde6e 100644 --- a/script/Registry.s.sol +++ b/script/Registry.s.sol @@ -1,19 +1,45 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.20; - -// ParaSwap Limit Order Contract (Sol 0.8.1) -address constant PARASWAP_AUGUSTUS_RFQ = 0x0927FD43a7a87E3E8b81Df2c44B03C4756849F6D; - -// ParaSwap On-Chain Aggregator (Sol 0.7.5) -address constant PARASWAP_AUGUSTUS_SWAPPER = 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57; +pragma solidity >=0.8.0; // Open Dollar address constant OD_ADDR = 0x221A0f68770658C15B525d0F89F5da2baAB5f321; +address constant VAULT721 = 0x0005AFE00fF7E7FF83667bFe4F2996720BAf0B36; // Open Dollar Pool Pair +bytes32 constant WETH = bytes32('WETH'); address constant WETH_ADDR = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1; // Open Dollar Protocol Collateral +bytes32 constant WSTETH = bytes32('WSTETH'); address constant WSTETH_ADDR = 0x5979D7b546E38E414F7E9822514be443A4800529; +bytes32 constant RETH = bytes32('RETH'); address constant RETH_ADDR = 0xEC70Dcb4A1EFa46b8F2D97C310C9c4790ba5ffA8; +bytes32 constant ARB = bytes32('ARB'); address constant ARB_ADDR = 0x912CE59144191C1204E64559FE8253a0e49E6548; + +// Aave +address constant AAVE_POOL_ADDRESS_PROVIDER = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb; + +// ParaSwap Limit Order Contract (Sol 0.8.1) +address constant PARASWAP_AUGUSTUS_RFQ = 0x0927FD43a7a87E3E8b81Df2c44B03C4756849F6D; + +// ParaSwap On-Chain Aggregator (Sol 0.7.5) +address constant PARASWAP_AUGUSTUS_SWAPPER = 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57; + +// Test Vars +address constant USER = 0x37c5B029f9c3691B3d47cb024f84E5E257aEb0BB; +uint256 constant SELL_AMOUNT = 1 ether; + +// Token Kekkac256 Hashes for Aave +bytes32 constant RETH_HASH = bytes32(keccak256('RETH')); +bytes32 constant WETH_HASH = bytes32(keccak256('WETH')); +bytes32 constant WSTETH_HASH = bytes32(keccak256('WSTETH')); +bytes32 constant AAVE_RETH_HASH = bytes32(keccak256('AAVE_RETH')); +bytes32 constant AAVE_WETH_HASH = bytes32(keccak256('AAVE_WETH')); +bytes32 constant AAVE_WSTETH_HASH = bytes32(keccak256('AAVE_WSTETH')); + +// Oracle Relayers +address constant MAINNET_CHAINLINK_ETH_USD_RELAYER = 0x3e6C1621f674da311E57646007fBfAd857084383; +address constant MAINNET_DENOMINATED_WSTETH_USD_ORACLE = 0xD0cf1FfFF3FB90c87210D76DFBc3AcfFd02D6B12; +address constant MAINNET_DENOMINATED_RETH_USD_ORACLE = 0x2b6b76D9854E9A7189c2F1b496c10043b373e453; +address constant MAINNET_CHAINLINK_ARB_USD_RELAYER = 0x2635f731BB6981E72F92A781578952450759F762; diff --git a/script/getDstAmount.js b/script/getDstAmount.js new file mode 100644 index 0000000..d831e3d --- /dev/null +++ b/script/getDstAmount.js @@ -0,0 +1,32 @@ +const {constructSimpleSDK, SwapSide} = require('@paraswap/sdk'); +const axios = require('axios'); +const ethers = require('ethers'); + +const paraSwapMin = constructSimpleSDK({chainId: 42161, axios}); + +const args = process.argv.slice(2); + +const FROM_TOKEN = args[0]; +const FROM_DECIMALS = args[1]; +const TO_TOKEN = args[2]; +const TO_DECIMALS = args[3]; +const SELL_AMOUNT = args[4]; +const CALLER = args[5]; + +async function getDstRoute(_fromToken, _fromDecimals, _toToken, _toDecimals, _sellAmount, _caller) { + const _priceRoute = await paraSwapMin.swap.getRate({ + srcToken: _fromToken, + srcDecimals: _fromDecimals, + destToken: _toToken, + destDecimals: _toDecimals, + amount: _sellAmount, + userAddress: _caller, + side: SwapSide.SELL, + }); + + const dstAmount = ethers.utils.defaultAbiCoder.encode(["(uint256)"],[[_priceRoute.destAmount]]); + + process.stdout.write(dstAmount); +} + +getDstRoute(FROM_TOKEN, FROM_DECIMALS, TO_TOKEN, TO_DECIMALS, SELL_AMOUNT, CALLER); \ No newline at end of file diff --git a/script/getSwapRoute.js b/script/getSwapRoute.js new file mode 100644 index 0000000..148db75 --- /dev/null +++ b/script/getSwapRoute.js @@ -0,0 +1,41 @@ +const {constructSimpleSDK, SwapSide} = require('@paraswap/sdk'); +const axios = require('axios'); + +const paraSwapMin = constructSimpleSDK({chainId: 42161, axios}); + +const args = process.argv.slice(2); + +const FROM_TOKEN = args[0]; +const FROM_DECIMALS = args[1]; +const TO_TOKEN = args[2]; +const TO_DECIMALS = args[3]; +const SELL_AMOUNT = args[4]; +const CALLER = args[5]; + +async function getSwapRoute(_fromToken, _fromDecimals, _toToken, _toDecimals, _sellAmount, _caller) { + const priceRoute = await paraSwapMin.swap.getRate({ + srcToken: _fromToken, + srcDecimals: _fromDecimals, + destToken: _toToken, + destDecimals: _toDecimals, + amount: _sellAmount, + userAddress: _caller, + side: SwapSide.SELL, + }); + + const txParams = await paraSwapMin.swap.buildTx( + { + srcToken: priceRoute.srcToken, + destToken: priceRoute.destToken, + srcAmount: priceRoute.srcAmount, + destAmount: priceRoute.destAmount, + priceRoute, + userAddress: _caller, + ignoreChecks: true + } + ); + + process.stdout.write(txParams.data); +} + +getSwapRoute(FROM_TOKEN, FROM_DECIMALS, TO_TOKEN, TO_DECIMALS, SELL_AMOUNT, CALLER); \ No newline at end of file diff --git a/src/leverage/LeverageCalculator.sol b/src/leverage/LeverageCalculator.sol index c3ddc2d..5261e79 100644 --- a/src/leverage/LeverageCalculator.sol +++ b/src/leverage/LeverageCalculator.sol @@ -42,10 +42,12 @@ contract LeverageCalculator { // TODO: recalculate collateral or execute leverage swap _debtIterator = calculateSingleLeverage(_safeId); } + + return _leverage; } /// @dev calculate max flashloan leverage based on initial locked collateral - function calculateFlashLeverage(uint256 _safeId) external view returns (uint256 _leverage) { + function calculateFlashLeverage(uint256 _safeId) external pure returns (uint256 _leverage) { // TODO: calculate max leverage return _safeId; } @@ -57,9 +59,9 @@ contract LeverageCalculator { /// @dev get cType and safe handler of NFV function getNFVIds(uint256 _safeId) public view returns (bytes32 _cType, address _safeHandler) { - IVault721.NFVState memory nftState = VAULT721.getNfvState(_safeId); - _cType = nftState.cType; - _safeHandler = nftState.safeHandler; + IVault721.NFVState memory _nftState = VAULT721.getNfvState(_safeId); + _cType = _nftState.cType; + _safeHandler = _nftState.safeHandler; } /// @dev get locked collateral and generated debt diff --git a/src/leverage/LeverageSwapper.sol b/src/leverage/LeverageSwapper.sol deleted file mode 100644 index 708bbc7..0000000 --- a/src/leverage/LeverageSwapper.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.20; - -contract LeverageSwapper { -// Todo create and send order to PARASWAP_AUGUSTUS_RFQ -} diff --git a/src/leverage/ParaswapSellAdapter.sol b/src/leverage/ParaswapSellAdapter.sol new file mode 100644 index 0000000..4eed1e5 --- /dev/null +++ b/src/leverage/ParaswapSellAdapter.sol @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.20; + +import 'forge-std/Test.sol'; +import {IERC20Metadata} from '@openzeppelin/token/ERC20/extensions/IERC20Metadata.sol'; +import {FlashLoanSimpleReceiverBase} from '@aave-core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol'; +import {IPoolAddressesProvider} from '@aave-core-v3/contracts/interfaces/IPoolAddressesProvider.sol'; +// import {PercentageMath} from '@aave-core-v3/contracts/protocol/libraries/math/PercentageMath.sol'; +import {IParaSwapAugustusRegistry} from '@aave-debt-swap/dependencies/paraswap/IParaSwapAugustusRegistry.sol'; +import {ODProxy} from '@opendollar/contracts/proxies/ODProxy.sol'; +import {IODSafeManager} from '@opendollar/interfaces/proxies/IODSafeManager.sol'; +import {ICollateralJoinFactory} from '@opendollar/interfaces/factories/ICollateralJoinFactory.sol'; +import {IVault721} from '@opendollar/interfaces/proxies/IVault721.sol'; +import {ISAFEEngine} from '@opendollar/interfaces/ISAFEEngine.sol'; +import {IParaswapSellAdapter} from 'src/leverage/interfaces/IParaswapSellAdapter.sol'; +import {IParaswapAugustus} from 'src/leverage/interfaces/IParaswapAugustus.sol'; +import {ExitActions} from 'src/leverage/ExitActions.sol'; + +/** + * TODO: + * - add access control + * - add modifiable contract for var updates + * - add withdraw function + * - enforce max slippage rate + * - simplify the constructor with a struct + * - remove Test inheritance + */ +contract ParaswapSellAdapter is FlashLoanSimpleReceiverBase, IParaswapSellAdapter, Test { + // using PercentageMath for uint256; + // uint256 public constant MAX_SLIPPAGE_PERCENT = 0.3e4; // 30.00% + uint256 public constant PREMIUM = 500_000_000_000; + + IParaSwapAugustusRegistry public immutable AUGUSTUS_REGISTRY; + ODProxy public immutable PS_ADAPTER_ODPROXY; + IERC20Metadata public immutable OPEN_DOLLAR; + + IParaswapAugustus public augustus; + + IODSafeManager public safeManager; + ICollateralJoinFactory public collateralJoinFactory; + // todo make interface for this + ExitActions public exitActions; + address public coinJoin; + + mapping(address => mapping(address => uint256)) internal _deposits; + + /** + * @param _augustusRegistry address of Paraswap AugustusRegistry + * @param _augustusSwapper address of Paraswap AugustusSwapper + * @param _poolProvider address of Aave PoolAddressProvider + * @param _vault721 address of OpenDollar Vault721 + * @param _exitActions address of OpenDollar ExitActions + * @param _collateralJoinFactory address of OpenDollar CollateralJoinFactory + * @param _coinJoin address of OpenDollar CoinJoin + */ + constructor( + address _systemCoin, + address _augustusRegistry, + address _augustusSwapper, + address _poolProvider, + address _vault721, + address _exitActions, + address _collateralJoinFactory, + address _coinJoin + ) FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_poolProvider)) { + OPEN_DOLLAR = IERC20Metadata(_systemCoin); + AUGUSTUS_REGISTRY = IParaSwapAugustusRegistry(_augustusRegistry); + augustus = IParaswapAugustus(_augustusSwapper); + IVault721 _v721 = IVault721(_vault721); + safeManager = IODSafeManager(_v721.safeManager()); + exitActions = ExitActions(_exitActions); + collateralJoinFactory = ICollateralJoinFactory(_collateralJoinFactory); + coinJoin = _coinJoin; + PS_ADAPTER_ODPROXY = ODProxy(_v721.build(address(this))); + } + + /// @dev deposit asset for msg.sender + function deposit(address _asset, uint256 _amount) external { + _deposit(msg.sender, _asset, _amount); + } + + /// @dev deposit asset for account + function deposit(address _onBehalfOf, address _asset, uint256 _amount) external { + _deposit(_onBehalfOf, _asset, _amount); + } + + /// @dev exact-in sell swap on ParaSwap + function sellOnParaSwap( + SellParams memory _sellParams, + uint256 _minDstAmount + ) external returns (uint256 _amountReceived) { + _amountReceived = _sellOnParaSwap( + _sellParams.offset, + _sellParams.swapCalldata, + IERC20Metadata(_sellParams.fromToken), + IERC20Metadata(_sellParams.toToken), + _sellParams.sellAmount, + _minDstAmount + ); + } + + /// @dev approve address(this) as safeHandler and request to borrow asset on Aave + function requestFlashloan( + SellParams memory _sellParams, + uint256 _collateralLoan, + uint256 _minDstAmount, + uint256 _safeId, + bytes32 _cType + ) external { + // deposit collateral, generate debt + bytes memory _payload = abi.encodeWithSelector( + exitActions.lockTokenCollateralAndGenerateDebtToAccount.selector, + address(this), + address(safeManager), + address(collateralJoinFactory.collateralJoins(_cType)), + coinJoin, + _safeId, + _collateralLoan - PREMIUM, + _sellParams.sellAmount + ); + + // borrow collateral + POOL.flashLoanSimple({ + receiverAddress: address(this), + asset: address(_sellParams.toToken), + amount: _collateralLoan, + params: abi.encode(_minDstAmount, _sellParams, _payload), + referralCode: uint16(block.number) + }); + } + + /// @dev flashloan callback from Aave + function executeOperation( + address asset, + uint256 amount, + uint256 premium, + address initiator, + bytes calldata params + ) external override returns (bool) { + (uint256 _minDstAmount, SellParams memory _sellParams, bytes memory _payload) = + abi.decode(params, (uint256, SellParams, bytes)); + + emit log_named_uint('RETH BAL AQUIRE LOAN', IERC20Metadata(_sellParams.toToken).balanceOf(address(this))); + + uint256 _beforebalance = IERC20Metadata(_sellParams.fromToken).balanceOf(address(this)); + uint256 _sellAmount = _sellParams.sellAmount; + + _executeFromProxy(_payload); + + // todo add error msg + // if (_sellAmount != OD.balanceOf(address(this)) - _beforebalance) revert(); + + // swap debt to collateral + _sellOnParaSwap( + _sellParams.offset, + _sellParams.swapCalldata, + IERC20Metadata(_sellParams.fromToken), + IERC20Metadata(_sellParams.toToken), + _sellAmount, + _minDstAmount + ); + emit log_named_uint('RETH BAL POST SWAP', IERC20Metadata(_sellParams.toToken).balanceOf(address(this))); + + uint256 _payBack = amount + premium; + IERC20Metadata(asset).approve(address(POOL), _payBack); + return true; + } + + /// @dev execute payload with delegate call via proxy for address(this) + function _executeFromProxy(bytes memory _payload) internal { + PS_ADAPTER_ODPROXY.execute(address(exitActions), _payload); + } + + /// @dev transfer asset to this contract to use in flashloan-swap + function _deposit(address _account, address _asset, uint256 _amount) internal { + IERC20Metadata(_asset).transferFrom(_account, address(this), _amount); + _deposits[_account][_asset] = _amount; + } + + /// @dev takes ParaSwap transaction data and executes sell swap + function _sellOnParaSwap( + uint256 _offset, + bytes memory _swapCalldata, + IERC20Metadata _fromToken, + IERC20Metadata _toToken, + uint256 _sellAmount, + uint256 _minDstAmount + ) internal returns (uint256 _amountReceived) { + if (!AUGUSTUS_REGISTRY.isValidAugustus(address(augustus))) revert InvalidAugustus(); + if (_minDstAmount == 0) revert ZeroValue(); + + uint256 _initBalFromToken = _fromToken.balanceOf(address(this)); + if (_initBalFromToken < _sellAmount) revert InsufficientBalance(); + uint256 _initBalToToken = _toToken.balanceOf(address(this)); + + address _tokenTransferProxy = augustus.getTokenTransferProxy(); + _fromToken.approve(_tokenTransferProxy, _sellAmount); + + if (_offset != 0) { + // ensure 1 slot _offset is within bounds of calldata, not overlapping with function selector + if (_offset < 4 && _offset > _swapCalldata.length - 32) revert OffsetOutOfRange(); + // overwrite the fromAmount with the correct amount for the swap + assembly { + mstore(add(_swapCalldata, add(_offset, 32)), _sellAmount) + } + } + (bool _ok,) = address(augustus).call(_swapCalldata); + if (!_ok) { + assembly { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + } + uint256 _amountSold = _initBalFromToken - _fromToken.balanceOf(address(this)); + if (_sellAmount > _amountSold) revert OverSell(); + + _amountReceived = _toToken.balanceOf(address(this)) - _initBalToToken; + if (_amountReceived < _minDstAmount) revert UnderBuy(); + emit Swapped(address(_fromToken), address(_toToken), _amountSold, _amountReceived); + } +} diff --git a/src/leverage/interfaces/IParaswapAugustus.sol b/src/leverage/interfaces/IParaswapAugustus.sol new file mode 100644 index 0000000..1ad4a3b --- /dev/null +++ b/src/leverage/interfaces/IParaswapAugustus.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.20; + +interface IParaswapAugustus { + function getTokenTransferProxy() external view returns (address _tokenTransferProxy); +} diff --git a/src/leverage/interfaces/IParaswapSellAdapter.sol b/src/leverage/interfaces/IParaswapSellAdapter.sol new file mode 100644 index 0000000..70aa514 --- /dev/null +++ b/src/leverage/interfaces/IParaswapSellAdapter.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.20; + +import {IPoolAddressesProvider} from '@aave-core-v3/contracts/interfaces/IPoolAddressesProvider.sol'; +import {IPool} from '@aave-core-v3/contracts/interfaces/IPool.sol'; + +interface IParaswapSellAdapter { + /** + * @dev emitted after a sell of an asset is made + * @param _fromAsset address of the asset sold + * @param _toAsset address of the asset received in exchange + * @param _fromAmount amount of asset sold + * @param _receivedAmount amount received from the sell + */ + event Swapped(address indexed _fromAsset, address indexed _toAsset, uint256 _fromAmount, uint256 _receivedAmount); + + error InvalidAugustus(); + error InsufficientBalance(); + error OffsetOutOfRange(); + error OverSell(); + error UnderBuy(); + error ZeroValue(); + + /** + * @param _offset offset of fromAmount in Augustus calldata if it should be overwritten, otherwise 0 + * @param _swapCalldata data for Paraswap adapter + * @param _fromToken address of the asset to swap from + * @param _toToken address of the asset to swap to + * @param _sellAmount amount of asset to swap from + */ + struct SellParams { + uint256 offset; + bytes swapCalldata; + address fromToken; + address toToken; + uint256 sellAmount; + } + + /** + * @param _sellParams IParaswapSellAdapter.SellParams + * @param _minDstAmount for sell/swap + * @return _amountReceived amount of asset bought + */ + function sellOnParaSwap( + SellParams memory _sellParams, + uint256 _minDstAmount + ) external returns (uint256 _amountReceived); + + /** + * @param _sellParams IParaswapSellAdapter.SellParams + * @param _minDstAmount accepted for sell/swap + * @param _safeId OpenDollar NFV/CDP + * @param _cType collateral type of OpenDollar NFV/CDP + */ + function requestFlashloan( + SellParams memory _sellParams, + uint256 _collateralLoan, + uint256 _minDstAmount, + uint256 _safeId, + bytes32 _cType + ) external; + + /** + * @param _asset token + * @param _amount to deposit + */ + function deposit(address _asset, uint256 _amount) external; + + /** + * @param _onBehalfOf account to receive balance + * @param _asset token + * @param _amount to deposit + */ + function deposit(address _onBehalfOf, address _asset, uint256 _amount) external; +} diff --git a/src/library/BytesLib.sol b/src/library/BytesLib.sol new file mode 100644 index 0000000..d904fae --- /dev/null +++ b/src/library/BytesLib.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +library BytesLib { + function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { + require(_length + 31 >= _length, 'slice_overflow'); + require(_bytes.length >= _start + _length, 'slice_outOfBounds'); + + bytes memory tempBytes; + + // Check length is 0. `iszero` return 1 for `true` and 0 for `false`. + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // Calculate length mod 32 to handle slices that are not a multiple of 32 in size. + let lengthmod := and(_length, 31) + + // tempBytes will have the following format in memory: + // When copying data we will offset the start forward to avoid allocating additional memory + // Therefore part of the length area will be written, but this will be overwritten later anyways. + // In case no offset is require, the start is set to the data region (0x20 from the tempBytes) + // mc will be used to keep track where to copy the data to. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // Same logic as for mc is applied and additionally the start offset specified for the method is added + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + // increase `mc` and `cc` to read the next word from memory + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + // Copy the data from source (cc location) to the slice data (mc location) + mstore(mc, mload(cc)) + } + + // Store the length of the slice. This will overwrite any partial data that + // was copied when having slices that are not a multiple of 32. + mstore(tempBytes, _length) + + // update free-memory pointer + // allocating the array padded to 32 bytes like the compiler does now + // To set the used memory as a multiple of 32, add 31 to the actual memory usage (mc) + // and remove the modulo 32 (the `and` with `not(31)`) + mstore(0x40, and(add(mc, 31), not(31))) + } + // if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + // zero out the 32 bytes slice we are about to return + // we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + // update free-memory pointer + // tempBytes uses 32 bytes in memory (even when empty) for the length. + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } +} diff --git a/swapCalldata.txt b/swapCalldata.txt new file mode 100644 index 0000000..ce12dee --- /dev/null +++ b/swapCalldata.txt @@ -0,0 +1,176 @@ +0x +0000000000000000000000000000000000000000000000000000000000000020 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 // AugustusSwapper +00000000000000000000000000000000000000000000000000000000000000a0 // 160 +00000000000000000000000000000000000000000000010f0cf064dd59200000 // 5000.000000000000000000 sell amount +000000000000000000000000000000000000000000000106876d7722aef86472 // 4842.805534270332363890 buy amount +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000264 // 612 ? +a6886da9 // method: directUniV3Swap +0000000000000000000000000000000000000000000000000000000000000020 +0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f // DAI +0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0 // LUSD +000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564 // Uniswap V3 Swap Router +00000000000000000000000000000000000000000000010f0cf064dd59200000 // 5000.000000000000000000 sell amount +000000000000000000000000000000000000000000000106876d7722aef86472 // 4842.805534270332363890 buy amount +00000000000000000000000000000000000000000000010ea602016b038e970f // 4992.583025020961199887 ? amount +0100000000000000000000000000000000000000000000000000000000031388 // 201608 ? +0000000000000000000000000000000000000000000000000000000065ba7eb7 // 1706720951 block deadline +0000000000000000000000009abf798f5314bfd793a9e57a654bed35af4a1d60 // Aave Paraswap Fee Claimer +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000001c0 // 448 ? +0000000000000000000000000000000000000000000000000000000000000220 // 544 ? +a049af4f8b274f93a886657ff862bc0800000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000002b // 43 ? +6b175474e89094c44da98b954eedeac495271d0f // DAI +0001f4 // 500 fee +5f98805a4e8be255a32880fdec7f6728c6568ba0 // LUSD +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000 + +PS calldata +0x +0000000000000000000000000000000000000000000000000000000000000040 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 // AugustusSwapper +0000000000000000000000000000000000000000000000000000000000000264 // 612 ? +a6886da9 // method: directUniV3Swap +0000000000000000000000000000000000000000000000000000000000000020 +0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f // DAI address +0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0 // LUSD address +000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564 // Uniswap V3 Swap Router +00000000000000000000000000000000000000000000010f0cf064dd59200000 // 5000.000000000000000000 sell amount +000000000000000000000000000000000000000000000106876d7722aef86472 // 4842.805534270332363890 low buy amount ? +00000000000000000000000000000000000000000000010ea602016b038e970f // 4992.583025020961199887 high buy amount ? +0100000000000000000000000000000000000000000000000000000000031388 +0000000000000000000000000000000000000000000000000000000065ba7eb7 // 1706720951 block deadline +0000000000000000000000009abf798f5314bfd793a9e57a654bed35af4a1d60 // Aave Paraswap Fee Claimer +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000001c0 +0000000000000000000000000000000000000000000000000000000000000220 +a049af4f8b274f93a886657ff862bc0800000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000002b +6b175474e89094c44da98b954eedeac495271d0f // DAI address +0001f4 // 500 fee +5f98805a4e8be255a32880fdec7f6728c6568ba // LUSD address +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000 + + + + + + 0x16980C16811bDe2B3358c1Ce4341541a4C772Ec9::swap(AugustusSwapper: [0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57], false, 3800000000000000000000 [3.8e21], 1461446703485210103287273052203988822378723970341 [1.461e48], 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57000000000000000000000000000000000000000000000000000000000000002b6b175474e89094c44da98b954eedeac495271d0f0001f45f98805a4e8be255a32880fdec7f6728c6568ba0000000000000000000000000000000000000000000) + +0x +0000000000000000000000000000000000000000000000000000000000000020 +0000000000000000000000000000000000000000000000000000000000000040 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 +000000000000000000000000000000000000000000000000000000000000002b +6b175474e89094c44da98b954eedeac495271d0f0001f45f98805a4e8be255a3 +2880fdec7f6728c6568ba0000000000000000000000000000000000000000000 + +0x +b22f4db8 +0000000000000000000000000000000000000000000000000000000000000020 +0000000000000000000000000000000000000000000000000000000000000240 +0000000000000000000000000000000000000000000000000000000000000340 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 +0000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000003a0 +00000000000000000000000000000000000000000000000000038d7ea4c68000 +0000000000000000000000000000000000000000000000000003cd1057045fcf +0000000000000000000000000000000000000000000000000003cd1057045fcf +000000000000000000000000000000000000000000000000000000006684571f +0100000000000000000000000000000000000000000000000000000000004000 +000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000001 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000400 +8e4c71b1204247ff94cdb5d7f7e6e70800000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000001 +0000000000000000000000000000000000000000000000000000000000000020 +4b3af34eb1135d59df8b9cdc2ff07d30d05334c400000000000000000000050d +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000001 +00000000000000000000000000000000000000000000000000038d7ea4c68000 +00000000000000000000000000000000000000000000000000000000000000a0 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000002 +000000000000000000000000ec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8 +00000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe +0000000000000000000000000000000000000000000000000000000000000002 +7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0000000000000000000000000000000000000000000000000000000000000000 + +--- + +0xa6886da9 +0000000000000000000000000000000000000000000000000000000000000020 +000000000000000000000000ec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8 +00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1 +000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564 +00000000000000000000000000000000000000000000000000038d7ea4c68000 // 1000000000000000 +0000000000000000000000000000000000000000000000000003f097e5fb8c73 // 1108960119327859 +0000000000000000000000000000000000000000000000000003f097e5fb8c73 // +0100000000000000000000000000000000000000000000000000000000004000 +00000000000000000000000000000000000000000000000000000000667e5377 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000001 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000001c0 +0000000000000000000000000000000000000000000000000000000000000220 +add3f0f4f7964104b5de7df070904ee100000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000002b +ec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa800006482af49447d8a07e3bd +95bd0d56f35241523fbab1000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +0xb22f4db8 +0000000000000000000000000000000000000000000000000000000000000020 +0000000000000000000000000000000000000000000000000000000000000240 +0000000000000000000000000000000000000000000000000000000000000340 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 +0000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000003a0 +0000000000000000000000000000000000000000000000000de0b6b3a7640000 +0000000000000000000000000000000000000000000000000f68f934184f96ed +0000000000000000000000000000000000000000000000000f68f934184f96ed +00000000000000000000000000000000000000000000000000000000668c6a84 +0100000000000000000000000000000000000000000000000000000000004000 +000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400cbc986cc13dd42f6bbb29a8ef40f6c9e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020d0ec47c54ca5e20aaae4616c25c825c7f48d40690000000000000000000004ef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa800000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000 + +0xb22f4db8 +0000000000000000000000000000000000000000000000000000000000000020 +0000000000000000000000000000000000000000000000000000000000000240 +0000000000000000000000000000000000000000000000000000000000000340 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 +0000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000003a0 +0000000000000000000000000000000000000000000000000de0b6b3a7640000 +0000000000000000000000000000000000000000000000000f68f934184f96ed +0000000000000000000000000000000000000000000000000f68f934184f96ed +00000000000000000000000000000000000000000000000000000000668c7086 +0100000000000000000000000000000000000000000000000000000000004000000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000cf523f16fb7472382bc62d864b8ced70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020d0ec47c54ca5e20aaae4616c25c825c7f48d40690000000000000000000004ef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa800000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000 + +0x54e3f31b +0000000000000000000000000000000000000000000000000000000000000020 +00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1 +0000000000000000000000005979d7b546e38e414f7e9822514be443a4800529 +0000000000000000000000000000000000000000000000000de0b6b3a7640000 +0000000000000000000000000000000000000000000000000bd991793e9402ca +0000000000000000000000000000000000000000000000000bd991793e9402ca +00000000000000000000000000000000000000000000000000000000000001e0 +0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000066839313c98e671c7ec34ccc845a42688f509a8d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000001f721e2e82f6676fce4ea07a5958cf098d339e180000000000000000000000000000000000000000000000000000000000000124c04b8d59000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee5700000000000000000000000000000000000000000000000000000000668c79330000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002882af49447d8a07e3bd95bd0d56f35241523fbab15979d7b546e38e414f7e9822514be443a480052900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/test/e2e/E2ECoinExit.t.sol b/test/e2e/E2ECoinExit.t.sol index da23ae1..9da2c68 100644 --- a/test/e2e/E2ECoinExit.t.sol +++ b/test/e2e/E2ECoinExit.t.sol @@ -1,12 +1,34 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.20; +import {IERC20} from '@openzeppelin/token/ERC20/IERC20.sol'; +import {MintableERC20} from '@opendollar/contracts/for-test/MintableERC20.sol'; import {RAY} from '@opendollar/libraries/Math.sol'; import {TKN} from '@opendollar/test/e2e/Common.t.sol'; -import {CommonTest} from 'test/CommonTest.t.sol'; +import {CommonTest} from 'test/e2e/common/CommonTest.t.sol'; contract E2ECoinExit is CommonTest { address public arbitraryContract = address(0x1234abcd); + address public arbitraryContract2 = address(0x1234abcd2); + address public arbitraryProxy2; + + function setUp() public virtual override { + super.setUp(); + aliceProxy = _deployOrFind(alice); + arbitraryProxy2 = _deployOrFind(arbitraryContract2); + _openSafe(aliceProxy, TKN); + + MintableERC20(token).mint(alice, DEPOSIT); + MintableERC20(token).mint(arbitraryContract2, DEPOSIT); + + vm.prank(alice); + IERC20(token).approve(aliceProxy, type(uint256).max); + + vm.prank(arbitraryContract2); + IERC20(token).approve(arbitraryProxy2, type(uint256).max); + + aliceNFV = vault721.getNfvState(vaults[aliceProxy]); + } function testLockCollateral() public { (uint256 _c1, uint256 _d1) = _getSAFE(TKN, aliceNFV.safeHandler); @@ -28,6 +50,19 @@ contract E2ECoinExit is CommonTest { assertEq(systemCoin.balanceOf(alice), 0); } + function testLockCollateralAndGebDebtToAccountFromAccountProxy() public { + vm.prank(aliceProxy); + safeManager.allowSAFE(vaults[aliceProxy], arbitraryProxy2, true); + + _lockCollateral(TKN, vaults[aliceProxy], DEPOSIT, arbitraryProxy2); + _genDebtToAccount(arbitraryContract2, vaults[aliceProxy], MINT, arbitraryProxy2); + (uint256 _c, uint256 _d) = _getSAFE(TKN, aliceNFV.safeHandler); + assertEq(_c, DEPOSIT); + assertEq(_d, MINT); + assertEq(systemCoin.balanceOf(arbitraryContract2), MINT); + assertEq(systemCoin.balanceOf(alice), 0); + } + function testLockCollateralAndGebDebtToProxy() public { _lockCollateral(TKN, vaults[aliceProxy], DEPOSIT, aliceProxy); _genDebtToProxy(vaults[aliceProxy], MINT, aliceProxy); @@ -93,4 +128,17 @@ contract E2ECoinExit is CommonTest { assertEq(systemCoin.balanceOf(arbitraryContract), MINT); assertEq(systemCoin.balanceOf(alice), 0); } + + function testDepositCollateralAndGenDebtToAccountFromAccountProxy() public { + vm.prank(aliceProxy); + safeManager.allowSAFE(vaults[aliceProxy], arbitraryProxy2, true); + + assertEq(systemCoin.balanceOf(arbitraryContract2), 0); + assertEq(systemCoin.balanceOf(alice), 0); + + _depositCollateralAndGenDebtToAccount(arbitraryContract2, TKN, vaults[aliceProxy], DEPOSIT, MINT, arbitraryProxy2); + + assertEq(systemCoin.balanceOf(arbitraryContract2), MINT); + assertEq(systemCoin.balanceOf(alice), 0); + } } diff --git a/test/e2e/LeverageCalculator.t.sol b/test/e2e/E2ELeverageCalculator.t.sol similarity index 93% rename from test/e2e/LeverageCalculator.t.sol rename to test/e2e/E2ELeverageCalculator.t.sol index ff2220d..4f2591b 100644 --- a/test/e2e/LeverageCalculator.t.sol +++ b/test/e2e/E2ELeverageCalculator.t.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.20; +import {MintableERC20} from '@opendollar/contracts/for-test/MintableERC20.sol'; import {IERC20} from '@openzeppelin/token/ERC20/IERC20.sol'; import {MintableERC20} from '@opendollar/contracts/for-test/MintableERC20.sol'; import {TKN} from '@opendollar/test/e2e/Common.t.sol'; -import {CommonTest} from 'test/CommonTest.t.sol'; +import {CommonTest} from 'test/e2e/common/CommonTest.t.sol'; contract E2ELeverageCalculator is CommonTest { address public constant LEVERAGE_HANDLER = address(0x1111); @@ -12,6 +13,16 @@ contract E2ELeverageCalculator is CommonTest { function setUp() public virtual override { super.setUp(); + aliceProxy = _deployOrFind(alice); + _openSafe(aliceProxy, TKN); + + MintableERC20(token).mint(alice, DEPOSIT); + + vm.prank(alice); + IERC20(token).approve(aliceProxy, type(uint256).max); + + aliceNFV = vault721.getNfvState(vaults[aliceProxy]); + MintableERC20(token).mint(address(this), DEPOSIT); leverageHandlerProxy = _deployOrFind(LEVERAGE_HANDLER); diff --git a/test/e2e/E2ESwapExit.t.sol b/test/e2e/E2ESwapExit.t.sol new file mode 100644 index 0000000..fd07037 --- /dev/null +++ b/test/e2e/E2ESwapExit.t.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.20; + +import '@script/Registry.s.sol'; +import {IERC20Metadata} from '@openzeppelin/token/ERC20/extensions/IERC20Metadata.sol'; +import {IVault721} from '@opendollar/interfaces/proxies/IVault721.sol'; +import {IDenominatedOracle} from '@opendollar/interfaces/oracles/IDenominatedOracle.sol'; +import {DelayedOracleForTest} from '@opendollar/test/mocks/DelayedOracleForTest.sol'; +import {AugustusRegistry} from '@aave-debt-swap/dependencies/paraswap/AugustusRegistry.sol'; +import {ParaswapSellAdapter, IParaswapSellAdapter} from 'src/leverage/ParaswapSellAdapter.sol'; +import {CommonTest} from 'test/e2e/common/CommonTest.t.sol'; +import {Math} from '@opendollar/libraries/Math.sol'; + +contract E2ESwapExit is CommonTest { + using Math for uint256; + + uint256 public constant PREMIUM = 500_000_000_000; + uint256 public constant INTEREST_RATE_MODE = 0; + uint16 public constant REF_CODE = 0; + address public SELL_ADAPTER; + + address public userProxy; + address public sellAdapterProxy; + + IParaswapSellAdapter public sellAdapter; + IVault721.NFVState public userNFV; + + IDenominatedOracle public rethOracle; + uint256 rethUsdPrice; + + function setUp() public virtual override { + super.setUp(); + rethOracle = IDenominatedOracle(MAINNET_DENOMINATED_RETH_USD_ORACLE); + (rethUsdPrice,) = rethOracle.getResultWithValidity(); + setCTypePrice(RETH, rethUsdPrice); + + userProxy = _deployOrFind(USER); + label(USER, 'USER-WALLET'); + label(userProxy, 'USER-PROXY'); + _openSafe(userProxy, RETH); + + vm.prank(USER); + IERC20Metadata(RETH_ADDR).approve(userProxy, type(uint256).max); + + userNFV = vault721.getNfvState(vaults[userProxy]); + + sellAdapter = new ParaswapSellAdapter( + address(systemCoin), + AugustusRegistry.ARBITRUM, + PARASWAP_AUGUSTUS_SWAPPER, + AAVE_POOL_ADDRESS_PROVIDER, + address(vault721), + address(exitActions), + address(collateralJoinFactory), + address(coinJoin) + ); + + SELL_ADAPTER = address(sellAdapter); + + sellAdapterProxy = _deployOrFind(SELL_ADAPTER); + label(SELL_ADAPTER, 'SELL-ADAPTER-CONTRACT'); + label(sellAdapterProxy, 'SELL-ADAPTER-PROXY'); + + vm.startPrank(SELL_ADAPTER); + IERC20Metadata(RETH_ADDR).approve(sellAdapterProxy, type(uint256).max); + IERC20Metadata(OD_ADDR).approve(sellAdapterProxy, type(uint256).max); + vm.stopPrank(); + } + + /** + * todo: test with initial deposit of collateral + * initial deposit + loan to overcome the over-collateralization "loss" + * in being able to returning to loan in full + premium + */ + function testRequestFlashloan() public { + assertEq(readCTypePrice(RETH), rethUsdPrice); + uint256 _collateralLoan = 1 ether; + uint256 _sellAmount = (_collateralLoan.wmul(rethUsdPrice) - PREMIUM) * 2 / 3; + emit log_named_uint('DEBT SELL AMOUNT', _sellAmount); + + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = + _getFullUserInputWithAmount(OD_ADDR, RETH_ADDR, _sellAmount); + + // todo: lock initial capital in safe + uint256 _initCapital = _collateralLoan / 2; + deal(RETH_ADDR, USER, _initCapital); + + vm.prank(userProxy); + safeManager.allowSAFE(vaults[userProxy], sellAdapterProxy, true); + + vm.startPrank(USER); + IERC20Metadata(RETH_ADDR).approve(SELL_ADAPTER, _initCapital); + sellAdapter.deposit(RETH_ADDR, _initCapital); + + // assertEq(IERC20Metadata(RETH_ADDR).balanceOf(SELL_ADAPTER), _initCapital); + // assertEq(IERC20Metadata(OD_ADDR).balanceOf(SELL_ADAPTER), 0); + + sellAdapter.requestFlashloan(_sellParams, _collateralLoan, _dstAmount, vaults[userProxy], RETH); + // assertEq(IERC20Metadata(RETH_ADDR).balanceOf(SELL_ADAPTER), 0); + + vm.stopPrank(); + } + + function setCTypePrice(bytes32 _cType, uint256 _price) public { + DelayedOracleForTest(address(delayedOracle[_cType])).setPriceAndValidity(_price, true); + oracleRelayer.updateCollateralPrice(_cType); + } + + function readCTypePrice(bytes32 _cType) public returns (uint256 _price) { + _price = delayedOracle[_cType].read(); + } +} diff --git a/test/e2e/E2ESwapSell.t.sol b/test/e2e/E2ESwapSell.t.sol new file mode 100644 index 0000000..35cb379 --- /dev/null +++ b/test/e2e/E2ESwapSell.t.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.20; + +import '@script/Registry.s.sol'; +import {AugustusRegistry} from '@aave-debt-swap/dependencies/paraswap/AugustusRegistry.sol'; +import {ParaswapSellAdapter, IParaswapSellAdapter} from 'src/leverage/ParaswapSellAdapter.sol'; +import {BaseTest} from 'test/e2e/common/BaseTest.t.sol'; +import {BytesLib} from 'src/library/BytesLib.sol'; + +contract E2ESwapSell is BaseTest { + IParaswapSellAdapter public sellAdapter; + + function setUp() public virtual { + vm.createSelectFork(vm.rpcUrl('mainnet')); + sellAdapter = new ParaswapSellAdapter( + address(0xaaa), + AugustusRegistry.ARBITRUM, + PARASWAP_AUGUSTUS_SWAPPER, + AAVE_POOL_ADDRESS_PROVIDER, + address(VAULT721), + address(0x123), + address(0x456), + address(0x789) + ); + } + + function testSwapRethToWeth() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(RETH_ADDR, WETH_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), RETH_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } + + function testSwapWethToReth() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(WETH_ADDR, RETH_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), WETH_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } + + function testSwapWstethToWeth() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(WSTETH_ADDR, WETH_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), WSTETH_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } + + function testSwapWethToWsteth() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(WETH_ADDR, WSTETH_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), WETH_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } + + function testSwapWstethToReth() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(WSTETH_ADDR, RETH_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), WSTETH_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } + + function testSwapRethToWsteth() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(RETH_ADDR, WSTETH_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), RETH_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } + + function testSwapRethToOpenDollar() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(RETH_ADDR, OD_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), RETH_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } + + function testSwapOpenDollarToReth() public { + (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) = _getFullUserInput(OD_ADDR, RETH_ADDR); + + vm.startPrank(USER); + _supplyAndDeposit(address(sellAdapter), OD_ADDR, SELL_AMOUNT); + sellAdapter.sellOnParaSwap(_sellParams, _dstAmount); + vm.stopPrank(); + } +} diff --git a/test/e2e/common/BaseTest.t.sol b/test/e2e/common/BaseTest.t.sol new file mode 100644 index 0000000..0b3d946 --- /dev/null +++ b/test/e2e/common/BaseTest.t.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.20; + +import 'forge-std/Test.sol'; +import '@script/Registry.s.sol'; +import {IERC20Metadata} from '@openzeppelin/token/ERC20/extensions/IERC20Metadata.sol'; +import {IParaswapSellAdapter} from 'src/leverage/ParaswapSellAdapter.sol'; + +contract BaseTest is Test { + function _supplyAndDeposit(address _adapter, address _asset, uint256 _amount) internal { + deal(_asset, msg.sender, _amount); + IERC20Metadata(_asset).approve(address(_adapter), _amount); + IParaswapSellAdapter(_adapter).deposit(_asset, _amount); + } + + function _getSingleUserInput( + address _fromToken, + address _toToken + ) internal returns (IParaswapSellAdapter.SellParams memory _sellParams) { + deal(_fromToken, USER, SELL_AMOUNT); + bytes memory _result = _getSwapRoute(_fromToken, 18, _toToken, 18, SELL_AMOUNT, USER); + _sellParams = IParaswapSellAdapter.SellParams(0, _result, _fromToken, _toToken, SELL_AMOUNT); + } + + function _getFullUserInput( + address _fromToken, + address _toToken + ) internal returns (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) { + (_dstAmount, _sellParams) = _getFullUserInputWithAmount(_fromToken, _toToken, SELL_AMOUNT); + } + + function _getFullUserInputWithAmount( + address _fromToken, + address _toToken, + uint256 _amount + ) internal returns (uint256 _dstAmount, IParaswapSellAdapter.SellParams memory _sellParams) { + deal(_fromToken, USER, _amount); + _dstAmount = uint256(bytes32(_getDstAmount(_fromToken, 18, _toToken, 18, _amount, USER))); + bytes memory _result = _getSwapRoute(_fromToken, 18, _toToken, 18, _amount, USER); + _sellParams = IParaswapSellAdapter.SellParams(0, _result, _fromToken, _toToken, _amount); + } + + function _getDstAmount( + address _fromToken, + uint256 _fromDecimals, + address _toToken, + uint256 _toDecimals, + uint256 _sellAmount, + address _caller + ) internal returns (bytes memory _result) { + string[] memory inputs = new string[](8); + inputs[0] = 'node'; + inputs[1] = './script/getDstAmount.js'; + inputs[2] = vm.toString(_fromToken); + inputs[3] = vm.toString(_fromDecimals); + inputs[4] = vm.toString(_toToken); + inputs[5] = vm.toString(_toDecimals); + inputs[6] = vm.toString(_sellAmount); + inputs[7] = vm.toString(_caller); + + _result = vm.ffi(inputs); + } + + function _getSwapRoute( + address _fromToken, + uint256 _fromDecimals, + address _toToken, + uint256 _toDecimals, + uint256 _sellAmount, + address _caller + ) internal returns (bytes memory _result) { + string[] memory inputs = new string[](8); + inputs[0] = 'node'; + inputs[1] = './script/getSwapRoute.js'; + inputs[2] = vm.toString(_fromToken); + inputs[3] = vm.toString(_fromDecimals); + inputs[4] = vm.toString(_toToken); + inputs[5] = vm.toString(_toDecimals); + inputs[6] = vm.toString(_sellAmount); + inputs[7] = vm.toString(_caller); + + _result = vm.ffi(inputs); + } +} + +// function _borrow(address _adapter, address _asset, uint256 _amount) internal { +// _adapter.borrow(_asset, _amount, 2, 0, USER); +// } + +// function _withdraw(address _adapter, address _asset, uint256 _amount) internal { +// _adapter.withdraw(_asset, _amount, USER); +// } diff --git a/test/CommonTest.t.sol b/test/e2e/common/CommonTest.t.sol similarity index 93% rename from test/CommonTest.t.sol rename to test/e2e/common/CommonTest.t.sol index 494912f..9bb3a2b 100644 --- a/test/CommonTest.t.sol +++ b/test/e2e/common/CommonTest.t.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.20; -import {IERC20} from '@openzeppelin/token/ERC20/IERC20.sol'; -import {MintableERC20} from '@opendollar/contracts/for-test/MintableERC20.sol'; import {Common, TKN} from '@opendollar/test/e2e/Common.t.sol'; import {Math} from '@opendollar/libraries/Math.sol'; import {ODProxy} from '@opendollar/contracts/proxies/ODProxy.sol'; @@ -10,8 +8,9 @@ import {IVault721} from '@opendollar/interfaces/proxies/IVault721.sol'; import {ISAFEEngine} from '@opendollar/interfaces/ISAFEEngine.sol'; import {ExitActions} from 'src/leverage/ExitActions.sol'; import {LeverageCalculator} from 'src/leverage/LeverageCalculator.sol'; +import {BaseTest} from 'test/e2e/common/BaseTest.t.sol'; -contract CommonTest is Common { +contract CommonTest is Common, BaseTest { using Math for uint256; uint256 public constant DEPOSIT = 10_000 ether; @@ -35,16 +34,6 @@ contract CommonTest is Common { exitActions = new ExitActions(); leverageCalculator = new LeverageCalculator(address(vault721)); token = address(collateral[TKN]); - - aliceProxy = _deployOrFind(alice); - _openSafe(aliceProxy, TKN); - - MintableERC20(token).mint(alice, DEPOSIT); - - vm.prank(alice); - IERC20(token).approve(aliceProxy, type(uint256).max); - - aliceNFV = vault721.getNfvState(vaults[aliceProxy]); } function _deployOrFind(address _owner) internal returns (address _proxy) { diff --git a/yarn.lock b/yarn.lock index 30ac482..ae7e46c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,6 +39,348 @@ ds-test "https://github.com/dapphub/ds-test" forge-std "https://github.com/foundry-rs/forge-std" +"@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" + "@noble/curves@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" @@ -72,10 +414,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@opendollar/contracts@0.0.0-e31c2151": - version "0.0.0-e31c2151" - resolved "https://registry.yarnpkg.com/@opendollar/contracts/-/contracts-0.0.0-e31c2151.tgz#d96fea17c8f865f6b35c74a80d0e95cdfed10943" - integrity sha512-mffuIIDH6YV7gxEbUQghPtKvCamcFoFG4YWnWozjtDec/vrusm2TCjrAKvzV9v8+Sha0dkr6ROryfyMxZIH+IQ== +"@opendollar/contracts@0.0.0-984c17c2": + version "0.0.0-984c17c2" + resolved "https://registry.yarnpkg.com/@opendollar/contracts/-/contracts-0.0.0-984c17c2.tgz#52a03256654cc7fe69cff430d60bed07d9a8648a" + integrity sha512-4AV3GKyi+deaSq1jsSUSP22/hkywYhF0EOE2v7cq7MnK3fuSKOSChKmLO0Hx/1PrRxhoE3/eIxqQuaPEqhpt0A== dependencies: "@defi-wonderland/solidity-utils" "0.0.0-4298c6c6" "@openzeppelin/contracts" "4.9.6" @@ -84,6 +426,11 @@ ethers "^6.12.0" forge-std "https://github.com/foundry-rs/forge-std.git#e8a047e3f40f13fa37af6fe14e6e06283d9a060e" +"@openzeppelin-contracts-3.4.2-solc-0.7@yarn:@openzeppelin/contracts@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" + integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== + "@openzeppelin/contracts-upgradeable@4.9.6": version "4.9.6" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.6.tgz#38b21708a719da647de4bb0e4802ee235a0d24df" @@ -178,6 +525,11 @@ acorn@^6.0.7: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +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== + aes-js@4.0.0-beta.5: version "4.0.0-beta.5" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" @@ -279,16 +631,45 @@ 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== + +axios@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" + integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +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.2: 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.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.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" @@ -311,6 +692,11 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" +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== + cacheable-lookup@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" @@ -411,6 +797,13 @@ 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" + commander@2.18.0: version "2.18.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" @@ -510,6 +903,11 @@ defer-to-connect@^2.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== +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== + detect-indent@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-7.0.1.tgz#cbb060a12842b9c4d333f1cac4aa4da1bb66bc25" @@ -543,6 +941,19 @@ dotenv@^16.4.5: version "1.0.0" resolved "https://github.com/dapphub/ds-test#e282159d5170298eb2455a6c05280ab5a73a4ef0" +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@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -670,6 +1081,42 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +ethers@^5.7.2: + 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" + ethers@^6.12.0: version "6.12.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.1.tgz#517ff6d66d4fd5433e38e903051da3e57c87ff37" @@ -765,6 +1212,11 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + "forge-std@git+https://github.com/foundry-rs/forge-std.git#e8a047e3f40f13fa37af6fe14e6e06283d9a060e": version "1.5.6" resolved "git+https://github.com/foundry-rs/forge-std.git#e8a047e3f40f13fa37af6fe14e6e06283d9a060e" @@ -778,6 +1230,15 @@ form-data-encoder@^2.1.2: resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -881,6 +1342,23 @@ 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" + http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" @@ -940,7 +1418,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== @@ -1016,6 +1494,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +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@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1121,6 +1604,18 @@ micromatch@^4.0.4: braces "^3.0.3" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + 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" + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -1136,6 +1631,16 @@ mimic-response@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== +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, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -1187,6 +1692,11 @@ normalize-url@^8.0.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1323,6 +1833,11 @@ proto-list@~1.2.1: resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -1438,6 +1953,11 @@ rxjs@^6.4.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +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@^5.5.0, semver@^5.5.1: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -1755,6 +2275,11 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + ws@8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"