├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── bot ├── .env.example ├── Cargo.lock ├── Cargo.toml ├── README.md ├── pools.json.zstd └── src │ ├── abi │ ├── IBrainDance.abi │ ├── IERC20.abi │ ├── IUniswapV2Factory.abi │ ├── IUniswapV2Pair.abi │ ├── IUniswapV2Router.abi │ ├── IUniswapV3Factory.abi │ ├── IUniswapV3Pool.abi │ └── mod.rs │ ├── cfmm │ ├── dex.rs │ ├── mod.rs │ └── pool.rs │ ├── forked_db │ ├── database_error.rs │ ├── fork_db.rs │ ├── fork_factory.rs │ ├── global_backend.rs │ └── mod.rs │ ├── lib.rs │ ├── main.rs │ ├── relay.rs │ ├── rpc_extensions │ └── mod.rs │ ├── runner │ ├── bundle_sender.rs │ ├── mod.rs │ ├── oracles.rs │ └── state.rs │ ├── simulate │ ├── helpers.rs │ ├── inspectors │ │ ├── access_list.rs │ │ ├── is_sando_safu.rs │ │ └── mod.rs │ ├── make_sandwich.rs │ └── mod.rs │ ├── types │ ├── block.rs │ ├── errors.rs │ ├── mod.rs │ └── sandwich_types │ │ ├── mod.rs │ │ ├── optimal_recipe.rs │ │ └── raw_ingredients.rs │ └── utils │ ├── constants.rs │ ├── contracts.rs │ ├── dotenv.rs │ ├── encode_packed.rs │ ├── mod.rs │ ├── state_diff.rs │ ├── testhelper.rs │ └── tx_builder │ ├── braindance │ ├── decode.rs │ ├── encode.rs │ └── mod.rs │ ├── mod.rs │ └── sandwich │ ├── mod.rs │ ├── v2.rs │ └── v3.rs └── contract ├── .env.example ├── .github └── workflows │ └── ci.yaml ├── .gitmodules ├── .solhint.json ├── LICENSE ├── README.md ├── foundry.toml ├── interfaces ├── IERC20.sol ├── IMetamorphicContractFactory.sol └── IWETH.sol ├── lib ├── forge-std │ ├── .github │ │ └── workflows │ │ │ ├── ci.yml │ │ │ └── tests.yml │ ├── .gitmodules │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── foundry.toml │ ├── lib │ │ └── ds-test │ │ │ ├── .github │ │ │ └── workflows │ │ │ │ └── build.yml │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── default.nix │ │ │ ├── demo │ │ │ └── demo.sol │ │ │ ├── package.json │ │ │ └── src │ │ │ ├── test.sol │ │ │ └── test.t.sol │ ├── package.json │ ├── src │ │ ├── Base.sol │ │ ├── Script.sol │ │ ├── StdAssertions.sol │ │ ├── StdChains.sol │ │ ├── StdCheats.sol │ │ ├── StdError.sol │ │ ├── StdInvariant.sol │ │ ├── StdJson.sol │ │ ├── StdMath.sol │ │ ├── StdStorage.sol │ │ ├── StdStyle.sol │ │ ├── StdUtils.sol │ │ ├── Test.sol │ │ ├── Vm.sol │ │ ├── console.sol │ │ ├── console2.sol │ │ ├── interfaces │ │ │ ├── IERC1155.sol │ │ │ ├── IERC165.sol │ │ │ ├── IERC20.sol │ │ │ ├── IERC4626.sol │ │ │ ├── IERC721.sol │ │ │ └── IMulticall3.sol │ │ └── test │ │ │ ├── Script.t.sol │ │ │ ├── StdAssertions.t.sol │ │ │ ├── StdCheats.t.sol │ │ │ ├── StdError.t.sol │ │ │ ├── StdMath.t.sol │ │ │ ├── StdStorage.t.sol │ │ │ └── fixtures │ │ │ └── broadcast.log.json │ └── test │ │ ├── StdAssertions.t.sol │ │ ├── StdChains.t.sol │ │ ├── StdCheats.t.sol │ │ ├── StdError.t.sol │ │ ├── StdMath.t.sol │ │ ├── StdStorage.t.sol │ │ ├── StdStyle.t.sol │ │ ├── StdUtils.t.sol │ │ ├── compilation │ │ ├── CompilationScript.sol │ │ ├── CompilationScriptBase.sol │ │ ├── CompilationTest.sol │ │ └── CompilationTestBase.sol │ │ └── fixtures │ │ └── broadcast.log.json ├── foundry-huff │ ├── .github │ │ └── workflows │ │ │ └── tests.yaml │ ├── .gitmodules │ ├── LICENSE │ ├── README.md │ ├── assets │ │ ├── Group 1.png │ │ ├── banner.jpg │ │ ├── black_white_huff-removebg-preview.png │ │ ├── black_white_huff.png │ │ ├── foundry.png │ │ ├── foundry_huff_banner.jpg │ │ ├── foundry_huff_banner.png │ │ ├── huff.png │ │ ├── inverted_huff.png │ │ ├── x-removebg-preview.png │ │ └── x.jpg │ ├── foundry.toml │ ├── lib │ │ ├── forge-std │ │ │ ├── .github │ │ │ │ └── workflows │ │ │ │ │ └── tests.yml │ │ │ ├── .gitmodules │ │ │ ├── LICENSE-APACHE │ │ │ ├── LICENSE-MIT │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ └── ds-test │ │ │ │ │ ├── LICENSE │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── default.nix │ │ │ │ │ ├── demo │ │ │ │ │ └── demo.sol │ │ │ │ │ └── src │ │ │ │ │ └── test.sol │ │ │ └── src │ │ │ │ ├── Script.sol │ │ │ │ ├── Test.sol │ │ │ │ ├── Vm.sol │ │ │ │ ├── console.sol │ │ │ │ ├── console2.sol │ │ │ │ └── test │ │ │ │ ├── Script.t.sol │ │ │ │ ├── StdAssertions.t.sol │ │ │ │ ├── StdCheats.t.sol │ │ │ │ ├── StdError.t.sol │ │ │ │ ├── StdMath.t.sol │ │ │ │ └── StdStorage.t.sol │ │ ├── foundry-huff │ │ │ └── scripts │ │ │ │ ├── binary_check.sh │ │ │ │ ├── file_writer.sh │ │ │ │ ├── rand_bytes.sh │ │ │ │ └── read_and_append.sh │ │ └── solidity-stringutils │ │ │ ├── .gitattributes │ │ │ ├── .github │ │ │ └── workflows │ │ │ │ └── ci.yml │ │ │ ├── .gitmodules │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README │ │ │ ├── README.md │ │ │ ├── dappfile │ │ │ ├── lib │ │ │ └── ds-test │ │ │ │ ├── LICENSE │ │ │ │ ├── Makefile │ │ │ │ ├── default.nix │ │ │ │ ├── demo │ │ │ │ └── demo.sol │ │ │ │ └── src │ │ │ │ └── test.sol │ │ │ ├── src │ │ │ ├── strings.sol │ │ │ └── strings.t.sol │ │ │ └── strings.sol │ ├── remappings.txt │ ├── scripts │ │ ├── binary_check.sh │ │ ├── file_writer.sh │ │ ├── rand_bytes.sh │ │ └── read_and_append.sh │ └── src │ │ ├── HuffConfig.sol │ │ ├── HuffDeployer.sol │ │ ├── depreciated │ │ ├── StatefulDeployer.sol │ │ └── StatefulDeployer.t.sol │ │ └── test │ │ ├── HuffConfig.t.sol │ │ ├── HuffDeployer.t.sol │ │ ├── Logging.t.sol │ │ ├── contracts │ │ ├── ConstOverride.huff │ │ ├── Constructor.huff │ │ ├── ConstructorNeedsValue.huff │ │ ├── LotsOfLogging.huff │ │ ├── NoConstructor.huff │ │ └── Number.huff │ │ └── interfaces │ │ ├── IConstructor.sol │ │ └── INumber.sol ├── v2-core │ ├── .gitattributes │ ├── .github │ │ └── workflows │ │ │ └── CI.yml │ ├── .mocharc.json │ ├── .prettierrc │ ├── .waffle.json │ ├── LICENSE │ ├── README.md │ ├── contracts │ │ ├── UniswapV2ERC20.sol │ │ ├── UniswapV2Factory.sol │ │ ├── UniswapV2Pair.sol │ │ ├── interfaces │ │ │ ├── IERC20.sol │ │ │ ├── IUniswapV2Callee.sol │ │ │ ├── IUniswapV2ERC20.sol │ │ │ ├── IUniswapV2Factory.sol │ │ │ └── IUniswapV2Pair.sol │ │ ├── libraries │ │ │ ├── Math.sol │ │ │ ├── SafeMath.sol │ │ │ └── UQ112x112.sol │ │ └── test │ │ │ └── ERC20.sol │ ├── package.json │ ├── test │ │ ├── UniswapV2ERC20.spec.ts │ │ ├── UniswapV2Factory.spec.ts │ │ ├── UniswapV2Pair.spec.ts │ │ └── shared │ │ │ ├── fixtures.ts │ │ │ └── utilities.ts │ ├── tsconfig.json │ └── yarn.lock ├── v2-periphery │ ├── .gitattributes │ ├── .github │ │ ├── stale.yml │ │ └── workflows │ │ │ └── CI.yml │ ├── .mocharc.json │ ├── .prettierrc │ ├── .waffle.json │ ├── .yarnrc │ ├── LICENSE │ ├── README.md │ ├── buildV1 │ │ ├── UniswapV1Exchange.json │ │ └── UniswapV1Factory.json │ ├── contracts │ │ ├── UniswapV2Migrator.sol │ │ ├── UniswapV2Router01.sol │ │ ├── UniswapV2Router02.sol │ │ ├── examples │ │ │ ├── ExampleComputeLiquidityValue.sol │ │ │ ├── ExampleFlashSwap.sol │ │ │ ├── ExampleOracleSimple.sol │ │ │ ├── ExampleSlidingWindowOracle.sol │ │ │ ├── ExampleSwapToPrice.sol │ │ │ └── README.md │ │ ├── interfaces │ │ │ ├── IERC20.sol │ │ │ ├── IUniswapV2Migrator.sol │ │ │ ├── IUniswapV2Router01.sol │ │ │ ├── IUniswapV2Router02.sol │ │ │ ├── IWETH.sol │ │ │ └── V1 │ │ │ │ ├── IUniswapV1Exchange.sol │ │ │ │ └── IUniswapV1Factory.sol │ │ ├── libraries │ │ │ ├── SafeMath.sol │ │ │ ├── UniswapV2Library.sol │ │ │ ├── UniswapV2LiquidityMathLibrary.sol │ │ │ └── UniswapV2OracleLibrary.sol │ │ └── test │ │ │ ├── DeflatingERC20.sol │ │ │ ├── ERC20.sol │ │ │ ├── RouterEventEmitter.sol │ │ │ └── WETH9.sol │ ├── package.json │ ├── test │ │ ├── ExampleComputeLiquidityValue.spec.ts │ │ ├── ExampleFlashSwap.spec.ts │ │ ├── ExampleOracleSimple.spec.ts │ │ ├── ExampleSlidingWindowOracle.spec.ts │ │ ├── ExampleSwapToPrice.spec.ts │ │ ├── UniswapV2Migrator.spec.ts │ │ ├── UniswapV2Router01.spec.ts │ │ ├── UniswapV2Router02.spec.ts │ │ └── shared │ │ │ ├── fixtures.ts │ │ │ └── utilities.ts │ ├── tsconfig.json │ └── yarn.lock └── v3-core │ ├── .gitattributes │ ├── .github │ └── workflows │ │ ├── fuzz-testing.yml │ │ ├── lint.yml │ │ ├── mythx.yml │ │ └── tests.yml │ ├── .prettierrc │ ├── .solhint.json │ ├── .yarnrc │ ├── LICENSE │ ├── README.md │ ├── audits │ ├── abdk │ │ └── audit.pdf │ └── tob │ │ ├── README.md │ │ ├── audit.pdf │ │ └── contracts │ │ └── crytic │ │ ├── echidna │ │ ├── E2E_mint_burn.config.yaml │ │ ├── E2E_mint_burn.sol │ │ ├── E2E_swap.config.yaml │ │ ├── E2E_swap.sol │ │ ├── Other.config.yaml │ │ ├── Other.sol │ │ └── Setup.sol │ │ └── manticore │ │ ├── 001.sol │ │ ├── 002.sol │ │ └── 003.sol │ ├── bug-bounty.md │ ├── contracts │ ├── NoDelegateCall.sol │ ├── UniswapV3Factory.sol │ ├── UniswapV3Pool.sol │ ├── UniswapV3PoolDeployer.sol │ ├── interfaces │ │ ├── IERC20Minimal.sol │ │ ├── IUniswapV3Factory.sol │ │ ├── IUniswapV3Pool.sol │ │ ├── IUniswapV3PoolDeployer.sol │ │ ├── LICENSE │ │ ├── callback │ │ │ ├── IUniswapV3FlashCallback.sol │ │ │ ├── IUniswapV3MintCallback.sol │ │ │ └── IUniswapV3SwapCallback.sol │ │ └── pool │ │ │ ├── IUniswapV3PoolActions.sol │ │ │ ├── IUniswapV3PoolDerivedState.sol │ │ │ ├── IUniswapV3PoolEvents.sol │ │ │ ├── IUniswapV3PoolImmutables.sol │ │ │ ├── IUniswapV3PoolOwnerActions.sol │ │ │ └── IUniswapV3PoolState.sol │ ├── libraries │ │ ├── BitMath.sol │ │ ├── FixedPoint128.sol │ │ ├── FixedPoint96.sol │ │ ├── FullMath.sol │ │ ├── LICENSE_GPL │ │ ├── LICENSE_MIT │ │ ├── LiquidityMath.sol │ │ ├── LowGasSafeMath.sol │ │ ├── Oracle.sol │ │ ├── Position.sol │ │ ├── SafeCast.sol │ │ ├── SqrtPriceMath.sol │ │ ├── SwapMath.sol │ │ ├── Tick.sol │ │ ├── TickBitmap.sol │ │ ├── TickMath.sol │ │ ├── TransferHelper.sol │ │ └── UnsafeMath.sol │ └── test │ │ ├── BitMathEchidnaTest.sol │ │ ├── BitMathTest.sol │ │ ├── FullMathEchidnaTest.sol │ │ ├── FullMathTest.sol │ │ ├── LiquidityMathTest.sol │ │ ├── LowGasSafeMathEchidnaTest.sol │ │ ├── MockTimeUniswapV3Pool.sol │ │ ├── MockTimeUniswapV3PoolDeployer.sol │ │ ├── NoDelegateCallTest.sol │ │ ├── OracleEchidnaTest.sol │ │ ├── OracleTest.sol │ │ ├── SqrtPriceMathEchidnaTest.sol │ │ ├── SqrtPriceMathTest.sol │ │ ├── SwapMathEchidnaTest.sol │ │ ├── SwapMathTest.sol │ │ ├── TestERC20.sol │ │ ├── TestUniswapV3Callee.sol │ │ ├── TestUniswapV3ReentrantCallee.sol │ │ ├── TestUniswapV3Router.sol │ │ ├── TestUniswapV3SwapPay.sol │ │ ├── TickBitmapEchidnaTest.sol │ │ ├── TickBitmapTest.sol │ │ ├── TickEchidnaTest.sol │ │ ├── TickMathEchidnaTest.sol │ │ ├── TickMathTest.sol │ │ ├── TickOverflowSafetyEchidnaTest.sol │ │ ├── TickTest.sol │ │ ├── UniswapV3PoolSwapTest.sol │ │ └── UnsafeMathEchidnaTest.sol │ ├── echidna.config.yml │ ├── hardhat.config.ts │ ├── package.json │ ├── test │ ├── BitMath.spec.ts │ ├── FullMath.spec.ts │ ├── LiquidityMath.spec.ts │ ├── NoDelegateCall.spec.ts │ ├── Oracle.spec.ts │ ├── SqrtPriceMath.spec.ts │ ├── SwapMath.spec.ts │ ├── Tick.spec.ts │ ├── TickBitmap.spec.ts │ ├── TickMath.spec.ts │ ├── UniswapV3Factory.spec.ts │ ├── UniswapV3Pool.arbitrage.spec.ts │ ├── UniswapV3Pool.gas.spec.ts │ ├── UniswapV3Pool.spec.ts │ ├── UniswapV3Pool.swaps.spec.ts │ ├── UniswapV3Router.spec.ts │ ├── __snapshots__ │ │ ├── BitMath.spec.ts.snap │ │ ├── LiquidityMath.spec.ts.snap │ │ ├── NoDelegateCall.spec.ts.snap │ │ ├── Oracle.spec.ts.snap │ │ ├── SqrtPriceMath.spec.ts.snap │ │ ├── SwapMath.spec.ts.snap │ │ ├── TickBitmap.spec.ts.snap │ │ ├── TickMath.spec.ts.snap │ │ ├── UniswapV3Factory.spec.ts.snap │ │ ├── UniswapV3Pool.arbitrage.spec.ts.snap │ │ ├── UniswapV3Pool.gas.spec.ts.snap │ │ └── UniswapV3Pool.swaps.spec.ts.snap │ └── shared │ │ ├── checkObservationEquals.ts │ │ ├── expect.ts │ │ ├── fixtures.ts │ │ ├── format.ts │ │ ├── snapshotGasCost.ts │ │ └── utilities.ts │ ├── tsconfig.json │ └── yarn.lock ├── script ├── Deploy.s.sol ├── Deposit.s.sol ├── Seppuku.s.sol └── Withdraw.s.sol ├── src ├── BrainDance.sol ├── lib │ ├── SafeMath.sol │ └── SafeTransfer.sol └── sandwich.huff └── test ├── BrainDance.t.sol ├── Mev.t.sol ├── helpers ├── GeneralHelper.sol └── MevHelper.sol └── interfaces ├── IERC20.sol ├── IUniswapV2.sol └── IWETH.sol /.gitignore: -------------------------------------------------------------------------------- 1 | bot/target 2 | contract/out 3 | contract/cache 4 | .env 5 | output.log 6 | __TEMP__* 7 | run-*.json 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "contract/lib/forge-std"] 2 | path = contract/lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "contract/lib/foundry-huff"] 5 | path = contract/lib/foundry-huff 6 | url = https://github.com/huff-language/foundry-huff 7 | [submodule "contract/lib/v3-core"] 8 | path = contract/lib/v3-core 9 | url = https://github.com/Uniswap/v3-core 10 | [submodule "contract/lib/v2-core"] 11 | path = contract/lib/v2-core 12 | url = https://github.com/Uniswap/v2-core 13 | [submodule "contract/lib/v2-periphery"] 14 | path = contract/lib/v2-periphery 15 | url = https://github.com/Uniswap/v2-periphery 16 | [submodule "contract/lib/v3-periphery"] 17 | path = contract/lib/v3-periphery 18 | url = https://github.com/uniswap/v3-periphery 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 0xmouseless 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sando-RS ! 2 | A practical MEV bot on how to perform V2/V3 and multi-meat sandwich attacks written using Rust and Huff. 3 | 4 | ## Brief Explanation 5 | Anytime that a transaction interacts with a Uniswap V2/V3 pool and their forks, there is some slippage introduced (router swaps, aggregator swaps, other mev bots). Sandwich bots are a toxic form of MEV as they profit off this slippage by frontrunning the transaction pushing the price of the asset up to the slippage limit and then immediately selling the asset through a backrun transaction. 6 | 7 | ## Features 8 | - **Fully Generalized**: Sandwich any tx that introduces slippage (routers, aggregators, mev bots, ...). 9 | - **V2 and V3 Logic**: Logic to handle Uniswap V2/V3 pools. 10 | - **Multi-Meat**: Build and send multi-meat sandwiches. 11 | - **Gas Optimized**: Contract written in Huff using unconventional gas optimizations. 12 | - **Local Simulations**: Fast concurrent EVM simulations to find sandwich opportunities. 13 | - **Token Dust**: Stores dust at the end of every bundle for lower gas usage next time token is traded. 14 | - **Salmonella Checks**: Detect if tx uses unusual opcodes that may produce different mainnet results. 15 | 16 | **Bot Logic Breakdown** can be found under [bot/README.md](https://github.com/0xethghost/sando-rs/tree/main/bot) 17 | 18 | **Contract Logic Breakdown** can be found under [contract/README.md](https://github.com/0xethghost/sando-rs/tree/main/contract) 19 | 20 | ## Acknowledgments 21 | - [subway](https://github.com/libevm/subway) 22 | - [subway-rs](https://github.com/refcell/subway-rs) 23 | - [cfmms-rs](https://github.com/0xKitsune/cfmms-rs) 24 | - [revm](https://github.com/bluealloy/revm) 25 | - [huff-language](https://github.com/huff-language/huff-rs) 26 | - [foundry](https://github.com/foundry-rs/foundry) 27 | - [reth](https://github.com/paradigmxyz/reth) 28 | - [ethers-rs](https://github.com/gakonst/ethers-rs) 29 | - [mev-template-rs](https://github.com/degatchi/mev-template-rs) 30 | - [rusty-sando](https://github.com/mouseless-eth/rusty-sando) 31 | -------------------------------------------------------------------------------- /bot/.env.example: -------------------------------------------------------------------------------- 1 | RPC_URL_WSS=ws://localhost:8545 2 | SEARCHER_PRIVATE_KEY=0000000000000000000000000000000000000000000000000000000000000001 3 | FLASHBOTS_AUTH_KEY=0000000000000000000000000000000000000000000000000000000000000002 4 | SANDWICH_CONTRACT=0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa 5 | SANDWICH_INCEPTION_BLOCK=... 6 | -------------------------------------------------------------------------------- /bot/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sando-rs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | description = "Optimized mev bot written using Rust and Huff" 7 | readme = "README.md" 8 | homepage = "https://github.com/0xethghost/sando-rs" 9 | repository = "https://github.com/0xethghost/sando-rs" 10 | keywords = ["Ethereum", "Mev", "Dex", "Sandwich"] 11 | authors = ["0xethghost "] 12 | 13 | [dependencies] 14 | ethers-flashbots = { git = "https://github.com/onbjerg/ethers-flashbots" } 15 | ethers = {version = "2.0.0", features = ["abigen", "ws"]} 16 | revm = {version = "=3.1.1", features = ["ethersdb", "serde", "std"]} 17 | revm-primitives= "=1.1.2" 18 | dotenv = "0.15.0" 19 | hashbrown = "0.14.0" 20 | tokio = { version = "1", features = ["full"] } 21 | log = "0.4.17" 22 | url = "2.3.1" 23 | dashmap = "5.4.0" 24 | async-recursion = "1.0.2" 25 | hex = "0.4.3" 26 | serde = "1.0.145" 27 | eyre = "0.6.8" 28 | reqwest = "0.11.12" 29 | time = "*" 30 | indoc = "2" 31 | indicatif = "0.17.1" 32 | thiserror = "1.0.37" 33 | fern = {version = "0.6", features = ["colored"]} 34 | chrono = "0.4.23" 35 | futures = "0.3.5" 36 | colored = "2.0.0" 37 | zstd = "0.12" 38 | serde_json = "1.0.107" 39 | 40 | [profile.release] 41 | debug = true 42 | 43 | [dev-dependencies] 44 | tokio-test = "*" 45 | -------------------------------------------------------------------------------- /bot/pools.json.zstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/bot/pools.json.zstd -------------------------------------------------------------------------------- /bot/src/abi/IUniswapV2Factory.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairCodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_migrator","type":"address"}],"name":"setMigrator","outputs":[],"stateMutability":"nonpayable","type":"function"}] 2 | -------------------------------------------------------------------------------- /bot/src/abi/IUniswapV3Factory.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"fee","type":"uint24"},{"indexed":true,"internalType":"int24","name":"tickSpacing","type":"int24"}],"name":"FeeAmountEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":true,"internalType":"uint24","name":"fee","type":"uint24"},{"indexed":false,"internalType":"int24","name":"tickSpacing","type":"int24"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolCreated","type":"event"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"}],"name":"createPool","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"}],"name":"enableFeeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"feeAmountTickSpacing","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint24","name":"","type":"uint24"}],"name":"getPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"parameters","outputs":[{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"}] 2 | -------------------------------------------------------------------------------- /bot/src/abi/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, str::FromStr}; 2 | 3 | use ethers::{ 4 | abi::{encode, Token}, 5 | prelude::*, 6 | }; 7 | use eyre::Result; 8 | 9 | abigen!( 10 | UniswapV2Factory, 11 | "src/abi/IUniswapV2Factory.abi", 12 | event_derives(serde::Deserialize, serde::Serialize) 13 | ); 14 | abigen!( 15 | UniswapV3Factory, 16 | "src/abi/IUniswapV3Factory.abi", 17 | event_derives(serde::Deserialize, serde::Serialize) 18 | ); 19 | abigen!( 20 | UniswapV3Pool, 21 | "src/abi/IUniswapV3Pool.abi", 22 | event_derives(serde::Deserialize, serde::Serialize) 23 | ); 24 | abigen!( 25 | UniswapV2Pair, 26 | "src/abi/IUniswapV2Pair.abi", 27 | event_derives(serde::Deserialize, serde::Serialize) 28 | ); 29 | abigen!( 30 | UniswapV2Router, 31 | "src/abi/IUniswapV2Router.abi", 32 | event_derives(serde::Deserialize, serde::Serialize) 33 | ); 34 | abigen!( 35 | Erc20, 36 | "src/abi/IERC20.abi", 37 | event_derives(serde::Deserialize, serde::Serialize) 38 | ); 39 | abigen!( 40 | BrainDance, 41 | "src/abi/IBrainDance.abi", 42 | event_derives(serde::Deserialize, serde::Serialize) 43 | ); 44 | 45 | pub fn get_self_destruct_byte_code(target: Address) -> Result { 46 | let mut raw_byte_code: String = 47 | fs::read_to_string("src/abi/SelfDestruct.byte").expect("unable to read file"); 48 | 49 | // Remove new line 50 | raw_byte_code.pop(); 51 | 52 | let target_as_string = encode(&[Token::Address(target)]); 53 | let target_as_string = hex::encode(target_as_string); 54 | let raw_byte_code = raw_byte_code + &target_as_string; 55 | 56 | Bytes::from_str(&raw_byte_code) 57 | } 58 | -------------------------------------------------------------------------------- /bot/src/cfmm/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod dex; 2 | pub use dex::*; 3 | 4 | pub mod pool; 5 | pub use pool::*; 6 | -------------------------------------------------------------------------------- /bot/src/cfmm/pool.rs: -------------------------------------------------------------------------------- 1 | // credit to 0xKitsune's cfmms-rs: https://github.com/0xKitsune/cfmms-rs/tree/main/src/pool 2 | use std::{ 3 | hash::{Hash, Hasher}, 4 | str::FromStr, 5 | }; 6 | 7 | use ethers::prelude::*; 8 | use serde::{Deserialize, Serialize}; 9 | 10 | #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] 11 | pub struct Pool { 12 | pub address: Address, 13 | pub token_0: Address, 14 | pub token_1: Address, 15 | pub swap_fee: U256, 16 | pub pool_variant: PoolVariant, 17 | pub has_dust: bool 18 | } 19 | 20 | #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] 21 | pub enum PoolVariant { 22 | UniswapV2, 23 | UniswapV3, 24 | } 25 | 26 | impl Pool { 27 | // Creates a new pool instance 28 | pub fn new( 29 | address: Address, 30 | token_a: Address, 31 | token_b: Address, 32 | swap_fee: U256, 33 | pool_variant: PoolVariant, 34 | ) -> Pool { 35 | let (token_0, token_1) = if token_a < token_b { 36 | (token_a, token_b) 37 | } else { 38 | (token_b, token_a) 39 | }; 40 | let has_dust = false; 41 | 42 | Pool { 43 | address, 44 | token_0, 45 | token_1, 46 | swap_fee, 47 | pool_variant, 48 | has_dust 49 | } 50 | } 51 | } 52 | 53 | impl PoolVariant { 54 | pub fn pool_created_event_signature(&self) -> H256 { 55 | match self { 56 | PoolVariant::UniswapV2 => { 57 | H256::from_str("0x0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9") 58 | .unwrap() 59 | } 60 | PoolVariant::UniswapV3 => { 61 | H256::from_str("0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118") 62 | .unwrap() 63 | } 64 | } 65 | } 66 | } 67 | 68 | impl Hash for Pool { 69 | fn hash(&self, state: &mut H) { 70 | self.address.hash(state); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /bot/src/forked_db/database_error.rs: -------------------------------------------------------------------------------- 1 | use futures::channel::mpsc::{SendError, TrySendError}; 2 | use std::sync::{mpsc::RecvError, Arc}; 3 | 4 | // Errors that can happen when working with [`revm::Database`] 5 | #[derive(Debug, thiserror::Error)] 6 | pub enum DatabaseError { 7 | #[error("Failed to fetch AccountInfo {0:?}")] 8 | MissingAccount(revm::primitives::B160), 9 | #[error("Could should already be loaded: {0:?}")] 10 | MissingCode(revm::primitives::B256), 11 | #[error(transparent)] 12 | Recv(#[from] RecvError), 13 | #[error(transparent)] 14 | Send(#[from] SendError), 15 | #[error("{0}")] 16 | Message(String), 17 | #[error("Failed to get account for {0:?}: {0:?}")] 18 | GetAccount(revm::primitives::Address, Arc), 19 | #[error("Failed to get storage for {0:?} at {1:?}: {2:?}")] 20 | GetStorage( 21 | revm::primitives::Address, 22 | revm::primitives::U256, 23 | Arc, 24 | ), 25 | #[error("Failed to get block hash for {0}: {1:?}")] 26 | GetBlockHash(revm::primitives::U256, Arc), 27 | } 28 | 29 | impl From> for DatabaseError { 30 | fn from(err: TrySendError) -> Self { 31 | err.into_send_error().into() 32 | } 33 | } 34 | 35 | impl DatabaseError { 36 | // Create a new error with a message 37 | pub fn msg(msg: impl Into) -> Self { 38 | DatabaseError::Message(msg.into()) 39 | } 40 | } 41 | 42 | // Result alias with `DatabaseError` as error 43 | pub type DatabaseResult = Result; 44 | -------------------------------------------------------------------------------- /bot/src/forked_db/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod database_error; 2 | pub use database_error::DatabaseError; 3 | 4 | pub mod global_backend; 5 | pub use global_backend::*; 6 | 7 | pub mod fork_db; 8 | pub mod fork_factory; 9 | -------------------------------------------------------------------------------- /bot/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod abi; 2 | pub mod cfmm; 3 | pub mod forked_db; 4 | pub mod relay; 5 | pub mod rpc_extensions; 6 | pub mod runner; 7 | pub mod simulate; 8 | pub mod types; 9 | pub mod utils; 10 | 11 | pub mod prelude { 12 | pub use super::{ 13 | abi::*, cfmm::*, forked_db::*, rpc_extensions::*, runner::*, simulate::*, types::*, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /bot/src/rpc_extensions/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use ethers::prelude::*; 4 | 5 | /// Subscribe to the rpc endpoint "SubscribePending" 6 | pub async fn subscribe_pending_txs_with_body( 7 | client: &Arc>, 8 | ) -> Result, ProviderError> 9 | { 10 | // this rpc is erigon specific 11 | client.subscribe(["newPendingTransactionsWithBody"]).await 12 | } 13 | -------------------------------------------------------------------------------- /bot/src/simulate/inspectors/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod access_list; 2 | pub mod is_sando_safu; 3 | -------------------------------------------------------------------------------- /bot/src/simulate/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod helpers; 2 | pub mod inspectors; 3 | pub mod make_sandwich; 4 | 5 | pub use helpers::*; 6 | pub use inspectors::*; 7 | pub use make_sandwich::*; 8 | -------------------------------------------------------------------------------- /bot/src/types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sandwich_types; 2 | 3 | pub mod errors; 4 | pub use errors::*; 5 | 6 | pub mod block; 7 | pub use block::*; 8 | -------------------------------------------------------------------------------- /bot/src/types/sandwich_types/mod.rs: -------------------------------------------------------------------------------- 1 | // Holds info needed to prepare sandwich 2 | mod raw_ingredients; 3 | pub use raw_ingredients::*; 4 | 5 | // Holds info to capture sandwich 6 | mod optimal_recipe; 7 | pub use optimal_recipe::*; 8 | -------------------------------------------------------------------------------- /bot/src/types/sandwich_types/raw_ingredients.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use ethers::prelude::*; 4 | use eyre::Result; 5 | 6 | use crate::{prelude::Pool, utils}; 7 | 8 | #[derive(Debug, Clone)] 9 | /// Holds all info needed to for sandwich simulations 10 | pub struct RawIngredients { 11 | /// the token that we start and end the sandwich with 12 | pub startend_token: Address, 13 | /// the token that bot holds only for duration of sandwich 14 | pub intermediary_token: Address, 15 | pub from: Address, 16 | pub sandwich_contract: Address, 17 | pub meats: Vec, 18 | pub target_pool: Pool, 19 | /// holds the state diffs produced from meats 20 | pub state_diffs: BTreeMap, 21 | } 22 | 23 | impl RawIngredients { 24 | // Create a new `RawIngredients` instance 25 | pub async fn new( 26 | target_pair: &Pool, 27 | victim_txs: Vec, 28 | start_token: Address, // which token to start trade from (input_token) 29 | state_diffs: BTreeMap, 30 | ) -> Result { 31 | let (mut input_token, mut output_token) = (target_pair.token_0, target_pair.token_1); 32 | 33 | // swap if input_token is equal to token_1 34 | if start_token == target_pair.token_1 { 35 | (input_token, output_token) = (output_token, input_token); 36 | } 37 | 38 | let sandwich_contract = utils::dotenv::get_sandwich_contract_address(); 39 | 40 | let from = utils::dotenv::get_searcher_wallet().address(); 41 | 42 | Ok(RawIngredients { 43 | from, 44 | meats: victim_txs, 45 | target_pool: *target_pair, 46 | sandwich_contract, 47 | startend_token: input_token, 48 | intermediary_token: output_token, 49 | state_diffs, 50 | }) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bot/src/utils/contracts.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use ethers::{prelude::*, providers}; 4 | 5 | use crate::prelude::{Erc20, UniswapV2Pair}; 6 | 7 | /// Create erc20 contract that we can interact with 8 | pub fn get_erc20_contract( 9 | erc20_address: &Address, 10 | client: &Arc>, 11 | ) -> Erc20> { 12 | Erc20::new(*erc20_address, client.clone()) 13 | } 14 | 15 | /// Create v2 pair contract that we can interact with 16 | pub fn get_pair_v2_contract( 17 | pair_address: &Address, 18 | client: &Arc>, 19 | ) -> UniswapV2Pair> { 20 | UniswapV2Pair::new(*pair_address, client.clone()) 21 | } 22 | -------------------------------------------------------------------------------- /bot/src/utils/encode_packed.rs: -------------------------------------------------------------------------------- 1 | // credit to: https://github.com/roberts-ivanovs/eth-encode-packed-rs 2 | pub use hex; // Re-export 3 | 4 | use ethers::prelude::*; 5 | 6 | pub struct TakeLastXBytes(pub usize); 7 | 8 | /// Represents a data type in solidity 9 | pub enum PackedToken<'a> { 10 | String(&'a str), 11 | Address(Address), 12 | Bytes(&'a [u8]), 13 | Bool(bool), 14 | Number(U256), 15 | NumberWithShift(U256, TakeLastXBytes), 16 | } 17 | 18 | /// Pack a single `SolidityDataType` into bytes 19 | fn pack<'a>(data_type: &'a PackedToken) -> Vec { 20 | let mut res = Vec::new(); 21 | match data_type { 22 | PackedToken::String(s) => { 23 | res.extend(s.as_bytes()); 24 | } 25 | PackedToken::Address(a) => { 26 | res.extend(a.0); 27 | } 28 | PackedToken::Number(n) => { 29 | for b in n.0.iter().rev() { 30 | let bytes = b.to_be_bytes(); 31 | res.extend(bytes); 32 | } 33 | } 34 | PackedToken::Bytes(b) => { 35 | res.extend(*b); 36 | } 37 | PackedToken::Bool(b) => { 38 | if *b { 39 | res.push(1); 40 | } else { 41 | res.push(0); 42 | } 43 | } 44 | PackedToken::NumberWithShift(n, to_take) => { 45 | let local_res = n.0.iter().rev().fold(vec![], |mut acc, i| { 46 | let bytes = i.to_be_bytes(); 47 | acc.extend(bytes); 48 | acc 49 | }); 50 | 51 | let to_skip = local_res.len() - (to_take.0 / 8); 52 | let local_res = local_res.into_iter().skip(to_skip).collect::>(); 53 | res.extend(local_res); 54 | } 55 | }; 56 | res 57 | } 58 | 59 | pub fn encode_packed(items: &[PackedToken]) -> (Vec, String) { 60 | let res = items.iter().fold(Vec::new(), |mut acc, i| { 61 | let pack = pack(i); 62 | acc.push(pack); 63 | acc 64 | }); 65 | let res = res.join(&[][..]); 66 | let hexed = hex::encode(&res); 67 | (res, hexed) 68 | } 69 | -------------------------------------------------------------------------------- /bot/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use ethers::{prelude::*, types::transaction::eip2718::TypedTransaction}; 4 | 5 | pub mod constants; 6 | pub mod contracts; 7 | 8 | pub mod dotenv; 9 | pub mod encode_packed; 10 | pub mod state_diff; 11 | pub mod testhelper; 12 | pub mod tx_builder; 13 | 14 | pub use encode_packed::*; 15 | 16 | // ========= GENERAL HELPERS 17 | 18 | /// Calculate the next block base fee 19 | // based on math provided here: https://ethereum.stackexchange.com/questions/107173/how-is-the-base-fee-per-gas-computed-for-a-new-block 20 | pub fn calculate_next_block_base_fee(block: Block) -> U256 { 21 | // Get the block base fee per gas 22 | let current_base_fee_per_gas = block.base_fee_per_gas.unwrap_or_default(); 23 | 24 | // Get the mount of gas used in the block 25 | let current_gas_used = block.gas_used; 26 | 27 | let current_gas_target = block.gas_limit / 2; 28 | 29 | if current_gas_used == current_gas_target { 30 | current_base_fee_per_gas 31 | } else if current_gas_used > current_gas_target { 32 | let gas_used_delta = current_gas_used - current_gas_target; 33 | let base_fee_per_gas_delta = 34 | current_base_fee_per_gas * gas_used_delta / current_gas_target / 8; 35 | 36 | return current_base_fee_per_gas + base_fee_per_gas_delta; 37 | } else { 38 | let gas_used_delta = current_gas_target - current_gas_used; 39 | let base_fee_per_gas_delta = 40 | current_base_fee_per_gas * gas_used_delta / current_gas_target / 8; 41 | 42 | return current_base_fee_per_gas - base_fee_per_gas_delta; 43 | } 44 | } 45 | 46 | /// Small helper function to convert [U256] into [H256]. 47 | pub fn u256_to_h256_be(u: U256) -> H256 { 48 | let mut h = H256::default(); 49 | u.to_big_endian(h.as_mut()); 50 | h 51 | } 52 | 53 | /// Sign eip1559 transactions 54 | pub async fn sign_eip1559( 55 | tx: Eip1559TransactionRequest, 56 | signer_wallet: &LocalWallet, 57 | ) -> Result { 58 | let tx_typed = TypedTransaction::Eip1559(tx); 59 | let signed_frontrun_tx_sig = match signer_wallet.sign_transaction(&tx_typed).await { 60 | Ok(s) => s, 61 | Err(e) => return Err(e), 62 | }; 63 | 64 | Ok(tx_typed.rlp_signed(&signed_frontrun_tx_sig)) 65 | } 66 | 67 | /// Create Websocket Client 68 | pub async fn create_websocket_client() -> eyre::Result>> { 69 | let client = dotenv::get_ws_provider().await; 70 | Ok(Arc::new(client)) 71 | } -------------------------------------------------------------------------------- /bot/src/utils/tx_builder/braindance/decode.rs: -------------------------------------------------------------------------------- 1 | use ethers::{abi::parse_abi, prelude::*}; 2 | 3 | // Decode the result of the braindance contract's calculateSwapV2 function 4 | pub fn decode_swap_v2_result(output: Bytes) -> Result<(U256, U256), AbiError> { 5 | let braindance_contract = BaseContract::from(parse_abi(&[ 6 | "function calculateSwapV2(uint amountIn, address targetPair, address inputToken, address outputToken) external returns (uint amountOut, uint realAfterBalance)", 7 | ]).unwrap()); 8 | 9 | braindance_contract.decode_output("calculateSwapV2", output) 10 | } 11 | 12 | // Decode the result of the braindance contract's calculateSwapV3 function 13 | pub fn decode_swap_v3_result(output: Bytes) -> Result<(U256, U256), AbiError> { 14 | let braindance_contract = BaseContract::from(parse_abi(&[ 15 | "function calculateSwapV3(int amountIn, address targetPoolAddress, address inputToken, address outputToken) public returns (uint amountOut, uint realAfterBalance)", 16 | ]).unwrap()); 17 | 18 | braindance_contract.decode_output("calculateSwapV3", output) 19 | } 20 | -------------------------------------------------------------------------------- /bot/src/utils/tx_builder/braindance/encode.rs: -------------------------------------------------------------------------------- 1 | use ethers::{abi::parse_abi, prelude::*}; 2 | 3 | // Build the data for the braindance contract's calculateSwapV2 function 4 | pub fn build_swap_v2_data( 5 | amount_in: U256, 6 | target_pool: Address, 7 | startend_token: Address, 8 | intermediary_token: Address, 9 | ) -> Bytes { 10 | let braindance_contract = BaseContract::from(parse_abi(&[ 11 | "function calculateSwapV2(uint amountIn, address targetPair, address inputToken, address outputToken) external returns (uint amountOut, uint realAfterBalance)", 12 | ]).unwrap()); 13 | 14 | braindance_contract 15 | .encode( 16 | "calculateSwapV2", 17 | (amount_in, target_pool, startend_token, intermediary_token), 18 | ) 19 | .unwrap() 20 | } 21 | 22 | // Build the data for the braindance contract's calculateSwapV3 function 23 | pub fn build_swap_v3_data( 24 | amount_in: I256, 25 | target_pool: Address, 26 | startend_token: Address, 27 | intermediary_token: Address, 28 | ) -> Bytes { 29 | let braindance_contract = BaseContract::from(parse_abi(&[ 30 | "function calculateSwapV3(int amountIn, address targetPoolAddress, address inputToken, address outputToken) public returns (uint amountOut, uint realAfterBalance)", 31 | ]).unwrap()); 32 | 33 | braindance_contract 34 | .encode( 35 | "calculateSwapV3", 36 | (amount_in, target_pool, startend_token, intermediary_token), 37 | ) 38 | .unwrap() 39 | } 40 | -------------------------------------------------------------------------------- /bot/src/utils/tx_builder/braindance/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod encode; 2 | pub use encode::*; 3 | 4 | pub mod decode; 5 | pub use decode::*; 6 | -------------------------------------------------------------------------------- /bot/src/utils/tx_builder/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod braindance; 2 | pub mod sandwich; 3 | 4 | pub use sandwich::*; 5 | -------------------------------------------------------------------------------- /bot/src/utils/tx_builder/sandwich/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::utils; 4 | use ethers::prelude::{k256::ecdsa::SigningKey, *}; 5 | use tokio::sync::RwLock; 6 | 7 | pub mod v2; 8 | pub mod v3; 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct SandwichMaker { 12 | pub v2: v2::SandwichLogicV2, 13 | pub v3: v3::SandwichLogicV3, 14 | pub sandwich_address: Address, 15 | pub searcher_wallet: Wallet, 16 | pub nonce: Arc>, 17 | } 18 | 19 | impl SandwichMaker { 20 | // Create a new `SandwichMaker` instance 21 | pub async fn new() -> Self { 22 | let sandwich_address = utils::dotenv::get_sandwich_contract_address(); 23 | let searcher_wallet = utils::dotenv::get_searcher_wallet(); 24 | 25 | let client = utils::create_websocket_client().await.unwrap(); 26 | 27 | let nonce = if let Ok(n) = client 28 | .get_transaction_count(searcher_wallet.address(), None) 29 | .await 30 | { 31 | n 32 | } else { 33 | panic!("Failed to get searcher wallet nonce..."); 34 | }; 35 | 36 | let nonce = Arc::new(RwLock::new(nonce)); 37 | 38 | Self { 39 | v2: v2::SandwichLogicV2::new(), 40 | v3: v3::SandwichLogicV3::new(), 41 | sandwich_address, 42 | searcher_wallet, 43 | nonce, 44 | } 45 | } 46 | 47 | pub async fn update_searcher_nonce(&self) { 48 | let mut nonce = self.nonce.write().await; 49 | let client = utils::create_websocket_client().await.unwrap(); 50 | 51 | if let Ok(n) = client 52 | .get_transaction_count(self.searcher_wallet.address(), None) 53 | .await 54 | { 55 | *nonce = n; 56 | } else { 57 | panic!("Failed to update searcher wallet nonce..."); 58 | }; 59 | } 60 | } 61 | 62 | /// Encoded swap value used by other token 63 | pub struct EncodedSwapValue { 64 | encoded_value: U256, 65 | mem_offset: U256, 66 | // real value after encoding 67 | byte_shift: U256, 68 | } 69 | 70 | impl EncodedSwapValue { 71 | fn new(encoded_value: U256, mem_offset: U256, byte_shift: U256) -> Self { 72 | Self { 73 | encoded_value, 74 | mem_offset, 75 | byte_shift, 76 | } 77 | } 78 | 79 | // returns the decoded value after applying byteshift (real value used during swaps) 80 | fn decode(&self) -> U256 { 81 | self.encoded_value * (U256::from(2).pow(U256::from(8) * self.byte_shift)) 82 | } 83 | } 84 | 85 | /// Return the divisor used for encoding call value (weth amount) 86 | pub fn get_weth_encode_divisor() -> U256 { 87 | U256::from_dec_str("4294967296").unwrap() 88 | } 89 | -------------------------------------------------------------------------------- /contract/.env.example: -------------------------------------------------------------------------------- 1 | HTTP_RPC_URL= 2 | PRIVATE_KEY= 3 | SEARCHER_PRIVATE_KEY= 4 | SEARCHER=0x... -------------------------------------------------------------------------------- /contract/.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push] 4 | 5 | jobs: 6 | tests: 7 | name: Tests with Foundry 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v3 12 | with: 13 | submodules: recursive 14 | 15 | - name: Install Foundry 16 | uses: foundry-rs/foundry-toolchain@v1 17 | with: 18 | version: nightly 19 | 20 | - name: Install Huff 21 | uses: huff-language/huff-toolchain@v2 22 | with: 23 | version: nightly 24 | 25 | - name: Run Tests 26 | run: forge test -vvv 27 | 28 | scripts: 29 | strategy: 30 | fail-fast: true 31 | name: Run Scripts 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v3 35 | with: 36 | submodules: recursive 37 | 38 | - name: Install Foundry 39 | uses: foundry-rs/foundry-toolchain@v1 40 | with: 41 | version: nightly 42 | 43 | - name: Install Huff 44 | uses: huff-language/huff-toolchain@v2 45 | with: 46 | version: nightly 47 | 48 | - name: Run Forge build 49 | run: | 50 | forge --version 51 | forge build --sizes 52 | id: build 53 | continue-on-error: true 54 | 55 | - name: Run scripts 56 | run: | 57 | ls -lsa 58 | ls script/ 59 | for file in script/*; do 60 | forge script $file -vvvv 61 | done -------------------------------------------------------------------------------- /contract/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/foundry-huff"] 2 | path = lib/foundry-huff 3 | url = https://github.com/huff-language/foundry-huff 4 | [submodule "lib/forge-std"] 5 | path = lib/forge-std 6 | url = https://github.com/foundry-rs/forge-std 7 | -------------------------------------------------------------------------------- /contract/.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /contract/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 0xmouseless 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /contract/foundry.toml: -------------------------------------------------------------------------------- 1 | 2 | [profile.default] 3 | solc_version = '0.8.15' 4 | auto_detect_solc = false 5 | optimizer = true 6 | optimizer_runs = 200 # Default amount 7 | via-ir = true 8 | ffi = true 9 | fuzz_runs = 1_000 10 | evm_version = 'shanghai' 11 | remappings = [ 12 | "forge-std=lib/forge-std/src/", 13 | "foundry-huff=lib/foundry-huff/src/", 14 | "ds-test/=lib/forge-std/lib/ds-test/src/", 15 | "forge-std/=lib/forge-std/src/", 16 | "foundry-huff/=lib/foundry-huff/src/", 17 | "stringutils/=lib/foundry-huff/lib/solidity-stringutils/", 18 | "v2-core/=lib/v2-core/contracts/", 19 | "v2-periphery/=lib/v2-periphery/contracts/", 20 | "v3-core/=lib/v3-core/contracts/", 21 | ] 22 | -------------------------------------------------------------------------------- /contract/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | /// @dev Interface of the ERC20 standard as defined in the EIP. 5 | interface IERC20 { 6 | /// @dev Returns the amount of tokens in existence. 7 | function totalSupply() external view returns (uint256); 8 | 9 | /// @dev Returns the amount of tokens owned by `account`. 10 | function balanceOf(address account) external view returns (uint256); 11 | 12 | /// @dev Moves `amount` tokens from the caller's account to `recipient`. 13 | function transfer(address recipient, uint256 amount) 14 | external 15 | returns (bool); 16 | 17 | /// @dev Returns the remaining number of tokens that `spender` will be 18 | function allowance(address owner, address spender) 19 | external 20 | view 21 | returns (uint256); 22 | 23 | /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 24 | function approve(address spender, uint256 amount) external returns (bool); 25 | 26 | /// @dev Moves `amount` tokens from `sender` to `recipient` using the 27 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 28 | 29 | /// @dev Emitted when `value` tokens are moved from one account (`from`) to 30 | event Transfer(address indexed from, address indexed to, uint256 value); 31 | 32 | /// @dev Emitted when the allowance of a `spender` for an `owner` is set by 33 | event Approval(address indexed owner, address indexed spender, uint256 value); 34 | } 35 | -------------------------------------------------------------------------------- /contract/interfaces/IMetamorphicContractFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | interface IMetamorphicContractFactory { 5 | function deployMetamorphicContractFromExistingImplementation( 6 | bytes32 salt, 7 | address implementationContract, 8 | bytes calldata metamorphicContractInitializationCalldata 9 | ) external returns ( 10 | address metamorphicContractAddress 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /contract/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | interface IWETH { 5 | function name() external view returns (string memory); 6 | 7 | function approve(address guy, uint256 wad) external returns (bool); 8 | 9 | function totalSupply() external view returns (uint256); 10 | 11 | function transferFrom( 12 | address src, 13 | address dst, 14 | uint256 wad 15 | ) external returns (bool); 16 | 17 | function withdraw(uint256 wad) external; 18 | 19 | function decimals() external view returns (uint8); 20 | 21 | function balanceOf(address) external view returns (uint256); 22 | 23 | function symbol() external view returns (string memory); 24 | 25 | function transfer(address dst, uint256 wad) external returns (bool); 26 | 27 | function deposit() external payable; 28 | 29 | function allowance(address, address) external view returns (uint256); 30 | } 31 | -------------------------------------------------------------------------------- /contract/lib/forge-std/.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | check: 6 | name: Foundry project 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | with: 11 | submodules: recursive 12 | 13 | - name: Install Foundry 14 | uses: onbjerg/foundry-toolchain@v1 15 | with: 16 | version: nightly 17 | 18 | - name: Install dependencies 19 | run: forge install 20 | - name: Run tests 21 | run: forge test -vvv 22 | - name: Build Test with older solc versions 23 | run: | 24 | forge build --contracts src/Test.sol --use solc:0.8.0 25 | forge build --contracts src/Test.sol --use solc:0.7.6 26 | forge build --contracts src/Test.sol --use solc:0.7.0 27 | forge build --contracts src/Test.sol --use solc:0.6.0 28 | -------------------------------------------------------------------------------- /contract/lib/forge-std/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | -------------------------------------------------------------------------------- /contract/lib/forge-std/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright Contributors to Forge Standard Library 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE.R 26 | -------------------------------------------------------------------------------- /contract/lib/forge-std/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | fs_permissions = [{ access = "read-write", path = "./"}] 3 | 4 | [rpc_endpoints] 5 | # The RPC URLs are modified versions of the default for testing initialization. 6 | mainnet = "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5" # Different API key. 7 | optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. 8 | arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. 9 | needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" 10 | 11 | [fmt] 12 | # These are all the `forge fmt` defaults. 13 | line_length = 120 14 | tab_width = 4 15 | bracket_spacing = false 16 | int_types = 'long' 17 | multiline_func_header = 'attributes_first' 18 | quote_style = 'double' 19 | number_underscore = 'preserve' 20 | single_line_statement_blocks = 'preserve' 21 | ignore = ["src/console.sol", "src/console2.sol"] -------------------------------------------------------------------------------- /contract/lib/forge-std/lib/ds-test/.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "Build" 2 | on: 3 | pull_request: 4 | push: 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: cachix/install-nix-action@v18 11 | with: 12 | nix_path: nixpkgs=channel:nixos-unstable 13 | extra_nix_config: | 14 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 15 | 16 | - name: setup dapp binary cache 17 | uses: cachix/cachix-action@v12 18 | with: 19 | name: dapp 20 | 21 | - name: install dapptools 22 | run: nix profile install github:dapphub/dapptools#dapp --accept-flake-config 23 | 24 | - name: install foundry 25 | uses: foundry-rs/foundry-toolchain@v1 26 | 27 | - name: test with solc-0.5.17 28 | run: dapp --use solc-0.5.17 test -v 29 | 30 | - name: test with solc-0.6.11 31 | run: dapp --use solc-0.6.11 test -v 32 | 33 | - name: test with solc-0.7.6 34 | run: dapp --use solc-0.7.6 test -v 35 | 36 | - name: test with solc-0.8.18 37 | run: dapp --use solc-0.8.18 test -v 38 | 39 | - name: Run tests with foundry 40 | run: forge test -vvv 41 | 42 | -------------------------------------------------------------------------------- /contract/lib/forge-std/lib/ds-test/Makefile: -------------------------------------------------------------------------------- 1 | all:; dapp build 2 | 3 | test: 4 | -dapp --use solc:0.4.23 build 5 | -dapp --use solc:0.4.26 build 6 | -dapp --use solc:0.5.17 build 7 | -dapp --use solc:0.6.12 build 8 | -dapp --use solc:0.7.5 build 9 | 10 | demo: 11 | DAPP_SRC=demo dapp --use solc:0.7.5 build 12 | -hevm dapp-test --verbose 3 13 | 14 | .PHONY: test demo 15 | -------------------------------------------------------------------------------- /contract/lib/forge-std/lib/ds-test/default.nix: -------------------------------------------------------------------------------- 1 | { solidityPackage, dappsys }: solidityPackage { 2 | name = "ds-test"; 3 | src = ./src; 4 | } 5 | -------------------------------------------------------------------------------- /contract/lib/forge-std/lib/ds-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ds-test", 3 | "version": "1.0.0", 4 | "description": "Assertions, equality checks and other test helpers ", 5 | "bugs": "https://github.com/dapphub/ds-test/issues", 6 | "license": "GPL-3.0", 7 | "author": "Contributors to ds-test", 8 | "files": [ 9 | "src/*" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/dapphub/ds-test.git" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /contract/lib/forge-std/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forge-std", 3 | "version": "1.5.2", 4 | "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", 5 | "homepage": "https://book.getfoundry.sh/forge/forge-std", 6 | "bugs": "https://github.com/foundry-rs/forge-std/issues", 7 | "license": "(Apache-2.0 OR MIT)", 8 | "author": "Contributors to Forge Standard Library", 9 | "files": [ 10 | "src/**/*" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/foundry-rs/forge-std.git" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/Base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import {StdStorage} from "./StdStorage.sol"; 5 | import {Vm, VmSafe} from "./Vm.sol"; 6 | 7 | abstract contract CommonBase { 8 | // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. 9 | address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); 10 | // console.sol and console2.sol work by executing a staticcall to this address. 11 | address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; 12 | // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. 13 | address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); 14 | // Address of the test contract, deployed by the DEFAULT_SENDER. 15 | address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; 16 | // Deterministic deployment address of the Multicall3 contract. 17 | address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11; 18 | 19 | uint256 internal constant UINT256_MAX = 20 | 115792089237316195423570985008687907853269984665640564039457584007913129639935; 21 | 22 | Vm internal constant vm = Vm(VM_ADDRESS); 23 | StdStorage internal stdstore; 24 | } 25 | 26 | abstract contract TestBase is CommonBase {} 27 | 28 | abstract contract ScriptBase is CommonBase { 29 | // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. 30 | address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; 31 | 32 | VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); 33 | } 34 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/Script.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | // 💬 ABOUT 5 | // Standard Library's default Script. 6 | 7 | // 🧩 MODULES 8 | import {ScriptBase} from "./Base.sol"; 9 | import {console} from "./console.sol"; 10 | import {console2} from "./console2.sol"; 11 | import {StdChains} from "./StdChains.sol"; 12 | import {StdCheatsSafe} from "./StdCheats.sol"; 13 | import {stdJson} from "./StdJson.sol"; 14 | import {stdMath} from "./StdMath.sol"; 15 | import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; 16 | import {StdUtils} from "./StdUtils.sol"; 17 | import {VmSafe} from "./Vm.sol"; 18 | 19 | // 📦 BOILERPLATE 20 | import {ScriptBase} from "./Base.sol"; 21 | 22 | // ⭐️ SCRIPT 23 | abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase { 24 | // Note: IS_SCRIPT() must return true. 25 | bool public IS_SCRIPT = true; 26 | } 27 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/StdError.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test 3 | pragma solidity >=0.6.2 <0.9.0; 4 | 5 | library stdError { 6 | bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); 7 | bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); 8 | bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); 9 | bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); 10 | bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); 11 | bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); 12 | bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); 13 | bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); 14 | bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); 15 | } 16 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/StdMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | library stdMath { 5 | int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; 6 | 7 | function abs(int256 a) internal pure returns (uint256) { 8 | // Required or it will fail when `a = type(int256).min` 9 | if (a == INT256_MIN) { 10 | return 57896044618658097711785492504343953926634992332820282019728792003956564819968; 11 | } 12 | 13 | return uint256(a > 0 ? a : -a); 14 | } 15 | 16 | function delta(uint256 a, uint256 b) internal pure returns (uint256) { 17 | return a > b ? a - b : b - a; 18 | } 19 | 20 | function delta(int256 a, int256 b) internal pure returns (uint256) { 21 | // a and b are of the same sign 22 | // this works thanks to two's complement, the left-most bit is the sign bit 23 | if ((a ^ b) > -1) { 24 | return delta(abs(a), abs(b)); 25 | } 26 | 27 | // a and b are of opposite signs 28 | return abs(a) + abs(b); 29 | } 30 | 31 | function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { 32 | uint256 absDelta = delta(a, b); 33 | 34 | return absDelta * 1e18 / b; 35 | } 36 | 37 | function percentDelta(int256 a, int256 b) internal pure returns (uint256) { 38 | uint256 absDelta = delta(a, b); 39 | uint256 absB = abs(b); 40 | 41 | return absDelta * 1e18 / absB; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | // 💬 ABOUT 7 | // Standard Library's default Test 8 | 9 | // 🧩 MODULES 10 | import {console} from "./console.sol"; 11 | import {console2} from "./console2.sol"; 12 | import {StdAssertions} from "./StdAssertions.sol"; 13 | import {StdChains} from "./StdChains.sol"; 14 | import {StdCheats} from "./StdCheats.sol"; 15 | import {stdError} from "./StdError.sol"; 16 | import {StdInvariant} from "./StdInvariant.sol"; 17 | import {stdJson} from "./StdJson.sol"; 18 | import {stdMath} from "./StdMath.sol"; 19 | import {StdStorage, stdStorage} from "./StdStorage.sol"; 20 | import {StdUtils} from "./StdUtils.sol"; 21 | import {Vm} from "./Vm.sol"; 22 | import {StdStyle} from "./StdStyle.sol"; 23 | 24 | // 📦 BOILERPLATE 25 | import {TestBase} from "./Base.sol"; 26 | import {DSTest} from "ds-test/test.sol"; 27 | 28 | // ⭐️ TEST 29 | abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils, TestBase { 30 | // Note: IS_TEST() must return true. 31 | // Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. 32 | } 33 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/interfaces/IERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2; 3 | 4 | interface IERC165 { 5 | /// @notice Query if a contract implements an interface 6 | /// @param interfaceID The interface identifier, as specified in ERC-165 7 | /// @dev Interface identification is specified in ERC-165. This function 8 | /// uses less than 30,000 gas. 9 | /// @return `true` if the contract implements `interfaceID` and 10 | /// `interfaceID` is not 0xffffffff, `false` otherwise 11 | function supportsInterface(bytes4 interfaceID) external view returns (bool); 12 | } 13 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2; 3 | 4 | /// @dev Interface of the ERC20 standard as defined in the EIP. 5 | /// @dev This includes the optional name, symbol, and decimals metadata. 6 | interface IERC20 { 7 | /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). 8 | event Transfer(address indexed from, address indexed to, uint256 value); 9 | 10 | /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` 11 | /// is the new allowance. 12 | event Approval(address indexed owner, address indexed spender, uint256 value); 13 | 14 | /// @notice Returns the amount of tokens in existence. 15 | function totalSupply() external view returns (uint256); 16 | 17 | /// @notice Returns the amount of tokens owned by `account`. 18 | function balanceOf(address account) external view returns (uint256); 19 | 20 | /// @notice Moves `amount` tokens from the caller's account to `to`. 21 | function transfer(address to, uint256 amount) external returns (bool); 22 | 23 | /// @notice Returns the remaining number of tokens that `spender` is allowed 24 | /// to spend on behalf of `owner` 25 | function allowance(address owner, address spender) external view returns (uint256); 26 | 27 | /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. 28 | /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 29 | function approve(address spender, uint256 amount) external returns (bool); 30 | 31 | /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. 32 | /// `amount` is then deducted from the caller's allowance. 33 | function transferFrom(address from, address to, uint256 amount) external returns (bool); 34 | 35 | /// @notice Returns the name of the token. 36 | function name() external view returns (string memory); 37 | 38 | /// @notice Returns the symbol of the token. 39 | function symbol() external view returns (string memory); 40 | 41 | /// @notice Returns the decimals places of the token. 42 | function decimals() external view returns (uint8); 43 | } 44 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/interfaces/IMulticall3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | interface IMulticall3 { 7 | struct Call { 8 | address target; 9 | bytes callData; 10 | } 11 | 12 | struct Call3 { 13 | address target; 14 | bool allowFailure; 15 | bytes callData; 16 | } 17 | 18 | struct Call3Value { 19 | address target; 20 | bool allowFailure; 21 | uint256 value; 22 | bytes callData; 23 | } 24 | 25 | struct Result { 26 | bool success; 27 | bytes returnData; 28 | } 29 | 30 | function aggregate(Call[] calldata calls) 31 | external 32 | payable 33 | returns (uint256 blockNumber, bytes[] memory returnData); 34 | 35 | function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData); 36 | 37 | function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData); 38 | 39 | function blockAndAggregate(Call[] calldata calls) 40 | external 41 | payable 42 | returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); 43 | 44 | function getBasefee() external view returns (uint256 basefee); 45 | 46 | function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash); 47 | 48 | function getBlockNumber() external view returns (uint256 blockNumber); 49 | 50 | function getChainId() external view returns (uint256 chainid); 51 | 52 | function getCurrentBlockCoinbase() external view returns (address coinbase); 53 | 54 | function getCurrentBlockDifficulty() external view returns (uint256 difficulty); 55 | 56 | function getCurrentBlockGasLimit() external view returns (uint256 gaslimit); 57 | 58 | function getCurrentBlockTimestamp() external view returns (uint256 timestamp); 59 | 60 | function getEthBalance(address addr) external view returns (uint256 balance); 61 | 62 | function getLastBlockHash() external view returns (bytes32 blockHash); 63 | 64 | function tryAggregate(bool requireSuccess, Call[] calldata calls) 65 | external 66 | payable 67 | returns (Result[] memory returnData); 68 | 69 | function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) 70 | external 71 | payable 72 | returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); 73 | } 74 | -------------------------------------------------------------------------------- /contract/lib/forge-std/src/test/Script.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "../Test.sol"; 5 | 6 | contract ScriptTest is Test 7 | { 8 | function testGenerateCorrectAddress() external { 9 | address creation = computeCreateAddress(0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9, 14); 10 | assertEq(creation, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); 11 | } 12 | 13 | function testDeriveRememberKey() external { 14 | string memory mnemonic = "test test test test test test test test test test test junk"; 15 | 16 | (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); 17 | assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); 18 | assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); 19 | } 20 | } -------------------------------------------------------------------------------- /contract/lib/forge-std/test/compilation/CompilationScript.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Script.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationScript is Script {} 11 | -------------------------------------------------------------------------------- /contract/lib/forge-std/test/compilation/CompilationScriptBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Script.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationScriptBase is ScriptBase {} 11 | -------------------------------------------------------------------------------- /contract/lib/forge-std/test/compilation/CompilationTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Test.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationTest is Test {} 11 | -------------------------------------------------------------------------------- /contract/lib/forge-std/test/compilation/CompilationTestBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Test.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationTestBase is TestBase {} 11 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push] 4 | 5 | jobs: 6 | tests: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | submodules: recursive 13 | 14 | - name: Install Foundry 15 | uses: foundry-rs/foundry-toolchain@v1 16 | with: 17 | version: nightly 18 | 19 | - name: Install Huff 20 | uses: huff-language/huff-toolchain@v2 21 | with: 22 | version: nightly 23 | 24 | - name: Print the Bytecode for fun 25 | run: huffc -b src/test/contracts/Number.huff 26 | 27 | - name: Print the Scripts 28 | run: ls -lsa lib/foundry-huff/scripts/ 29 | 30 | - name: Run Tests 31 | run: forge test -vvv 32 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/solidity-stringutils"] 2 | path = lib/solidity-stringutils 3 | url = https://github.com/Arachnid/solidity-stringutils 4 | [submodule "lib/forge-std"] 5 | path = lib/forge-std 6 | url = https://github.com/foundry-rs/forge-std 7 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/Group 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/Group 1.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/banner.jpg -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/black_white_huff-removebg-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/black_white_huff-removebg-preview.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/black_white_huff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/black_white_huff.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/foundry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/foundry.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/foundry_huff_banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/foundry_huff_banner.jpg -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/foundry_huff_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/foundry_huff_banner.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/huff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/huff.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/inverted_huff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/inverted_huff.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/x-removebg-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/x-removebg-preview.png -------------------------------------------------------------------------------- /contract/lib/foundry-huff/assets/x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/foundry-huff/assets/x.jpg -------------------------------------------------------------------------------- /contract/lib/foundry-huff/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | ffi = true 6 | fuzz_runs = 2_000 -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/forge-std/.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | check: 6 | name: Foundry project 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | with: 11 | submodules: recursive 12 | 13 | - name: Install Foundry 14 | uses: onbjerg/foundry-toolchain@v1 15 | with: 16 | version: nightly 17 | 18 | - name: Install dependencies 19 | run: forge install 20 | - name: Run tests 21 | run: forge test -vvv 22 | - name: Build Test with older solc versions 23 | run: | 24 | forge build --contracts src/Test.sol --use solc:0.8.0 25 | forge build --contracts src/Test.sol --use solc:0.7.0 26 | forge build --contracts src/Test.sol --use solc:0.6.0 27 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/forge-std/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/forge-std/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 Brock Elmore 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE.R 26 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/forge-std/lib/ds-test/Makefile: -------------------------------------------------------------------------------- 1 | all:; dapp build 2 | 3 | test: 4 | -dapp --use solc:0.4.23 build 5 | -dapp --use solc:0.4.26 build 6 | -dapp --use solc:0.5.17 build 7 | -dapp --use solc:0.6.12 build 8 | -dapp --use solc:0.7.5 build 9 | 10 | demo: 11 | DAPP_SRC=demo dapp --use solc:0.7.5 build 12 | -hevm dapp-test --verbose 3 13 | 14 | .PHONY: test demo 15 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/forge-std/lib/ds-test/default.nix: -------------------------------------------------------------------------------- 1 | { solidityPackage, dappsys }: solidityPackage { 2 | name = "ds-test"; 3 | src = ./src; 4 | } 5 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/forge-std/src/test/Script.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "../Test.sol"; 5 | 6 | contract ScriptTest is Test 7 | { 8 | function testGenerateCorrectAddress() external { 9 | address creation = computeCreateAddress(0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9, 14); 10 | assertEq(creation, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); 11 | } 12 | } -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/foundry-huff/scripts/binary_check.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | if ! [[ "$(npm list -g huffc)" =~ "empty" ]]; then 4 | # huffc was installed via npm, return 0x00 5 | echo -n 0x00 6 | elif [[ "$(yarn global list)" =~ "huffc" ]]; then 7 | # huffc was installed via yarn, return 0x00 8 | echo -n 0x00 9 | else 10 | echo -n 0x01 11 | fi 12 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/foundry-huff/scripts/file_writer.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "$2" > $1 4 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/foundry-huff/scripts/rand_bytes.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -n $(hexdump -n 16 -v -e '"0x" 32/1 "%02x" "\n"' /dev/urandom) -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/foundry-huff/scripts/read_and_append.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cat $2 >> $1 4 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI" 2 | on: "push" 3 | jobs: 4 | tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2.3.4 8 | - uses: cachix/install-nix-action@v13 9 | - name: Install dapp 10 | run: nix-env -iA dapp -f $(curl -sS https://api.github.com/repos/dapphub/dapptools/releases/latest | jq -r .tarball_url) 11 | - name: Fetch submodules 12 | run: git submodule update --init 13 | - name: Run tests 14 | run: make test 15 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/Makefile: -------------------------------------------------------------------------------- 1 | all :; dapp build 2 | clean :; dapp clean 3 | test :; dapp test 4 | deploy :; dapp create SolidityStringutils 5 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/README: -------------------------------------------------------------------------------- 1 | Basic string utilities for Solidity, optimized for low gas usage. 2 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/dappfile: -------------------------------------------------------------------------------- 1 | version: 2.0.0 2 | tags: [] 3 | layout: 4 | sol_sources: . 5 | build_dir: build 6 | dependencies: {} 7 | ignore: [] 8 | name: ethereum-stringutils 9 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/lib/ds-test/Makefile: -------------------------------------------------------------------------------- 1 | all:; dapp build 2 | 3 | test: 4 | -dapp --use solc:0.4.23 build 5 | -dapp --use solc:0.4.26 build 6 | -dapp --use solc:0.5.17 build 7 | -dapp --use solc:0.6.12 build 8 | -dapp --use solc:0.7.5 build 9 | 10 | demo: 11 | DAPP_SRC=demo dapp --use solc:0.7.5 build 12 | -hevm dapp-test --verbose 3 13 | 14 | .PHONY: test demo 15 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/lib/ds-test/default.nix: -------------------------------------------------------------------------------- 1 | { solidityPackage, dappsys }: solidityPackage { 2 | name = "ds-test"; 3 | src = ./src; 4 | } 5 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/lib/solidity-stringutils/strings.sol: -------------------------------------------------------------------------------- 1 | ./src/strings.sol -------------------------------------------------------------------------------- /contract/lib/foundry-huff/remappings.txt: -------------------------------------------------------------------------------- 1 | forge-std/=lib/forge-std/src/ 2 | stringutils/=lib/solidity-stringutils/ -------------------------------------------------------------------------------- /contract/lib/foundry-huff/scripts/binary_check.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | if ! [[ "$(npm list -g huffc)" =~ "empty" ]]; then 4 | # huffc was installed via npm, return 0x00 5 | echo -n 0x00 6 | elif [[ "$(yarn global list)" =~ "huffc" ]]; then 7 | # huffc was installed via yarn, return 0x00 8 | echo -n 0x00 9 | else 10 | echo -n 0x01 11 | fi 12 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/scripts/file_writer.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "$2" > $1 4 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/scripts/rand_bytes.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -n $(hexdump -n 16 -v -e '"0x" 32/1 "%02x" "\n"' /dev/urandom) -------------------------------------------------------------------------------- /contract/lib/foundry-huff/scripts/read_and_append.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cat $2 >> $1 4 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/HuffConfig.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | import {INumber} from "./interfaces/INumber.sol"; 7 | import {IConstructor} from "./interfaces/IConstructor.sol"; 8 | import {HuffConfig} from "../HuffConfig.sol"; 9 | 10 | contract HuffConfigTest is Test { 11 | HuffConfig public config; 12 | INumber public number; 13 | 14 | function setUp() public { 15 | config = new HuffConfig(); 16 | } 17 | 18 | function testWithArgs(bytes memory some) public { 19 | config.with_args(some); 20 | assertEq(config.args(), some); 21 | } 22 | 23 | function testWithValue(uint256 value) public { 24 | config.with_value(value); 25 | assertEq(config.value(), value); 26 | } 27 | 28 | function testWithCode(string memory code) public { 29 | config.with_code(code); 30 | assertEq(config.code(), code); 31 | } 32 | 33 | function testWithConstantOverrides( 34 | string memory key, 35 | string memory value 36 | ) public { 37 | config.with_constant(key, value); 38 | (string memory k, string memory v) = config.const_overrides(0); 39 | assertEq(key, k); 40 | assertEq(value, v); 41 | } 42 | 43 | function testSetBroadcast(bool broadcast) public { 44 | config.set_broadcast(broadcast); 45 | bool b = config.should_broadcast(); 46 | assertEq(b, broadcast); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/contracts/ConstOverride.huff: -------------------------------------------------------------------------------- 1 | #define constant a = 0x01 2 | 3 | #define macro MAIN() = takes (0) returns (0) { 4 | [a] 5 | [b] 6 | } -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/contracts/Constructor.huff: -------------------------------------------------------------------------------- 1 | /* Interface */ 2 | #define function getArgOne() view returns (address) 3 | #define function getArgTwo() view returns (uint256) 4 | 5 | /* Storage Slots */ 6 | #define constant CONSTRUCTOR_ARG_ONE = FREE_STORAGE_POINTER() 7 | #define constant CONSTRUCTOR_ARG_TWO = FREE_STORAGE_POINTER() 8 | 9 | /* Events */ 10 | #define event ArgumentsUpdated(address indexed one, uint256 indexed two) 11 | 12 | #define constant ARGUMENTS_TOPIC = 0xd0a6a6b9636b3b1e85120bfc8c36f7bc862769b48e0854deaf8780636a71ce7d 13 | 14 | /* Constructor */ 15 | #define macro CONSTRUCTOR() = takes(0) returns (0) { 16 | // Copy the first argument into memory 17 | 0x20 // [size] - byte size to copy 18 | 0x40 codesize sub // [offset, size] - offset in the code to copy from 19 | 0x00 // [mem, offset, size] - offset in memory to copy to 20 | codecopy // [] 21 | 22 | // Store the first argument in storage 23 | 0x00 mload dup1 // [arg1, arg1] 24 | [CONSTRUCTOR_ARG_ONE] // [CONSTRUCTOR_ARG_ONE, arg1, arg1] 25 | sstore // [arg1] 26 | 27 | // Copy the second argument into memory 28 | 0x20 // [size, arg1] - byte size to copy 29 | 0x20 codesize sub // [offset, size, arg1] - offset in the code to copy from 30 | 0x00 // [mem, offset, size, arg1] - offset in memory to copy to 31 | codecopy // [arg1] 32 | 33 | // Store the second argument in storage 34 | 0x00 mload dup1 // [arg2, arg2, arg1] 35 | [CONSTRUCTOR_ARG_TWO] // [CONSTRUCTOR_ARG_TWO, arg2, arg2, arg1] 36 | sstore // [arg2, arg1] 37 | 38 | // Emit the owner updated event 39 | swap1 // [arg1, arg2] 40 | [ARGUMENTS_TOPIC] // [sig, arg1, arg2] 41 | 0x00 0x00 // [0, 0, sig, arg1, arg2] 42 | log3 // [] 43 | } 44 | 45 | /* First Argument Accessor */ 46 | #define macro GET_ARG_ONE() = takes (0) returns (0) { 47 | [CONSTRUCTOR_ARG_ONE] sload 48 | 0x00 mstore 49 | 0x20 0x00 return 50 | } 51 | 52 | /* Second Argument Accessor */ 53 | #define macro GET_ARG_TWO() = takes (0) returns (0) { 54 | [CONSTRUCTOR_ARG_TWO] sload 55 | 0x00 mstore 56 | 0x20 0x00 return 57 | } 58 | 59 | /* Main Macro */ 60 | #define macro MAIN() = takes (0) returns (0) { 61 | 0x00 calldataload 0xE0 shr 62 | dup1 0xbb01e52d eq arg_one jumpi 63 | dup1 0x98e45be4 eq arg_two jumpi 64 | 65 | arg_one: 66 | GET_ARG_ONE() 67 | arg_two: 68 | GET_ARG_TWO() 69 | } 70 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/contracts/ConstructorNeedsValue.huff: -------------------------------------------------------------------------------- 1 | 2 | #define macro CONSTRUCTOR() = takes (0) returns (0) { 3 | callvalue // [msg.value] 4 | iszero // [is_msg_value_zero] 5 | iszero // [is_msg_value_non_zero] 6 | deposited // [deposited_jumpdest, is_msg_value_non_zero] 7 | jumpi // [] 8 | 0x00 0x00 revert 9 | deposited: 10 | } 11 | 12 | #define macro MAIN() = takes (0) returns (0) { 13 | 0x00 calldataload 0xE0 shr 14 | 0x00 mstore 15 | 0x20 0x00 return 16 | } -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/contracts/LotsOfLogging.huff: -------------------------------------------------------------------------------- 1 | /* Events */ 2 | #define event LogOne() 3 | #define event LogTwo(address indexed a) 4 | #define event LogThree(address indexed a, uint256 indexed b) 5 | #define event LogFour(address indexed a, uint256 indexed b, bytes32 indexed c) 6 | #define event Extended(address indexed a, uint256 indexed b, bytes32 indexed h1, bytes32 h2, bytes32 two) 7 | 8 | /* Constructor */ 9 | #define macro CONSTRUCTOR() = takes(0) returns (0) { 10 | // Empty Anonymous Log 11 | // 0x00 0x00 log0 12 | 13 | // LogOne 14 | __EVENT_HASH(LogOne) // [hash] 15 | 0x00 0x00 log1 // [] 16 | 17 | // LogTwo 18 | caller // [address] 19 | __EVENT_HASH(LogTwo) // [hash, address] 20 | 0x00 0x00 log2 // [] 21 | 22 | // LogThree 23 | selfbalance // [balance] 24 | caller // [address, balance] 25 | __EVENT_HASH(LogThree) // [hash, address, balance] 26 | 0x00 0x00 log3 // [] 27 | 28 | // LogFour 29 | 0x01 0x00 mstore // [] 30 | 0x20 0x00 sha3 // [bytes32_hash] 31 | selfbalance // [balance, bytes32_hash] 32 | caller // [address, balance, bytes32_hash] 33 | __EVENT_HASH(LogFour) // [hash, address, balance, bytes32_hash] 34 | 0x00 0x00 log4 // [] 35 | 36 | // Evented Log 37 | 0x01 0x00 mstore // [] 38 | 0x20 0x00 sha3 // [hash1] 39 | 0x02 0x00 mstore // [hash1] 40 | 0x20 0x00 sha3 // [hash2, hash1] 41 | 0x00 mstore // [hash1] 42 | 0x03 0x20 mstore // [hash1] 43 | 0x20 0x20 sha3 // [two, hash1] 44 | 0x20 mstore // [hash1] 45 | selfbalance // [balance, hash1] 46 | caller // [address, balance, hash1] 47 | __EVENT_HASH(Extended) // [hash, address, balance, hash1] 48 | 0x40 0x00 log4 // [] 49 | } 50 | 51 | /* Main Macro - Does Nothing */ 52 | #define macro MAIN() = takes (0) returns (0) { 53 | 0x00 calldataload 0xE0 shr 54 | 0x00 mstore 55 | 0x20 0x00 return 56 | } 57 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/contracts/NoConstructor.huff: -------------------------------------------------------------------------------- 1 | /* Interface */ 2 | #define function getArgOne() view returns (address) 3 | #define function getArgTwo() view returns (uint256) 4 | 5 | /* Storage Slots */ 6 | #define constant CONSTRUCTOR_ARG_ONE = FREE_STORAGE_POINTER() 7 | #define constant CONSTRUCTOR_ARG_TWO = FREE_STORAGE_POINTER() 8 | 9 | /* Events */ 10 | #define event ArgumentsUpdated(address indexed one, uint256 indexed two) 11 | 12 | #define constant ARGUMENTS_TOPIC = 0xd0a6a6b9636b3b1e85120bfc8c36f7bc862769b48e0854deaf8780636a71ce7d 13 | 14 | /* First Argument Accessor */ 15 | #define macro GET_ARG_ONE() = takes (0) returns (0) { 16 | [CONSTRUCTOR_ARG_ONE] sload 17 | 0x00 mstore 18 | 0x20 0x00 return 19 | } 20 | 21 | /* Second Argument Accessor */ 22 | #define macro GET_ARG_TWO() = takes (0) returns (0) { 23 | [CONSTRUCTOR_ARG_TWO] sload 24 | 0x00 mstore 25 | 0x20 0x00 return 26 | } 27 | 28 | /* Main Macro */ 29 | #define macro MAIN() = takes (0) returns (0) { 30 | 0x00 calldataload 0xE0 shr 31 | dup1 0xbb01e52d eq arg_one jumpi 32 | dup1 0x98e45be4 eq arg_two jumpi 33 | 34 | arg_one: 35 | GET_ARG_ONE() 36 | arg_two: 37 | GET_ARG_TWO() 38 | } 39 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/contracts/Number.huff: -------------------------------------------------------------------------------- 1 | /* Interface */ 2 | #define function setNumber(uint256) nonpayable returns () 3 | #define function getNumber() view returns (uint256) 4 | 5 | /* Storage Slots */ 6 | #define constant NUMBER_LOCATION = FREE_STORAGE_POINTER() 7 | 8 | /* Methods */ 9 | #define macro SET_NUMBER() = takes (0) returns (0) { 10 | 0x04 calldataload // [number] 11 | [NUMBER_LOCATION] // [ptr, number] 12 | sstore // [] 13 | } 14 | 15 | #define macro GET_NUMBER() = takes (0) returns (0) { 16 | // Load number from storage. 17 | [NUMBER_LOCATION] // [ptr] 18 | sload // [number] 19 | 20 | // Store number in memory. 21 | 0x00 mstore 22 | 23 | // Return number 24 | 0x20 0x00 return 25 | } 26 | 27 | #define macro MAIN() = takes (0) returns (0) { 28 | // Identify which function is being called. 29 | 0x00 calldataload 0xE0 shr 30 | dup1 0x3fb5c1cb eq set jumpi 31 | dup1 0xf2c9ecd8 eq get jumpi 32 | 33 | set: 34 | SET_NUMBER() 35 | get: 36 | GET_NUMBER() 37 | 38 | } -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/interfaces/IConstructor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | interface IConstructor { 5 | function getArgOne() external returns (address); 6 | function getArgTwo() external returns (uint256); 7 | } 8 | -------------------------------------------------------------------------------- /contract/lib/foundry-huff/src/test/interfaces/INumber.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | interface INumber { 5 | function setNumber(uint256) external; 6 | function getNumber() external returns (uint256); 7 | } 8 | -------------------------------------------------------------------------------- /contract/lib/v2-core/.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /contract/lib/v2-core/.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | matrix: 13 | node: ['10.x', '12.x'] 14 | os: [ubuntu-latest] 15 | 16 | runs-on: ${{ matrix.os }} 17 | 18 | steps: 19 | - uses: actions/checkout@v1 20 | - uses: actions/setup-node@v1 21 | with: 22 | node-version: ${{ matrix.node }} 23 | 24 | - run: npm install -g yarn 25 | 26 | - id: yarn-cache 27 | run: echo "::set-output name=dir::$(yarn cache dir)" 28 | - uses: actions/cache@v1 29 | with: 30 | path: ${{ steps.yarn-cache.outputs.dir }} 31 | key: ${{ matrix.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 32 | restore-keys: | 33 | ${{ matrix.os }}-yarn- 34 | 35 | - run: yarn 36 | - run: yarn lint 37 | - run: yarn test 38 | -------------------------------------------------------------------------------- /contract/lib/v2-core/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extension": ["ts"], 3 | "spec": "./test/**/*.spec.ts", 4 | "require": "ts-node/register", 5 | "timeout": 12000 6 | } 7 | -------------------------------------------------------------------------------- /contract/lib/v2-core/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "printWidth": 120 5 | } 6 | -------------------------------------------------------------------------------- /contract/lib/v2-core/.waffle.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerVersion": "./node_modules/solc", 3 | "outputType": "all", 4 | "compilerOptions": { 5 | "outputSelection": { 6 | "*": { 7 | "*": [ 8 | "evm.bytecode.object", 9 | "evm.deployedBytecode.object", 10 | "abi", 11 | "evm.bytecode.sourceMap", 12 | "evm.deployedBytecode.sourceMap", 13 | "metadata" 14 | ], 15 | "": ["ast"] 16 | } 17 | }, 18 | "evmVersion": "istanbul", 19 | "optimizer": { 20 | "enabled": true, 21 | "runs": 999999 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contract/lib/v2-core/README.md: -------------------------------------------------------------------------------- 1 | # Uniswap V2 2 | 3 | [![Actions Status](https://github.com/Uniswap/uniswap-v2-core/workflows/CI/badge.svg)](https://github.com/Uniswap/uniswap-v2-core/actions) 4 | [![Version](https://img.shields.io/npm/v/@uniswap/v2-core)](https://www.npmjs.com/package/@uniswap/v2-core) 5 | 6 | In-depth documentation on Uniswap V2 is available at [uniswap.org](https://uniswap.org/docs). 7 | 8 | The built contract artifacts can be browsed via [unpkg.com](https://unpkg.com/browse/@uniswap/v2-core@latest/). 9 | 10 | # Local Development 11 | 12 | The following assumes the use of `node@>=10`. 13 | 14 | ## Install Dependencies 15 | 16 | `yarn` 17 | 18 | ## Compile Contracts 19 | 20 | `yarn compile` 21 | 22 | ## Run Tests 23 | 24 | `yarn test` 25 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/UniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './interfaces/IUniswapV2Factory.sol'; 4 | import './UniswapV2Pair.sol'; 5 | 6 | contract UniswapV2Factory is IUniswapV2Factory { 7 | address public feeTo; 8 | address public feeToSetter; 9 | 10 | mapping(address => mapping(address => address)) public getPair; 11 | address[] public allPairs; 12 | 13 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 14 | 15 | constructor(address _feeToSetter) public { 16 | feeToSetter = _feeToSetter; 17 | } 18 | 19 | function allPairsLength() external view returns (uint) { 20 | return allPairs.length; 21 | } 22 | 23 | function createPair(address tokenA, address tokenB) external returns (address pair) { 24 | require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES'); 25 | (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 26 | require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS'); 27 | require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient 28 | bytes memory bytecode = type(UniswapV2Pair).creationCode; 29 | bytes32 salt = keccak256(abi.encodePacked(token0, token1)); 30 | assembly { 31 | pair := create2(0, add(bytecode, 32), mload(bytecode), salt) 32 | } 33 | IUniswapV2Pair(pair).initialize(token0, token1); 34 | getPair[token0][token1] = pair; 35 | getPair[token1][token0] = pair; // populate mapping in the reverse direction 36 | allPairs.push(pair); 37 | emit PairCreated(token0, token1, pair, allPairs.length); 38 | } 39 | 40 | function setFeeTo(address _feeTo) external { 41 | require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); 42 | feeTo = _feeTo; 43 | } 44 | 45 | function setFeeToSetter(address _feeToSetter) external { 46 | require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); 47 | feeToSetter = _feeToSetter; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IERC20 { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external view returns (string memory); 8 | function symbol() external view returns (string memory); 9 | function decimals() external view returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/interfaces/IUniswapV2Callee.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV2Callee { 4 | function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; 5 | } 6 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/interfaces/IUniswapV2ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV2ERC20 { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external pure returns (string memory); 8 | function symbol() external pure returns (string memory); 9 | function decimals() external pure returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | 18 | function DOMAIN_SEPARATOR() external view returns (bytes32); 19 | function PERMIT_TYPEHASH() external pure returns (bytes32); 20 | function nonces(address owner) external view returns (uint); 21 | 22 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 23 | } 24 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/interfaces/IUniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV2Factory { 4 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 5 | 6 | function feeTo() external view returns (address); 7 | function feeToSetter() external view returns (address); 8 | 9 | function getPair(address tokenA, address tokenB) external view returns (address pair); 10 | function allPairs(uint) external view returns (address pair); 11 | function allPairsLength() external view returns (uint); 12 | 13 | function createPair(address tokenA, address tokenB) external returns (address pair); 14 | 15 | function setFeeTo(address) external; 16 | function setFeeToSetter(address) external; 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/interfaces/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV2Pair { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external pure returns (string memory); 8 | function symbol() external pure returns (string memory); 9 | function decimals() external pure returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | 18 | function DOMAIN_SEPARATOR() external view returns (bytes32); 19 | function PERMIT_TYPEHASH() external pure returns (bytes32); 20 | function nonces(address owner) external view returns (uint); 21 | 22 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 23 | 24 | event Mint(address indexed sender, uint amount0, uint amount1); 25 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 26 | event Swap( 27 | address indexed sender, 28 | uint amount0In, 29 | uint amount1In, 30 | uint amount0Out, 31 | uint amount1Out, 32 | address indexed to 33 | ); 34 | event Sync(uint112 reserve0, uint112 reserve1); 35 | 36 | function MINIMUM_LIQUIDITY() external pure returns (uint); 37 | function factory() external view returns (address); 38 | function token0() external view returns (address); 39 | function token1() external view returns (address); 40 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 41 | function price0CumulativeLast() external view returns (uint); 42 | function price1CumulativeLast() external view returns (uint); 43 | function kLast() external view returns (uint); 44 | 45 | function mint(address to) external returns (uint liquidity); 46 | function burn(address to) external returns (uint amount0, uint amount1); 47 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 48 | function skim(address to) external; 49 | function sync() external; 50 | 51 | function initialize(address, address) external; 52 | } 53 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/libraries/Math.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for performing various math operations 4 | 5 | library Math { 6 | function min(uint x, uint y) internal pure returns (uint z) { 7 | z = x < y ? x : y; 8 | } 9 | 10 | // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) 11 | function sqrt(uint y) internal pure returns (uint z) { 12 | if (y > 3) { 13 | z = y; 14 | uint x = y / 2 + 1; 15 | while (x < z) { 16 | z = x; 17 | x = (y / x + x) / 2; 18 | } 19 | } else if (y != 0) { 20 | z = 1; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/libraries/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 4 | 5 | library SafeMath { 6 | function add(uint x, uint y) internal pure returns (uint z) { 7 | require((z = x + y) >= x, 'ds-math-add-overflow'); 8 | } 9 | 10 | function sub(uint x, uint y) internal pure returns (uint z) { 11 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 12 | } 13 | 14 | function mul(uint x, uint y) internal pure returns (uint z) { 15 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/libraries/UQ112x112.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 4 | 5 | // range: [0, 2**112 - 1] 6 | // resolution: 1 / 2**112 7 | 8 | library UQ112x112 { 9 | uint224 constant Q112 = 2**112; 10 | 11 | // encode a uint112 as a UQ112x112 12 | function encode(uint112 y) internal pure returns (uint224 z) { 13 | z = uint224(y) * Q112; // never overflows 14 | } 15 | 16 | // divide a UQ112x112 by a uint112, returning a UQ112x112 17 | function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { 18 | z = x / uint224(y); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contract/lib/v2-core/contracts/test/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import '../UniswapV2ERC20.sol'; 4 | 5 | contract ERC20 is UniswapV2ERC20 { 6 | constructor(uint _totalSupply) public { 7 | _mint(msg.sender, _totalSupply); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /contract/lib/v2-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@uniswap/v2-core", 3 | "description": "🎛 Core contracts for the UniswapV2 protocol", 4 | "version": "1.0.1", 5 | "homepage": "https://uniswap.org", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/Uniswap/uniswap-v2-core" 9 | }, 10 | "keywords": [ 11 | "uniswap", 12 | "ethereum", 13 | "v2", 14 | "core", 15 | "uniswap-v2" 16 | ], 17 | "files": [ 18 | "contracts", 19 | "build" 20 | ], 21 | "engines": { 22 | "node": ">=10" 23 | }, 24 | "devDependencies": { 25 | "@types/chai": "^4.2.6", 26 | "@types/mocha": "^5.2.7", 27 | "chai": "^4.2.0", 28 | "ethereum-waffle": "^2.4.1", 29 | "ethereumjs-util": "^6.2.0", 30 | "mocha": "^6.2.2", 31 | "prettier": "^1.19.1", 32 | "rimraf": "^3.0.0", 33 | "solc": "0.5.16", 34 | "ts-node": "^8.5.4", 35 | "typescript": "^3.7.3" 36 | }, 37 | "scripts": { 38 | "lint": "yarn prettier ./test/*.ts --check", 39 | "lint:fix": "yarn prettier ./test/*.ts --write", 40 | "clean": "rimraf ./build/", 41 | "precompile": "yarn clean", 42 | "compile": "waffle .waffle.json", 43 | "pretest": "yarn compile", 44 | "test": "mocha", 45 | "prepublishOnly": "yarn test" 46 | }, 47 | "license": "GPL-3.0-or-later" 48 | } 49 | -------------------------------------------------------------------------------- /contract/lib/v2-core/test/shared/fixtures.ts: -------------------------------------------------------------------------------- 1 | import { Contract, Wallet } from 'ethers' 2 | import { Web3Provider } from 'ethers/providers' 3 | import { deployContract } from 'ethereum-waffle' 4 | 5 | import { expandTo18Decimals } from './utilities' 6 | 7 | import ERC20 from '../../build/ERC20.json' 8 | import UniswapV2Factory from '../../build/UniswapV2Factory.json' 9 | import UniswapV2Pair from '../../build/UniswapV2Pair.json' 10 | 11 | interface FactoryFixture { 12 | factory: Contract 13 | } 14 | 15 | const overrides = { 16 | gasLimit: 9999999 17 | } 18 | 19 | export async function factoryFixture(_: Web3Provider, [wallet]: Wallet[]): Promise { 20 | const factory = await deployContract(wallet, UniswapV2Factory, [wallet.address], overrides) 21 | return { factory } 22 | } 23 | 24 | interface PairFixture extends FactoryFixture { 25 | token0: Contract 26 | token1: Contract 27 | pair: Contract 28 | } 29 | 30 | export async function pairFixture(provider: Web3Provider, [wallet]: Wallet[]): Promise { 31 | const { factory } = await factoryFixture(provider, [wallet]) 32 | 33 | const tokenA = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides) 34 | const tokenB = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides) 35 | 36 | await factory.createPair(tokenA.address, tokenB.address, overrides) 37 | const pairAddress = await factory.getPair(tokenA.address, tokenB.address) 38 | const pair = new Contract(pairAddress, JSON.stringify(UniswapV2Pair.abi), provider).connect(wallet) 39 | 40 | const token0Address = (await pair.token0()).address 41 | const token0 = tokenA.address === token0Address ? tokenA : tokenB 42 | const token1 = tokenA.address === token0Address ? tokenB : tokenA 43 | 44 | return { factory, token0, token1, pair } 45 | } 46 | -------------------------------------------------------------------------------- /contract/lib/v2-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "resolveJsonModule": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /contract/lib/v2-periphery/.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | issues: 4 | # Number of days of inactivity before an Issue or Pull Request becomes stale 5 | daysUntilStale: 7 6 | 7 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 8 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 9 | daysUntilClose: 7 10 | 11 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 12 | onlyLabels: 13 | - question 14 | - autoclose 15 | 16 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 17 | exemptLabels: 18 | - p0 19 | - bug 20 | 21 | # Comment to post when marking as stale. Set to `false` to disable 22 | markComment: > 23 | This issue has been automatically marked as stale because it has not had 24 | recent activity. It will be closed if no further activity occurs. Thank you 25 | for your contributions. 26 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | matrix: 13 | node: ['10.x', '12.x'] 14 | os: [ubuntu-latest] 15 | 16 | runs-on: ${{ matrix.os }} 17 | 18 | steps: 19 | - uses: actions/checkout@v1 20 | - uses: actions/setup-node@v1 21 | with: 22 | node-version: ${{ matrix.node }} 23 | 24 | - run: npm install -g yarn 25 | 26 | - id: yarn-cache 27 | run: echo "::set-output name=dir::$(yarn cache dir)" 28 | - uses: actions/cache@v1 29 | with: 30 | path: ${{ steps.yarn-cache.outputs.dir }} 31 | key: ${{ matrix.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 32 | restore-keys: | 33 | ${{ matrix.os }}-yarn- 34 | 35 | - run: yarn 36 | 37 | - run: yarn lint 38 | - run: yarn test 39 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extension": ["ts"], 3 | "spec": "./test/**/*.spec.ts", 4 | "require": "ts-node/register", 5 | "timeout": 12000 6 | } 7 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "printWidth": 120 5 | } 6 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/.waffle.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerVersion": "./node_modules/solc", 3 | "outputType": "all", 4 | "compilerOptions": { 5 | "outputSelection": { 6 | "*": { 7 | "*": [ 8 | "evm.bytecode.object", 9 | "evm.deployedBytecode.object", 10 | "abi", 11 | "evm.bytecode.sourceMap", 12 | "evm.deployedBytecode.sourceMap", 13 | "metadata" 14 | ], 15 | "": ["ast"] 16 | } 17 | }, 18 | "evmVersion": "istanbul", 19 | "optimizer": { 20 | "enabled": true, 21 | "runs": 999999 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/.yarnrc: -------------------------------------------------------------------------------- 1 | ignore-scripts true 2 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/README.md: -------------------------------------------------------------------------------- 1 | # Uniswap V2 2 | 3 | [![Actions Status](https://github.com/Uniswap/uniswap-v2-periphery/workflows/CI/badge.svg)](https://github.com/Uniswap/uniswap-v2-periphery/actions) 4 | [![npm](https://img.shields.io/npm/v/@uniswap/v2-periphery?style=flat-square)](https://npmjs.com/package/@uniswap/v2-periphery) 5 | 6 | In-depth documentation on Uniswap V2 is available at [uniswap.org](https://uniswap.org/docs). 7 | 8 | The built contract artifacts can be browsed via [unpkg.com](https://unpkg.com/browse/@uniswap/v2-periphery@latest/). 9 | 10 | # Local Development 11 | 12 | The following assumes the use of `node@>=10`. 13 | 14 | ## Install Dependencies 15 | 16 | `yarn` 17 | 18 | ## Compile Contracts 19 | 20 | `yarn compile` 21 | 22 | ## Run Tests 23 | 24 | `yarn test` 25 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/UniswapV2Migrator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.6.6; 2 | 3 | import '@uniswap/lib/contracts/libraries/TransferHelper.sol'; 4 | 5 | import './interfaces/IUniswapV2Migrator.sol'; 6 | import './interfaces/V1/IUniswapV1Factory.sol'; 7 | import './interfaces/V1/IUniswapV1Exchange.sol'; 8 | import './interfaces/IUniswapV2Router01.sol'; 9 | import './interfaces/IERC20.sol'; 10 | 11 | contract UniswapV2Migrator is IUniswapV2Migrator { 12 | IUniswapV1Factory immutable factoryV1; 13 | IUniswapV2Router01 immutable router; 14 | 15 | constructor(address _factoryV1, address _router) public { 16 | factoryV1 = IUniswapV1Factory(_factoryV1); 17 | router = IUniswapV2Router01(_router); 18 | } 19 | 20 | // needs to accept ETH from any v1 exchange and the router. ideally this could be enforced, as in the router, 21 | // but it's not possible because it requires a call to the v1 factory, which takes too much gas 22 | receive() external payable {} 23 | 24 | function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) 25 | external 26 | override 27 | { 28 | IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(token)); 29 | uint liquidityV1 = exchangeV1.balanceOf(msg.sender); 30 | require(exchangeV1.transferFrom(msg.sender, address(this), liquidityV1), 'TRANSFER_FROM_FAILED'); 31 | (uint amountETHV1, uint amountTokenV1) = exchangeV1.removeLiquidity(liquidityV1, 1, 1, uint(-1)); 32 | TransferHelper.safeApprove(token, address(router), amountTokenV1); 33 | (uint amountTokenV2, uint amountETHV2,) = router.addLiquidityETH{value: amountETHV1}( 34 | token, 35 | amountTokenV1, 36 | amountTokenMin, 37 | amountETHMin, 38 | to, 39 | deadline 40 | ); 41 | if (amountTokenV1 > amountTokenV2) { 42 | TransferHelper.safeApprove(token, address(router), 0); // be a good blockchain citizen, reset allowance to 0 43 | TransferHelper.safeTransfer(token, msg.sender, amountTokenV1 - amountTokenV2); 44 | } else if (amountETHV1 > amountETHV2) { 45 | // addLiquidityETH guarantees that all of amountETHV1 or amountTokenV1 will be used, hence this else is safe 46 | TransferHelper.safeTransferETH(msg.sender, amountETHV1 - amountETHV2); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## Disclaimer 4 | 5 | These contracts are for demonstrative purposes only. 6 | While these contracts have unit tests, and we generally expect them to be 7 | correct, there are no guarantees about the correctness or security of 8 | these contracts. We hold these contracts to a different standard of 9 | correctness and security than other contracts in this repository. 10 | E.g., we have explicitly excluded these contracts from the 11 | [bug bounty](https://uniswap.org/bug-bounty/#scope). 12 | 13 | You must do your own due diligence if you wish to use code 14 | from these examples in your project. 15 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IERC20 { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external view returns (string memory); 8 | function symbol() external view returns (string memory); 9 | function decimals() external view returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/interfaces/IUniswapV2Migrator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV2Migrator { 4 | function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external; 5 | } 6 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | import './IUniswapV2Router01.sol'; 4 | 5 | interface IUniswapV2Router02 is IUniswapV2Router01 { 6 | function removeLiquidityETHSupportingFeeOnTransferTokens( 7 | address token, 8 | uint liquidity, 9 | uint amountTokenMin, 10 | uint amountETHMin, 11 | address to, 12 | uint deadline 13 | ) external returns (uint amountETH); 14 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 15 | address token, 16 | uint liquidity, 17 | uint amountTokenMin, 18 | uint amountETHMin, 19 | address to, 20 | uint deadline, 21 | bool approveMax, uint8 v, bytes32 r, bytes32 s 22 | ) external returns (uint amountETH); 23 | 24 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 25 | uint amountIn, 26 | uint amountOutMin, 27 | address[] calldata path, 28 | address to, 29 | uint deadline 30 | ) external; 31 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 32 | uint amountOutMin, 33 | address[] calldata path, 34 | address to, 35 | uint deadline 36 | ) external payable; 37 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 38 | uint amountIn, 39 | uint amountOutMin, 40 | address[] calldata path, 41 | address to, 42 | uint deadline 43 | ) external; 44 | } 45 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IWETH { 4 | function deposit() external payable; 5 | function transfer(address to, uint value) external returns (bool); 6 | function withdraw(uint) external; 7 | } 8 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/interfaces/V1/IUniswapV1Exchange.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV1Exchange { 4 | function balanceOf(address owner) external view returns (uint); 5 | function transferFrom(address from, address to, uint value) external returns (bool); 6 | function removeLiquidity(uint, uint, uint, uint) external returns (uint, uint); 7 | function tokenToEthSwapInput(uint, uint, uint) external returns (uint); 8 | function ethToTokenSwapInput(uint, uint) external payable returns (uint); 9 | } 10 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/interfaces/V1/IUniswapV1Factory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IUniswapV1Factory { 4 | function getExchange(address) external view returns (address); 5 | } 6 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/libraries/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.6.6; 2 | 3 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 4 | 5 | library SafeMath { 6 | function add(uint x, uint y) internal pure returns (uint z) { 7 | require((z = x + y) >= x, 'ds-math-add-overflow'); 8 | } 9 | 10 | function sub(uint x, uint y) internal pure returns (uint z) { 11 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 12 | } 13 | 14 | function mul(uint x, uint y) internal pure returns (uint z) { 15 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/contracts/libraries/UniswapV2OracleLibrary.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; 4 | import '@uniswap/lib/contracts/libraries/FixedPoint.sol'; 5 | 6 | // library with helper methods for oracles that are concerned with computing average prices 7 | library UniswapV2OracleLibrary { 8 | using FixedPoint for *; 9 | 10 | // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] 11 | function currentBlockTimestamp() internal view returns (uint32) { 12 | return uint32(block.timestamp % 2 ** 32); 13 | } 14 | 15 | // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. 16 | function currentCumulativePrices( 17 | address pair 18 | ) internal view returns (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) { 19 | blockTimestamp = currentBlockTimestamp(); 20 | price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); 21 | price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast(); 22 | 23 | // if time has elapsed since the last update on the pair, mock the accumulated price values 24 | (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves(); 25 | if (blockTimestampLast != blockTimestamp) { 26 | // subtraction overflow is desired 27 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; 28 | // addition overflow is desired 29 | // counterfactual 30 | price0Cumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; 31 | // counterfactual 32 | price1Cumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@uniswap/v2-periphery", 3 | "version": "1.1.0-beta.0", 4 | "description": "🎚 Peripheral smart contracts for interacting with Uniswap V2", 5 | "engines": { 6 | "node": ">=10" 7 | }, 8 | "homepage": "https://uniswap.org", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/Uniswap/uniswap-v2-periphery" 12 | }, 13 | "files": [ 14 | "build", 15 | "contracts" 16 | ], 17 | "dependencies": { 18 | "@uniswap/lib": "4.0.1-alpha", 19 | "@uniswap/v2-core": "1.0.0" 20 | }, 21 | "devDependencies": { 22 | "@types/chai": "^4.2.6", 23 | "@types/mocha": "^5.2.7", 24 | "chai": "^4.2.0", 25 | "ethereum-waffle": "^2.4.1", 26 | "ethereumjs-util": "^6.2.0", 27 | "mocha": "^6.2.2", 28 | "ncp": "^2.0.0", 29 | "prettier": "^1.19.1", 30 | "rimraf": "^3.0.0", 31 | "solc": "0.6.6", 32 | "ts-node": "^8.5.4", 33 | "typescript": "^3.7.3" 34 | }, 35 | "scripts": { 36 | "lint": "yarn prettier ./test/*.ts --check", 37 | "lint:fix": "yarn prettier ./test/*.ts --write", 38 | "clean": "rimraf ./build/", 39 | "copy-v1-artifacts": "ncp ./buildV1 ./build", 40 | "precompile": "yarn clean", 41 | "compile": "waffle .waffle.json", 42 | "postcompile": "yarn copy-v1-artifacts", 43 | "pretest": "yarn compile", 44 | "test": "mocha", 45 | "prepublishOnly": "yarn test" 46 | }, 47 | "license": "GPL-3.0-or-later" 48 | } 49 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/test/ExampleOracleSimple.spec.ts: -------------------------------------------------------------------------------- 1 | import chai, { expect } from 'chai' 2 | import { Contract } from 'ethers' 3 | import { BigNumber } from 'ethers/utils' 4 | import { solidity, MockProvider, createFixtureLoader, deployContract } from 'ethereum-waffle' 5 | 6 | import { expandTo18Decimals, mineBlock, encodePrice } from './shared/utilities' 7 | import { v2Fixture } from './shared/fixtures' 8 | 9 | import ExampleOracleSimple from '../build/ExampleOracleSimple.json' 10 | 11 | chai.use(solidity) 12 | 13 | const overrides = { 14 | gasLimit: 9999999 15 | } 16 | 17 | const token0Amount = expandTo18Decimals(5) 18 | const token1Amount = expandTo18Decimals(10) 19 | 20 | describe('ExampleOracleSimple', () => { 21 | const provider = new MockProvider({ 22 | hardfork: 'istanbul', 23 | mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn', 24 | gasLimit: 9999999 25 | }) 26 | const [wallet] = provider.getWallets() 27 | const loadFixture = createFixtureLoader(provider, [wallet]) 28 | 29 | let token0: Contract 30 | let token1: Contract 31 | let pair: Contract 32 | let exampleOracleSimple: Contract 33 | 34 | async function addLiquidity() { 35 | await token0.transfer(pair.address, token0Amount) 36 | await token1.transfer(pair.address, token1Amount) 37 | await pair.mint(wallet.address, overrides) 38 | } 39 | 40 | beforeEach(async function() { 41 | const fixture = await loadFixture(v2Fixture) 42 | 43 | token0 = fixture.token0 44 | token1 = fixture.token1 45 | pair = fixture.pair 46 | await addLiquidity() 47 | exampleOracleSimple = await deployContract( 48 | wallet, 49 | ExampleOracleSimple, 50 | [fixture.factoryV2.address, token0.address, token1.address], 51 | overrides 52 | ) 53 | }) 54 | 55 | it('update', async () => { 56 | const blockTimestamp = (await pair.getReserves())[2] 57 | await mineBlock(provider, blockTimestamp + 60 * 60 * 23) 58 | await expect(exampleOracleSimple.update(overrides)).to.be.reverted 59 | await mineBlock(provider, blockTimestamp + 60 * 60 * 24) 60 | await exampleOracleSimple.update(overrides) 61 | 62 | const expectedPrice = encodePrice(token0Amount, token1Amount) 63 | 64 | expect(await exampleOracleSimple.price0Average()).to.eq(expectedPrice[0]) 65 | expect(await exampleOracleSimple.price1Average()).to.eq(expectedPrice[1]) 66 | 67 | expect(await exampleOracleSimple.consult(token0.address, token0Amount)).to.eq(token1Amount) 68 | expect(await exampleOracleSimple.consult(token1.address, token1Amount)).to.eq(token0Amount) 69 | }) 70 | }) 71 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/test/shared/utilities.ts: -------------------------------------------------------------------------------- 1 | import { Contract } from 'ethers' 2 | import { Web3Provider } from 'ethers/providers' 3 | import { BigNumber, bigNumberify, keccak256, defaultAbiCoder, toUtf8Bytes, solidityPack } from 'ethers/utils' 4 | 5 | export const MINIMUM_LIQUIDITY = bigNumberify(10).pow(3) 6 | 7 | const PERMIT_TYPEHASH = keccak256( 8 | toUtf8Bytes('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)') 9 | ) 10 | 11 | export function expandTo18Decimals(n: number): BigNumber { 12 | return bigNumberify(n).mul(bigNumberify(10).pow(18)) 13 | } 14 | 15 | function getDomainSeparator(name: string, tokenAddress: string) { 16 | return keccak256( 17 | defaultAbiCoder.encode( 18 | ['bytes32', 'bytes32', 'bytes32', 'uint256', 'address'], 19 | [ 20 | keccak256(toUtf8Bytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')), 21 | keccak256(toUtf8Bytes(name)), 22 | keccak256(toUtf8Bytes('1')), 23 | 1, 24 | tokenAddress 25 | ] 26 | ) 27 | ) 28 | } 29 | 30 | export async function getApprovalDigest( 31 | token: Contract, 32 | approve: { 33 | owner: string 34 | spender: string 35 | value: BigNumber 36 | }, 37 | nonce: BigNumber, 38 | deadline: BigNumber 39 | ): Promise { 40 | const name = await token.name() 41 | const DOMAIN_SEPARATOR = getDomainSeparator(name, token.address) 42 | return keccak256( 43 | solidityPack( 44 | ['bytes1', 'bytes1', 'bytes32', 'bytes32'], 45 | [ 46 | '0x19', 47 | '0x01', 48 | DOMAIN_SEPARATOR, 49 | keccak256( 50 | defaultAbiCoder.encode( 51 | ['bytes32', 'address', 'address', 'uint256', 'uint256', 'uint256'], 52 | [PERMIT_TYPEHASH, approve.owner, approve.spender, approve.value, nonce, deadline] 53 | ) 54 | ) 55 | ] 56 | ) 57 | ) 58 | } 59 | 60 | export async function mineBlock(provider: Web3Provider, timestamp: number): Promise { 61 | await new Promise(async (resolve, reject) => { 62 | ;(provider._web3Provider.sendAsync as any)( 63 | { jsonrpc: '2.0', method: 'evm_mine', params: [timestamp] }, 64 | (error: any, result: any): void => { 65 | if (error) { 66 | reject(error) 67 | } else { 68 | resolve(result) 69 | } 70 | } 71 | ) 72 | }) 73 | } 74 | 75 | export function encodePrice(reserve0: BigNumber, reserve1: BigNumber) { 76 | return [reserve1.mul(bigNumberify(2).pow(112)).div(reserve0), reserve0.mul(bigNumberify(2).pow(112)).div(reserve1)] 77 | } 78 | -------------------------------------------------------------------------------- /contract/lib/v2-periphery/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "resolveJsonModule": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /contract/lib/v3-core/.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /contract/lib/v3-core/.github/workflows/fuzz-testing.yml: -------------------------------------------------------------------------------- 1 | name: Fuzz Testing 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | echidna: 11 | name: Echidna 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | testName: 17 | - TickBitmapEchidnaTest 18 | - TickMathEchidnaTest 19 | - SqrtPriceMathEchidnaTest 20 | - SwapMathEchidnaTest 21 | - TickEchidnaTest 22 | - TickOverflowSafetyEchidnaTest 23 | - OracleEchidnaTest 24 | - BitMathEchidnaTest 25 | - LowGasSafeMathEchidnaTest 26 | - UnsafeMathEchidnaTest 27 | - FullMathEchidnaTest 28 | 29 | steps: 30 | - uses: actions/checkout@v2 31 | 32 | - name: Set up node 33 | uses: actions/setup-node@v1 34 | with: 35 | node-version: 12 36 | 37 | - name: Set up Python 3.8 38 | uses: actions/setup-python@v2 39 | with: 40 | python-version: 3.8 41 | 42 | - name: Install node dependencies 43 | run: yarn install --frozen-lockfile 44 | 45 | - name: Install pip3 46 | run: | 47 | python -m pip install --upgrade pip 48 | 49 | - name: Install slither 50 | run: | 51 | pip3 install slither-analyzer 52 | 53 | - name: Install echidna 54 | run: | 55 | sudo wget -O /tmp/echidna-test.tar.gz https://github.com/crytic/echidna/releases/download/v1.6.0/echidna-test-v1.6.0-Ubuntu-18.04.tar.gz 56 | sudo tar -xf /tmp/echidna-test.tar.gz -C /usr/bin 57 | sudo chmod +x /usr/bin/echidna-test 58 | 59 | - name: Run ${{ matrix.testName }} 60 | run: echidna-test . --contract ${{ matrix.testName }} --config echidna.config.yml 61 | -------------------------------------------------------------------------------- /contract/lib/v3-core/.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | run-linters: 11 | name: Run linters 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Check out Git repository 16 | uses: actions/checkout@v2 17 | 18 | - name: Set up node 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: 12 22 | 23 | - name: Install dependencies 24 | run: yarn install --frozen-lockfile 25 | 26 | - name: Run linters 27 | uses: wearerequired/lint-action@a8497ddb33fb1205941fd40452ca9fff07e0770d 28 | with: 29 | github_token: ${{ secrets.github_token }} 30 | prettier: true 31 | auto_fix: true 32 | prettier_extensions: 'css,html,js,json,jsx,md,sass,scss,ts,tsx,vue,yaml,yml,sol' 33 | -------------------------------------------------------------------------------- /contract/lib/v3-core/.github/workflows/mythx.yml: -------------------------------------------------------------------------------- 1 | name: Mythx 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | mythx: 8 | name: Submit to Mythx 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Set up node 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 12 18 | 19 | - name: Set up Python 3.8 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: 3.8 23 | 24 | - name: Install node dependencies 25 | run: yarn install --frozen-lockfile 26 | 27 | - name: Install pip3 28 | run: | 29 | python -m pip install --upgrade pip 30 | 31 | - name: Install mythx CLI 32 | run: | 33 | pip3 install mythx-cli 34 | 35 | - name: Install solc-select 36 | run: | 37 | pip3 install solc-select 38 | 39 | - name: Install solc 0.7.6 40 | run: | 41 | solc-select install 0.7.6 42 | solc-select use 0.7.6 43 | 44 | - name: Submit code to Mythx 45 | run: | 46 | mythx --api-key ${{ secrets.MYTHX_API_KEY }} \ 47 | --yes \ 48 | analyze \ 49 | --mode deep \ 50 | --async \ 51 | --create-group \ 52 | --group-name "@uniswap/v3-core@${{ github.sha }}" \ 53 | --solc-version 0.7.6 \ 54 | --check-properties \ 55 | contracts/test/TickBitmapEchidnaTest.sol --include TickBitmapEchidnaTest \ 56 | contracts/test/TickMathEchidnaTest.sol --include TickMathEchidnaTest \ 57 | contracts/test/SqrtPriceMathEchidnaTest.sol --include SqrtPriceMathEchidnaTest \ 58 | contracts/test/SwapMathEchidnaTest.sol --include SwapMathEchidnaTest \ 59 | contracts/test/TickEchidnaTest.sol --include TickEchidnaTest \ 60 | contracts/test/TickOverflowSafetyEchidnaTest.sol --include TickOverflowSafetyEchidnaTest \ 61 | contracts/test/OracleEchidnaTest.sol --include OracleEchidnaTest \ 62 | contracts/test/BitMathEchidnaTest.sol --include BitMathEchidnaTest \ 63 | contracts/test/LowGasSafeMathEchidnaTest.sol --include LowGasSafeMathEchidnaTest \ 64 | contracts/test/UnsafeMathEchidnaTest.sol --include UnsafeMathEchidnaTest \ 65 | contracts/test/FullMathEchidnaTest.sol --include FullMathEchidnaTest 66 | -------------------------------------------------------------------------------- /contract/lib/v3-core/.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | unit-tests: 11 | name: Unit Tests 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - uses: actions/setup-node@v1 17 | with: 18 | node-version: 12.x 19 | 20 | - id: yarn-cache 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | 23 | - uses: actions/cache@v1 24 | with: 25 | path: ${{ steps.yarn-cache.outputs.dir }} 26 | key: yarn-${{ hashFiles('**/yarn.lock') }} 27 | restore-keys: | 28 | yarn- 29 | 30 | - name: Install dependencies 31 | run: yarn install --frozen-lockfile 32 | 33 | # This is required separately from yarn test because it generates the typechain definitions 34 | - name: Compile 35 | run: yarn compile 36 | 37 | - name: Run unit tests 38 | run: yarn test 39 | -------------------------------------------------------------------------------- /contract/lib/v3-core/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "printWidth": 120 5 | } 6 | -------------------------------------------------------------------------------- /contract/lib/v3-core/.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier"], 3 | "rules": { 4 | "prettier/prettier": "error" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /contract/lib/v3-core/.yarnrc: -------------------------------------------------------------------------------- 1 | ignore-scripts true 2 | -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/abdk/audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/v3-core/audits/abdk/audit.pdf -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xethghost/sando-rs/b701de35e41aeb63821c3b48392bff44f01290ae/contract/lib/v3-core/audits/tob/audit.pdf -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/contracts/crytic/echidna/E2E_mint_burn.config.yaml: -------------------------------------------------------------------------------- 1 | checkAsserts: true 2 | coverage: true 3 | codeSize: 0x60000 4 | corpusDir: echidna_e2e_mint_burn_corpus 5 | seqLen: 10 6 | testLimit: 100000 7 | timeout: 600 # 10 minutes 8 | 9 | # blacklist 10 | filterFunctions: 11 | [ 12 | 'E2E_mint_burn.viewInitRandomPoolParams(uint128)', 13 | 'E2E_mint_burn.viewMintRandomNewPosition(uint128,int24,uint24,int24)', 14 | 'E2E_mint_burn.viewBurnRandomPositionIdx(uint128,uint128)', 15 | 'E2E_mint_burn.viewBurnRandomPositionBurnAmount(uint128,uint128)', 16 | ] 17 | -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/contracts/crytic/echidna/E2E_swap.config.yaml: -------------------------------------------------------------------------------- 1 | checkAsserts: true 2 | coverage: true 3 | codeSize: 0x60000 4 | corpusDir: echidna_e2e_swap_corpus 5 | seqLen: 10 6 | testLimit: 100000 7 | timeout: 3600 # 1 hour 8 | 9 | # blacklist 10 | filterFunctions: ['E2E_swap.viewRandomInit(uint128)'] 11 | -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/contracts/crytic/echidna/Other.config.yaml: -------------------------------------------------------------------------------- 1 | checkAsserts: true 2 | coverage: true 3 | codeSize: 0x60000 4 | corpusDir: echidna_other_corpus 5 | seqLen: 1000 6 | testLimit: 100000 7 | timeout: 3600 # 1 hour 8 | -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/contracts/crytic/echidna/Other.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.7.6; 2 | 3 | import '../../../../../contracts/libraries/SqrtPriceMath.sol'; 4 | import '../../../../../contracts/libraries/TickMath.sol'; 5 | 6 | contract Other { 7 | // prop #30 8 | function test_getNextSqrtPriceFromInAndOutput( 9 | uint160 sqrtPX96, 10 | uint128 liquidity, 11 | uint256 amount, 12 | bool add 13 | ) public { 14 | require(sqrtPX96 >= TickMath.MIN_SQRT_RATIO && sqrtPX96 < TickMath.MAX_SQRT_RATIO); 15 | require(liquidity < 3121856577256316178563069792952001939); // max liquidity per tick 16 | uint256 next_sqrt = SqrtPriceMath.getNextSqrtPriceFromInput(sqrtPX96, liquidity, amount, add); 17 | assert(next_sqrt >= TickMath.MIN_SQRT_RATIO && next_sqrt < TickMath.MAX_SQRT_RATIO); 18 | next_sqrt = SqrtPriceMath.getNextSqrtPriceFromOutput(sqrtPX96, liquidity, amount, add); 19 | assert(next_sqrt >= TickMath.MIN_SQRT_RATIO && next_sqrt < TickMath.MAX_SQRT_RATIO); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/contracts/crytic/manticore/001.sol: -------------------------------------------------------------------------------- 1 | import '../../../../../contracts/libraries/BitMath.sol'; 2 | 3 | contract VerifyBitMathMsb { 4 | function verify(uint256 x) external { 5 | uint256 msb = BitMath.mostSignificantBit(x); 6 | 7 | bool property = x >= 2**msb && (msb == 255 || x < 2**(msb + 1)); 8 | 9 | require(!property); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/contracts/crytic/manticore/002.sol: -------------------------------------------------------------------------------- 1 | import '../../../../../contracts/libraries/BitMath.sol'; 2 | 3 | contract VerifyBitMathLsb { 4 | function verify(uint256 x) external { 5 | uint256 lsb = BitMath.leastSignificantBit(x); 6 | 7 | // (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0) 8 | bool property = ((x & (2**lsb)) != 0) && ((x & (2**(lsb - 1))) == 0); 9 | 10 | require(!property); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /contract/lib/v3-core/audits/tob/contracts/crytic/manticore/003.sol: -------------------------------------------------------------------------------- 1 | import '../../../../../contracts/libraries/LiquidityMath.sol'; 2 | 3 | contract VerifyLiquidityMathAddDelta { 4 | function verify(uint128 x, int128 y) external { 5 | uint256 z = LiquidityMath.addDelta(x, y); 6 | 7 | require(z != x + uint128(y)); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/NoDelegateCall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity =0.7.6; 3 | 4 | /// @title Prevents delegatecall to a contract 5 | /// @notice Base contract that provides a modifier for preventing delegatecall to methods in a child contract 6 | abstract contract NoDelegateCall { 7 | /// @dev The original address of this contract 8 | address private immutable original; 9 | 10 | constructor() { 11 | // Immutables are computed in the init code of the contract, and then inlined into the deployed bytecode. 12 | // In other words, this variable won't change when it's checked at runtime. 13 | original = address(this); 14 | } 15 | 16 | /// @dev Private method is used instead of inlining into modifier because modifiers are copied into each method, 17 | /// and the use of immutable means the address bytes are copied in every place the modifier is used. 18 | function checkNotDelegateCall() private view { 19 | require(address(this) == original); 20 | } 21 | 22 | /// @notice Prevents delegatecall into the modified method 23 | modifier noDelegateCall() { 24 | checkNotDelegateCall(); 25 | _; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/UniswapV3PoolDeployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity =0.7.6; 3 | 4 | import './interfaces/IUniswapV3PoolDeployer.sol'; 5 | 6 | import './UniswapV3Pool.sol'; 7 | 8 | contract UniswapV3PoolDeployer is IUniswapV3PoolDeployer { 9 | struct Parameters { 10 | address factory; 11 | address token0; 12 | address token1; 13 | uint24 fee; 14 | int24 tickSpacing; 15 | } 16 | 17 | /// @inheritdoc IUniswapV3PoolDeployer 18 | Parameters public override parameters; 19 | 20 | /// @dev Deploys a pool with the given parameters by transiently setting the parameters storage slot and then 21 | /// clearing it after deploying the pool. 22 | /// @param factory The contract address of the Uniswap V3 factory 23 | /// @param token0 The first token of the pool by address sort order 24 | /// @param token1 The second token of the pool by address sort order 25 | /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip 26 | /// @param tickSpacing The spacing between usable ticks 27 | function deploy( 28 | address factory, 29 | address token0, 30 | address token1, 31 | uint24 fee, 32 | int24 tickSpacing 33 | ) internal returns (address pool) { 34 | parameters = Parameters({factory: factory, token0: token0, token1: token1, fee: fee, tickSpacing: tickSpacing}); 35 | pool = address(new UniswapV3Pool{salt: keccak256(abi.encode(token0, token1, fee))}()); 36 | delete parameters; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/interfaces/IUniswapV3Pool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | import './pool/IUniswapV3PoolImmutables.sol'; 5 | import './pool/IUniswapV3PoolState.sol'; 6 | import './pool/IUniswapV3PoolDerivedState.sol'; 7 | import './pool/IUniswapV3PoolActions.sol'; 8 | import './pool/IUniswapV3PoolOwnerActions.sol'; 9 | import './pool/IUniswapV3PoolEvents.sol'; 10 | 11 | /// @title The interface for a Uniswap V3 Pool 12 | /// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform 13 | /// to the ERC20 specification 14 | /// @dev The pool interface is broken up into many smaller pieces 15 | interface IUniswapV3Pool is 16 | IUniswapV3PoolImmutables, 17 | IUniswapV3PoolState, 18 | IUniswapV3PoolDerivedState, 19 | IUniswapV3PoolActions, 20 | IUniswapV3PoolOwnerActions, 21 | IUniswapV3PoolEvents 22 | { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/interfaces/IUniswapV3PoolDeployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title An interface for a contract that is capable of deploying Uniswap V3 Pools 5 | /// @notice A contract that constructs a pool must implement this to pass arguments to the pool 6 | /// @dev This is used to avoid having constructor arguments in the pool contract, which results in the init code hash 7 | /// of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain 8 | interface IUniswapV3PoolDeployer { 9 | /// @notice Get the parameters to be used in constructing the pool, set transiently during pool creation. 10 | /// @dev Called by the pool constructor to fetch the parameters of the pool 11 | /// Returns factory The factory address 12 | /// Returns token0 The first token of the pool by address sort order 13 | /// Returns token1 The second token of the pool by address sort order 14 | /// Returns fee The fee collected upon every swap in the pool, denominated in hundredths of a bip 15 | /// Returns tickSpacing The minimum number of ticks between initialized ticks 16 | function parameters() 17 | external 18 | view 19 | returns ( 20 | address factory, 21 | address token0, 22 | address token1, 23 | uint24 fee, 24 | int24 tickSpacing 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Callback for IUniswapV3PoolActions#flash 5 | /// @notice Any contract that calls IUniswapV3PoolActions#flash must implement this interface 6 | interface IUniswapV3FlashCallback { 7 | /// @notice Called to `msg.sender` after transferring to the recipient from IUniswapV3Pool#flash. 8 | /// @dev In the implementation you must repay the pool the tokens sent by flash plus the computed fee amounts. 9 | /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. 10 | /// @param fee0 The fee amount in token0 due to the pool by the end of the flash 11 | /// @param fee1 The fee amount in token1 due to the pool by the end of the flash 12 | /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#flash call 13 | function uniswapV3FlashCallback( 14 | uint256 fee0, 15 | uint256 fee1, 16 | bytes calldata data 17 | ) external; 18 | } 19 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/interfaces/callback/IUniswapV3MintCallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Callback for IUniswapV3PoolActions#mint 5 | /// @notice Any contract that calls IUniswapV3PoolActions#mint must implement this interface 6 | interface IUniswapV3MintCallback { 7 | /// @notice Called to `msg.sender` after minting liquidity to a position from IUniswapV3Pool#mint. 8 | /// @dev In the implementation you must pay the pool tokens owed for the minted liquidity. 9 | /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. 10 | /// @param amount0Owed The amount of token0 due to the pool for the minted liquidity 11 | /// @param amount1Owed The amount of token1 due to the pool for the minted liquidity 12 | /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#mint call 13 | function uniswapV3MintCallback( 14 | uint256 amount0Owed, 15 | uint256 amount1Owed, 16 | bytes calldata data 17 | ) external; 18 | } 19 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Callback for IUniswapV3PoolActions#swap 5 | /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface 6 | interface IUniswapV3SwapCallback { 7 | /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. 8 | /// @dev In the implementation you must pay the pool tokens owed for the swap. 9 | /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. 10 | /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. 11 | /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by 12 | /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. 13 | /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by 14 | /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. 15 | /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call 16 | function uniswapV3SwapCallback( 17 | int256 amount0Delta, 18 | int256 amount1Delta, 19 | bytes calldata data 20 | ) external; 21 | } 22 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Pool state that never changes 5 | /// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values 6 | interface IUniswapV3PoolImmutables { 7 | /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface 8 | /// @return The contract address 9 | function factory() external view returns (address); 10 | 11 | /// @notice The first of the two tokens of the pool, sorted by address 12 | /// @return The token contract address 13 | function token0() external view returns (address); 14 | 15 | /// @notice The second of the two tokens of the pool, sorted by address 16 | /// @return The token contract address 17 | function token1() external view returns (address); 18 | 19 | /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 20 | /// @return The fee 21 | function fee() external view returns (uint24); 22 | 23 | /// @notice The pool tick spacing 24 | /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive 25 | /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... 26 | /// This value is an int24 to avoid casting even though it is always positive. 27 | /// @return The tick spacing 28 | function tickSpacing() external view returns (int24); 29 | 30 | /// @notice The maximum amount of position liquidity that can use any tick in the range 31 | /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and 32 | /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool 33 | /// @return The max amount of liquidity per tick 34 | function maxLiquidityPerTick() external view returns (uint128); 35 | } 36 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Permissioned pool actions 5 | /// @notice Contains pool methods that may only be called by the factory owner 6 | interface IUniswapV3PoolOwnerActions { 7 | /// @notice Set the denominator of the protocol's % share of the fees 8 | /// @param feeProtocol0 new protocol fee for token0 of the pool 9 | /// @param feeProtocol1 new protocol fee for token1 of the pool 10 | function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external; 11 | 12 | /// @notice Collect the protocol fee accrued to the pool 13 | /// @param recipient The address to which collected protocol fees should be sent 14 | /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1 15 | /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0 16 | /// @return amount0 The protocol fee collected in token0 17 | /// @return amount1 The protocol fee collected in token1 18 | function collectProtocol( 19 | address recipient, 20 | uint128 amount0Requested, 21 | uint128 amount1Requested 22 | ) external returns (uint128 amount0, uint128 amount1); 23 | } 24 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/FixedPoint128.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.4.0; 3 | 4 | /// @title FixedPoint128 5 | /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) 6 | library FixedPoint128 { 7 | uint256 internal constant Q128 = 0x100000000000000000000000000000000; 8 | } 9 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/FixedPoint96.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.4.0; 3 | 4 | /// @title FixedPoint96 5 | /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) 6 | /// @dev Used in SqrtPriceMath.sol 7 | library FixedPoint96 { 8 | uint8 internal constant RESOLUTION = 96; 9 | uint256 internal constant Q96 = 0x1000000000000000000000000; 10 | } 11 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Remco Bloemen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/LiquidityMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Math library for liquidity 5 | library LiquidityMath { 6 | /// @notice Add a signed liquidity delta to liquidity and revert if it overflows or underflows 7 | /// @param x The liquidity before change 8 | /// @param y The delta by which liquidity should be changed 9 | /// @return z The liquidity delta 10 | function addDelta(uint128 x, int128 y) internal pure returns (uint128 z) { 11 | if (y < 0) { 12 | require((z = x - uint128(-y)) < x, 'LS'); 13 | } else { 14 | require((z = x + uint128(y)) >= x, 'LA'); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/LowGasSafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.7.0; 3 | 4 | /// @title Optimized overflow and underflow safe math operations 5 | /// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas cost 6 | library LowGasSafeMath { 7 | /// @notice Returns x + y, reverts if sum overflows uint256 8 | /// @param x The augend 9 | /// @param y The addend 10 | /// @return z The sum of x and y 11 | function add(uint256 x, uint256 y) internal pure returns (uint256 z) { 12 | require((z = x + y) >= x); 13 | } 14 | 15 | /// @notice Returns x - y, reverts if underflows 16 | /// @param x The minuend 17 | /// @param y The subtrahend 18 | /// @return z The difference of x and y 19 | function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { 20 | require((z = x - y) <= x); 21 | } 22 | 23 | /// @notice Returns x * y, reverts if overflows 24 | /// @param x The multiplicand 25 | /// @param y The multiplier 26 | /// @return z The product of x and y 27 | function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { 28 | require(x == 0 || (z = x * y) / x == y); 29 | } 30 | 31 | /// @notice Returns x + y, reverts if overflows or underflows 32 | /// @param x The augend 33 | /// @param y The addend 34 | /// @return z The sum of x and y 35 | function add(int256 x, int256 y) internal pure returns (int256 z) { 36 | require((z = x + y) >= x == (y >= 0)); 37 | } 38 | 39 | /// @notice Returns x - y, reverts if overflows or underflows 40 | /// @param x The minuend 41 | /// @param y The subtrahend 42 | /// @return z The difference of x and y 43 | function sub(int256 x, int256 y) internal pure returns (int256 z) { 44 | require((z = x - y) <= x == (y >= 0)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/SafeCast.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Safe casting methods 5 | /// @notice Contains methods for safely casting between types 6 | library SafeCast { 7 | /// @notice Cast a uint256 to a uint160, revert on overflow 8 | /// @param y The uint256 to be downcasted 9 | /// @return z The downcasted integer, now type uint160 10 | function toUint160(uint256 y) internal pure returns (uint160 z) { 11 | require((z = uint160(y)) == y); 12 | } 13 | 14 | /// @notice Cast a int256 to a int128, revert on overflow or underflow 15 | /// @param y The int256 to be downcasted 16 | /// @return z The downcasted integer, now type int128 17 | function toInt128(int256 y) internal pure returns (int128 z) { 18 | require((z = int128(y)) == y); 19 | } 20 | 21 | /// @notice Cast a uint256 to a int256, revert on overflow 22 | /// @param y The uint256 to be casted 23 | /// @return z The casted integer, now type int256 24 | function toInt256(uint256 y) internal pure returns (int256 z) { 25 | require(y < 2**255); 26 | z = int256(y); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/TransferHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.6.0; 3 | 4 | import '../interfaces/IERC20Minimal.sol'; 5 | 6 | /// @title TransferHelper 7 | /// @notice Contains helper methods for interacting with ERC20 tokens that do not consistently return true/false 8 | library TransferHelper { 9 | /// @notice Transfers tokens from msg.sender to a recipient 10 | /// @dev Calls transfer on token contract, errors with TF if transfer fails 11 | /// @param token The contract address of the token which will be transferred 12 | /// @param to The recipient of the transfer 13 | /// @param value The value of the transfer 14 | function safeTransfer( 15 | address token, 16 | address to, 17 | uint256 value 18 | ) internal { 19 | (bool success, bytes memory data) = 20 | token.call(abi.encodeWithSelector(IERC20Minimal.transfer.selector, to, value)); 21 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'TF'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/libraries/UnsafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Math functions that do not check inputs or outputs 5 | /// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks 6 | library UnsafeMath { 7 | /// @notice Returns ceil(x / y) 8 | /// @dev division by 0 has unspecified behavior, and must be checked externally 9 | /// @param x The dividend 10 | /// @param y The divisor 11 | /// @return z The quotient, ceil(x / y) 12 | function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) { 13 | assembly { 14 | z := add(div(x, y), gt(mod(x, y), 0)) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/BitMathEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/BitMath.sol'; 5 | 6 | contract BitMathEchidnaTest { 7 | function mostSignificantBitInvariant(uint256 input) external pure { 8 | uint8 msb = BitMath.mostSignificantBit(input); 9 | assert(input >= (uint256(2)**msb)); 10 | assert(msb == 255 || input < uint256(2)**(msb + 1)); 11 | } 12 | 13 | function leastSignificantBitInvariant(uint256 input) external pure { 14 | uint8 lsb = BitMath.leastSignificantBit(input); 15 | assert(input & (uint256(2)**lsb) != 0); 16 | assert(input & (uint256(2)**lsb - 1) == 0); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/BitMathTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/BitMath.sol'; 5 | 6 | contract BitMathTest { 7 | function mostSignificantBit(uint256 x) external pure returns (uint8 r) { 8 | return BitMath.mostSignificantBit(x); 9 | } 10 | 11 | function getGasCostOfMostSignificantBit(uint256 x) external view returns (uint256) { 12 | uint256 gasBefore = gasleft(); 13 | BitMath.mostSignificantBit(x); 14 | return gasBefore - gasleft(); 15 | } 16 | 17 | function leastSignificantBit(uint256 x) external pure returns (uint8 r) { 18 | return BitMath.leastSignificantBit(x); 19 | } 20 | 21 | function getGasCostOfLeastSignificantBit(uint256 x) external view returns (uint256) { 22 | uint256 gasBefore = gasleft(); 23 | BitMath.leastSignificantBit(x); 24 | return gasBefore - gasleft(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/FullMathEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/FullMath.sol'; 5 | 6 | contract FullMathEchidnaTest { 7 | function checkMulDivRounding( 8 | uint256 x, 9 | uint256 y, 10 | uint256 d 11 | ) external pure { 12 | require(d > 0); 13 | 14 | uint256 ceiled = FullMath.mulDivRoundingUp(x, y, d); 15 | uint256 floored = FullMath.mulDiv(x, y, d); 16 | 17 | if (mulmod(x, y, d) > 0) { 18 | assert(ceiled - floored == 1); 19 | } else { 20 | assert(ceiled == floored); 21 | } 22 | } 23 | 24 | function checkMulDiv( 25 | uint256 x, 26 | uint256 y, 27 | uint256 d 28 | ) external pure { 29 | require(d > 0); 30 | uint256 z = FullMath.mulDiv(x, y, d); 31 | if (x == 0 || y == 0) { 32 | assert(z == 0); 33 | return; 34 | } 35 | 36 | // recompute x and y via mulDiv of the result of floor(x*y/d), should always be less than original inputs by < d 37 | uint256 x2 = FullMath.mulDiv(z, d, y); 38 | uint256 y2 = FullMath.mulDiv(z, d, x); 39 | assert(x2 <= x); 40 | assert(y2 <= y); 41 | 42 | assert(x - x2 < d); 43 | assert(y - y2 < d); 44 | } 45 | 46 | function checkMulDivRoundingUp( 47 | uint256 x, 48 | uint256 y, 49 | uint256 d 50 | ) external pure { 51 | require(d > 0); 52 | uint256 z = FullMath.mulDivRoundingUp(x, y, d); 53 | if (x == 0 || y == 0) { 54 | assert(z == 0); 55 | return; 56 | } 57 | 58 | // recompute x and y via mulDiv of the result of floor(x*y/d), should always be less than original inputs by < d 59 | uint256 x2 = FullMath.mulDiv(z, d, y); 60 | uint256 y2 = FullMath.mulDiv(z, d, x); 61 | assert(x2 >= x); 62 | assert(y2 >= y); 63 | 64 | assert(x2 - x < d); 65 | assert(y2 - y < d); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/FullMathTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/FullMath.sol'; 5 | 6 | contract FullMathTest { 7 | function mulDiv( 8 | uint256 x, 9 | uint256 y, 10 | uint256 z 11 | ) external pure returns (uint256) { 12 | return FullMath.mulDiv(x, y, z); 13 | } 14 | 15 | function mulDivRoundingUp( 16 | uint256 x, 17 | uint256 y, 18 | uint256 z 19 | ) external pure returns (uint256) { 20 | return FullMath.mulDivRoundingUp(x, y, z); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/LiquidityMathTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/LiquidityMath.sol'; 5 | 6 | contract LiquidityMathTest { 7 | function addDelta(uint128 x, int128 y) external pure returns (uint128 z) { 8 | return LiquidityMath.addDelta(x, y); 9 | } 10 | 11 | function getGasCostOfAddDelta(uint128 x, int128 y) external view returns (uint256) { 12 | uint256 gasBefore = gasleft(); 13 | LiquidityMath.addDelta(x, y); 14 | return gasBefore - gasleft(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/LowGasSafeMathEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/LowGasSafeMath.sol'; 5 | 6 | contract LowGasSafeMathEchidnaTest { 7 | function checkAdd(uint256 x, uint256 y) external pure { 8 | uint256 z = LowGasSafeMath.add(x, y); 9 | assert(z == x + y); 10 | assert(z >= x && z >= y); 11 | } 12 | 13 | function checkSub(uint256 x, uint256 y) external pure { 14 | uint256 z = LowGasSafeMath.sub(x, y); 15 | assert(z == x - y); 16 | assert(z <= x); 17 | } 18 | 19 | function checkMul(uint256 x, uint256 y) external pure { 20 | uint256 z = LowGasSafeMath.mul(x, y); 21 | assert(z == x * y); 22 | assert(x == 0 || y == 0 || (z >= x && z >= y)); 23 | } 24 | 25 | function checkAddi(int256 x, int256 y) external pure { 26 | int256 z = LowGasSafeMath.add(x, y); 27 | assert(z == x + y); 28 | assert(y < 0 ? z < x : z >= x); 29 | } 30 | 31 | function checkSubi(int256 x, int256 y) external pure { 32 | int256 z = LowGasSafeMath.sub(x, y); 33 | assert(z == x - y); 34 | assert(y < 0 ? z > x : z <= x); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/MockTimeUniswapV3Pool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../UniswapV3Pool.sol'; 5 | 6 | // used for testing time dependent behavior 7 | contract MockTimeUniswapV3Pool is UniswapV3Pool { 8 | // Monday, October 5, 2020 9:00:00 AM GMT-05:00 9 | uint256 public time = 1601906400; 10 | 11 | function setFeeGrowthGlobal0X128(uint256 _feeGrowthGlobal0X128) external { 12 | feeGrowthGlobal0X128 = _feeGrowthGlobal0X128; 13 | } 14 | 15 | function setFeeGrowthGlobal1X128(uint256 _feeGrowthGlobal1X128) external { 16 | feeGrowthGlobal1X128 = _feeGrowthGlobal1X128; 17 | } 18 | 19 | function advanceTime(uint256 by) external { 20 | time += by; 21 | } 22 | 23 | function _blockTimestamp() internal view override returns (uint32) { 24 | return uint32(time); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/MockTimeUniswapV3PoolDeployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../interfaces/IUniswapV3PoolDeployer.sol'; 5 | 6 | import './MockTimeUniswapV3Pool.sol'; 7 | 8 | contract MockTimeUniswapV3PoolDeployer is IUniswapV3PoolDeployer { 9 | struct Parameters { 10 | address factory; 11 | address token0; 12 | address token1; 13 | uint24 fee; 14 | int24 tickSpacing; 15 | } 16 | 17 | Parameters public override parameters; 18 | 19 | event PoolDeployed(address pool); 20 | 21 | function deploy( 22 | address factory, 23 | address token0, 24 | address token1, 25 | uint24 fee, 26 | int24 tickSpacing 27 | ) external returns (address pool) { 28 | parameters = Parameters({factory: factory, token0: token0, token1: token1, fee: fee, tickSpacing: tickSpacing}); 29 | pool = address( 30 | new MockTimeUniswapV3Pool{salt: keccak256(abi.encodePacked(token0, token1, fee, tickSpacing))}() 31 | ); 32 | emit PoolDeployed(pool); 33 | delete parameters; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/NoDelegateCallTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../NoDelegateCall.sol'; 5 | 6 | contract NoDelegateCallTest is NoDelegateCall { 7 | function canBeDelegateCalled() public view returns (uint256) { 8 | return block.timestamp / 5; 9 | } 10 | 11 | function cannotBeDelegateCalled() public view noDelegateCall returns (uint256) { 12 | return block.timestamp / 5; 13 | } 14 | 15 | function getGasCostOfCanBeDelegateCalled() external view returns (uint256) { 16 | uint256 gasBefore = gasleft(); 17 | canBeDelegateCalled(); 18 | return gasBefore - gasleft(); 19 | } 20 | 21 | function getGasCostOfCannotBeDelegateCalled() external view returns (uint256) { 22 | uint256 gasBefore = gasleft(); 23 | cannotBeDelegateCalled(); 24 | return gasBefore - gasleft(); 25 | } 26 | 27 | function callsIntoNoDelegateCallFunction() external view { 28 | noDelegateCallPrivate(); 29 | } 30 | 31 | function noDelegateCallPrivate() private view noDelegateCall {} 32 | } 33 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/SwapMathEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/SwapMath.sol'; 5 | 6 | contract SwapMathEchidnaTest { 7 | function checkComputeSwapStepInvariants( 8 | uint160 sqrtPriceRaw, 9 | uint160 sqrtPriceTargetRaw, 10 | uint128 liquidity, 11 | int256 amountRemaining, 12 | uint24 feePips 13 | ) external pure { 14 | require(sqrtPriceRaw > 0); 15 | require(sqrtPriceTargetRaw > 0); 16 | require(feePips > 0); 17 | require(feePips < 1e6); 18 | 19 | (uint160 sqrtQ, uint256 amountIn, uint256 amountOut, uint256 feeAmount) = 20 | SwapMath.computeSwapStep(sqrtPriceRaw, sqrtPriceTargetRaw, liquidity, amountRemaining, feePips); 21 | 22 | assert(amountIn <= type(uint256).max - feeAmount); 23 | 24 | if (amountRemaining < 0) { 25 | assert(amountOut <= uint256(-amountRemaining)); 26 | } else { 27 | assert(amountIn + feeAmount <= uint256(amountRemaining)); 28 | } 29 | 30 | if (sqrtPriceRaw == sqrtPriceTargetRaw) { 31 | assert(amountIn == 0); 32 | assert(amountOut == 0); 33 | assert(feeAmount == 0); 34 | assert(sqrtQ == sqrtPriceTargetRaw); 35 | } 36 | 37 | // didn't reach price target, entire amount must be consumed 38 | if (sqrtQ != sqrtPriceTargetRaw) { 39 | if (amountRemaining < 0) assert(amountOut == uint256(-amountRemaining)); 40 | else assert(amountIn + feeAmount == uint256(amountRemaining)); 41 | } 42 | 43 | // next price is between price and price target 44 | if (sqrtPriceTargetRaw <= sqrtPriceRaw) { 45 | assert(sqrtQ <= sqrtPriceRaw); 46 | assert(sqrtQ >= sqrtPriceTargetRaw); 47 | } else { 48 | assert(sqrtQ >= sqrtPriceRaw); 49 | assert(sqrtQ <= sqrtPriceTargetRaw); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/SwapMathTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/SwapMath.sol'; 5 | 6 | contract SwapMathTest { 7 | function computeSwapStep( 8 | uint160 sqrtP, 9 | uint160 sqrtPTarget, 10 | uint128 liquidity, 11 | int256 amountRemaining, 12 | uint24 feePips 13 | ) 14 | external 15 | pure 16 | returns ( 17 | uint160 sqrtQ, 18 | uint256 amountIn, 19 | uint256 amountOut, 20 | uint256 feeAmount 21 | ) 22 | { 23 | return SwapMath.computeSwapStep(sqrtP, sqrtPTarget, liquidity, amountRemaining, feePips); 24 | } 25 | 26 | function getGasCostOfComputeSwapStep( 27 | uint160 sqrtP, 28 | uint160 sqrtPTarget, 29 | uint128 liquidity, 30 | int256 amountRemaining, 31 | uint24 feePips 32 | ) external view returns (uint256) { 33 | uint256 gasBefore = gasleft(); 34 | SwapMath.computeSwapStep(sqrtP, sqrtPTarget, liquidity, amountRemaining, feePips); 35 | return gasBefore - gasleft(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TestERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../interfaces/IERC20Minimal.sol'; 5 | 6 | contract TestERC20 is IERC20Minimal { 7 | mapping(address => uint256) public override balanceOf; 8 | mapping(address => mapping(address => uint256)) public override allowance; 9 | 10 | constructor(uint256 amountToMint) { 11 | mint(msg.sender, amountToMint); 12 | } 13 | 14 | function mint(address to, uint256 amount) public { 15 | uint256 balanceNext = balanceOf[to] + amount; 16 | require(balanceNext >= amount, 'overflow balance'); 17 | balanceOf[to] = balanceNext; 18 | } 19 | 20 | function transfer(address recipient, uint256 amount) external override returns (bool) { 21 | uint256 balanceBefore = balanceOf[msg.sender]; 22 | require(balanceBefore >= amount, 'insufficient balance'); 23 | balanceOf[msg.sender] = balanceBefore - amount; 24 | 25 | uint256 balanceRecipient = balanceOf[recipient]; 26 | require(balanceRecipient + amount >= balanceRecipient, 'recipient balance overflow'); 27 | balanceOf[recipient] = balanceRecipient + amount; 28 | 29 | emit Transfer(msg.sender, recipient, amount); 30 | return true; 31 | } 32 | 33 | function approve(address spender, uint256 amount) external override returns (bool) { 34 | allowance[msg.sender][spender] = amount; 35 | emit Approval(msg.sender, spender, amount); 36 | return true; 37 | } 38 | 39 | function transferFrom( 40 | address sender, 41 | address recipient, 42 | uint256 amount 43 | ) external override returns (bool) { 44 | uint256 allowanceBefore = allowance[sender][msg.sender]; 45 | require(allowanceBefore >= amount, 'allowance insufficient'); 46 | 47 | allowance[sender][msg.sender] = allowanceBefore - amount; 48 | 49 | uint256 balanceRecipient = balanceOf[recipient]; 50 | require(balanceRecipient + amount >= balanceRecipient, 'overflow balance recipient'); 51 | balanceOf[recipient] = balanceRecipient + amount; 52 | uint256 balanceSender = balanceOf[sender]; 53 | require(balanceSender >= amount, 'underflow balance sender'); 54 | balanceOf[sender] = balanceSender - amount; 55 | 56 | emit Transfer(sender, recipient, amount); 57 | return true; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TestUniswapV3ReentrantCallee.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/TickMath.sol'; 5 | 6 | import '../interfaces/callback/IUniswapV3SwapCallback.sol'; 7 | 8 | import '../interfaces/IUniswapV3Pool.sol'; 9 | 10 | contract TestUniswapV3ReentrantCallee is IUniswapV3SwapCallback { 11 | string private constant expectedReason = 'LOK'; 12 | 13 | function swapToReenter(address pool) external { 14 | IUniswapV3Pool(pool).swap(address(0), false, 1, TickMath.MAX_SQRT_RATIO - 1, new bytes(0)); 15 | } 16 | 17 | function uniswapV3SwapCallback( 18 | int256, 19 | int256, 20 | bytes calldata 21 | ) external override { 22 | // try to reenter swap 23 | try IUniswapV3Pool(msg.sender).swap(address(0), false, 1, 0, new bytes(0)) {} catch Error( 24 | string memory reason 25 | ) { 26 | require(keccak256(abi.encode(reason)) == keccak256(abi.encode(expectedReason))); 27 | } 28 | 29 | // try to reenter mint 30 | try IUniswapV3Pool(msg.sender).mint(address(0), 0, 0, 0, new bytes(0)) {} catch Error(string memory reason) { 31 | require(keccak256(abi.encode(reason)) == keccak256(abi.encode(expectedReason))); 32 | } 33 | 34 | // try to reenter collect 35 | try IUniswapV3Pool(msg.sender).collect(address(0), 0, 0, 0, 0) {} catch Error(string memory reason) { 36 | require(keccak256(abi.encode(reason)) == keccak256(abi.encode(expectedReason))); 37 | } 38 | 39 | // try to reenter burn 40 | try IUniswapV3Pool(msg.sender).burn(0, 0, 0) {} catch Error(string memory reason) { 41 | require(keccak256(abi.encode(reason)) == keccak256(abi.encode(expectedReason))); 42 | } 43 | 44 | // try to reenter flash 45 | try IUniswapV3Pool(msg.sender).flash(address(0), 0, 0, new bytes(0)) {} catch Error(string memory reason) { 46 | require(keccak256(abi.encode(reason)) == keccak256(abi.encode(expectedReason))); 47 | } 48 | 49 | // try to reenter collectProtocol 50 | try IUniswapV3Pool(msg.sender).collectProtocol(address(0), 0, 0) {} catch Error(string memory reason) { 51 | require(keccak256(abi.encode(reason)) == keccak256(abi.encode(expectedReason))); 52 | } 53 | 54 | require(false, 'Unable to reenter'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TestUniswapV3SwapPay.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../interfaces/IERC20Minimal.sol'; 5 | 6 | import '../interfaces/callback/IUniswapV3SwapCallback.sol'; 7 | import '../interfaces/IUniswapV3Pool.sol'; 8 | 9 | contract TestUniswapV3SwapPay is IUniswapV3SwapCallback { 10 | function swap( 11 | address pool, 12 | address recipient, 13 | bool zeroForOne, 14 | uint160 sqrtPriceX96, 15 | int256 amountSpecified, 16 | uint256 pay0, 17 | uint256 pay1 18 | ) external { 19 | IUniswapV3Pool(pool).swap( 20 | recipient, 21 | zeroForOne, 22 | amountSpecified, 23 | sqrtPriceX96, 24 | abi.encode(msg.sender, pay0, pay1) 25 | ); 26 | } 27 | 28 | function uniswapV3SwapCallback( 29 | int256, 30 | int256, 31 | bytes calldata data 32 | ) external override { 33 | (address sender, uint256 pay0, uint256 pay1) = abi.decode(data, (address, uint256, uint256)); 34 | 35 | if (pay0 > 0) { 36 | IERC20Minimal(IUniswapV3Pool(msg.sender).token0()).transferFrom(sender, msg.sender, uint256(pay0)); 37 | } else if (pay1 > 0) { 38 | IERC20Minimal(IUniswapV3Pool(msg.sender).token1()).transferFrom(sender, msg.sender, uint256(pay1)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TickBitmapEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/TickBitmap.sol'; 5 | 6 | contract TickBitmapEchidnaTest { 7 | using TickBitmap for mapping(int16 => uint256); 8 | 9 | mapping(int16 => uint256) private bitmap; 10 | 11 | // returns whether the given tick is initialized 12 | function isInitialized(int24 tick) private view returns (bool) { 13 | (int24 next, bool initialized) = bitmap.nextInitializedTickWithinOneWord(tick, 1, true); 14 | return next == tick ? initialized : false; 15 | } 16 | 17 | function flipTick(int24 tick) external { 18 | bool before = isInitialized(tick); 19 | bitmap.flipTick(tick, 1); 20 | assert(isInitialized(tick) == !before); 21 | } 22 | 23 | function checkNextInitializedTickWithinOneWordInvariants(int24 tick, bool lte) external view { 24 | (int24 next, bool initialized) = bitmap.nextInitializedTickWithinOneWord(tick, 1, lte); 25 | if (lte) { 26 | // type(int24).min + 256 27 | require(tick >= -8388352); 28 | assert(next <= tick); 29 | assert(tick - next < 256); 30 | // all the ticks between the input tick and the next tick should be uninitialized 31 | for (int24 i = tick; i > next; i--) { 32 | assert(!isInitialized(i)); 33 | } 34 | assert(isInitialized(next) == initialized); 35 | } else { 36 | // type(int24).max - 256 37 | require(tick < 8388351); 38 | assert(next > tick); 39 | assert(next - tick <= 256); 40 | // all the ticks between the input tick and the next tick should be uninitialized 41 | for (int24 i = tick + 1; i < next; i++) { 42 | assert(!isInitialized(i)); 43 | } 44 | assert(isInitialized(next) == initialized); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TickBitmapTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/TickBitmap.sol'; 5 | 6 | contract TickBitmapTest { 7 | using TickBitmap for mapping(int16 => uint256); 8 | 9 | mapping(int16 => uint256) public bitmap; 10 | 11 | function flipTick(int24 tick) external { 12 | bitmap.flipTick(tick, 1); 13 | } 14 | 15 | function getGasCostOfFlipTick(int24 tick) external returns (uint256) { 16 | uint256 gasBefore = gasleft(); 17 | bitmap.flipTick(tick, 1); 18 | return gasBefore - gasleft(); 19 | } 20 | 21 | function nextInitializedTickWithinOneWord(int24 tick, bool lte) 22 | external 23 | view 24 | returns (int24 next, bool initialized) 25 | { 26 | return bitmap.nextInitializedTickWithinOneWord(tick, 1, lte); 27 | } 28 | 29 | function getGasCostOfNextInitializedTickWithinOneWord(int24 tick, bool lte) external view returns (uint256) { 30 | uint256 gasBefore = gasleft(); 31 | bitmap.nextInitializedTickWithinOneWord(tick, 1, lte); 32 | return gasBefore - gasleft(); 33 | } 34 | 35 | // returns whether the given tick is initialized 36 | function isInitialized(int24 tick) external view returns (bool) { 37 | (int24 next, bool initialized) = bitmap.nextInitializedTickWithinOneWord(tick, 1, true); 38 | return next == tick ? initialized : false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TickEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/Tick.sol'; 5 | 6 | contract TickEchidnaTest { 7 | function checkTickSpacingToParametersInvariants(int24 tickSpacing) external pure { 8 | require(tickSpacing <= TickMath.MAX_TICK); 9 | require(tickSpacing > 0); 10 | 11 | int24 minTick = (TickMath.MIN_TICK / tickSpacing) * tickSpacing; 12 | int24 maxTick = (TickMath.MAX_TICK / tickSpacing) * tickSpacing; 13 | 14 | uint128 maxLiquidityPerTick = Tick.tickSpacingToMaxLiquidityPerTick(tickSpacing); 15 | 16 | // symmetry around 0 tick 17 | assert(maxTick == -minTick); 18 | // positive max tick 19 | assert(maxTick > 0); 20 | // divisibility 21 | assert((maxTick - minTick) % tickSpacing == 0); 22 | 23 | uint256 numTicks = uint256((maxTick - minTick) / tickSpacing) + 1; 24 | // max liquidity at every tick is less than the cap 25 | assert(uint256(maxLiquidityPerTick) * numTicks <= type(uint128).max); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TickMathEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/TickMath.sol'; 5 | 6 | contract TickMathEchidnaTest { 7 | // uniqueness and increasing order 8 | function checkGetSqrtRatioAtTickInvariants(int24 tick) external pure { 9 | uint160 ratio = TickMath.getSqrtRatioAtTick(tick); 10 | assert(TickMath.getSqrtRatioAtTick(tick - 1) < ratio && ratio < TickMath.getSqrtRatioAtTick(tick + 1)); 11 | assert(ratio >= TickMath.MIN_SQRT_RATIO); 12 | assert(ratio <= TickMath.MAX_SQRT_RATIO); 13 | } 14 | 15 | // the ratio is always between the returned tick and the returned tick+1 16 | function checkGetTickAtSqrtRatioInvariants(uint160 ratio) external pure { 17 | int24 tick = TickMath.getTickAtSqrtRatio(ratio); 18 | assert(ratio >= TickMath.getSqrtRatioAtTick(tick) && ratio < TickMath.getSqrtRatioAtTick(tick + 1)); 19 | assert(tick >= TickMath.MIN_TICK); 20 | assert(tick < TickMath.MAX_TICK); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TickMathTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/TickMath.sol'; 5 | 6 | contract TickMathTest { 7 | function getSqrtRatioAtTick(int24 tick) external pure returns (uint160) { 8 | return TickMath.getSqrtRatioAtTick(tick); 9 | } 10 | 11 | function getGasCostOfGetSqrtRatioAtTick(int24 tick) external view returns (uint256) { 12 | uint256 gasBefore = gasleft(); 13 | TickMath.getSqrtRatioAtTick(tick); 14 | return gasBefore - gasleft(); 15 | } 16 | 17 | function getTickAtSqrtRatio(uint160 sqrtPriceX96) external pure returns (int24) { 18 | return TickMath.getTickAtSqrtRatio(sqrtPriceX96); 19 | } 20 | 21 | function getGasCostOfGetTickAtSqrtRatio(uint160 sqrtPriceX96) external view returns (uint256) { 22 | uint256 gasBefore = gasleft(); 23 | TickMath.getTickAtSqrtRatio(sqrtPriceX96); 24 | return gasBefore - gasleft(); 25 | } 26 | 27 | function MIN_SQRT_RATIO() external pure returns (uint160) { 28 | return TickMath.MIN_SQRT_RATIO; 29 | } 30 | 31 | function MAX_SQRT_RATIO() external pure returns (uint160) { 32 | return TickMath.MAX_SQRT_RATIO; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/TickTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | pragma abicoder v2; 4 | 5 | import '../libraries/Tick.sol'; 6 | 7 | contract TickTest { 8 | using Tick for mapping(int24 => Tick.Info); 9 | 10 | mapping(int24 => Tick.Info) public ticks; 11 | 12 | function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing) external pure returns (uint128) { 13 | return Tick.tickSpacingToMaxLiquidityPerTick(tickSpacing); 14 | } 15 | 16 | function setTick(int24 tick, Tick.Info memory info) external { 17 | ticks[tick] = info; 18 | } 19 | 20 | function getFeeGrowthInside( 21 | int24 tickLower, 22 | int24 tickUpper, 23 | int24 tickCurrent, 24 | uint256 feeGrowthGlobal0X128, 25 | uint256 feeGrowthGlobal1X128 26 | ) external view returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) { 27 | return ticks.getFeeGrowthInside(tickLower, tickUpper, tickCurrent, feeGrowthGlobal0X128, feeGrowthGlobal1X128); 28 | } 29 | 30 | function update( 31 | int24 tick, 32 | int24 tickCurrent, 33 | int128 liquidityDelta, 34 | uint256 feeGrowthGlobal0X128, 35 | uint256 feeGrowthGlobal1X128, 36 | uint160 secondsPerLiquidityCumulativeX128, 37 | int56 tickCumulative, 38 | uint32 time, 39 | bool upper, 40 | uint128 maxLiquidity 41 | ) external returns (bool flipped) { 42 | return 43 | ticks.update( 44 | tick, 45 | tickCurrent, 46 | liquidityDelta, 47 | feeGrowthGlobal0X128, 48 | feeGrowthGlobal1X128, 49 | secondsPerLiquidityCumulativeX128, 50 | tickCumulative, 51 | time, 52 | upper, 53 | maxLiquidity 54 | ); 55 | } 56 | 57 | function clear(int24 tick) external { 58 | ticks.clear(tick); 59 | } 60 | 61 | function cross( 62 | int24 tick, 63 | uint256 feeGrowthGlobal0X128, 64 | uint256 feeGrowthGlobal1X128, 65 | uint160 secondsPerLiquidityCumulativeX128, 66 | int56 tickCumulative, 67 | uint32 time 68 | ) external returns (int128 liquidityNet) { 69 | return 70 | ticks.cross( 71 | tick, 72 | feeGrowthGlobal0X128, 73 | feeGrowthGlobal1X128, 74 | secondsPerLiquidityCumulativeX128, 75 | tickCumulative, 76 | time 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/UniswapV3PoolSwapTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../interfaces/IERC20Minimal.sol'; 5 | 6 | import '../interfaces/callback/IUniswapV3SwapCallback.sol'; 7 | import '../interfaces/IUniswapV3Pool.sol'; 8 | 9 | contract UniswapV3PoolSwapTest is IUniswapV3SwapCallback { 10 | int256 private _amount0Delta; 11 | int256 private _amount1Delta; 12 | 13 | function getSwapResult( 14 | address pool, 15 | bool zeroForOne, 16 | int256 amountSpecified, 17 | uint160 sqrtPriceLimitX96 18 | ) 19 | external 20 | returns ( 21 | int256 amount0Delta, 22 | int256 amount1Delta, 23 | uint160 nextSqrtRatio 24 | ) 25 | { 26 | (amount0Delta, amount1Delta) = IUniswapV3Pool(pool).swap( 27 | address(0), 28 | zeroForOne, 29 | amountSpecified, 30 | sqrtPriceLimitX96, 31 | abi.encode(msg.sender) 32 | ); 33 | 34 | (nextSqrtRatio, , , , , , ) = IUniswapV3Pool(pool).slot0(); 35 | } 36 | 37 | function uniswapV3SwapCallback( 38 | int256 amount0Delta, 39 | int256 amount1Delta, 40 | bytes calldata data 41 | ) external override { 42 | address sender = abi.decode(data, (address)); 43 | 44 | if (amount0Delta > 0) { 45 | IERC20Minimal(IUniswapV3Pool(msg.sender).token0()).transferFrom(sender, msg.sender, uint256(amount0Delta)); 46 | } else if (amount1Delta > 0) { 47 | IERC20Minimal(IUniswapV3Pool(msg.sender).token1()).transferFrom(sender, msg.sender, uint256(amount1Delta)); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contract/lib/v3-core/contracts/test/UnsafeMathEchidnaTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.7.6; 3 | 4 | import '../libraries/UnsafeMath.sol'; 5 | 6 | contract UnsafeMathEchidnaTest { 7 | function checkDivRoundingUp(uint256 x, uint256 d) external pure { 8 | require(d > 0); 9 | uint256 z = UnsafeMath.divRoundingUp(x, d); 10 | uint256 diff = z - (x / d); 11 | if (x % d == 0) { 12 | assert(diff == 0); 13 | } else { 14 | assert(diff == 1); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contract/lib/v3-core/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import 'hardhat-typechain' 2 | import '@nomiclabs/hardhat-ethers' 3 | import '@nomiclabs/hardhat-waffle' 4 | import '@nomiclabs/hardhat-etherscan' 5 | 6 | export default { 7 | networks: { 8 | hardhat: { 9 | allowUnlimitedContractSize: false, 10 | }, 11 | mainnet: { 12 | url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, 13 | }, 14 | ropsten: { 15 | url: `https://ropsten.infura.io/v3/${process.env.INFURA_API_KEY}`, 16 | }, 17 | rinkeby: { 18 | url: `https://rinkeby.infura.io/v3/${process.env.INFURA_API_KEY}`, 19 | }, 20 | goerli: { 21 | url: `https://goerli.infura.io/v3/${process.env.INFURA_API_KEY}`, 22 | }, 23 | kovan: { 24 | url: `https://kovan.infura.io/v3/${process.env.INFURA_API_KEY}`, 25 | }, 26 | }, 27 | etherscan: { 28 | // Your API key for Etherscan 29 | // Obtain one at https://etherscan.io/ 30 | apiKey: process.env.ETHERSCAN_API_KEY, 31 | }, 32 | solidity: { 33 | version: '0.7.6', 34 | settings: { 35 | optimizer: { 36 | enabled: true, 37 | runs: 800, 38 | }, 39 | metadata: { 40 | // do not include the metadata hash, since this is machine dependent 41 | // and we want all generated code to be deterministic 42 | // https://docs.soliditylang.org/en/v0.7.6/metadata.html 43 | bytecodeHash: 'none', 44 | }, 45 | }, 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /contract/lib/v3-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@uniswap/v3-core", 3 | "description": "🦄 Core smart contracts of Uniswap V3", 4 | "license": "BUSL-1.1", 5 | "publishConfig": { 6 | "access": "public" 7 | }, 8 | "version": "1.0.0", 9 | "homepage": "https://uniswap.org", 10 | "keywords": [ 11 | "uniswap", 12 | "core", 13 | "v3" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/Uniswap/uniswap-v3-core" 18 | }, 19 | "files": [ 20 | "contracts/interfaces", 21 | "contracts/libraries", 22 | "artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json", 23 | "artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json", 24 | "artifacts/contracts/interfaces/**/*.json", 25 | "!artifacts/contracts/interfaces/**/*.dbg.json" 26 | ], 27 | "engines": { 28 | "node": ">=10" 29 | }, 30 | "dependencies": {}, 31 | "devDependencies": { 32 | "@nomiclabs/hardhat-ethers": "^2.0.2", 33 | "@nomiclabs/hardhat-etherscan": "^2.1.1", 34 | "@nomiclabs/hardhat-waffle": "^2.0.1", 35 | "@typechain/ethers-v5": "^4.0.0", 36 | "@types/chai": "^4.2.6", 37 | "@types/mocha": "^5.2.7", 38 | "chai": "^4.2.0", 39 | "decimal.js": "^10.2.1", 40 | "ethereum-waffle": "^3.0.2", 41 | "ethers": "^5.0.8", 42 | "hardhat": "^2.2.0", 43 | "hardhat-typechain": "^0.3.5", 44 | "mocha": "^6.2.2", 45 | "mocha-chai-jest-snapshot": "^1.1.0", 46 | "prettier": "^2.0.5", 47 | "prettier-plugin-solidity": "^1.0.0-alpha.59", 48 | "solhint": "^3.2.1", 49 | "solhint-plugin-prettier": "^0.0.5", 50 | "ts-generator": "^0.1.1", 51 | "ts-node": "^8.5.4", 52 | "typechain": "^4.0.0", 53 | "typescript": "^3.7.3" 54 | }, 55 | "scripts": { 56 | "compile": "hardhat compile", 57 | "test": "hardhat test" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/LiquidityMath.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from './shared/expect' 2 | import { LiquidityMathTest } from '../typechain/LiquidityMathTest' 3 | import { ethers, waffle } from 'hardhat' 4 | import snapshotGasCost from './shared/snapshotGasCost' 5 | 6 | const { BigNumber } = ethers 7 | 8 | describe('LiquidityMath', () => { 9 | let liquidityMath: LiquidityMathTest 10 | const fixture = async () => { 11 | const factory = await ethers.getContractFactory('LiquidityMathTest') 12 | return (await factory.deploy()) as LiquidityMathTest 13 | } 14 | beforeEach('deploy LiquidityMathTest', async () => { 15 | liquidityMath = await waffle.loadFixture(fixture) 16 | }) 17 | 18 | describe('#addDelta', () => { 19 | it('1 + 0', async () => { 20 | expect(await liquidityMath.addDelta(1, 0)).to.eq(1) 21 | }) 22 | it('1 + -1', async () => { 23 | expect(await liquidityMath.addDelta(1, -1)).to.eq(0) 24 | }) 25 | it('1 + 1', async () => { 26 | expect(await liquidityMath.addDelta(1, 1)).to.eq(2) 27 | }) 28 | it('2**128-15 + 15 overflows', async () => { 29 | await expect(liquidityMath.addDelta(BigNumber.from(2).pow(128).sub(15), 15)).to.be.revertedWith('LA') 30 | }) 31 | it('0 + -1 underflows', async () => { 32 | await expect(liquidityMath.addDelta(0, -1)).to.be.revertedWith('LS') 33 | }) 34 | it('3 + -4 underflows', async () => { 35 | await expect(liquidityMath.addDelta(3, -4)).to.be.revertedWith('LS') 36 | }) 37 | it('gas add', async () => { 38 | await snapshotGasCost(liquidityMath.getGasCostOfAddDelta(15, 4)) 39 | }) 40 | it('gas sub', async () => { 41 | await snapshotGasCost(liquidityMath.getGasCostOfAddDelta(15, -4)) 42 | }) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/NoDelegateCall.spec.ts: -------------------------------------------------------------------------------- 1 | import { ethers, waffle } from 'hardhat' 2 | import { NoDelegateCallTest } from '../typechain/NoDelegateCallTest' 3 | import { expect } from './shared/expect' 4 | import snapshotGasCost from './shared/snapshotGasCost' 5 | 6 | describe('NoDelegateCall', () => { 7 | const [wallet, other] = waffle.provider.getWallets() 8 | 9 | let loadFixture: ReturnType 10 | before('create fixture loader', async () => { 11 | loadFixture = waffle.createFixtureLoader([wallet, other]) 12 | }) 13 | 14 | const noDelegateCallFixture = async () => { 15 | const noDelegateCallTestFactory = await ethers.getContractFactory('NoDelegateCallTest') 16 | const noDelegateCallTest = (await noDelegateCallTestFactory.deploy()) as NoDelegateCallTest 17 | const minimalProxyFactory = new ethers.ContractFactory( 18 | noDelegateCallTestFactory.interface, 19 | `3d602d80600a3d3981f3363d3d373d3d3d363d73${noDelegateCallTest.address.slice(2)}5af43d82803e903d91602b57fd5bf3`, 20 | wallet 21 | ) 22 | const proxy = (await minimalProxyFactory.deploy()) as NoDelegateCallTest 23 | return { noDelegateCallTest, proxy } 24 | } 25 | 26 | let base: NoDelegateCallTest 27 | let proxy: NoDelegateCallTest 28 | 29 | beforeEach('deploy test contracts', async () => { 30 | ;({ noDelegateCallTest: base, proxy } = await loadFixture(noDelegateCallFixture)) 31 | }) 32 | 33 | it('runtime overhead', async () => { 34 | await snapshotGasCost( 35 | (await base.getGasCostOfCannotBeDelegateCalled()).sub(await base.getGasCostOfCanBeDelegateCalled()) 36 | ) 37 | }) 38 | 39 | it('proxy can call the method without the modifier', async () => { 40 | await proxy.canBeDelegateCalled() 41 | }) 42 | it('proxy cannot call the method with the modifier', async () => { 43 | await expect(proxy.cannotBeDelegateCalled()).to.be.reverted 44 | }) 45 | 46 | it('can call the method that calls into a private method with the modifier', async () => { 47 | await base.callsIntoNoDelegateCallFunction() 48 | }) 49 | it('proxy cannot call the method that calls a private method with the modifier', async () => { 50 | await expect(proxy.callsIntoNoDelegateCallFunction()).to.be.reverted 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/__snapshots__/BitMath.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`BitMath #leastSignificantBit gas cost of max uint128 1`] = `431`; 4 | 5 | exports[`BitMath #leastSignificantBit gas cost of max uint256 1`] = `431`; 6 | 7 | exports[`BitMath #leastSignificantBit gas cost of smaller number 1`] = `429`; 8 | 9 | exports[`BitMath #mostSignificantBit gas cost of max uint128 1`] = `367`; 10 | 11 | exports[`BitMath #mostSignificantBit gas cost of max uint256 1`] = `385`; 12 | 13 | exports[`BitMath #mostSignificantBit gas cost of smaller number 1`] = `295`; 14 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/__snapshots__/LiquidityMath.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`LiquidityMath #addDelta gas add 1`] = `162`; 4 | 5 | exports[`LiquidityMath #addDelta gas sub 1`] = `176`; 6 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/__snapshots__/NoDelegateCall.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`NoDelegateCall runtime overhead 1`] = `30`; 4 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/__snapshots__/SqrtPriceMath.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`SqrtPriceMath #getAmount0Delta gas cost for amount0 where roundUp = true 1`] = `610`; 4 | 5 | exports[`SqrtPriceMath #getAmount0Delta gas cost for amount0 where roundUp = true 2`] = `478`; 6 | 7 | exports[`SqrtPriceMath #getAmount1Delta gas cost for amount0 where roundUp = false 1`] = `478`; 8 | 9 | exports[`SqrtPriceMath #getAmount1Delta gas cost for amount0 where roundUp = true 1`] = `610`; 10 | 11 | exports[`SqrtPriceMath #getNextSqrtPriceFromInput zeroForOne = false gas 1`] = `536`; 12 | 13 | exports[`SqrtPriceMath #getNextSqrtPriceFromInput zeroForOne = true gas 1`] = `753`; 14 | 15 | exports[`SqrtPriceMath #getNextSqrtPriceFromOutput zeroForOne = false gas 1`] = `848`; 16 | 17 | exports[`SqrtPriceMath #getNextSqrtPriceFromOutput zeroForOne = true gas 1`] = `441`; 18 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/__snapshots__/SwapMath.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`SwapMath #computeSwapStep gas swap one for zero exact in capped 1`] = `2103`; 4 | 5 | exports[`SwapMath #computeSwapStep gas swap one for zero exact in partial 1`] = `2802`; 6 | 7 | exports[`SwapMath #computeSwapStep gas swap one for zero exact out capped 1`] = `1855`; 8 | 9 | exports[`SwapMath #computeSwapStep gas swap one for zero exact out partial 1`] = `2802`; 10 | 11 | exports[`SwapMath #computeSwapStep gas swap zero for one exact in capped 1`] = `2104`; 12 | 13 | exports[`SwapMath #computeSwapStep gas swap zero for one exact in partial 1`] = `3106`; 14 | 15 | exports[`SwapMath #computeSwapStep gas swap zero for one exact out capped 1`] = `1856`; 16 | 17 | exports[`SwapMath #computeSwapStep gas swap zero for one exact out partial 1`] = `3106`; 18 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/__snapshots__/TickBitmap.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`TickBitmap #flipTick gas cost of flipping a tick that results in deleting a word 1`] = `13427`; 4 | 5 | exports[`TickBitmap #flipTick gas cost of flipping first tick in word to initialized 1`] = `43965`; 6 | 7 | exports[`TickBitmap #flipTick gas cost of flipping second tick in word to initialized 1`] = `26865`; 8 | 9 | exports[`TickBitmap #nextInitializedTickWithinOneWord lte = false gas cost for entire word 1`] = `2627`; 10 | 11 | exports[`TickBitmap #nextInitializedTickWithinOneWord lte = false gas cost just below boundary 1`] = `2627`; 12 | 13 | exports[`TickBitmap #nextInitializedTickWithinOneWord lte = false gas cost on boundary 1`] = `2627`; 14 | 15 | exports[`TickBitmap #nextInitializedTickWithinOneWord lte = true gas cost for entire word 1`] = `2618`; 16 | 17 | exports[`TickBitmap #nextInitializedTickWithinOneWord lte = true gas cost just below boundary 1`] = `2928`; 18 | 19 | exports[`TickBitmap #nextInitializedTickWithinOneWord lte = true gas cost on boundary 1`] = `2618`; 20 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/__snapshots__/UniswapV3Factory.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`UniswapV3Factory #createPool gas 1`] = `4557092`; 4 | 5 | exports[`UniswapV3Factory factory bytecode size 1`] = `24535`; 6 | 7 | exports[`UniswapV3Factory pool bytecode size 1`] = `22142`; 8 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/shared/checkObservationEquals.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, BigNumberish } from 'ethers' 2 | import { expect } from './expect' 3 | 4 | // helper function because we cannot do a simple deep equals with the 5 | // observation result object returned from ethers because it extends array 6 | export default function checkObservationEquals( 7 | { 8 | tickCumulative, 9 | blockTimestamp, 10 | initialized, 11 | secondsPerLiquidityCumulativeX128, 12 | }: { 13 | tickCumulative: BigNumber 14 | secondsPerLiquidityCumulativeX128: BigNumber 15 | initialized: boolean 16 | blockTimestamp: number 17 | }, 18 | expected: { 19 | tickCumulative: BigNumberish 20 | secondsPerLiquidityCumulativeX128: BigNumberish 21 | initialized: boolean 22 | blockTimestamp: number 23 | } 24 | ) { 25 | expect( 26 | { 27 | initialized, 28 | blockTimestamp, 29 | tickCumulative: tickCumulative.toString(), 30 | secondsPerLiquidityCumulativeX128: secondsPerLiquidityCumulativeX128.toString(), 31 | }, 32 | `observation is equivalent` 33 | ).to.deep.eq({ 34 | ...expected, 35 | tickCumulative: expected.tickCumulative.toString(), 36 | secondsPerLiquidityCumulativeX128: expected.secondsPerLiquidityCumulativeX128.toString(), 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/shared/expect.ts: -------------------------------------------------------------------------------- 1 | import { expect, use } from 'chai' 2 | import { solidity } from 'ethereum-waffle' 3 | import { jestSnapshotPlugin } from 'mocha-chai-jest-snapshot' 4 | 5 | use(solidity) 6 | use(jestSnapshotPlugin()) 7 | 8 | export { expect } 9 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/shared/format.ts: -------------------------------------------------------------------------------- 1 | import { Decimal } from 'decimal.js' 2 | import { BigNumberish } from 'ethers' 3 | 4 | export function formatTokenAmount(num: BigNumberish): string { 5 | return new Decimal(num.toString()).dividedBy(new Decimal(10).pow(18)).toPrecision(5) 6 | } 7 | 8 | export function formatPrice(price: BigNumberish): string { 9 | return new Decimal(price.toString()).dividedBy(new Decimal(2).pow(96)).pow(2).toPrecision(5) 10 | } 11 | -------------------------------------------------------------------------------- /contract/lib/v3-core/test/shared/snapshotGasCost.ts: -------------------------------------------------------------------------------- 1 | import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider' 2 | import { expect } from './expect' 3 | import { Contract, BigNumber, ContractTransaction } from 'ethers' 4 | 5 | export default async function snapshotGasCost( 6 | x: 7 | | TransactionResponse 8 | | Promise 9 | | ContractTransaction 10 | | Promise 11 | | TransactionReceipt 12 | | Promise 13 | | BigNumber 14 | | Contract 15 | | Promise 16 | ): Promise { 17 | const resolved = await x 18 | if ('deployTransaction' in resolved) { 19 | const receipt = await resolved.deployTransaction.wait() 20 | expect(receipt.gasUsed.toNumber()).toMatchSnapshot() 21 | } else if ('wait' in resolved) { 22 | const waited = await resolved.wait() 23 | expect(waited.gasUsed.toNumber()).toMatchSnapshot() 24 | } else if (BigNumber.isBigNumber(resolved)) { 25 | expect(resolved.toNumber()).toMatchSnapshot() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contract/lib/v3-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist", 8 | "typeRoots": ["./typechain", "./node_modules/@types"], 9 | "types": ["@nomiclabs/hardhat-ethers", "@nomiclabs/hardhat-waffle"] 10 | }, 11 | "include": ["./test"], 12 | "files": ["./hardhat.config.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /contract/script/Deploy.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | import "forge-std/Script.sol"; 5 | import "forge-std/console.sol"; 6 | import "foundry-huff/HuffDeployer.sol"; 7 | import "../interfaces/IMetamorphicContractFactory.sol"; 8 | 9 | contract Deploy is Script { 10 | IMetamorphicContractFactory factory; 11 | // serachers 12 | function setUp() public { 13 | factory = IMetamorphicContractFactory(0x00000000e82eb0431756271F0d00CFB143685e7B); 14 | } 15 | 16 | function run() public{ 17 | address sandwich = HuffDeployer.broadcast("sandwich"); 18 | bytes32 salt = bytes32(0x91bf9f374fd56cc3c421f9c988af6e5c4a61df8262bc4795a02024e288e38303); 19 | vm.broadcast(0x91BF9F374fD56CC3C421f9C988af6E5C4A61DF82); 20 | address metamorphicContract = factory.deployMetamorphicContractFromExistingImplementation(salt, sandwich, ""); 21 | console.log(metamorphicContract); 22 | } 23 | } -------------------------------------------------------------------------------- /contract/script/Deposit.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | contract Deposit is Script { 7 | address sandwich; 8 | mapping(string => uint8) internal functionSigsToJumpLabel; 9 | 10 | // serachers 11 | function setUp() public { 12 | setupSigJumpLabelMapping(); 13 | sandwich = 0x000000146741612bA673d5c70000c65e6bf9e100; 14 | } 15 | 16 | function run() public { 17 | uint8 depositLabel = getJumpLabelFromSig("depositWeth"); 18 | uint8 head = uint8(block.number); 19 | bytes memory payload = abi.encodePacked(head, depositLabel); 20 | uint amountDeposit = 4 ether; 21 | uint256 searcherPrivateKey = vm.envUint("SEARCHER_PRIVATE_KEY"); 22 | vm.broadcast(searcherPrivateKey); 23 | // vm.broadcast(0x501E809C8C8d268E136B6975b331EA398e07d35e); 24 | (bool result, ) = sandwich.call{value: amountDeposit}(payload); 25 | require(result, "Call reverted"); 26 | } 27 | 28 | function getJumpLabelFromSig( 29 | string memory sig 30 | ) public view returns (uint8) { 31 | return functionSigsToJumpLabel[sig]; 32 | } 33 | 34 | function setupSigJumpLabelMapping() private { 35 | uint256 startingIndex = 0x30; 36 | 37 | string[22] memory functionNames = [ 38 | "v2_input_single", 39 | "v2_output0_single", 40 | "v2_output1_single", 41 | "v3_input0", 42 | "v3_input1", 43 | "v3_output0", 44 | "v3_output1", 45 | "v2_input_multi_first", 46 | "v2_input_multi_next", 47 | "v2_output_multi_first", 48 | "v2_output_multi_next", 49 | "prepare_stack", 50 | "v3_input0_multi", 51 | "v3_input1_multi", 52 | "v3_output0_multi", 53 | "v3_output1_multi", 54 | "arbitrage_weth_input", 55 | "arbitrage_v2_swap_to_other", 56 | "arbitrage_v2_swap_to_this", 57 | "seppuku", 58 | "recoverWeth", 59 | "depositWeth" 60 | ]; 61 | 62 | for (uint256 i = 0; i < functionNames.length; i++) { 63 | functionSigsToJumpLabel[functionNames[i]] = uint8( 64 | startingIndex + (0x05 * i) 65 | ); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contract/script/Seppuku.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | contract Seppuku is Script { 7 | address sandwich; 8 | mapping(string => uint8) internal functionSigsToJumpLabel; 9 | // serachers 10 | function setUp() public { 11 | setupSigJumpLabelMapping(); 12 | sandwich = 0x000000146741612bA673d5c70000c65e6bf9e100; 13 | } 14 | 15 | function run() public{ 16 | uint8 seppukuLabel = getJumpLabelFromSig("seppuku"); 17 | uint8 head = uint8(block.number); 18 | bytes memory payload = abi.encodePacked(head, seppukuLabel); 19 | uint256 searcherPrivateKey = vm.envUint("SEARCHER_PRIVATE_KEY"); 20 | vm.broadcast(searcherPrivateKey); 21 | (bool result,) = sandwich.call(payload); 22 | require(result, "Call reverted"); 23 | } 24 | 25 | 26 | function getJumpLabelFromSig( 27 | string memory sig 28 | ) public view returns (uint8) { 29 | return functionSigsToJumpLabel[sig]; 30 | } 31 | 32 | function setupSigJumpLabelMapping() private { 33 | uint256 startingIndex = 0x30; 34 | 35 | string[22] memory functionNames = [ 36 | "v2_input_single", 37 | "v2_output0_single", 38 | "v2_output1_single", 39 | "v3_input0", 40 | "v3_input1", 41 | "v3_output0", 42 | "v3_output1", 43 | "v2_input_multi_first", 44 | "v2_input_multi_next", 45 | "v2_output_multi_first", 46 | "v2_output_multi_next", 47 | "prepare_stack", 48 | "v3_input0_multi", 49 | "v3_input1_multi", 50 | "v3_output0_multi", 51 | "v3_output1_multi", 52 | "arbitrage_weth_input", 53 | "arbitrage_v2_swap_to_other", 54 | "arbitrage_v2_swap_to_this", 55 | "seppuku", 56 | "recoverWeth", 57 | "depositWeth" 58 | ]; 59 | 60 | for (uint256 i = 0; i < functionNames.length; i++) { 61 | functionSigsToJumpLabel[functionNames[i]] = uint8( 62 | startingIndex + (0x05 * i) 63 | ); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /contract/script/Withdraw.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | import "forge-std/Script.sol"; 5 | import "forge-std/console.sol"; 6 | 7 | contract Withdraw is Script { 8 | address sandwich; 9 | mapping(string => uint8) internal functionSigsToJumpLabel; 10 | 11 | // serachers 12 | function setUp() public { 13 | setupSigJumpLabelMapping(); 14 | sandwich = 0x000000146741612bA673d5c70000c65e6bf9e100; 15 | } 16 | 17 | function run() public { 18 | uint8 withdrawLabel = getJumpLabelFromSig("recoverWeth"); 19 | uint8 head = uint8(block.number); 20 | uint amountWithdraw = 4.041820827974101895 ether; 21 | uint callvalue = amountWithdraw / wethEncodeMultiple(); 22 | bytes memory payload = abi.encodePacked(head, withdrawLabel); 23 | console.logBytes(payload); 24 | uint256 searcherPrivateKey = vm.envUint("SEARCHER_PRIVATE_KEY"); 25 | vm.broadcast(searcherPrivateKey); 26 | (bool result, ) = sandwich.call{value: callvalue}(payload); 27 | require(result, "Call reverted"); 28 | } 29 | 30 | function getJumpLabelFromSig( 31 | string memory sig 32 | ) public view returns (uint8) { 33 | return functionSigsToJumpLabel[sig]; 34 | } 35 | 36 | function setupSigJumpLabelMapping() private { 37 | uint256 startingIndex = 0x30; 38 | 39 | string[22] memory functionNames = [ 40 | "v2_input_single", 41 | "v2_output0_single", 42 | "v2_output1_single", 43 | "v3_input0", 44 | "v3_input1", 45 | "v3_output0", 46 | "v3_output1", 47 | "v2_input_multi_first", 48 | "v2_input_multi_next", 49 | "v2_output_multi_first", 50 | "v2_output_multi_next", 51 | "prepare_stack", 52 | "v3_input0_multi", 53 | "v3_input1_multi", 54 | "v3_output0_multi", 55 | "v3_output1_multi", 56 | "arbitrage_weth_input", 57 | "arbitrage_v2_swap_to_other", 58 | "arbitrage_v2_swap_to_this", 59 | "seppuku", 60 | "recoverWeth", 61 | "depositWeth" 62 | ]; 63 | 64 | for (uint256 i = 0; i < functionNames.length; i++) { 65 | functionSigsToJumpLabel[functionNames[i]] = uint8( 66 | startingIndex + (0x05 * i) 67 | ); 68 | } 69 | } 70 | 71 | function wethEncodeMultiple() public pure returns (uint256) { 72 | return uint256(0x100000000); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /contract/src/lib/SafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.6; 3 | 4 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 5 | 6 | library SafeMath { 7 | function add(uint x, uint y) internal pure returns (uint z) { 8 | require((z = x + y) >= x, 'ds-math-add-overflow'); 9 | } 10 | 11 | function sub(uint x, uint y) internal pure returns (uint z) { 12 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 13 | } 14 | 15 | function mul(uint x, uint y) internal pure returns (uint z) { 16 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contract/src/lib/SafeTransfer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import "../../interfaces/IERC20.sol"; 5 | 6 | library SafeTransfer { 7 | function safeTransferFrom( 8 | IERC20 token, 9 | address from, 10 | address to, 11 | uint256 value 12 | ) internal { 13 | (bool s, ) = address(token).call( 14 | abi.encodeWithSelector( 15 | IERC20.transferFrom.selector, 16 | from, 17 | to, 18 | value 19 | ) 20 | ); 21 | require(s, "safeTransferFrom failed"); 22 | } 23 | 24 | function safeTransfer( 25 | IERC20 token, 26 | address to, 27 | uint256 value 28 | ) internal { 29 | (bool s, ) = address(token).call( 30 | abi.encodeWithSelector(IERC20.transfer.selector, to, value) 31 | ); 32 | require(s, "safeTransfer failed"); 33 | } 34 | 35 | function safeApprove( 36 | IERC20 token, 37 | address to, 38 | uint256 value 39 | ) internal { 40 | (bool s, ) = address(token).call( 41 | abi.encodeWithSelector(IERC20.approve.selector, to, value) 42 | ); 43 | require(s, "safeApprove failed"); 44 | } 45 | 46 | function safeTransferETH(address to, uint256 value) internal { 47 | (bool s, ) = to.call{value: value}(new bytes(0)); 48 | require(s, "safeTransferETH failed"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contract/test/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.15; 3 | 4 | interface IWETH { 5 | function name() external view returns (string memory); 6 | 7 | function approve(address guy, uint256 wad) external returns (bool); 8 | 9 | function totalSupply() external view returns (uint256); 10 | 11 | function transferFrom( 12 | address src, 13 | address dst, 14 | uint256 wad 15 | ) external returns (bool); 16 | 17 | function withdraw(uint256 wad) external; 18 | 19 | function decimals() external view returns (uint8); 20 | 21 | function balanceOf(address) external view returns (uint256); 22 | 23 | function symbol() external view returns (string memory); 24 | 25 | function transfer(address dst, uint256 wad) external returns (bool); 26 | 27 | function deposit() external payable; 28 | 29 | function allowance(address, address) external view returns (uint256); 30 | } 31 | --------------------------------------------------------------------------------