diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c93e107 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,47 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + ci: + runs-on: ubuntu-latest + steps: + - name: Install ZKSync Foundry + run: curl -L https://raw.githubusercontent.com/matter-labs/foundry-zksync/main/install-foundry-zksync | bash + + - name: Check out the repo + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install Dependencies + run: pnpm install + + - name: Build Hardhat + run: pnpm compile + + - name: Style + run: pnpm style + + - name: Forge Build + run: pnpm forge-build + + - name: Forge Fmt + run: pnpm forge-fmt + + - name: Test Hardhat + run: pnpm test:hardhat + + - name: Forge Test + run: pnpm test:forge + + + diff --git a/contracts/Rewards/test/TestSetup.sol b/contracts/Rewards/test/TestSetup.sol index 5027859..c200f63 100644 --- a/contracts/Rewards/test/TestSetup.sol +++ b/contracts/Rewards/test/TestSetup.sol @@ -26,17 +26,22 @@ contract TestSetup is Test { bytes4 panic = 0x4e487b71; bytes overflow = abi.encodePacked(panic, bytes32(uint256(0x11))); - StakingContractMainnet stakingContract = new StakingContractMainnet(); + StakingContractMainnet stakingContract; - Token tokenA = new Token(); - Token tokenB = new Token(); - Token tokenC = new Token(); + Token tokenA; + Token tokenB; + Token tokenC; uint256 pastIncentive; uint256 ongoingIncentive; uint256 futureIncentive; function setUp() public { + stakingContract = new StakingContractMainnet(); + tokenA = new Token(); + tokenB = new Token(); + tokenC = new Token(); + tokenA.mint(MAX_UINT256); tokenB.mint(MAX_UINT256); tokenC.mint(MAX_UINT256); diff --git a/contracts/Router/test/MagicSwapV2Router.t.sol b/contracts/Router/test/MagicSwapV2Router.t.sol index ae4be2f..30d1760 100644 --- a/contracts/Router/test/MagicSwapV2Router.t.sol +++ b/contracts/Router/test/MagicSwapV2Router.t.sol @@ -1,25 +1,29 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.20; -import "forge-std/Test.sol"; +import {console2, Test} from "forge-std/Test.sol"; -import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; -import "lib/ERC721Mintable.sol"; -import "lib/ERC1155Mintable.sol"; +import {ERC721Mintable} from "lib/ERC721Mintable.sol"; +import {ERC1155Mintable} from "lib/ERC1155Mintable.sol"; -import "./mock/WETH.sol"; -import "../MagicSwapV2Router.sol"; -import "../../UniswapV2/core/UniswapV2Factory.sol"; -import "../../Vault/NftVaultFactory.sol"; +import {WETH} from "./mock/WETH.sol"; +import { IMagicSwapV2Router, MagicSwapV2Router} from "../MagicSwapV2Router.sol"; +import {UniswapV2Factory} from "../../UniswapV2/core/UniswapV2Factory.sol"; +import {IUniswapV2Router01} from "../../UniswapV2/periphery/interfaces/IUniswapV2Router01.sol"; +import {NftVaultFactory, INftVault} from "../../Vault/NftVaultFactory.sol"; +import {TestHelper} from "../../test/TestHelper.sol"; +import {TestUniswapV2LibraryContract} from "../../test/TestUniswapV2LibraryContract.sol"; -contract MagicSwapV2RouterTest is Test { +contract MagicSwapV2RouterTest is Test, TestHelper { WETH weth; UniswapV2Factory factory; MagicSwapV2Router magicSwapV2Router; NftVaultFactory nftVaultFactory; ERC721Mintable nft1; ERC1155Mintable nft2; + TestUniswapV2LibraryContract uniswapV2Library; uint256 ONE; @@ -49,9 +53,14 @@ contract MagicSwapV2RouterTest is Test { function setUp() public { weth = new WETH(); + uniswapV2Library = new TestUniswapV2LibraryContract(); + patchUniswapV2Library(address(uniswapV2Library), "TestUniswapV2LibraryContract.sol", ""); + factory = new UniswapV2Factory(0, 30, protocolFeeBeneficiary); magicSwapV2Router = new MagicSwapV2Router(address(factory), address(weth)); + bytes memory args = abi.encode(address(factory), address(weth)); + patchUniswapV2Library(address(magicSwapV2Router), "MagicSwapV2Router.sol", args); nftVaultFactory = new NftVaultFactory(); @@ -123,7 +132,7 @@ contract MagicSwapV2RouterTest is Test { uint256[] memory _tokenId, uint256[] memory _amount, address _owner - ) public { + ) public view { for (uint256 i = 0; i < _collection.length; i++) { if (_collection[i] == address(nft1)) { assertEq(nft1.ownerOf(_tokenId[i]), _owner); @@ -140,7 +149,7 @@ contract MagicSwapV2RouterTest is Test { address _vault, address _owner, uint256 _prevBalance - ) public { + ) public view { uint256 totalAmount; for (uint256 i = 0; i < _collection.length; i++) { @@ -277,7 +286,7 @@ contract MagicSwapV2RouterTest is Test { assertEq(amountA1, nftAmountToERC20(_amount1)); assertEq(amountB1, amountBDesired1); - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); assertEq(weth.balanceOf(pair), amountB1); _checkNftBalances(_collection1, _tokenId1, _amount1, address(vault2)); @@ -345,7 +354,6 @@ contract MagicSwapV2RouterTest is Test { } function testAddLiquidityNFTETH(uint256 _tokenId, uint256 _amount) public { - console2.logBytes32(keccak256(type(UniswapV2Pair).creationCode)); vm.assume(_tokenId < type(uint256).max - 100); vm.assume(_amount > 0); vm.assume(_amount < type(uint112).max / ONE / 10); @@ -380,7 +388,7 @@ contract MagicSwapV2RouterTest is Test { assertEq(amountA1, nftAmountToERC20(_amount1)); assertEq(amountB1, amountBDesired1); - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); assertEq(weth.balanceOf(pair), amountB1); _checkNftBalances(_collection1, _tokenId1, _amount1, address(vault2)); @@ -495,7 +503,7 @@ contract MagicSwapV2RouterTest is Test { assertEq(amountB1, nftAmountToERC20(_amountB1)); // All vault tokens were transferred to the pair - pair = UniswapV2Library.pairFor(address(factory), address(vault1), address(vault2)); + pair = uniswapV2Library.pairFor(address(factory), address(vault1), address(vault2)); assertEq(IERC20(address(vault1)).balanceOf(pair), amountA1); assertEq(IERC20(address(vault2)).balanceOf(pair), amountB1); @@ -621,7 +629,7 @@ contract MagicSwapV2RouterTest is Test { ); } - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); vm.prank(user1); IERC20(pair).approve(address(magicSwapV2Router), lpAmount1); @@ -777,7 +785,7 @@ contract MagicSwapV2RouterTest is Test { ); } - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); vm.prank(user1); IERC20(pair).approve(address(magicSwapV2Router), lpAmount1); @@ -969,10 +977,10 @@ contract MagicSwapV2RouterTest is Test { path[1] = address(weth); (uint256 reserveVault, uint256 reserveWeth) = - UniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + uniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); uint256 amountIn = nftAmountToERC20(_amount1); - uint256 amountOut = UniswapV2Library.getAmountOut(amountIn, reserveVault, reserveWeth, pair, address(factory)); + uint256 amountOut = uniswapV2Library.getAmountOut(amountIn, reserveVault, reserveWeth, pair, address(factory)); uint256 amountOutMin = amountOut; vm.prank(user2); @@ -1014,10 +1022,10 @@ contract MagicSwapV2RouterTest is Test { wrongPath[1] = address(vault1); (uint256 reserveVault, uint256 reserveWeth) = - UniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + uniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); uint256 amountIn = nftAmountToERC20(_amount1); - uint256 amountOut = UniswapV2Library.getAmountOut(amountIn, reserveVault, reserveWeth, pair, address(factory)); + uint256 amountOut = uniswapV2Library.getAmountOut(amountIn, reserveVault, reserveWeth, pair, address(factory)); uint256 amountOutMin = amountOut; uint256 prevETHBalance = user2.balance; @@ -1065,10 +1073,10 @@ contract MagicSwapV2RouterTest is Test { path[1] = address(vault2); (uint256 reserveVault, uint256 reserveWeth) = - UniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + uniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); uint256 amountOut = nftAmountToERC20(_amount1); - uint256 amountIn = UniswapV2Library.getAmountIn(amountOut, reserveWeth, reserveVault, pair, address(factory)); + uint256 amountIn = uniswapV2Library.getAmountIn(amountOut, reserveWeth, reserveVault, pair, address(factory)); uint256 amountInMax = amountIn; _dealWeth(user2, amountIn); @@ -1111,10 +1119,10 @@ contract MagicSwapV2RouterTest is Test { path[1] = address(vault2); (uint256 reserveVault, uint256 reserveWeth) = - UniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); - address pair = UniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); + uniswapV2Library.getReserves(address(factory), address(vault2), address(weth)); + address pair = uniswapV2Library.pairFor(address(factory), address(vault2), address(weth)); uint256 amountOut = nftAmountToERC20(_amount1); - uint256 amountIn = UniswapV2Library.getAmountIn(amountOut, reserveWeth, reserveVault, pair, address(factory)); + uint256 amountIn = uniswapV2Library.getAmountIn(amountOut, reserveWeth, reserveVault, pair, address(factory)); uint256 dust = 1e18; vm.deal(user2, amountIn + dust); @@ -1168,7 +1176,7 @@ contract MagicSwapV2RouterTest is Test { uint256 amountOut; { amountIn = nftAmountToERC20(_amountIn); - uint256[] memory amounts = UniswapV2Library.getAmountsOut(address(factory), amountIn, path); + uint256[] memory amounts = uniswapV2Library.getAmountsOut(address(factory), amountIn, path); amountOut = amounts[amounts.length - 1]; console2.log("amountOut", amountOut); } @@ -1180,7 +1188,7 @@ contract MagicSwapV2RouterTest is Test { uint256 prevPairVault2Balance; { - address pair = UniswapV2Library.pairFor(address(factory), path[1], path[2]); + address pair = uniswapV2Library.pairFor(address(factory), path[1], path[2]); prevPairVault2Balance = IERC20(address(vault2)).balanceOf(pair); } @@ -1198,7 +1206,7 @@ contract MagicSwapV2RouterTest is Test { console2.log("dust", dust); assertTrue(dust > 0); assertEq( - IERC20(address(vault2)).balanceOf(UniswapV2Library.pairFor(address(factory), path[1], path[2])), + IERC20(address(vault2)).balanceOf(uniswapV2Library.pairFor(address(factory), path[1], path[2])), prevPairVault2Balance - amountOut + dust ); diff --git a/contracts/UniswapV2/core/test/Oracle.t.sol b/contracts/UniswapV2/core/test/Oracle.t.sol index cf420a4..a1cf084 100644 --- a/contracts/UniswapV2/core/test/Oracle.t.sol +++ b/contracts/UniswapV2/core/test/Oracle.t.sol @@ -24,15 +24,19 @@ contract OracleTest is Test { UniswapV2Pair public pair; UniswapV2Factory factory; - ERC20Mintable public DAI = new ERC20Mintable(); - ERC20Mintable public WETH = new ERC20Mintable(); - OracleImpl public oracleImpl = new OracleImpl(); + ERC20Mintable public DAI; + ERC20Mintable public WETH; + OracleImpl public oracleImpl; address user1 = address(10000001); address protocolFeeBeneficiary = address(10000005); function setUp() public { + DAI = new ERC20Mintable(); + WETH = new ERC20Mintable(); + oracleImpl = new OracleImpl(); + vm.warp(TIMESTAMP); factory = new UniswapV2Factory(150, 30, protocolFeeBeneficiary); diff --git a/contracts/UniswapV2/core/test/UniswapV2Factory.t.sol b/contracts/UniswapV2/core/test/UniswapV2Factory.t.sol index b7008c0..77ca1a2 100644 --- a/contracts/UniswapV2/core/test/UniswapV2Factory.t.sol +++ b/contracts/UniswapV2/core/test/UniswapV2Factory.t.sol @@ -1,16 +1,17 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.20; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; -import "lib/ERC20Mintable.sol"; +import {ERC20} from "lib/ERC20Mintable.sol"; -import "../UniswapV2Factory.sol"; -import "../../periphery/libraries/UniswapV2Library.sol"; +import {IUniswapV2Factory, UniswapV2Factory} from "../UniswapV2Factory.sol"; +import {TestUniswapV2LibraryContract} from "../../../test/TestUniswapV2LibraryContract.sol"; +import {TestHelper} from "../../../test/TestHelper.sol"; -contract UniswapV2FactoryTest is Test { +contract UniswapV2FactoryTest is Test, TestHelper { UniswapV2Factory factory; - + TestUniswapV2LibraryContract uniswapV2Library; address pool1; address hacker = address(10000004); address owner = address(10000005); @@ -31,6 +32,10 @@ contract UniswapV2FactoryTest is Test { event ProtocolFeeBeneficiarySet(address beneficiary); function setUp() public { + uniswapV2Library = new TestUniswapV2LibraryContract(); + bytes memory args = abi.encode(); + patchUniswapV2Library(address(uniswapV2Library), "TestUniswapV2LibraryContract.sol", args); + vm.prank(owner); factory = new UniswapV2Factory(0, 0, protocolFeeBeneficiary); @@ -334,7 +339,7 @@ contract UniswapV2FactoryTest is Test { /// @notice we cannot test the create2 address, because the foundry and hardhat generated bytecode /// is different which makes both the hash and the address different - function testCreatePair(address _tokenA, address _tokenB) public { + function testCreatePairUni(address _tokenA, address _tokenB) public { vm.assume(_tokenA != address(0)); vm.assume(_tokenB != address(0)); vm.assume(_tokenA != _tokenB); @@ -342,11 +347,11 @@ contract UniswapV2FactoryTest is Test { vm.mockCall(_tokenA, abi.encodeCall(ERC20.decimals, ()), abi.encode(18)); vm.mockCall(_tokenB, abi.encodeCall(ERC20.decimals, ()), abi.encode(18)); - (address token0, address token1) = UniswapV2Library.sortTokens(_tokenA, _tokenB); - // address expectedPair = UniswapV2Library.pairFor(address(factory), _tokenA, _tokenB); + (address token0, address token1) = uniswapV2Library.sortTokens(_tokenA, _tokenB); + address expectedPair = uniswapV2Library.pairFor(address(factory), _tokenA, _tokenB); - // vm.expectEmit(true, true, true, true); - // emit PairCreated(token0, token1, expectedPair, 2); + vm.expectEmit(true, true, true, true); + emit PairCreated(token0, token1, expectedPair, 2); address pair = factory.createPair(_tokenA, _tokenB); // assertEq(pair, expectedPair); diff --git a/contracts/UniswapV2/periphery/libraries/UniswapV2Library.sol b/contracts/UniswapV2/periphery/libraries/UniswapV2Library.sol index 5fc56e6..90446bc 100644 --- a/contracts/UniswapV2/periphery/libraries/UniswapV2Library.sol +++ b/contracts/UniswapV2/periphery/libraries/UniswapV2Library.sol @@ -11,6 +11,8 @@ import "../../core/libraries/SafeMath.sol"; library UniswapV2Library { using SafeMath for uint256; + bytes32 constant INIT_CODE_HASH = hex'010004df694643e2d7e17535f16c21e9d1698b06c2ef330166830639b23b7f43'; + /// @dev returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); @@ -28,7 +30,7 @@ library UniswapV2Library { bytes32(0x2020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494), // keccak256("zksyncCreate2") bytes32(uint256(uint160(factory))), // sender keccak256(abi.encodePacked(token0, token1)), // salt - hex'010004df694643e2d7e17535f16c21e9d1698b06c2ef330166830639b23b7f43', // init code hash + INIT_CODE_HASH, bytes32(0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) // constructor input hash: keccak256("") ) ) diff --git a/contracts/Vault/test/NftVault.t.sol b/contracts/Vault/test/NftVault.t.sol index f045a2a..8fe13be 100644 --- a/contracts/Vault/test/NftVault.t.sol +++ b/contracts/Vault/test/NftVault.t.sol @@ -11,7 +11,7 @@ import "../NftVault.sol"; import "../NftVaultFactory.sol"; contract NftVaultTest is Test { - NftVaultFactory public nftVaultFactory = new NftVaultFactory(); + NftVaultFactory public nftVaultFactory; address user1 = address(1001); address user2 = address(1002); @@ -39,6 +39,7 @@ contract NftVaultTest is Test { event Deposit(address indexed to, address indexed collection, uint256 tokenId, uint256 amount); function setUp() public { + nftVaultFactory = new NftVaultFactory(); collectionERC721all = INftVault.CollectionData({ addr: address(new ERC721Mintable()), nftType: INftVault.NftType.ERC721, diff --git a/contracts/test/TestHelper.sol b/contracts/test/TestHelper.sol new file mode 100644 index 0000000..e3c7104 --- /dev/null +++ b/contracts/test/TestHelper.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import {Test} from "forge-std/Test.sol"; + +contract TestHelper is Test { + function patchUniswapV2Library(address contractUsingUniswapV2Library, string memory contractFilename, bytes memory args) + public + { + bytes memory bytecode = abi.encodePacked(vm.getCode(contractFilename), args); + + bytes32 ORIGINAL_INIT_CODE_HASH = 0x010004df694643e2d7e17535f16c21e9d1698b06c2ef330166830639b23b7f43; + bytes32 NEW_INIT_CODE_HASH = 0x010004dba4c88c36b9cf5b708cdea396e454c1d162b487daa289669537fe8f0d; + + // bytecode = contractUsingUniswapV2Library.code; + bytecode = veryBadBytesReplacer(bytecode, ORIGINAL_INIT_CODE_HASH, NEW_INIT_CODE_HASH); + vm.etch(contractUsingUniswapV2Library, bytecode); + } + + /** + * @dev Non-optimised code to replace a certain 32 bytes sequence in a longer bytes object. + * @dev Assumes the 32 bytes sequence is exactly once present in the bytes object. + * Reverts if it is not present and only replaces first occurrence if present multiple times. + */ + function veryBadBytesReplacer(bytes memory bytecode, bytes32 target, bytes32 replacement) + internal + pure + returns (bytes memory result) + { + result = veryBadBytesReplacer(bytecode, abi.encodePacked(target), abi.encodePacked(replacement)); + } + + function veryBadBytesReplacer(bytes memory bytecode, bytes memory target, bytes memory replacement) + internal + pure + returns (bytes memory result) + { + require(target.length <= bytecode.length); + require(target.length == replacement.length); + + uint256 lengthTarget = target.length; + uint256 lengthBytecode = bytecode.length - lengthTarget + 1; + uint256 i; + for (i; i < lengthBytecode;) { + uint256 j = 0; + for (j; j < lengthTarget;) { + if (bytecode[i + j] == target[j]) { + if (j == lengthTarget - 1) { + // Target found, replace with replacement, and return result. + return result = replaceBytes(bytecode, replacement, i); + } + } else { + break; + } + unchecked { + ++j; + } + } + + unchecked { + ++i; + } + } + // Should always find one single match. -> revert if not. + revert(); + } + + function veryBadBytesReplacer( + bytes memory bytecode, + bytes memory target, + bytes memory replacement, + bool replaceFirstOnly + ) internal pure returns (bytes memory) { + require(target.length <= bytecode.length); + require(target.length == replacement.length); + + uint256 lengthTarget = target.length; + uint256 lengthBytecode = bytecode.length - lengthTarget + 1; + for (uint256 i; i < lengthBytecode; ++i) { + uint256 j = 0; + for (j; j < lengthTarget; ++j) { + if (bytecode[i + j] == target[j]) { + if (j == lengthTarget - 1) { + // Target found, replace with replacement. + bytecode = replaceBytes(bytecode, replacement, i); + if (replaceFirstOnly) return bytecode; + } + } else { + break; + } + } + } + return bytecode; + } + + /** + * @dev Reverts if startPosition + replacement.length is bigger than bytecode.length. + */ + function replaceBytes(bytes memory bytecode, bytes memory replacement, uint256 startPosition) + internal + pure + returns (bytes memory) + { + uint256 lengthReplacement = replacement.length; + for (uint256 j; j < lengthReplacement;) { + bytecode[startPosition + j] = replacement[j]; + + unchecked { + ++j; + } + } + return bytecode; + } +} diff --git a/contracts/test/TestUniswapV2LibraryContract.sol b/contracts/test/TestUniswapV2LibraryContract.sol new file mode 100644 index 0000000..2625c37 --- /dev/null +++ b/contracts/test/TestUniswapV2LibraryContract.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import {UniswapV2Library} from "../UniswapV2/periphery/libraries/UniswapV2Library.sol"; + +contract TestUniswapV2LibraryContract { + function sortTokens(address tokenA, address tokenB) public pure returns (address token0, address token1) { + return UniswapV2Library.sortTokens(tokenA, tokenB); + } + + function pairFor(address factory, address tokenA, address tokenB) public pure returns (address pair) { + return UniswapV2Library.pairFor(factory, tokenA, tokenB); + } + + function getReserves(address factory, address tokenA, address tokenB) + public + view + returns (uint256 reserveA, uint256 reserveB) + { + return UniswapV2Library.getReserves(factory, tokenA, tokenB); + } + + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) public pure returns (uint256 amountB) { + return UniswapV2Library.quote(amountA, reserveA, reserveB); + } + + function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut, address pair, address factory) + public + view + returns (uint256 amountOut) + { + return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut, pair, factory); + } + + function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut, address pair, address factory) + public + view + returns (uint256 amountIn) + { + return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut, pair, factory); + } + + function getAmountsOut(address factory, uint256 amountIn, address[] memory path) + public + view + returns (uint256[] memory amounts) + { + return UniswapV2Library.getAmountsOut(factory, amountIn, path); + } + + function getAmountsIn(address factory, uint256 amountOut, address[] memory path) + public + view + returns (uint256[] memory amounts) + { + return UniswapV2Library.getAmountsIn(factory, amountOut, path); + } +} diff --git a/foundry.toml b/foundry.toml index 6bc8570..2767e60 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,7 +7,6 @@ cache_path = 'cache_forge' bytecode_hash = 'none' solc_version = '0.8.20' - [etherscan] arbitrum = { key = "${ARBISCAN_API_KEY}" } arbitrum-sepolia = { key = "${ARBISCAN_API_KEY}", chain = "arbitrum-sepolia", url = "https://api-sepolia.arbiscan.io/api"}