diff --git a/.prettierrc.json b/.prettierrc.json index 7d95f61e..8f504e10 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,5 @@ { + "plugins": ["prettier-plugin-solidity"], "overrides": [ { "files": "*.sol", @@ -8,7 +9,6 @@ "useTabs": false, "singleQuote": false, "bracketSpacing": true, - "explicitTypes": "always", "trailingComma": "none" } }, diff --git a/.solhint.json b/.solhint.json index 23c48a2c..d49667ba 100755 --- a/.solhint.json +++ b/.solhint.json @@ -5,7 +5,7 @@ "mark-callable-contracts": ["off"], "reason-string": ["error", { "maxLength": 50 }], "function-max-lines": ["error", 99], - "max-line-length": ["error", 99], + "max-line-length": ["off"], "compiler-version": ["error", "0.8.12"], "private-vars-leading-underscore": ["off"], "const-name-snakecase": ["off"], @@ -16,6 +16,13 @@ } ], "prettier/prettier": "warn", - "comprehensive-interface": ["off"] + "comprehensive-interface": ["off"], + "foundry-test-functions": ["off"], + "gas-small-strings": ["off"], + "gas-increment-by-one": ["off"], + "func-named-parameters": ["off"], + "gas-custom-errors": ["off"], + "named-parameters-mapping": ["off"], + "gas-indexed-events": ["off"] } } diff --git a/contracts/callers/SimpleCaller.sol b/contracts/callers/SimpleCaller.sol index 7c4c9568..b9a5362f 100644 --- a/contracts/callers/SimpleCaller.sol +++ b/contracts/callers/SimpleCaller.sol @@ -21,9 +21,7 @@ import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { ICaller } from "../interfaces/ICaller.sol"; import { Base } from "../shared/Base.sol"; -import { ActionType } from "../shared/Enums.sol"; -import { HighInputBalanceChange, ZeroTarget } from "../shared/Errors.sol"; -import { AbsoluteTokenAmount } from "../shared/Structs.sol"; +import { ZeroTarget } from "../shared/Errors.sol"; import { TokensHandler } from "../shared/TokensHandler.sol"; /** diff --git a/contracts/callers/UniswapV2Caller.sol b/contracts/callers/UniswapV2Caller.sol index 5593cfc7..bb60de2c 100644 --- a/contracts/callers/UniswapV2Caller.sol +++ b/contracts/callers/UniswapV2Caller.sol @@ -25,7 +25,7 @@ import { IUniswapV2Pair } from "../interfaces/IUniswapV2Pair.sol"; import { IWETH9 } from "../interfaces/IWETH9.sol"; import { Base } from "../shared/Base.sol"; import { SwapType } from "../shared/Enums.sol"; -import { BadToken, InconsistentPairsAndDirectionsLengths, InputSlippage, LowReserve, ZeroAmountIn, ZeroAmountOut, ZeroLength } from "../shared/Errors.sol"; +import { InconsistentPairsAndDirectionsLengths, InputSlippage, LowReserve, ZeroAmountIn, ZeroAmountOut, ZeroLength } from "../shared/Errors.sol"; import { TokensHandler } from "../shared/TokensHandler.sol"; import { Weth } from "../shared/Weth.sol"; @@ -68,8 +68,9 @@ contract UniswapV2Caller is ICaller, TokensHandler, Weth { uint256 length = pairs.length; if (length == uint256(0)) revert ZeroLength(); - if (directions.length != length) + if (directions.length != length) { revert InconsistentPairsAndDirectionsLengths(length, directions.length); + } uint256[] memory amounts = (swapType == SwapType.FixedInputs) ? getAmountsOut(fixedSideAmount, pairs, directions) diff --git a/contracts/callers/UniswapV3Caller.sol b/contracts/callers/UniswapV3Caller.sol new file mode 100644 index 00000000..28afc90f --- /dev/null +++ b/contracts/callers/UniswapV3Caller.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity 0.8.12; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IUniswapV3SwapCallback } from "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol"; +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; + +import { IWETH9 } from "./../interfaces/IWETH9.sol"; +import { Base } from "./../shared/Base.sol"; +import { TokensHandler } from "./../shared/TokensHandler.sol"; +import { Weth } from "./../shared/Weth.sol"; + +contract UniswapV3Caller is TokensHandler, Weth, IUniswapV3SwapCallback { + address internal constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + uint160 internal constant MIN_SQRT_RATIO = 4295128739; + uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; + + /** + * @notice Sets Wrapped Ether address for the current chain + * @param weth Wrapped Ether address + */ + constructor(address weth) Weth(weth) { + // solhint-disable-previous-line no-empty-blocks + } + + function callBytes(bytes calldata callerCallData) external { + ( + address inputToken, + address outputToken, + address pool, + bool direction, + uint256 fixedSideAmount, + bool isExactInput + ) = abi.decode(callerCallData, (address, address, address, bool, uint256, bool)); + + if (isExactInput) { + exactInputSwap(inputToken, pool, direction, fixedSideAmount); + } else { + exactOutputSwap(inputToken, pool, direction, fixedSideAmount); + } + + // Unwrap weth if necessary + if (outputToken == ETH) withdrawEth(); + + // In case of non-zero input token, transfer the remaining amount back to `msg.sender` + Base.transfer(inputToken, msg.sender, Base.getBalance(inputToken)); + + // In case of non-zero output token, transfer the total balance to `msg.sender` + Base.transfer(outputToken, msg.sender, Base.getBalance(outputToken)); + } + + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) external { + address inputToken = abi.decode(data, (address)); + + if (amount0Delta > 0) { + if (inputToken == ETH) { + depositEth(uint256(amount0Delta)); + } + Base.transfer(IUniswapV3Pool(msg.sender).token0(), msg.sender, uint256(amount0Delta)); + } else { + if (inputToken == ETH) { + depositEth(uint256(amount1Delta)); + } + Base.transfer(IUniswapV3Pool(msg.sender).token1(), msg.sender, uint256(amount1Delta)); + } + } + + function exactInputSwap( + address inputToken, + address pool, + bool direction, + uint256 amountIn + ) internal { + IUniswapV3Pool(pool).swap( + address(this), + direction, + int256(amountIn), + direction ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1, + abi.encode(inputToken) + ); + } + + function exactOutputSwap( + address inputToken, + address pool, + bool direction, + uint256 amountOut + ) internal { + IUniswapV3Pool(pool).swap( + address(this), + direction, + -int256(amountOut), + direction ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1, + abi.encode(inputToken) + ); + } + + function depositEth(uint256 amount) internal { + IWETH9(getWeth()).deposit{ value: amount }(); + } + + function withdrawEth() internal { + uint256 wethBalance = IERC20(getWeth()).balanceOf(address(this)); + if (wethBalance > uint256(0)) IWETH9(getWeth()).withdraw(wethBalance); + } +} diff --git a/contracts/interfaces/ICaller.sol b/contracts/interfaces/ICaller.sol index 39e6afc1..414e3e28 100644 --- a/contracts/interfaces/ICaller.sol +++ b/contracts/interfaces/ICaller.sol @@ -17,8 +17,6 @@ pragma solidity 0.8.12; -import { AbsoluteTokenAmount } from "../shared/Structs.sol"; - import { ITokensHandler } from "./ITokensHandler.sol"; interface ICaller is ITokensHandler { diff --git a/contracts/interfaces/IDAIPermit.sol b/contracts/interfaces/IDAIPermit.sol index f146f886..2ab20a8c 100644 --- a/contracts/interfaces/IDAIPermit.sol +++ b/contracts/interfaces/IDAIPermit.sol @@ -31,5 +31,5 @@ interface IDAIPermit is IERC20 { bytes32 s ) external; - function nonces(address holder) external view returns (uint256); + function nonces(address holder) external view returns (uint256 nonce); } diff --git a/contracts/interfaces/IEIP2612.sol b/contracts/interfaces/IEIP2612.sol index b74e17f2..35b0729d 100644 --- a/contracts/interfaces/IEIP2612.sol +++ b/contracts/interfaces/IEIP2612.sol @@ -30,5 +30,5 @@ interface IEIP2612 is IERC20 { bytes32 s ) external; - function nonces(address holder) external view returns (uint256); + function nonces(address holder) external view returns (uint256 nonce); } diff --git a/contracts/interfaces/IRouter.sol b/contracts/interfaces/IRouter.sol index 513e81bb..d9d33a57 100644 --- a/contracts/interfaces/IRouter.sol +++ b/contracts/interfaces/IRouter.sol @@ -17,17 +17,9 @@ pragma solidity 0.8.12; -import { - AbsoluteTokenAmount, - Input, - SwapDescription, - AccountSignature, - ProtocolFeeSignature, - Fee -} from "../shared/Structs.sol"; - -import { ITokensHandler } from "./ITokensHandler.sol"; +import { AbsoluteTokenAmount, Input, SwapDescription, AccountSignature, ProtocolFeeSignature } from "../shared/Structs.sol"; import { ISignatureVerifier } from "./ISignatureVerifier.sol"; +import { ITokensHandler } from "./ITokensHandler.sol"; interface IRouter is ITokensHandler, ISignatureVerifier { /** @@ -89,7 +81,9 @@ interface IRouter is ITokensHandler, ISignatureVerifier { SwapDescription calldata swapDescription, AccountSignature calldata accountSignature, ProtocolFeeSignature calldata protocolFeeSignature - ) external payable + ) + external + payable returns ( uint256 inputBalanceChange, uint256 actualOutputAmount, diff --git a/contracts/interfaces/ISignatureVerifier.sol b/contracts/interfaces/ISignatureVerifier.sol index e5c0e7ed..a379bb54 100644 --- a/contracts/interfaces/ISignatureVerifier.sol +++ b/contracts/interfaces/ISignatureVerifier.sol @@ -17,9 +17,6 @@ pragma solidity 0.8.12; -import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; -import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - import { AbsoluteTokenAmount, Input, SwapDescription } from "../shared/Structs.sol"; interface ISignatureVerifier { diff --git a/contracts/interfaces/IUniswapV2Pair.sol b/contracts/interfaces/IUniswapV2Pair.sol index 00496ef5..3b8fb277 100644 --- a/contracts/interfaces/IUniswapV2Pair.sol +++ b/contracts/interfaces/IUniswapV2Pair.sol @@ -23,27 +23,23 @@ pragma solidity 0.8.12; * github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2Pair.sol. */ interface IUniswapV2Pair { - function mint(address) external returns (uint256); + function mint(address to) external returns (uint256 liquidity); - function burn(address) external returns (uint256, uint256); + function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( - uint256, - uint256, - address, - bytes calldata + uint256 amount0Out, + uint256 amount1Out, + address to, + bytes calldata data ) external; function getReserves() external view - returns ( - uint112, - uint112, - uint32 - ); + returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); - function token0() external view returns (address); + function token0() external view returns (address token0); - function token1() external view returns (address); + function token1() external view returns (address token1); } diff --git a/contracts/interfaces/IUniswapV2Router02.sol b/contracts/interfaces/IUniswapV2Router02.sol index 0796174f..1b18cf07 100644 --- a/contracts/interfaces/IUniswapV2Router02.sol +++ b/contracts/interfaces/IUniswapV2Router02.sol @@ -24,9 +24,9 @@ pragma solidity 0.8.12; */ interface IUniswapV2Router02 { function swapExactETHForTokens( - uint256, - address[] calldata, - address, - uint256 + uint256 amountOutMin, + address[] calldata path, + address to, + uint256 deadline ) external payable; } diff --git a/contracts/interfaces/IWETH9.sol b/contracts/interfaces/IWETH9.sol index b4761ddf..75eb5a38 100644 --- a/contracts/interfaces/IWETH9.sol +++ b/contracts/interfaces/IWETH9.sol @@ -26,7 +26,7 @@ pragma solidity 0.8.12; interface IWETH9 { function deposit() external payable; - function withdraw(uint256) external; + function withdraw(uint256 amount) external; - function balanceOf(address) external view returns (uint256); + function balanceOf(address account) external view returns (uint256 balance); } diff --git a/contracts/interfaces/IYearnPermit.sol b/contracts/interfaces/IYearnPermit.sol index 3bfcebbd..3afc6c31 100644 --- a/contracts/interfaces/IYearnPermit.sol +++ b/contracts/interfaces/IYearnPermit.sol @@ -20,11 +20,5 @@ pragma solidity 0.8.12; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IYearnPermit is IERC20 { - function permit( - address, - address, - uint256, - uint256, - bytes calldata - ) external; + function permit(address, address, uint256, uint256, bytes calldata) external; } diff --git a/contracts/router/Router.sol b/contracts/router/Router.sol index 6164c08d..71afed55 100644 --- a/contracts/router/Router.sol +++ b/contracts/router/Router.sol @@ -18,8 +18,8 @@ pragma solidity 0.8.12; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; @@ -30,39 +30,10 @@ import { IRouter } from "../interfaces/IRouter.sol"; import { IYearnPermit } from "../interfaces/IYearnPermit.sol"; import { Base } from "../shared/Base.sol"; import { AmountType, PermitType, SwapType } from "../shared/Enums.sol"; -import { - BadAmount, - BadAccount, - BadAccountSignature, - BadAmountType, - BadFeeAmount, - BadFeeBeneficiary, - BadFeeShare, - BadFeeSignature, - ExceedingDelimiterAmount, - ExceedingLimitFee, - HighInputBalanceChange, - InsufficientAllowance, - InsufficientMsgValue, - LowActualOutputAmount, - NoneAmountType, - NonePermitType, - NoneSwapType, - PassedDeadline -} from "../shared/Errors.sol"; +import { BadAmount, BadAccount, BadAccountSignature, BadAmountType, BadFeeAmount, BadFeeBeneficiary, BadFeeShare, BadFeeSignature, ExceedingDelimiterAmount, ExceedingLimitFee, HighInputBalanceChange, InsufficientAllowance, InsufficientMsgValue, LowActualOutputAmount, NoneAmountType, NonePermitType, NoneSwapType, PassedDeadline } from "../shared/Errors.sol"; import { Ownable } from "../shared/Ownable.sol"; -import { - AbsoluteTokenAmount, - AccountSignature, - Fee, - ProtocolFeeSignature, - Input, - Permit, - SwapDescription, - TokenAmount -} from "../shared/Structs.sol"; +import { AbsoluteTokenAmount, AccountSignature, Fee, ProtocolFeeSignature, Input, Permit, SwapDescription, TokenAmount } from "../shared/Structs.sol"; import { TokensHandler } from "../shared/TokensHandler.sol"; - import { ProtocolFee } from "./ProtocolFee.sol"; import { SignatureVerifier } from "./SignatureVerifier.sol"; @@ -86,8 +57,9 @@ contract Router is SwapDescription calldata swapDescription, AccountSignature calldata accountSignature ) external override nonReentrant { - if (msg.sender != swapDescription.account) + if (msg.sender != swapDescription.account) { revert BadAccount(msg.sender, swapDescription.account); + } validateAndExpireAccountSignature(input, output, swapDescription, accountSignature); } @@ -102,7 +74,10 @@ contract Router is AccountSignature calldata accountSignature, ProtocolFeeSignature calldata protocolFeeSignature ) - external payable override nonReentrant + external + payable + override + nonReentrant returns ( uint256 inputBalanceChange, uint256 actualOutputAmount, @@ -164,8 +139,9 @@ contract Router is uint256 outputBalanceChange = Base.getBalance(output.token) - initialOutputBalance; // Check input requirements, prevent the underflow - if (inputBalanceChange > absoluteInputAmount) + if (inputBalanceChange > absoluteInputAmount) { revert HighInputBalanceChange(inputBalanceChange, absoluteInputAmount); + } // Calculate the refund amount uint256 refundAmount = absoluteInputAmount - inputBalanceChange; @@ -180,8 +156,9 @@ contract Router is ); // Check output requirements, prevent revert on transfers - if (actualOutputAmount < output.absoluteAmount) + if (actualOutputAmount < output.absoluteAmount) { revert LowActualOutputAmount(actualOutputAmount, output.absoluteAmount); + } // Transfer the refund back to the user, // do nothing in zero input token case as `refundAmount` is zero @@ -267,8 +244,9 @@ contract Router is ) internal { uint256 allowance = IERC20(token).allowance(account, address(this)); if (allowance < amount) { - if (permit.permitCallData.length == uint256(0)) + if (permit.permitCallData.length == uint256(0)) { revert InsufficientAllowance(allowance, amount); + } Address.functionCall( token, @@ -327,8 +305,9 @@ contract Router is AccountSignature calldata accountSignature ) internal { if (accountSignature.signature.length == uint256(0)) { - if (msg.sender != swapDescription.account) + if (msg.sender != swapDescription.account) { revert BadAccount(msg.sender, swapDescription.account); + } return; } bytes32 hashedAccountSignatureData = hashAccountSignatureData( @@ -366,15 +345,18 @@ contract Router is Fee memory protocolFee = swapDescription.protocolFee; if (protocolFeeSignature.signature.length == uint256(0)) { - if (protocolFee.share != baseProtocolFee.share) + if (protocolFee.share != baseProtocolFee.share) { revert BadFeeShare(protocolFee.share, baseProtocolFee.share); - if (protocolFee.beneficiary != baseProtocolFee.beneficiary) + } + if (protocolFee.beneficiary != baseProtocolFee.beneficiary) { revert BadFeeBeneficiary(protocolFee.beneficiary, baseProtocolFee.beneficiary); + } return; } - if (protocolFee.share > baseProtocolFee.share) + if (protocolFee.share > baseProtocolFee.share) { revert ExceedingLimitFee(protocolFee.share, baseProtocolFee.share); + } bytes32 hashedProtocolFeeSignatureData = hashProtocolFeeSignatureData( input, @@ -392,8 +374,9 @@ contract Router is ) revert BadFeeSignature(); // solhint-disable not-rely-on-time - if (block.timestamp > protocolFeeSignature.deadline) + if (block.timestamp > protocolFeeSignature.deadline) { revert PassedDeadline(block.timestamp, protocolFeeSignature.deadline); + } // solhint-enable not-rely-on-time } @@ -405,11 +388,10 @@ contract Router is * @param account Address of the account to transfer token from * @return absoluteTokenAmount Absolute token amount */ - function getAbsoluteInputAmount(TokenAmount calldata tokenAmount, address account) - internal - view - returns (uint256 absoluteTokenAmount) - { + function getAbsoluteInputAmount( + TokenAmount calldata tokenAmount, + address account + ) internal view returns (uint256 absoluteTokenAmount) { AmountType amountType = tokenAmount.amountType; address token = tokenAmount.token; uint256 amount = tokenAmount.amount; @@ -420,8 +402,9 @@ contract Router is if (amountType == AmountType.Absolute) return amount; - if (token == ETH || token == address(0)) + if (token == ETH || token == address(0)) { revert BadAmountType(amountType, AmountType.Absolute); + } if (amount > DELIMITER) revert ExceedingDelimiterAmount(amount); @@ -456,18 +439,15 @@ contract Router is ) internal pure - returns ( - uint256 returnedAmount, - uint256 protocolFeeAmount, - uint256 marketplaceFeeAmount - ) + returns (uint256 returnedAmount, uint256 protocolFeeAmount, uint256 marketplaceFeeAmount) { if (swapType == SwapType.None) revert NoneSwapType(); uint256 outputAbsoluteAmount = output.absoluteAmount; if (output.token == address(0)) { - if (outputAbsoluteAmount > uint256(0)) + if (outputAbsoluteAmount > uint256(0)) { revert BadAmount(outputAbsoluteAmount, uint256(0)); + } return (uint256(0), uint256(0), uint256(0)); } @@ -490,8 +470,9 @@ contract Router is uint256 totalFeeAmount = outputBalanceChange - returnedAmount; // This check is important in fixed outputs case as we never actually check that // total fee amount is not too large and should always just pass in fixed inputs case - if (totalFeeAmount * DELIMITER > totalFeeShare * returnedAmount) + if (totalFeeAmount * DELIMITER > totalFeeShare * returnedAmount) { revert BadFeeAmount(totalFeeAmount, (returnedAmount * totalFeeShare) / DELIMITER); + } protocolFeeAmount = (totalFeeAmount * protocolFee.share) / totalFeeShare; marketplaceFeeAmount = totalFeeAmount - protocolFeeAmount; diff --git a/contracts/router/SignatureVerifier.sol b/contracts/router/SignatureVerifier.sol index 6d1695dc..dbdc01cf 100644 --- a/contracts/router/SignatureVerifier.sol +++ b/contracts/router/SignatureVerifier.sol @@ -21,16 +21,7 @@ import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/draft-EIP712. import { ISignatureVerifier } from "../interfaces/ISignatureVerifier.sol"; import { UsedHash } from "../shared/Errors.sol"; -import { - AbsoluteTokenAmount, - AccountSignature, - ProtocolFeeSignature, - Fee, - Input, - Permit, - SwapDescription, - TokenAmount -} from "../shared/Structs.sol"; +import { AbsoluteTokenAmount, Fee, Input, Permit, SwapDescription, TokenAmount } from "../shared/Structs.sol"; contract SignatureVerifier is ISignatureVerifier, EIP712 { mapping(bytes32 => bool) private isHashUsed_; @@ -175,7 +166,7 @@ contract SignatureVerifier is ISignatureVerifier, EIP712 { * @param output Outut described in `hashDada()` function * @param swapDescription Swap parameters described in `hashDada()` function * @param saltOrDeadline Salt/deadline parameter preventing double-spending - * @return `execute()` function data hashed + * @return hashedData `execute()` function data hashed */ function hash( bytes32 typehash, @@ -183,7 +174,7 @@ contract SignatureVerifier is ISignatureVerifier, EIP712 { AbsoluteTokenAmount memory output, SwapDescription memory swapDescription, uint256 saltOrDeadline - ) internal pure returns (bytes32) { + ) internal pure returns (bytes32 hashedData) { return keccak256( abi.encode( @@ -198,17 +189,19 @@ contract SignatureVerifier is ISignatureVerifier, EIP712 { /** * @param input Input struct to be hashed - * @return Hashed Input structs array + * @return hashedInput Hashed Input structs array */ - function hash(Input memory input) internal pure returns (bytes32) { + function hash(Input memory input) internal pure returns (bytes32 hashedInput) { return keccak256(abi.encode(INPUT_TYPEHASH, hash(input.tokenAmount), hash(input.permit))); } /** * @param tokenAmount TokenAmount struct to be hashed - * @return Hashed TokenAmount struct + * @return hashedTokenAmount Hashed TokenAmount struct */ - function hash(TokenAmount memory tokenAmount) internal pure returns (bytes32) { + function hash( + TokenAmount memory tokenAmount + ) internal pure returns (bytes32 hashedTokenAmount) { return keccak256( abi.encode( @@ -222,9 +215,9 @@ contract SignatureVerifier is ISignatureVerifier, EIP712 { /** * @param permit Permit struct to be hashed - * @return Hashed Permit struct + * @return hashedPermit Hashed Permit struct */ - function hash(Permit memory permit) internal pure returns (bytes32) { + function hash(Permit memory permit) internal pure returns (bytes32 hashedPermit) { return keccak256( abi.encode( @@ -237,9 +230,11 @@ contract SignatureVerifier is ISignatureVerifier, EIP712 { /** * @param absoluteTokenAmount AbsoluteTokenAmount struct to be hashed - * @return Hashed AbsoluteTokenAmount struct + * @return hashedAbsoluteTokenAmount Hashed AbsoluteTokenAmount struct */ - function hash(AbsoluteTokenAmount memory absoluteTokenAmount) internal pure returns (bytes32) { + function hash( + AbsoluteTokenAmount memory absoluteTokenAmount + ) internal pure returns (bytes32 hashedAbsoluteTokenAmount) { return keccak256( abi.encode( @@ -252,9 +247,11 @@ contract SignatureVerifier is ISignatureVerifier, EIP712 { /** * @param swapDescription SwapDescription struct to be hashed - * @return Hashed SwapDescription struct + * @return hashedSwapDescription Hashed SwapDescription struct */ - function hash(SwapDescription memory swapDescription) internal pure returns (bytes32) { + function hash( + SwapDescription memory swapDescription + ) internal pure returns (bytes32 hashedSwapDescription) { return keccak256( abi.encode( @@ -271,9 +268,9 @@ contract SignatureVerifier is ISignatureVerifier, EIP712 { /** * @param fee Fee struct to be hashed - * @return Hashed Fee struct + * @return hashedFee Hashed Fee struct */ - function hash(Fee memory fee) internal pure returns (bytes32) { + function hash(Fee memory fee) internal pure returns (bytes32 hashedFee) { return keccak256(abi.encode(FEE_TYPEHASH, fee.share, fee.beneficiary)); } } diff --git a/contracts/shared/Base.sol b/contracts/shared/Base.sol index ef0049cb..306e0aa9 100644 --- a/contracts/shared/Base.sol +++ b/contracts/shared/Base.sol @@ -17,11 +17,11 @@ pragma solidity 0.8.12; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; -import { FailedEtherTransfer, ZeroReceiver } from "./Errors.sol"; +import { ZeroReceiver } from "./Errors.sol"; /** * @title Library unifying transfer, approval, and getting balance for ERC20 tokens and Ether @@ -38,11 +38,7 @@ library Base { * @dev Reverts on zero `receiver`, does nothing for zero amount * @dev Should not be used with zero token address */ - function transfer( - address token, - address receiver, - uint256 amount - ) internal { + function transfer(address token, address receiver, uint256 amount) internal { if (amount == uint256(0)) return; if (receiver == address(0)) revert ZeroReceiver(); @@ -60,11 +56,7 @@ library Base { * @param amount Tokens amount to be approved * @dev Should not be used with zero or `ETH` token address */ - function safeApproveMax( - address token, - address spender, - uint256 amount - ) internal { + function safeApproveMax(address token, address spender, uint256 amount) internal { uint256 allowance = IERC20(token).allowance(address(this), spender); if (allowance < amount) { if (allowance > uint256(0)) { @@ -80,7 +72,7 @@ library Base { * @param account Address of the account * @dev Should not be used with zero token address */ - function getBalance(address token, address account) internal view returns (uint256) { + function getBalance(address token, address account) internal view returns (uint256 balance) { if (token == ETH) return account.balance; return IERC20(token).balanceOf(account); @@ -91,7 +83,7 @@ library Base { * @param token Address of the token * @dev Returns `0` for zero token address in order to handle empty token case */ - function getBalance(address token) internal view returns (uint256) { + function getBalance(address token) internal view returns (uint256 balance) { if (token == address(0)) return uint256(0); return Base.getBalance(token, address(this)); diff --git a/contracts/shared/Errors.sol b/contracts/shared/Errors.sol index a347d7ab..b9731b00 100644 --- a/contracts/shared/Errors.sol +++ b/contracts/shared/Errors.sol @@ -17,7 +17,7 @@ pragma solidity 0.8.12; -import { ActionType, AmountType, PermitType, SwapType } from "./Enums.sol"; +import { AmountType } from "./Enums.sol"; import { Fee } from "./Structs.sol"; error BadAccount(address account, address expectedAccount); diff --git a/contracts/shared/Weth.sol b/contracts/shared/Weth.sol index eddfc63d..dc170715 100644 --- a/contracts/shared/Weth.sol +++ b/contracts/shared/Weth.sol @@ -21,14 +21,14 @@ pragma solidity 0.8.12; * @title Abstract contract storing Wrapped Ether address for the current chain */ abstract contract Weth { - address private immutable weth_; + address private immutable WETH; /** * @notice Sets Wrapped Ether address for the current chain * @param weth Wrapped Ether address */ constructor(address weth) { - weth_ = weth; + WETH = weth; } /** @@ -36,6 +36,6 @@ abstract contract Weth { * @return weth Wrapped Ether address */ function getWeth() public view returns (address weth) { - return weth_; + return WETH; } } diff --git a/hardhat.config.ts b/hardhat.config.ts index 02326597..2cdf03eb 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -36,7 +36,8 @@ const config: HardhatUserConfig = { // }, hardhat: { forking: { - url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, + // url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, + url: "https://rpc.zerion.io/v1/ethereum" }, blockGasLimit: 10000000, gas: 10000000, @@ -123,7 +124,7 @@ const config: HardhatUserConfig = { blast: process.env.BLAST_API_KEY ? process.env.BLAST_API_KEY.toString() : '', bsc: process.env.BSC_API_KEY ? process.env.BSC_API_KEY.toString() : '', celo: process.env.CELO_API_KEY ? process.env.CELO_API_KEY.toString() : '', - gnosis: process.env.GNOSIS_API_KEY ? process.env.GNOSIS_API_KEY.toString() : '', + xdai: process.env.GNOSIS_API_KEY ? process.env.GNOSIS_API_KEY.toString() : '', linea: process.env.LINEA_API_KEY ? process.env.LINEA_API_KEY.toString() : '', mainnet: process.env.ETHEREUM_API_KEY ? process.env.ETHEREUM_API_KEY.toString() : '', mantle: process.env.MANTLE_API_KEY ? process.env.MANTLE_API_KEY.toString() : '', diff --git a/package-lock.json b/package-lock.json index a28574d4..d3ee4884 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,9 @@ "hasInstallScript": true, "license": "LGPL-3.0-only", "dependencies": { - "@openzeppelin/contracts": "4.4.0" + "@openzeppelin/contracts": "4.4.0", + "@uniswap/v3-core": "^1.0.1", + "@uniswap/v3-periphery": "^1.4.4" }, "devDependencies": { "@babel/core": "7.22.9", @@ -43,11 +45,11 @@ "lint-staged": "11.0.0", "mrm": "3.0.10", "pinst": "2.1.6", - "prettier": "2.8.8", - "prettier-plugin-solidity": "1.1.3", + "prettier": "3.3.3", + "prettier-plugin-solidity": "1.4.1", "regenerator-runtime": "0.13.11", - "solhint": "3.4.1", - "solhint-plugin-prettier": "0.0.5", + "solhint": "5.0.3", + "solhint-plugin-prettier": "0.1.0", "solidity-coverage": "0.8.4", "truffle": "5.11.1", "ts-node": "10.9.1", @@ -4719,6 +4721,53 @@ "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.4.0.tgz", "integrity": "sha512-dlKiZmDvJnGRLHojrDoFZJmsQVeltVeoiRN7RK+cf2FmkhASDEblE0RiaYdxPNsUZa6mRG8393b9bfyp+V5IAw==" }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@prettier/sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.3.0.tgz", + "integrity": "sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==", + "dev": true, + "funding": { + "url": "https://github.com/prettier/prettier-synchronized?sponsor=1" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -5807,9 +5856,9 @@ "dev": true }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, "node_modules/@types/http-errors": { @@ -6016,6 +6065,50 @@ "@types/sinon": "*" } }, + "node_modules/@uniswap/lib": { + "version": "4.0.1-alpha", + "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-4.0.1-alpha.tgz", + "integrity": "sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v2-core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@uniswap/v2-core/-/v2-core-1.0.1.tgz", + "integrity": "sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v3-core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.1.tgz", + "integrity": "sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v3-periphery": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@uniswap/v3-periphery/-/v3-periphery-1.4.4.tgz", + "integrity": "sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw==", + "dependencies": { + "@openzeppelin/contracts": "3.4.2-solc-0.7", + "@uniswap/lib": "^4.0.1-alpha", + "@uniswap/v2-core": "^1.0.1", + "@uniswap/v3-core": "^1.0.0", + "base64-sol": "1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v3-periphery/node_modules/@openzeppelin/contracts": { + "version": "3.4.2-solc-0.7", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz", + "integrity": "sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA==" + }, "node_modules/@vue/component-compiler-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", @@ -6068,6 +6161,22 @@ "url": "https://opencollective.com/postcss/" } }, + "node_modules/@vue/component-compiler-utils/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@vue/component-compiler-utils/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6659,9 +6768,9 @@ "dev": true }, "node_modules/antlr4": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.0.tgz", - "integrity": "sha512-zooUbt+UscjnWyOrsuY/tVFL4rwrAGwOivpQmvmUDE22hy/lUA467Rc1rcixyRwcRUIXFYBwv7+dClDSHdmmew==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", + "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==", "dev": true, "engines": { "node": ">=16" @@ -7457,6 +7566,11 @@ } ] }, + "node_modules/base64-sol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-sol/-/base64-sol-1.0.1.tgz", + "integrity": "sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg==" + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -8846,6 +8960,16 @@ "dev": true, "optional": true }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -22496,7 +22620,6 @@ "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.9.tgz", "integrity": "sha512-bdM5cEGCOhDSwminryHJbRmXc1x7dPKg6Pqns3qyTwFlxsqUgxE29lsERS3PlIW1HTjoIGMUqsk1zQQwST1Yxw==", "dev": true, - "hasInstallScript": true, "dependencies": { "node-gyp-build": "4.3.0" } @@ -22534,7 +22657,6 @@ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", "dev": true, - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -22614,7 +22736,6 @@ "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", "dev": true, - "hasInstallScript": true, "dependencies": { "node-addon-api": "^2.0.0", "node-gyp-build": "^4.2.0" @@ -22625,7 +22746,6 @@ "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", "dev": true, - "hasInstallScript": true, "dependencies": { "abstract-leveldown": "^7.2.0", "napi-macros": "~2.0.0", @@ -22708,7 +22828,6 @@ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", "dev": true, - "hasInstallScript": true, "dependencies": { "elliptic": "^6.5.2", "node-addon-api": "^2.0.0", @@ -22720,7 +22839,6 @@ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", "dev": true, - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -23116,9 +23234,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/graphemer": { @@ -23873,9 +23991,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-errors": { @@ -29188,15 +29306,15 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -29215,30 +29333,26 @@ } }, "node_modules/prettier-plugin-solidity": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz", - "integrity": "sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.1.tgz", + "integrity": "sha512-Mq8EtfacVZ/0+uDKTtHZGW3Aa7vEbX/BNx63hmVg6YTiTXSiuKP0amj0G6pGwjmLaOfymWh3QgXEZkjQbU8QRg==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.16.0", - "semver": "^7.3.8", - "solidity-comments-extractor": "^0.0.7" + "@solidity-parser/parser": "^0.18.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=12" + "node": ">=16" }, "peerDependencies": { - "prettier": ">=2.3.0 || >=3.0.0-alpha.0" + "prettier": ">=2.3.0" } }, "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", - "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", - "dev": true, - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", + "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "dev": true }, "node_modules/prettier-plugin-solidity/node_modules/lru-cache": { "version": "6.0.0", @@ -29328,6 +29442,12 @@ "extend": "^3.0.0" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -30905,14 +31025,14 @@ } }, "node_modules/solhint": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.1.tgz", - "integrity": "sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.3.tgz", + "integrity": "sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.16.0", + "@solidity-parser/parser": "^0.18.0", "ajv": "^6.12.6", - "antlr4": "^4.11.0", + "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", "chalk": "^4.1.2", "commander": "^10.0.0", @@ -30921,9 +31041,10 @@ "glob": "^8.0.3", "ignore": "^5.2.4", "js-yaml": "^4.1.0", + "latest-version": "^7.0.0", "lodash": "^4.17.21", "pluralize": "^8.0.0", - "semver": "^6.3.0", + "semver": "^7.5.2", "strip-ansi": "^6.0.1", "table": "^6.8.1", "text-table": "^0.2.0" @@ -30936,25 +31057,47 @@ } }, "node_modules/solhint-plugin-prettier": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz", - "integrity": "sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.1.0.tgz", + "integrity": "sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==", "dev": true, "dependencies": { + "@prettier/sync": "^0.3.0", "prettier-linter-helpers": "^1.0.0" }, "peerDependencies": { - "prettier": "^1.15.0 || ^2.0.0", - "prettier-plugin-solidity": "^1.0.0-alpha.14" + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.0.0" + } + }, + "node_modules/solhint/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, "node_modules/solhint/node_modules/@solidity-parser/parser": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", - "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", + "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "dev": true + }, + "node_modules/solhint/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", "dev": true, "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" } }, "node_modules/solhint/node_modules/argparse": { @@ -30972,6 +31115,33 @@ "balanced-match": "^1.0.0" } }, + "node_modules/solhint/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/solhint/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/solhint/node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", @@ -30999,6 +31169,63 @@ "url": "https://github.com/sponsors/d-fischer" } }, + "node_modules/solhint/node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/solhint/node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/solhint/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/solhint/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -31018,6 +31245,44 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/solhint/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/solhint/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/solhint/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -31030,6 +31295,60 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/solhint/node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/solhint/node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/solhint/node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dev": true, + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/solhint/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -31042,11 +31361,114 @@ "node": ">=10" } }, - "node_modules/solidity-comments-extractor": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", - "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", - "dev": true + "node_modules/solhint/node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/solhint/node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dev": true, + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/solhint/node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/solhint/node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/solhint/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, "node_modules/solidity-coverage": { "version": "0.8.4", @@ -33003,7 +33425,6 @@ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", "dev": true, - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -33361,7 +33782,6 @@ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", "dev": true, - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -33656,6 +34076,22 @@ "node": ">=4" } }, + "node_modules/ts-generator/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/ts-generator/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -39252,6 +39688,39 @@ "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.4.0.tgz", "integrity": "sha512-dlKiZmDvJnGRLHojrDoFZJmsQVeltVeoiRN7RK+cf2FmkhASDEblE0RiaYdxPNsUZa6mRG8393b9bfyp+V5IAw==" }, + "@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true + }, + "@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "requires": { + "graceful-fs": "4.2.10" + } + }, + "@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dev": true, + "requires": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + } + }, + "@prettier/sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.3.0.tgz", + "integrity": "sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==", + "dev": true, + "requires": {} + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -40273,9 +40742,9 @@ "dev": true }, "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, "@types/http-errors": { @@ -40482,6 +40951,40 @@ "@types/sinon": "*" } }, + "@uniswap/lib": { + "version": "4.0.1-alpha", + "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-4.0.1-alpha.tgz", + "integrity": "sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==" + }, + "@uniswap/v2-core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@uniswap/v2-core/-/v2-core-1.0.1.tgz", + "integrity": "sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q==" + }, + "@uniswap/v3-core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.1.tgz", + "integrity": "sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ==" + }, + "@uniswap/v3-periphery": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@uniswap/v3-periphery/-/v3-periphery-1.4.4.tgz", + "integrity": "sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw==", + "requires": { + "@openzeppelin/contracts": "3.4.2-solc-0.7", + "@uniswap/lib": "^4.0.1-alpha", + "@uniswap/v2-core": "^1.0.1", + "@uniswap/v3-core": "^1.0.0", + "base64-sol": "1.0.1" + }, + "dependencies": { + "@openzeppelin/contracts": { + "version": "3.4.2-solc-0.7", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz", + "integrity": "sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA==" + } + } + }, "@vue/component-compiler-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", @@ -40525,6 +41028,13 @@ "source-map": "^0.6.1" } }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -41004,9 +41514,9 @@ "dev": true }, "antlr4": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.0.tgz", - "integrity": "sha512-zooUbt+UscjnWyOrsuY/tVFL4rwrAGwOivpQmvmUDE22hy/lUA467Rc1rcixyRwcRUIXFYBwv7+dClDSHdmmew==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", + "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==", "dev": true }, "antlr4ts": { @@ -41621,6 +42131,11 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "base64-sol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-sol/-/base64-sol-1.0.1.tgz", + "integrity": "sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg==" + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -42747,6 +43262,16 @@ } } }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -54036,9 +54561,9 @@ } }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "graphemer": { @@ -54610,9 +55135,9 @@ } }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-errors": { @@ -58809,9 +59334,9 @@ "dev": true }, "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true }, "prettier-linter-helpers": { @@ -58824,24 +59349,20 @@ } }, "prettier-plugin-solidity": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz", - "integrity": "sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.1.tgz", + "integrity": "sha512-Mq8EtfacVZ/0+uDKTtHZGW3Aa7vEbX/BNx63hmVg6YTiTXSiuKP0amj0G6pGwjmLaOfymWh3QgXEZkjQbU8QRg==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.16.0", - "semver": "^7.3.8", - "solidity-comments-extractor": "^0.0.7" + "@solidity-parser/parser": "^0.18.0", + "semver": "^7.5.4" }, "dependencies": { "@solidity-parser/parser": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", - "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", - "dev": true, - "requires": { - "antlr4ts": "^0.5.0-alpha.4" - } + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", + "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "dev": true }, "lru-cache": { "version": "6.0.0", @@ -58915,6 +59436,12 @@ "extend": "^3.0.0" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -60161,14 +60688,14 @@ } }, "solhint": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.1.tgz", - "integrity": "sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.3.tgz", + "integrity": "sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.16.0", + "@solidity-parser/parser": "^0.18.0", "ajv": "^6.12.6", - "antlr4": "^4.11.0", + "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", "chalk": "^4.1.2", "commander": "^10.0.0", @@ -60177,22 +60704,35 @@ "glob": "^8.0.3", "ignore": "^5.2.4", "js-yaml": "^4.1.0", + "latest-version": "^7.0.0", "lodash": "^4.17.21", "pluralize": "^8.0.0", "prettier": "^2.8.3", - "semver": "^6.3.0", + "semver": "^7.5.2", "strip-ansi": "^6.0.1", "table": "^6.8.1", "text-table": "^0.2.0" }, "dependencies": { + "@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true + }, "@solidity-parser/parser": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", - "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", + "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", "dev": true, "requires": { - "antlr4ts": "^0.5.0-alpha.4" + "defer-to-connect": "^2.0.1" } }, "argparse": { @@ -60210,6 +60750,27 @@ "balanced-match": "^1.0.0" } }, + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true + }, + "cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + } + }, "commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", @@ -60228,6 +60789,41 @@ "path-type": "^4.0.0" } }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, "glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -60241,6 +60837,35 @@ "once": "^1.3.0" } }, + "got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + } + }, + "http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -60250,6 +60875,42 @@ "argparse": "^2.0.1" } }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dev": true, + "requires": { + "package-json": "^8.1.0" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true + }, "minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -60258,24 +60919,83 @@ "requires": { "brace-expansion": "^2.0.1" } + }, + "normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dev": true, + "requires": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + } + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true + }, + "registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "requires": { + "@pnpm/npm-conf": "^2.1.0" + } + }, + "registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "requires": { + "rc": "1.2.8" + } + }, + "responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "requires": { + "lowercase-keys": "^3.0.0" + } + }, + "semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true } } }, "solhint-plugin-prettier": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz", - "integrity": "sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.1.0.tgz", + "integrity": "sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==", "dev": true, "requires": { + "@prettier/sync": "^0.3.0", "prettier-linter-helpers": "^1.0.0" } }, - "solidity-comments-extractor": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", - "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", - "dev": true - }, "solidity-coverage": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.4.tgz", @@ -62253,6 +62973,13 @@ "dev": true, "peer": true }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "peer": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/package.json b/package.json index 5db1dc85..f8a8e92c 100755 --- a/package.json +++ b/package.json @@ -31,7 +31,9 @@ "license": "LGPL-3.0-only", "repository": "https://github.com/zeriontech/defi-sdk", "dependencies": { - "@openzeppelin/contracts": "4.4.0" + "@openzeppelin/contracts": "4.4.0", + "@uniswap/v3-core": "^1.0.1", + "@uniswap/v3-periphery": "^1.4.4" }, "devDependencies": { "@babel/core": "7.22.9", @@ -42,8 +44,8 @@ "@matterlabs/hardhat-zksync-deploy": "^0.6.3", "@matterlabs/hardhat-zksync-solc": "^0.4.1", "@matterlabs/hardhat-zksync-verify": "^0.2.0", - "@nomiclabs/hardhat-ethers": "2.2.3", "@nomicfoundation/hardhat-verify": "1.1.1", + "@nomiclabs/hardhat-ethers": "2.2.3", "@nomiclabs/hardhat-waffle": "2.0.6", "@types/chai": "4.3.5", "@types/mocha": "10.0.1", @@ -64,11 +66,11 @@ "lint-staged": "11.0.0", "mrm": "3.0.10", "pinst": "2.1.6", - "prettier": "2.8.8", - "prettier-plugin-solidity": "1.1.3", + "prettier": "3.3.3", + "prettier-plugin-solidity": "1.4.1", "regenerator-runtime": "0.13.11", - "solhint": "3.4.1", - "solhint-plugin-prettier": "0.0.5", + "solhint": "5.0.3", + "solhint-plugin-prettier": "0.1.0", "solidity-coverage": "0.8.4", "truffle": "5.11.1", "ts-node": "10.9.1", diff --git a/scripts/4_deploy_uniswap_v2_caller copy.js b/scripts/4_deploy_uniswap_v2_caller copy.js new file mode 100644 index 00000000..520cb6ef --- /dev/null +++ b/scripts/4_deploy_uniswap_v2_caller copy.js @@ -0,0 +1,23 @@ +import deploymentAddresses from './deployment'; + +try { + (async () => { + console.log('Make sure 0x161b29D1919D4E06b53eE449376181B5082b30B9 is used and nonce is 3-6'); + + const chainIdHex = await hre.network.provider.request({ method: 'eth_chainId' }); + const chainId = parseInt(chainIdHex.toString(), 16).toString(); + + console.log(`Working with chainId ${chainId}`); + + // We get the contract to deploy + const Contract = await ethers.getContractFactory('UniswapV2Caller'); + const contract = await Contract.deploy(deploymentAddresses.weth[chainId]); + + console.log(`${'UniswapV2Caller'} deployed to: ${contract.address}`); + + return contract.address; + })(); +} catch (error) { + console.error(error); + process.exit(1); +} diff --git a/scripts/5_deploy_uniswap_v2_caller.js b/scripts/5_deploy_uniswap_v2_caller.js new file mode 100644 index 00000000..29561842 --- /dev/null +++ b/scripts/5_deploy_uniswap_v2_caller.js @@ -0,0 +1,23 @@ +import deploymentAddresses from './deployment'; + +try { + (async () => { + console.log('Make sure 0x161b29D1919D4E06b53eE449376181B5082b30B9 is used and nonce is 7'); + + const chainIdHex = await hre.network.provider.request({ method: 'eth_chainId' }); + const chainId = parseInt(chainIdHex.toString(), 16).toString(); + + console.log(`Working with chainId ${chainId}`); + + // We get the contract to deploy + const Contract = await ethers.getContractFactory('UniswapV3Caller'); + const contract = await Contract.deploy(deploymentAddresses.weth[chainId]); + + console.log(`${'UniswapV3Caller'} deployed to: ${contract.address}`); + + return contract.address; + })(); +} catch (error) { + console.error(error); + process.exit(1); +} diff --git a/scripts/4_verify.js b/scripts/6_verify.js similarity index 78% rename from scripts/4_verify.js rename to scripts/6_verify.js index 8782a48e..e3872d19 100644 --- a/scripts/4_verify.js +++ b/scripts/6_verify.js @@ -16,6 +16,12 @@ try { deploymentAddresses.weth[chainId], ], }); + await hre.run('verify:verify', { + address: deploymentAddresses.uniswapV3Caller[chainId], + constructorArguments: [ + deploymentAddresses.weth[chainId], + ], + }); })(); } catch (error) { console.error(error); diff --git a/scripts/deployment.js b/scripts/deployment.js index c564f661..e7660ef2 100644 --- a/scripts/deployment.js +++ b/scripts/deployment.js @@ -44,9 +44,16 @@ const deploymentAddresses = { 1313161554: '0xC629Bf86f02ef13E8F1f5F75adE8a8165587998F', }, uniswapV2Caller: { + 56: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', + 100: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', + 137: '0x53F5D89914327C3900FC2C9D297B9B30129F463e', + 250: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', 1101: '0xe76BA87E04555e1a5afcCb0c8c5AC4d0b29e3dBE', 5000: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', + 8453: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', 34443: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', + 42161: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', + 43114: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', 59144: '0xe76BA87E04555e1a5afcCb0c8c5AC4d0b29e3dBE', 81457: '0xC0AC45d01a64660629506b5889722C6dA25F4084', 167000: '0xE81B24bcD0a706ae3Ece36C42CF96c010EEeF37a', @@ -55,9 +62,16 @@ const deploymentAddresses = { 666666666: '0xe76BA87E04555e1a5afcCb0c8c5AC4d0b29e3dBE', }, weth: { + 56: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', + 100: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', + 137: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', + 250: '0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83', 1101: '0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9', 5000: '0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111', + 8453: '0x4200000000000000000000000000000000000006', 34443: '0x4200000000000000000000000000000000000006', + 42161: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + 43114: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', 59144: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', 81457: '0x4300000000000000000000000000000000000004', 167000: '0xA51894664A773981C6C112C43ce576f315d5b1B6', diff --git a/test/callers/UniswapV2Caller.js b/test/callers/UniswapV2Caller.js index 792fa3f2..322c02d8 100644 --- a/test/callers/UniswapV2Caller.js +++ b/test/callers/UniswapV2Caller.js @@ -1,4 +1,5 @@ import buyTokenOnUniswap from '../helpers/buyTokenOnUniswap'; +import logChange from '../helpers/logger'; import { wethAddress, ethAddress, daiAddress } from '../helpers/tokens'; const { expect } = require('chai'); @@ -28,6 +29,21 @@ describe('UniswapV2Caller', () => { const logger = new ethers.utils.Logger('1'); const abiCoder = new ethers.utils.AbiCoder(); + async function execute(i, out, sp, as, fs, opt = {}) { + const ethBefore = await owner.getBalance(); + const daiBefore = await dai.balanceOf(owner.address); + const wethBefore = await weth.balanceOf(owner.address); + + const tx = await router.functions.execute(i, out, sp, as, fs, opt); + const receipt = await tx.wait(); + + logger.info(`Called router for ${receipt.gasUsed} gas`); + + logChange(logger, 'eth', ethBefore, (await owner.getBalance()).add(receipt.gasUsed.mul(receipt.effectiveGasPrice))); + logChange(logger, 'dai', daiBefore, await dai.balanceOf(owner.address)); + logChange(logger, 'weth', wethBefore, await weth.balanceOf(owner.address)); + } + before(async () => { // await network.provider.request({ // method: "hardhat_reset", @@ -70,11 +86,11 @@ describe('UniswapV2Caller', () => { beforeEach(async () => { router = await Router.deploy(); + await router.setProtocolFeeDefault(protocolFeeDefault); }); it('should not do weth -> dai trade with high slippage', async () => { await weth.approve(router.address, ethers.utils.parseUnits('1', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( @@ -111,15 +127,8 @@ describe('UniswapV2Caller', () => { it('should do weth -> dai trade', async () => { await weth.approve(router.address, ethers.utils.parseUnits('1', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); - logger.info( - `weth balance is ${ethers.utils.formatUnits(await weth.balanceOf(owner.address), 18)}`, - ); - const tx = await router.functions.execute( + await execute( // input [[weth.address, ethers.utils.parseUnits('1', 18), AMOUNT_ABSOLUTE], zeroPermit], // output @@ -148,22 +157,10 @@ describe('UniswapV2Caller', () => { // fee signature zeroSignature, ); - logger.info(`Called router for ${(await tx.wait()).gasUsed} gas`); - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); - logger.info( - `weth balance is ${ethers.utils.formatUnits(await weth.balanceOf(owner.address), 18)}`, - ); }); it('should do eth -> dai trade', async () => { - await router.setProtocolFeeDefault(protocolFeeDefault); - - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); - const tx = await router.functions.execute( + await execute( // input [[ethAddress, ethers.utils.parseUnits('1', 18), AMOUNT_ABSOLUTE], zeroPermit], // output @@ -195,15 +192,9 @@ describe('UniswapV2Caller', () => { value: ethers.utils.parseEther('1'), }, ); - logger.info(`Called router for ${(await tx.wait()).gasUsed} gas`); - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); }); it('should not do eth -> dai trade with too large marketplace fee', async () => { - await router.setProtocolFeeDefault(protocolFeeDefault); - await expect( router.functions.execute( // input @@ -241,8 +232,6 @@ describe('UniswapV2Caller', () => { }); it('should not do eth -> dai trade with high slippage', async () => { - await router.setProtocolFeeDefault(protocolFeeDefault); - await expect( router.functions.execute( // input @@ -279,9 +268,8 @@ describe('UniswapV2Caller', () => { ).to.be.reverted; }); - it('should do dai -> eth trade with 0 input', async () => { + it('should not do dai -> eth trade with 0 input', async () => { await dai.approve(router.address, ethers.utils.parseUnits('500', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( @@ -318,12 +306,8 @@ describe('UniswapV2Caller', () => { it.only('should do dai -> eth trade', async () => { await dai.approve(router.address, ethers.utils.parseUnits('500', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); - const tx = await router.functions.execute( + await execute( // input [[daiAddress, ethers.utils.parseUnits('500', 18), AMOUNT_ABSOLUTE], zeroPermit], // output @@ -352,15 +336,10 @@ describe('UniswapV2Caller', () => { // fee signature zeroSignature, ); - logger.info(`Called router for ${(await tx.wait()).gasUsed} gas`); - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); }); - it('should do dai -> weth trade with 0 output', async () => { + it('should not do dai -> weth trade with 0 output', async () => { await dai.approve(router.address, ethers.utils.parseUnits('500', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( @@ -397,7 +376,6 @@ describe('UniswapV2Caller', () => { it('should not do dai -> weth trade with empty path', async () => { await dai.approve(router.address, ethers.utils.parseUnits('1', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( @@ -434,7 +412,6 @@ describe('UniswapV2Caller', () => { it('should not do dai -> weth trade with bad directions length', async () => { await dai.approve(router.address, ethers.utils.parseUnits('5000', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( @@ -471,7 +448,6 @@ describe('UniswapV2Caller', () => { it('should not do dai -> weth trade with huge fee', async () => { await dai.approve(router.address, ethers.utils.parseUnits('5000', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( @@ -508,15 +484,8 @@ describe('UniswapV2Caller', () => { it('should do dai -> weth trade', async () => { await dai.approve(router.address, ethers.utils.parseUnits('500', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); - logger.info( - `weth balance is ${ethers.utils.formatUnits(await weth.balanceOf(owner.address), 18)}`, - ); - const tx = await router.functions.execute( + await execute( // input [[daiAddress, ethers.utils.parseUnits('500', 18), AMOUNT_ABSOLUTE], zeroPermit], // output @@ -545,18 +514,10 @@ describe('UniswapV2Caller', () => { // fee signature zeroSignature, ); - logger.info(`Called router for ${(await tx.wait()).gasUsed} gas`); - logger.info( - `dai balance is ${ethers.utils.formatUnits(await dai.balanceOf(owner.address), 18)}`, - ); - logger.info( - `weth balance is ${ethers.utils.formatUnits(await weth.balanceOf(owner.address), 18)}`, - ); }); it('should not do dai -> weth trade with high token slippage', async () => { await dai.approve(router.address, ethers.utils.parseUnits('500', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( @@ -593,7 +554,6 @@ describe('UniswapV2Caller', () => { it('should not do dai -> weth trade with not enough liquidity', async () => { await dai.approve(router.address, ethers.utils.parseUnits('500', 18)); - await router.setProtocolFeeDefault(protocolFeeDefault); await expect( router.functions.execute( diff --git a/test/callers/UniswapV3Caller.js b/test/callers/UniswapV3Caller.js new file mode 100644 index 00000000..6ede88bc --- /dev/null +++ b/test/callers/UniswapV3Caller.js @@ -0,0 +1,288 @@ +import buyTokenOnUniswap from '../helpers/buyTokenOnUniswap'; +import logChange from '../helpers/logger'; +import { wethAddress, ethAddress, daiAddress } from '../helpers/tokens'; + +const { ethers } = require('hardhat'); + +const AMOUNT_ABSOLUTE = 2; +const SWAP_FIXED_INPUTS = 1; +const SWAP_FIXED_OUTPUTS = 2; +const EMPTY_BYTES = '0x'; + +const uniDaiWethAddress = '0xC2e9F25Be6257c210d7Adf0D4Cd6E3E881ba25f8'; + +const zeroPermit = ['0', EMPTY_BYTES]; +const zeroSignature = ['0', EMPTY_BYTES]; + +describe('UniswapV3Caller', () => { + let owner; + let notOwner; + let caller; + let Router; + let Caller; + let router; + let weth; + let dai; + let protocolFeeDefault; + const logger = new ethers.utils.Logger('1'); + const abiCoder = new ethers.utils.AbiCoder(); + + async function execute(i, out, sp, as, fs, opt = {}) { + const ethBefore = await owner.getBalance(); + const daiBefore = await dai.balanceOf(owner.address); + const wethBefore = await weth.balanceOf(owner.address); + + const tx = await router.functions.execute(i, out, sp, as, fs, opt); + const receipt = await tx.wait(); + + logger.info(`Called router for ${receipt.gasUsed} gas`); + + logChange(logger, 'eth', ethBefore, (await owner.getBalance()).add(receipt.gasUsed.mul(receipt.effectiveGasPrice))); + logChange(logger, 'dai', daiBefore, await dai.balanceOf(owner.address)); + logChange(logger, 'weth', wethBefore, await weth.balanceOf(owner.address)); + } + + before(async () => { + // await network.provider.request({ + // method: "hardhat_reset", + // params: [ + // { + // forking: { + // jsonRpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, + // }, + // }, + // ], + // }); + + Caller = await ethers.getContractFactory('UniswapV3Caller'); + Router = await ethers.getContractFactory('Router'); + + [owner, notOwner] = await ethers.getSigners(); + + const weth9 = await ethers.getContractAt('IWETH9', wethAddress); + + await weth9.deposit({ + value: ethers.utils.parseEther('2'), + gasLimit: 1000000, + }); + + caller = await Caller.deploy(wethAddress); + + weth = await ethers.getContractAt('IERC20', wethAddress, owner); + dai = await ethers.getContractAt('IERC20', daiAddress, owner); + + await buyTokenOnUniswap(owner, daiAddress); + protocolFeeDefault = [ethers.utils.parseUnits('0', 18), notOwner.address]; + }); + + beforeEach(async () => { + router = await Router.deploy(); + await router.setProtocolFeeDefault(protocolFeeDefault); + }); + + it('should do eth -> dai trade fixed inputs', async () => { + await execute( + // input + [[ethAddress, ethers.utils.parseUnits('1', 18), AMOUNT_ABSOLUTE], zeroPermit], + // output + [daiAddress, ethers.utils.parseUnits('1000', 18)], + // swap description + [ + SWAP_FIXED_INPUTS, + protocolFeeDefault, + protocolFeeDefault, + owner.address, + caller.address, + abiCoder.encode( + ['address', 'address', 'address', 'bool', 'uint256', 'bool'], + [ + ethAddress, + daiAddress, + uniDaiWethAddress, + false, + ethers.utils.parseUnits('1', 18), + true, + ], + ), + ], + // account signature + zeroSignature, + // fee signature + zeroSignature, + { + value: ethers.utils.parseEther('1'), + }, + ); + }); + + it('should do dai -> eth trade fixed inputs', async () => { + await dai.approve(router.address, ethers.utils.parseUnits('1000', 18)); + + await execute( + // input + [[daiAddress, ethers.utils.parseUnits('1000', 18), AMOUNT_ABSOLUTE], zeroPermit], + // output + [ethAddress, ethers.utils.parseUnits('0.1', 18)], + // swap description + [ + SWAP_FIXED_INPUTS, + protocolFeeDefault, + protocolFeeDefault, + owner.address, + caller.address, + abiCoder.encode( + ['address', 'address', 'address', 'bool', 'uint256', 'bool'], + [ + daiAddress, + ethAddress, + uniDaiWethAddress, + true, + ethers.utils.parseUnits('1000', 18), + true, + ], + ), + ], + // account signature + zeroSignature, + // fee signature + zeroSignature, + ); + }); + + it('should do weth -> dai trade fixed inputs', async () => { + await weth.approve(router.address, ethers.utils.parseUnits('1', 18)); + + await execute( + // input + [[wethAddress, ethers.utils.parseUnits('1', 18), AMOUNT_ABSOLUTE], zeroPermit], + // output + [daiAddress, ethers.utils.parseUnits('1000', 18)], + // swap description + [ + SWAP_FIXED_INPUTS, + protocolFeeDefault, + protocolFeeDefault, + owner.address, + caller.address, + abiCoder.encode( + ['address', 'address', 'address', 'bool', 'uint256', 'bool'], + [ + wethAddress, + daiAddress, + uniDaiWethAddress, + false, + ethers.utils.parseUnits('1', 18), + true, + ], + ), + ], + // account signature + zeroSignature, + // fee signature + zeroSignature, + ); + }); + + it('should do eth -> dai trade fixed outputs', async () => { + await execute( + // input + [[ethAddress, ethers.utils.parseUnits('1', 18), AMOUNT_ABSOLUTE], zeroPermit], + // output + [daiAddress, ethers.utils.parseUnits('1000', 18)], + // swap description + [ + SWAP_FIXED_OUTPUTS, + protocolFeeDefault, + protocolFeeDefault, + owner.address, + caller.address, + abiCoder.encode( + ['address', 'address', 'address', 'bool', 'uint256', 'bool'], + [ + ethAddress, + daiAddress, + uniDaiWethAddress, + false, + ethers.utils.parseUnits('1000', 18), + false, + ], + ), + ], + // account signature + zeroSignature, + // fee signature + zeroSignature, + { + value: ethers.utils.parseEther('1'), + }, + ); + }); + + it('should do dai -> eth trade fixed outputs', async () => { + await dai.approve(router.address, ethers.utils.parseUnits('1000', 18)); + + await execute( + // input + [[daiAddress, ethers.utils.parseUnits('1000', 18), AMOUNT_ABSOLUTE], zeroPermit], + // output + [ethAddress, ethers.utils.parseUnits('0.1', 18)], + // swap description + [ + SWAP_FIXED_OUTPUTS, + protocolFeeDefault, + protocolFeeDefault, + owner.address, + caller.address, + abiCoder.encode( + ['address', 'address', 'address', 'bool', 'uint256', 'bool'], + [ + daiAddress, + ethAddress, + uniDaiWethAddress, + true, + ethers.utils.parseUnits('0.1', 18), + false, + ], + ), + ], + // account signature + zeroSignature, + // fee signature + zeroSignature, + ); + }); + + it('should do weth -> dai trade fixed outputs', async () => { + await weth.approve(router.address, ethers.utils.parseUnits('1', 18)); + + await execute( + // input + [[wethAddress, ethers.utils.parseUnits('1', 18), AMOUNT_ABSOLUTE], zeroPermit], + // output + [daiAddress, ethers.utils.parseUnits('1000', 18)], + // swap description + [ + SWAP_FIXED_OUTPUTS, + protocolFeeDefault, + protocolFeeDefault, + owner.address, + caller.address, + abiCoder.encode( + ['address', 'address', 'address', 'bool', 'uint256', 'bool'], + [ + wethAddress, + daiAddress, + uniDaiWethAddress, + false, + ethers.utils.parseUnits('1000', 18), + false, + ], + ), + ], + // account signature + zeroSignature, + // fee signature + zeroSignature, + ); + }); +}); diff --git a/test/helpers/latestTime.js b/test/helpers/latestTime.js index 2f6e4cd1..ed312b26 100755 --- a/test/helpers/latestTime.js +++ b/test/helpers/latestTime.js @@ -1,7 +1,7 @@ // Returns the time of the last mined block in seconds -async function latestTime() { +const latestTime = async () => { const block = await web3.eth.getBlock('latest'); return block.timestamp; -} +}; export default latestTime; diff --git a/test/helpers/logger.js b/test/helpers/logger.js new file mode 100644 index 00000000..05e724f3 --- /dev/null +++ b/test/helpers/logger.js @@ -0,0 +1,11 @@ +const { ethers } = require('hardhat'); + +const logChange = (logger, name, before, after) => { + if (!before.eq(after)) { + logger.info( + `${name} balance change is ${before.gt(after) ? '-' : '+'}${ethers.utils.formatUnits(before.gt(after) ? before.sub(after) : after.sub(before), 18)}`, + ); + } +}; + +export default logChange; diff --git a/test/router/Router.js b/test/router/Router.js index 1f2bb983..af6d3abc 100644 --- a/test/router/Router.js +++ b/test/router/Router.js @@ -270,6 +270,23 @@ describe('Router', () => { ).to.be.reverted; }); + it('should not execute with bad amount type', async () => { + await expect( + router.functions.execute( + // input + [[AddressZero, ethers.utils.parseUnits('0', 18), '0'], zeroPermit], + // output + [ethAddress, '0'], + // swap description + [SWAP_FIXED_INPUTS, zeroFee, zeroFee, owner.address, mockCaller.address, EMPTY_BYTES], + // account signature + zeroSignature, + // fee signature + zeroSignature, + ), + ).to.be.reverted; + }); + it('should not execute with relative amount for ETH', async () => { await expect( router.functions.execute(