├── .gitignore ├── Addresses.txt ├── README.md ├── contracts ├── Address.sol ├── Arbitrage.sol ├── BlackListRegistry.sol ├── DevSplitter.sol ├── ERC20.sol ├── ERC31337.sol ├── EnumerableSet.sol ├── FreeParticipantRegistry.sol ├── GatedERC20.sol ├── IERC20.sol ├── IERC31337.sol ├── IFloorCalculator.sol ├── IGatedERC20.sol ├── IOwned.sol ├── IRootKitDistribution.sol ├── IStoneface.sol ├── ITokensRecoverable.sol ├── ITransferGate.sol ├── IUniswapV2Factory.sol ├── IUniswapV2Pair.sol ├── IUniswapV2Router01.sol ├── IUniswapV2Router02.sol ├── IVault.sol ├── IWETH.sol ├── IWrappedERC20.sol ├── IWrappedERC20Events.sol ├── KETH.sol ├── KethToWethLiquidityZapper.sol ├── LiquidityLockedERC20.sol ├── Owned.sol ├── RootKit.sol ├── RootKitDirect.sol ├── RootKitDistribution.sol ├── RootKitEasyMoneyButton.sol ├── RootKitFloorCalculator.sol ├── RootKitLiquidity.sol ├── RootKitLiquidityGeneration.sol ├── RootKitLiquidityMatching.sol ├── RootKitMoneyButton.sol ├── RootKitRuggableFloorCalculator.sol ├── RootKitStaking.sol ├── RootKitTransferGate.sol ├── RootKitVault.sol ├── RootWethZapper.sol ├── RootkitTwoPoolCalculator.sol ├── SafeERC20.sol ├── SafeMath.sol ├── SingleSideLiquidityAdder.sol ├── Stoneface.sol ├── TokensRecoverable.sol ├── UniswapV2Library.sol ├── Vault.sol ├── WETH9.sol ├── WbtcToWethLiquidityZapper.sol ├── WethToKethLiquidityZapper.sol ├── WrappedERC20.sol ├── json │ ├── UniswapV2Factory.json │ ├── UniswapV2Library.json │ ├── UniswapV2OracleLibrary.json │ ├── UniswapV2Pair.json │ └── UniswapV2Router02.json └── test │ ├── ERC20Test.sol │ ├── GatedERC20Test.sol │ ├── LiquidityLockedERC20Test.sol │ ├── OwnedTest.sol │ ├── RootKitDistributionTest.sol │ ├── TokensRecoverableTest.sol │ └── TransferGateTest.sol ├── data └── abi │ ├── DevSplitter.json │ ├── ERC20.json │ ├── ERC20Test.json │ ├── ERC31337.json │ ├── GatedERC20.json │ ├── GatedERC20Test.json │ ├── GrootGrower.json │ ├── GrootKit.json │ ├── IERC20.json │ ├── IERC31337.json │ ├── IFloorCalculator.json │ ├── IGatedERC20.json │ ├── IOwned.json │ ├── IRootKitDistribution.json │ ├── IStoneface.json │ ├── ITokensRecoverable.json │ ├── ITransferGate.json │ ├── IUniswapV2Factory.json │ ├── IUniswapV2Pair.json │ ├── IUniswapV2Router01.json │ ├── IUniswapV2Router02.json │ ├── IWETH.json │ ├── IWrappedERC20.json │ ├── IWrappedERC20Events.json │ ├── KETH.json │ ├── LiquidityLockedERC20.json │ ├── LiquidityLockedERC20Test.json │ ├── Owned.json │ ├── OwnedTest.json │ ├── RootKit.json │ ├── RootKitDirect.json │ ├── RootKitDistribution.json │ ├── RootKitDistributionTest.json │ ├── RootKitFloorCalculator.json │ ├── RootKitLiquidity.json │ ├── RootKitLiquidityGeneration.json │ ├── RootKitLiquidityMatching.json │ ├── RootKitMoneyButton.json │ ├── RootKitRuggableFloorCalculator.json │ ├── RootKitStaking.json │ ├── RootKitTransferGate.json │ ├── RootKitVault.json │ ├── RootWethZapper.json │ ├── Stoneface.json │ ├── TokensRecoverable.json │ ├── TokensRecoverableTest.json │ ├── TransferGateTest.json │ ├── WETH9.json │ ├── WbtcToWethLiquidityZapper.json │ └── WrappedERC20.json ├── hardhat.config.js ├── package.json ├── redeploy.js ├── test ├── ERC20.js ├── ERC31337.js ├── GatedERC20.js ├── GrootGrower.js ├── GrootKit.js ├── KETH.js ├── LiquidityLockedERC20.js ├── Owned.js ├── RootKit.js ├── RootKitDirect.js ├── RootKitDistribution.js ├── RootKitFloorCalculator.js ├── RootKitLiquidityGeneration.js ├── RootKitLiquidityMatching.js ├── RootKitMoneyButton.js ├── RootKitRuggableFloorCalculator.js ├── RootKitStaking.js ├── RootKitTransferGate.js ├── RootKitVault.js ├── RootWethZapper.js ├── Simulations.js ├── Stoneface.js ├── TokensRecoverable.js ├── WbtcToWethLiquidityZapper.js └── helpers.js ├── transferOwnership.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | artifacts 2 | node_modules 3 | cache 4 | deploy.js 5 | .DS_Store 6 | data 7 | -------------------------------------------------------------------------------- /Addresses.txt: -------------------------------------------------------------------------------- 1 | Deployer: 0x804CC8D469483d202c69752ce0304F71ae14ABdf 2 | Buy Back: 0xc27c10ABf2fD6B39Cda4c5478BB2BF1E12919c99 3 | Fee Collector: 0x30d1db7f73C7f9819e0676F5052D3B2D45FF3Fe5 4 | Ignore Address: 0x4D605Ded7e5a9B22ecB8B90576Cd9b405190C1EB 5 | sub deployer: 0xE662896E5b6D9c5dfc6F10F12Ca4a3e4b51f81D0 6 | --- 7 | WETH: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 8 | Uniswap Router: 0x7a250d5630b4cf539739df2c5dacb4c659f2488d 9 | Uniswap Factory: 0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f 10 | --- 11 | WETH/ROOT: 0x01f8989c1e556f5c89c7D46786dB98eEAAe82c33 12 | KETH/ROOT: 0x44EE37ba8c98493F2590811c197Ddd474C911D46 13 | WETH LP/ROOT Pool: 0x283c7d44A93DB3C211B61FdbE3C3BB2678f5D657 14 | KETH LP/ROOT Pool: 0x318B64B3222C40496830644632f24015D4b2B095 15 | --- 16 | 17 | 18 | Active ROOT contracts 19 | RootKit: 0xCb5f72d37685C3D5aD0bB5F982443BC8FcdF570E 20 | KETH: 0x93747501F46Ae40b8A4B8F1a1529696AE24ea04e 21 | RootKitStaking: 0x39E9fB78b543748950827BF4c606F58724b67a80 22 | Transfer gate: 0x105E66f0bfD5b3b1E386D0dC6EC00F3342EF3fF6 23 | Calculator: 0xA12C55637E642C0e79C5923125cd7eeb8be3a53F 24 | 25 | Vault: 0xc547D2bc0C3606602a4C9A530BFadDBc07A7f06F 26 | arbitrage: 0xcf53281777CeBcD2D2646E12Ca9e8fAeA0e1a3aF 27 | SingleSideLiqudityAdder: 0x75013Cbfc60fda02c7B18cD1066d7B6C46970D25 28 | arb and single add bot: 0x439Fd1FDfF5D1c46F67220c7C38d04F366372332 29 | 30 | 31 | INACTIVE / OLD contracts 32 | Vault: 0xDE2F4d32b713aDaE849F8A221bf2ed54c262B7c6 33 | arbitrage: 0x908756371035f31C40E15e5Fe678bBbF4329FFe8 34 | Vault: 0x424eE0bA90c1B07A7c8A1A38aE999a88ED2cA5D1 35 | arbitrage: 0x74702a9a9436FD6D3Cee6efa977Cc5CA766260bf 36 | SingleSideLiqudityAdder: 0x8cA54514Ba470011da257F3C3DE9ea810f537070 37 | RootKitDirect: 0x1DDDbC37231965897d4131BdbA0ade7069d28AB0 38 | RootKitLiquidityMatching: 0x1545C3F9d22C8c3aeefcA138f7d956F494A9d923 39 | Transfer Gate: 0xBcEd48FD991846E267B02FBC1b7aFE2cc2E483D2 40 | Floor Calculator: 0x621642243CC6bE2D18b451e2386c52d1e9f7eDF6 41 | KETH: 0x1df2099f6AbBf0b05C12a61835137D84F10DAA96 42 | Vault: 0xaa360Bd89Ac14533940114cf7205DdF5e0CA7fa6 43 | Distribution: 0xdc436261C356E136b1671442d0bD0Ae183a6d77D 44 | Liquidity Generation: 0x4C66a6f06B8bC4243479121A4eF0061650e5D137 45 | KETH/ROOT: 0x0617d5ffb29c03ac35f1863b8a50ce1b52d446f6 46 | WBTC/ROOT: 0x920c87d8b3cc675d6acff2830becf76d55bc974c 47 | Wrapper for KETH/ROOT: 0xBfBb9B401114e367f7E174cDF4FBb8Fcc0585fcc 48 | Wrapper for WBTC/ROOT: 0xBabc2015dAb61008f5E248DD3511Fd46a4103418 49 | Wrapper for WETH/ROOT: 0x12a06769C5a8881aafb4eA0F6D8b7Ad79EaEBc35 50 | Stoneface (7 days): 0xB0684173F62815b2121C1030cA2423123bA81905 51 | Stoneface (3 days): 0x95c017BeE88284bEf2253E3c347980EF2a0e2ec2 52 | RootKitMoneyButton: 0x7803B983492EB76406BDbF222D77937198ABa03c 53 | ezmoney: 0x572CA9fDF01c481754f145f17D44474505e843b0 54 | bobber for keth1: 0x1b8e7D4b29DdAf1147fD58D64636247a3533e4cC 55 | calc: 0xD4ed41a41bD5114341Eb2Dd066BD7A927B98DC14 - CURRENT 56 | transfergate: 0x12b0CC3C0DC7E4d525db490f24Dd4B3526820C50 - CURRENT 57 | bobberG2: 0xb42aaff6505c829c7697cdb6e593b34fafa8d629 - CURRENT 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Root Protocol

4 |
5 | 6 | logo 7 | 8 |
9 | 10 | [![](https://img.shields.io/badge/telegram-t.me/rootkitfinance-blue.svg)](https://t.me/rootkitfinance) [![](https://img.shields.io/badge/twitter-%40rootkitfinance-blue.svg)](https://twitter.com/rootkitfinance) 11 | 12 |
13 | 14 |
15 | 16 | ## Quick Links 17 | 18 | - 🌐 [Website](https://rootkit.finance/) 19 | - 📖 [Medium](https://medium.com/@rootkitfinance) 20 | - 🔗 [Twitter](https://twitter.com/rootkitfinance) 21 | - 🔗 [Telegram](https://t.me/rootkitfinance) 22 | 23 | ## Intro 24 | 25 | The Root Protocol is the rootkit to the financial system. It's financial sorcery on the blockchain. 26 | 27 | ### Official Twitter accounts 28 | 29 | Main twitter: 30 | 31 | https://twitter.com/rootkitfinance 32 | 33 | ### Telegram channels 34 | 35 | Main: 36 | 37 | https://t.me/rootkitfinance 38 | 39 | ### Github repositories 40 | 41 | https://github.com/RootkitFinance 42 | 43 | ### Documentation 44 | 45 | https://medium.com/@rootkitfinance 46 | 47 | ### Audits 48 | 49 | COMING SOON 50 | 51 | ### Articles 52 | 53 | Official 54 | 55 | Introducing Rootkit Finance 56 | 57 | https://rootkitfinance.medium.com/introducing-rootkit-finance-3f41e8eb580a 58 | 59 | True Fair Launch 60 | 61 | https://rootkitfinance.medium.com/true-fair-launch-fe6b2ca47bc4 62 | 63 | ## Getting Started 64 | 65 | Visit `src` to review the contracts. 66 | 67 | To execute tests: 68 | 69 | ``` 70 | npm test 71 | ``` 72 | 73 | Report bugs to `rootkitfinance exe` in Telegram 74 | -------------------------------------------------------------------------------- /contracts/Arbitrage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IERC20.sol"; 5 | import "./IERC31337.sol"; 6 | import "./TokensRecoverable.sol"; 7 | import "./IUniswapV2Router02.sol"; 8 | 9 | contract Arbitrage is TokensRecoverable 10 | { 11 | IERC20 public immutable baseToken; 12 | IERC31337 public immutable eliteToken; 13 | IERC20 public immutable rootedToken; 14 | IUniswapV2Router02 public immutable uniswapRouter; 15 | 16 | mapping (address => bool) public arbitrageurs; 17 | 18 | event Profit(uint256 _value); 19 | 20 | constructor(IERC20 _baseToken, IERC31337 _eliteToken, IERC20 _rootedToken, IUniswapV2Router02 _uniswapRouter) 21 | { 22 | baseToken = _baseToken; 23 | eliteToken = _eliteToken; 24 | rootedToken = _rootedToken; 25 | uniswapRouter = _uniswapRouter; 26 | 27 | _baseToken.approve(address(_uniswapRouter), uint256(-1)); 28 | _eliteToken.approve(address(_uniswapRouter), uint256(-1)); 29 | _rootedToken.approve(address(_uniswapRouter), uint256(-1)); 30 | _baseToken.approve(address(_eliteToken), uint256(-1)); 31 | } 32 | 33 | modifier arbitrageurOnly() 34 | { 35 | require(arbitrageurs[msg.sender], "Not an arbitrageur"); 36 | _; 37 | } 38 | 39 | function setArbitrageur(address arbitrageur, bool allow) public ownerOnly() 40 | { 41 | arbitrageurs[arbitrageur] = allow; 42 | } 43 | 44 | function balancePriceBase(uint256 baseAmount, uint256 minAmountOut) public arbitrageurOnly() 45 | { 46 | uint256 rootedAmount = buyRootedToken(address(baseToken), baseAmount, 0); 47 | uint256 eliteAmount = sellRootedToken(address(eliteToken), rootedAmount, minAmountOut); 48 | 49 | require(eliteAmount > baseAmount, "No profit"); 50 | eliteToken.withdrawTokens(eliteAmount); 51 | emit Profit(eliteAmount - baseAmount); 52 | } 53 | 54 | function balancePriceElite(uint256 eliteAmount, uint256 minAmountOut) public arbitrageurOnly() 55 | { 56 | eliteToken.depositTokens(eliteAmount); 57 | uint256 rootedAmount = buyRootedToken(address(eliteToken), eliteAmount, 0); 58 | uint256 baseAmount = sellRootedToken(address(baseToken), rootedAmount, minAmountOut); 59 | 60 | require(baseAmount > eliteAmount, "No profit"); 61 | emit Profit(baseAmount - eliteAmount); 62 | } 63 | 64 | function buyRootedToken(address token, uint256 amountToSpend, uint256 minAmountOut) private returns (uint256) 65 | { 66 | address[] memory path = new address[](2); 67 | path[0] = address(token); 68 | path[1] = address(rootedToken); 69 | uint256[] memory amounts = uniswapRouter.swapExactTokensForTokens(amountToSpend, minAmountOut, path, address(this), block.timestamp); 70 | return amounts[1]; 71 | } 72 | 73 | function sellRootedToken(address token, uint256 amountToSpend, uint256 minAmountOut) private returns (uint256) 74 | { 75 | address[] memory path = new address[](2); 76 | path[0] = address(rootedToken); 77 | path[1] = address(token); 78 | uint256[] memory amounts = uniswapRouter.swapExactTokensForTokens(amountToSpend, minAmountOut, path, address(this), block.timestamp); 79 | return amounts[1]; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /contracts/BlackListRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | 6 | contract BlackListRegistry is Owned 7 | { 8 | mapping (address => bool) public blackList; 9 | 10 | function setBlackListed(address account, bool blackListed) public ownerOnly() 11 | { 12 | blackList[account] = blackListed; 13 | } 14 | } -------------------------------------------------------------------------------- /contracts/DevSplitter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IERC20.sol"; 5 | import "./SafeMath.sol"; 6 | import "./SafeERC20.sol"; 7 | import "./Address.sol"; 8 | 9 | contract DevSplitter 10 | { 11 | using SafeMath for uint256; 12 | using SafeERC20 for IERC20; 13 | using Address for address; 14 | 15 | mapping (IERC20 => uint256) public totalPaid; 16 | mapping (IERC20 => mapping(address => uint256)) public totalPaidToPayee; 17 | 18 | mapping (address => uint256) public share; 19 | uint256 immutable public totalShares; 20 | 21 | constructor(address[] memory payees, uint256[] memory shares) 22 | { 23 | require (payees.length == shares.length && payees.length > 0); 24 | 25 | uint256 total = 0; 26 | for (uint256 x=0; x 0 && share[payee] == 0); 30 | require (!payee.isContract(), "Cannot pay a contract"); 31 | total = total.add(sh); 32 | share[payee] = sh; 33 | } 34 | totalShares = total; 35 | } 36 | 37 | receive() external payable {} 38 | 39 | function owed(IERC20 token, address payee) public view returns (uint256) { 40 | uint256 balance = address(token) == address(0) ? address(this).balance : token.balanceOf(address(this)); 41 | uint256 payeeShare = balance.add(totalPaid[token]).mul(share[payee]) / totalShares; 42 | uint256 paid = totalPaidToPayee[token][payee]; 43 | return payeeShare > paid ? payeeShare - paid : 0; 44 | } 45 | 46 | function pay(IERC20 token, address payable payee) public { 47 | uint256 toPay = owed(token, payee); 48 | require (toPay > 0, "Nothing to pay"); 49 | 50 | totalPaid[token] = totalPaid[token].add(toPay); 51 | totalPaidToPayee[token][payee] = totalPaidToPayee[token][payee].add(toPay); 52 | 53 | if (address(token) == address(0)) { 54 | (bool success,) = payee.call{ value: toPay }(""); 55 | require (success, "Transfer failed"); 56 | } 57 | else { 58 | token.safeTransfer(payee, toPay); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /contracts/ERC31337.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | A wrapped token, where the underlying token can be swept 6 | and used for other purposes 7 | Governed by an installable floor calculator contract 8 | Sweepable by designated sweeper addresses 9 | */ 10 | 11 | import "./IERC20.sol"; 12 | import "./SafeERC20.sol"; 13 | import "./Owned.sol"; 14 | import "./IFloorCalculator.sol"; 15 | import "./WrappedERC20.sol"; 16 | import "./IERC31337.sol"; 17 | 18 | contract ERC31337 is WrappedERC20, IERC31337 19 | { 20 | using SafeERC20 for IERC20; 21 | 22 | IFloorCalculator public override floorCalculator; 23 | 24 | mapping (address => bool) public override sweepers; 25 | 26 | constructor(IERC20 _wrappedToken, string memory _name, string memory _symbol) 27 | WrappedERC20(_wrappedToken, _name, _symbol) 28 | { 29 | } 30 | 31 | function setFloorCalculator(IFloorCalculator _floorCalculator) public override ownerOnly() 32 | { 33 | floorCalculator = _floorCalculator; 34 | } 35 | 36 | function setSweeper(address sweeper, bool allow) public override ownerOnly() 37 | { 38 | sweepers[sweeper] = allow; 39 | } 40 | 41 | function sweepFloor(address to) public override returns (uint256 amountSwept) 42 | { 43 | require (to != address(0)); 44 | require (sweepers[msg.sender], "Sweepers only"); 45 | amountSwept = floorCalculator.calculateSubFloor(wrappedToken, this); 46 | if (amountSwept > 0) { 47 | wrappedToken.safeTransfer(to, amountSwept); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /contracts/FreeParticipantRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | 6 | contract FreeParticipantRegistry is Owned 7 | { 8 | address public transferGate; 9 | mapping (address => bool) public freeParticipantControllers; 10 | mapping (address => bool) public freeParticipant; 11 | 12 | modifier transferGateOnly() 13 | { 14 | require (msg.sender == transferGate, "Transfer Gate only"); 15 | _; 16 | } 17 | 18 | function setTransferGate(address _transferGate) public ownerOnly() 19 | { 20 | transferGate = _transferGate; 21 | } 22 | 23 | function setFreeParticipantController(address freeParticipantController, bool allow) public transferGateOnly() 24 | { 25 | freeParticipantControllers[freeParticipantController] = allow; 26 | } 27 | 28 | function setFreeParticipant(address participant, bool free) public transferGateOnly() 29 | { 30 | freeParticipant[participant] = free; 31 | } 32 | } -------------------------------------------------------------------------------- /contracts/GatedERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | pragma experimental ABIEncoderV2; 4 | 5 | /* ROOTKIT: 6 | A standard ERC20 with an extra hook: An installable transfer 7 | gate allowing for token tax and burn on transfer 8 | */ 9 | 10 | import "./ERC20.sol"; 11 | import "./ITransferGate.sol"; 12 | import "./Owned.sol"; 13 | import "./SafeMath.sol"; 14 | import "./TokensRecoverable.sol"; 15 | import "./IGatedERC20.sol"; 16 | 17 | abstract contract GatedERC20 is ERC20, TokensRecoverable, IGatedERC20 18 | { 19 | using SafeMath for uint256; 20 | 21 | ITransferGate public override transferGate; 22 | 23 | constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) 24 | { 25 | } 26 | 27 | function setTransferGate(ITransferGate _transferGate) public override ownerOnly() 28 | { 29 | transferGate = _transferGate; 30 | } 31 | 32 | function _transfer(address sender, address recipient, uint256 amount) internal virtual override 33 | { 34 | require(sender != address(0), "ERC20: transfer from the zero address"); 35 | require(recipient != address(0), "ERC20: transfer to the zero address"); 36 | 37 | _beforeTokenTransfer(sender, recipient, amount); 38 | 39 | ITransferGate _transferGate = transferGate; 40 | uint256 remaining = amount; 41 | if (address(_transferGate) != address(0)) { 42 | (uint256 burn, TransferGateTarget[] memory targets) = _transferGate.handleTransfer(msg.sender, sender, recipient, amount); 43 | if (burn > 0) { 44 | amount = remaining = remaining.sub(burn, "Burn too much"); 45 | _burn(sender, burn); 46 | } 47 | for (uint256 x = 0; x < targets.length; ++x) { 48 | (address dest, uint256 amt) = (targets[x].destination, targets[x].amount); 49 | remaining = remaining.sub(amt, "Transfer too much"); 50 | _balanceOf[dest] = _balanceOf[dest].add(amt); 51 | } 52 | } 53 | _balanceOf[sender] = _balanceOf[sender].sub(amount, "ERC20: transfer amount exceeds balance"); 54 | _balanceOf[recipient] = _balanceOf[recipient].add(remaining); 55 | emit Transfer(sender, recipient, amount); 56 | } 57 | } -------------------------------------------------------------------------------- /contracts/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IERC20 5 | { 6 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 7 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 8 | 9 | function totalSupply() external view returns (uint256); 10 | function balanceOf(address _account) external view returns (uint256); 11 | function transfer(address _recipient, uint256 _amount) external returns (bool); 12 | function allowance(address _owner, address _spender) external view returns (uint256); 13 | function approve(address _spender, uint256 _amount) external returns (bool); 14 | function transferFrom(address _sender, address _recipient, uint256 _amount) external returns (bool); 15 | 16 | function name() external view returns (string memory); 17 | function symbol() external view returns (string memory); 18 | function decimals() external view returns (uint8); 19 | } -------------------------------------------------------------------------------- /contracts/IERC31337.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IWrappedERC20.sol"; 5 | import "./IFloorCalculator.sol"; 6 | 7 | interface IERC31337 is IWrappedERC20 8 | { 9 | function floorCalculator() external view returns (IFloorCalculator); 10 | function sweepers(address _sweeper) external view returns (bool); 11 | 12 | function setFloorCalculator(IFloorCalculator _floorCalculator) external; 13 | function setSweeper(address _sweeper, bool _allow) external; 14 | function sweepFloor(address _to) external returns (uint256 amountSwept); 15 | } -------------------------------------------------------------------------------- /contracts/IFloorCalculator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IERC20.sol"; 5 | 6 | interface IFloorCalculator 7 | { 8 | function calculateSubFloor(IERC20 wrappedToken, IERC20 backingToken) external view returns (uint256); 9 | } -------------------------------------------------------------------------------- /contracts/IGatedERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IERC20.sol"; 5 | import "./ITransferGate.sol"; 6 | 7 | interface IGatedERC20 is IERC20 8 | { 9 | function transferGate() external view returns (ITransferGate); 10 | 11 | function setTransferGate(ITransferGate _transferGate) external; 12 | } -------------------------------------------------------------------------------- /contracts/IOwned.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IOwned 5 | { 6 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 7 | 8 | function owner() external view returns (address); 9 | 10 | function transferOwnership(address newOwner) external; 11 | function claimOwnership() external; 12 | } -------------------------------------------------------------------------------- /contracts/IRootKitDistribution.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IRootKitDistribution 5 | { 6 | function distributionComplete() external view returns (bool); 7 | 8 | function distribute() external payable; 9 | function claim(address _to, uint256 _contribution) external; 10 | } -------------------------------------------------------------------------------- /contracts/IStoneface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "./IOwned.sol"; 6 | import "./IRootKitDistribution.sol"; 7 | 8 | interface IStoneface 9 | { 10 | event PendingOwnershipTransfer(IOwned target, address newOwner, uint256 when); 11 | 12 | struct TransferOwnership 13 | { 14 | uint256 when; 15 | IOwned target; 16 | address newOwner; 17 | } 18 | 19 | function delay() external view returns (uint256); 20 | function pendingTransferOwnership(uint256 index) external view returns (TransferOwnership memory); 21 | function pendingTransferOwnershipCount() external view returns (uint256); 22 | function callTransferOwnership(IOwned target, address newOwner) external; 23 | function callTransferOwnershipNow(uint256 index) external; 24 | function callClaimOwnership(IOwned target) external; 25 | function rootKitDistribution() external view returns (IRootKitDistribution); 26 | function watchDistribution(IRootKitDistribution _rootKitDistribution) external; 27 | } -------------------------------------------------------------------------------- /contracts/ITokensRecoverable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IERC20.sol"; 5 | 6 | interface ITokensRecoverable 7 | { 8 | function recoverTokens(IERC20 token) external; 9 | } -------------------------------------------------------------------------------- /contracts/ITransferGate.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | pragma experimental ABIEncoderV2; 4 | 5 | struct TransferGateTarget 6 | { 7 | address destination; 8 | uint256 amount; 9 | } 10 | 11 | interface ITransferGate 12 | { 13 | function handleTransfer(address msgSender, address from, address to, uint256 amount) external 14 | returns (uint256 burn, TransferGateTarget[] memory targets); 15 | } -------------------------------------------------------------------------------- /contracts/IUniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IUniswapV2Factory { 5 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 6 | 7 | function feeTo() external view returns (address); 8 | function feeToSetter() external view returns (address); 9 | 10 | function getPair(address tokenA, address tokenB) external view returns (address pair); 11 | function allPairs(uint) external view returns (address pair); 12 | function allPairsLength() external view returns (uint); 13 | 14 | function createPair(address tokenA, address tokenB) external returns (address pair); 15 | 16 | function setFeeTo(address) external; 17 | function setFeeToSetter(address) external; 18 | } -------------------------------------------------------------------------------- /contracts/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IUniswapV2Pair { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | 25 | event Mint(address indexed sender, uint amount0, uint amount1); 26 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 27 | event Swap( 28 | address indexed sender, 29 | uint amount0In, 30 | uint amount1In, 31 | uint amount0Out, 32 | uint amount1Out, 33 | address indexed to 34 | ); 35 | event Sync(uint112 reserve0, uint112 reserve1); 36 | 37 | function MINIMUM_LIQUIDITY() external pure returns (uint); 38 | function factory() external view returns (address); 39 | function token0() external view returns (address); 40 | function token1() external view returns (address); 41 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 42 | function price0CumulativeLast() external view returns (uint); 43 | function price1CumulativeLast() external view returns (uint); 44 | function kLast() external view returns (uint); 45 | 46 | function mint(address to) external returns (uint liquidity); 47 | function burn(address to) external returns (uint amount0, uint amount1); 48 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 49 | function skim(address to) external; 50 | function sync() external; 51 | 52 | function initialize(address, address) external; 53 | } -------------------------------------------------------------------------------- /contracts/IUniswapV2Router01.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IUniswapV2Router01 { 5 | function factory() external pure returns (address); 6 | function WETH() external pure returns (address); 7 | 8 | function addLiquidity( 9 | address tokenA, 10 | address tokenB, 11 | uint amountADesired, 12 | uint amountBDesired, 13 | uint amountAMin, 14 | uint amountBMin, 15 | address to, 16 | uint deadline 17 | ) external returns (uint amountA, uint amountB, uint liquidity); 18 | function addLiquidityETH( 19 | address token, 20 | uint amountTokenDesired, 21 | uint amountTokenMin, 22 | uint amountETHMin, 23 | address to, 24 | uint deadline 25 | ) external payable returns (uint amountToken, uint amountETH, uint liquidity); 26 | function removeLiquidity( 27 | address tokenA, 28 | address tokenB, 29 | uint liquidity, 30 | uint amountAMin, 31 | uint amountBMin, 32 | address to, 33 | uint deadline 34 | ) external returns (uint amountA, uint amountB); 35 | function removeLiquidityETH( 36 | address token, 37 | uint liquidity, 38 | uint amountTokenMin, 39 | uint amountETHMin, 40 | address to, 41 | uint deadline 42 | ) external returns (uint amountToken, uint amountETH); 43 | function removeLiquidityWithPermit( 44 | address tokenA, 45 | address tokenB, 46 | uint liquidity, 47 | uint amountAMin, 48 | uint amountBMin, 49 | address to, 50 | uint deadline, 51 | bool approveMax, uint8 v, bytes32 r, bytes32 s 52 | ) external returns (uint amountA, uint amountB); 53 | function removeLiquidityETHWithPermit( 54 | address token, 55 | uint liquidity, 56 | uint amountTokenMin, 57 | uint amountETHMin, 58 | address to, 59 | uint deadline, 60 | bool approveMax, uint8 v, bytes32 r, bytes32 s 61 | ) external returns (uint amountToken, uint amountETH); 62 | function swapExactTokensForTokens( 63 | uint amountIn, 64 | uint amountOutMin, 65 | address[] calldata path, 66 | address to, 67 | uint deadline 68 | ) external returns (uint[] memory amounts); 69 | function swapTokensForExactTokens( 70 | uint amountOut, 71 | uint amountInMax, 72 | address[] calldata path, 73 | address to, 74 | uint deadline 75 | ) external returns (uint[] memory amounts); 76 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 77 | external 78 | payable 79 | returns (uint[] memory amounts); 80 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 81 | external 82 | returns (uint[] memory amounts); 83 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 84 | external 85 | returns (uint[] memory amounts); 86 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 87 | external 88 | payable 89 | returns (uint[] memory amounts); 90 | 91 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 92 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 93 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 94 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 95 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 96 | } -------------------------------------------------------------------------------- /contracts/IUniswapV2Router02.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import './IUniswapV2Router01.sol'; 5 | 6 | interface IUniswapV2Router02 is IUniswapV2Router01 { 7 | function removeLiquidityETHSupportingFeeOnTransferTokens( 8 | address token, 9 | uint liquidity, 10 | uint amountTokenMin, 11 | uint amountETHMin, 12 | address to, 13 | uint deadline 14 | ) external returns (uint amountETH); 15 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 16 | address token, 17 | uint liquidity, 18 | uint amountTokenMin, 19 | uint amountETHMin, 20 | address to, 21 | uint deadline, 22 | bool approveMax, uint8 v, bytes32 r, bytes32 s 23 | ) external returns (uint amountETH); 24 | 25 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 26 | uint amountIn, 27 | uint amountOutMin, 28 | address[] calldata path, 29 | address to, 30 | uint deadline 31 | ) external; 32 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 33 | uint amountOutMin, 34 | address[] calldata path, 35 | address to, 36 | uint deadline 37 | ) external payable; 38 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 39 | uint amountIn, 40 | uint amountOutMin, 41 | address[] calldata path, 42 | address to, 43 | uint deadline 44 | ) external; 45 | } -------------------------------------------------------------------------------- /contracts/IVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IVault 5 | { 6 | function balancePriceBase(uint256 amount, uint256 minAmountOut) external; 7 | function balancePriceElite(uint256 amount, uint256 minAmountOut) external; 8 | function removeBuyAndTax(uint256 amount, uint256 minAmountOut, address token, uint16 tax, uint256 time) external; 9 | function buyAndTax(address token, uint256 amountToSpend, uint256 minAmountOut, uint16 tax, uint256 time) external; 10 | function sweepFloor() external; 11 | function zapEliteToBase(uint256 liquidity) external; 12 | function zapBaseToElite(uint256 liquidity) external; 13 | function wrapToElite(uint256 baseAmount) external; 14 | function unwrapElite(uint256 eliteAmount) external; 15 | function addLiquidity(address eliteOrBase, uint256 baseAmount) external; 16 | function removeLiquidity(address eliteOrBase, uint256 tokens) external; 17 | function buyRooted(address token, uint256 amountToSpend, uint256 minAmountOut) external; 18 | function sellRooted(address token, uint256 amountToSpend, uint256 minAmountOut) external; 19 | } -------------------------------------------------------------------------------- /contracts/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IERC20.sol"; 5 | import "./IWrappedERC20Events.sol"; 6 | 7 | interface IWETH is IERC20, IWrappedERC20Events 8 | { 9 | function deposit() external payable; 10 | function withdraw(uint256 _amount) external; 11 | } 12 | -------------------------------------------------------------------------------- /contracts/IWrappedERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IERC20.sol"; 5 | import "./IWrappedERC20Events.sol"; 6 | 7 | interface IWrappedERC20 is IERC20, IWrappedERC20Events 8 | { 9 | function wrappedToken() external view returns (IERC20); 10 | function depositTokens(uint256 _amount) external; 11 | function withdrawTokens(uint256 _amount) external; 12 | } -------------------------------------------------------------------------------- /contracts/IWrappedERC20Events.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | interface IWrappedERC20Events 5 | { 6 | event Deposit(address indexed from, uint256 amount); 7 | event Withdrawal(address indexed to, uint256 amount); 8 | } 9 | -------------------------------------------------------------------------------- /contracts/KETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | Technically a wrapped WETH 6 | So a wrapped wrapped ethereum 7 | But also accepts raw ETH 8 | Also functions exactly like WETH (deposit/withdraw/direct send) 9 | */ 10 | 11 | import "./ERC31337.sol"; 12 | import "./IWETH.sol"; 13 | import "./SafeMath.sol"; 14 | 15 | contract KETH is ERC31337, IWETH 16 | { 17 | using SafeMath for uint256; 18 | 19 | mapping (address => bool) public freeParticipant; 20 | uint16 public burnRate; 21 | 22 | constructor (IWETH _weth) ERC31337(_weth, "RootKit ETH", "KETH") 23 | { 24 | _mint(msg.sender, 2000 ether); 25 | } 26 | 27 | receive() external payable 28 | { 29 | if (msg.sender != address(wrappedToken)) { 30 | deposit(); 31 | } 32 | } 33 | 34 | function deposit() public payable override 35 | { 36 | uint256 amount = msg.value; 37 | IWETH(address(wrappedToken)).deposit{ value: amount }(); 38 | _mint(msg.sender, amount); 39 | emit Deposit(msg.sender, amount); 40 | } 41 | 42 | function withdraw(uint256 _amount) public override 43 | { 44 | _burn(msg.sender, _amount); 45 | IWETH(address(wrappedToken)).withdraw(_amount); 46 | emit Withdrawal(msg.sender, _amount); 47 | (bool success,) = msg.sender.call{ value: _amount }(""); 48 | require (success, "Transfer failed"); 49 | } 50 | 51 | function setFreeParticipant(address participant, bool free) public ownerOnly() 52 | { 53 | freeParticipant[participant] = free; 54 | } 55 | 56 | function setBurnRate(uint16 _burnRate) public ownerOnly() 57 | { 58 | require (_burnRate <= 2000 , "Dump tax rate should be less than or equal to 20%"); // protecting everyone from Ponzo 59 | 60 | burnRate = _burnRate; 61 | } 62 | 63 | function burn(uint256 amount) public 64 | { 65 | _burn(msg.sender, amount); 66 | } 67 | 68 | function _transfer(address sender, address recipient, uint256 amount) internal virtual override 69 | { 70 | require(sender != address(0), "ERC20: transfer from the zero address"); 71 | require(recipient != address(0), "ERC20: transfer to the zero address"); 72 | 73 | _beforeTokenTransfer(sender, recipient, amount); 74 | 75 | if (burnRate > 0 && !freeParticipant[sender] && !freeParticipant[recipient]) { 76 | uint256 burnAmount = amount * burnRate / 10000; 77 | amount = amount.sub(burnAmount, "Burn too much"); 78 | _burn(sender, burnAmount); 79 | } 80 | _balanceOf[sender] = _balanceOf[sender].sub(amount, "ERC20: transfer amount exceeds balance"); 81 | _balanceOf[recipient] = _balanceOf[recipient].add(amount); 82 | 83 | emit Transfer(sender, recipient, amount); 84 | } 85 | } -------------------------------------------------------------------------------- /contracts/KethToWethLiquidityZapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | import "./TokensRecoverable.sol"; 6 | import "./RootKit.sol"; 7 | import "./IERC31337.sol"; 8 | import "./IUniswapV2Router02.sol"; 9 | import "./IWETH.sol"; 10 | import "./IUniswapV2Pair.sol"; 11 | import "./IERC20.sol"; 12 | import "./RootKitTransferGate.sol"; 13 | import "./UniswapV2Library.sol"; 14 | import "./KETH.sol"; 15 | 16 | contract KethToWethLiquidityZapper is TokensRecoverable 17 | { 18 | IUniswapV2Router02 immutable uniswapV2Router; 19 | IERC31337 immutable wrappedKethRootKit; 20 | IUniswapV2Pair kethRootKit; 21 | IUniswapV2Pair wethRootKit; 22 | RootKit immutable rootKit; 23 | IWETH immutable weth; 24 | KETH immutable keth; 25 | 26 | constructor(IUniswapV2Router02 _uniswapV2Router, IERC31337 _wrappedKethRootKit, RootKit _rootKit) 27 | { 28 | uniswapV2Router = _uniswapV2Router; 29 | wrappedKethRootKit = _wrappedKethRootKit; 30 | rootKit = _rootKit; 31 | 32 | IUniswapV2Pair _kethRootKit = IUniswapV2Pair(address(_wrappedKethRootKit.wrappedToken())); 33 | kethRootKit = _kethRootKit; 34 | 35 | IWETH _weth = IWETH(_uniswapV2Router.WETH()); 36 | weth = _weth; 37 | 38 | KETH _keth = KETH(payable(_kethRootKit.token0() == address(_rootKit) ? _kethRootKit.token1() :_kethRootKit.token0())); 39 | keth = _keth; 40 | 41 | wethRootKit = IUniswapV2Pair(IUniswapV2Factory(_uniswapV2Router.factory()).getPair(address(_weth), address(_rootKit))); 42 | 43 | _kethRootKit.approve(address(_uniswapV2Router), uint256(-1)); 44 | _keth.approve(address(_uniswapV2Router), uint256(-1)); 45 | _weth.approve(address(_uniswapV2Router), uint256(-1)); 46 | _rootKit.approve(address(_uniswapV2Router), uint256(-1)); 47 | 48 | require (_kethRootKit.token0() == address(_rootKit) || _kethRootKit.token1() == address(_rootKit), "Sanity"); 49 | require (_kethRootKit.token0() != address(_weth) && _kethRootKit.token1() != address(_weth), "Sanity"); 50 | } 51 | 52 | function go() public ownerOnly() 53 | { 54 | wrappedKethRootKit.sweepFloor(address(this)); 55 | uint256 liquidity = kethRootKit.balanceOf(address(this)); 56 | require (liquidity > 0, "Nothing unwrapped"); 57 | RootKitTransferGate gate = RootKitTransferGate(address(rootKit.transferGate())); 58 | gate.setUnrestricted(true); 59 | (uint256 amountRootKit, uint256 amountKeth) = uniswapV2Router.removeLiquidity(address(rootKit), address(keth), liquidity, 0, 0, address(this), block.timestamp); 60 | keth.withdrawTokens(amountKeth); 61 | (,,liquidity) = uniswapV2Router.addLiquidity(address(rootKit), address(weth), amountRootKit, amountKeth, 0, 0, address(this), block.timestamp); 62 | require (liquidity > 0, "Nothing wrapped"); 63 | wethRootKit.transfer(msg.sender, liquidity); 64 | uint256 balance = weth.balanceOf(address(this)); 65 | if (balance > 0) { weth.transfer(msg.sender, balance ); } 66 | balance = keth.balanceOf(address(this)); 67 | if (balance > 0) { keth.transfer(msg.sender, balance ); } 68 | balance = rootKit.balanceOf(address(this)); 69 | if (balance > 0) { rootKit.transfer(msg.sender, balance ); } 70 | gate.setUnrestricted(false); 71 | } 72 | } -------------------------------------------------------------------------------- /contracts/LiquidityLockedERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./ERC20.sol"; 5 | import "./Owned.sol"; 6 | import "./IUniswapV2Pair.sol"; 7 | import "./GatedERC20.sol"; 8 | 9 | abstract contract LiquidityLockedERC20 is GatedERC20 10 | { 11 | mapping (IUniswapV2Pair => bool) public liquidityPairLocked; 12 | mapping (address => bool) public liquidityController; 13 | 14 | struct CallRecord 15 | { 16 | address origin; 17 | uint32 blockNumber; 18 | bool transferFrom; 19 | } 20 | 21 | CallRecord balanceAllowed; 22 | 23 | constructor(string memory _name, string memory _symbol) 24 | GatedERC20(_name, _symbol) 25 | { 26 | } 27 | 28 | function setLiquidityLock(IUniswapV2Pair _liquidityPair, bool _locked) public 29 | { 30 | require (liquidityController[msg.sender], "Liquidity controller only"); 31 | require (_liquidityPair.token0() == address(this) || _liquidityPair.token1() == address(this), "Unrelated pair"); 32 | liquidityPairLocked[_liquidityPair] = _locked; 33 | } 34 | 35 | function setLiquidityController(address _liquidityController, bool _canControl) public ownerOnly() 36 | { 37 | liquidityController[_liquidityController] = _canControl; 38 | } 39 | 40 | function balanceOf(address account) public override view returns (uint256) 41 | { 42 | IUniswapV2Pair pair = IUniswapV2Pair(address(msg.sender)); 43 | if (liquidityPairLocked[pair]) { 44 | CallRecord memory last = balanceAllowed; 45 | require (last.origin == tx.origin && last.blockNumber == block.number, "Liquidity is locked"); 46 | if (last.transferFrom) { 47 | (uint256 reserve0, uint256 reserve1,) = pair.getReserves(); 48 | IERC20 tok = IERC20(pair.token0()); 49 | if (address(tok) == address(this)) { 50 | require (IERC20(pair.token1()).balanceOf(address(pair)) < reserve1, "Liquidity is locked"); 51 | } 52 | else { 53 | require (tok.balanceOf(address(pair)) < reserve0, "Liquidity is locked"); 54 | } 55 | } 56 | } 57 | return super.balanceOf(account); 58 | } 59 | 60 | function allowBalance(bool _transferFrom) private 61 | { 62 | CallRecord memory last = balanceAllowed; 63 | CallRecord memory allow = CallRecord({ 64 | origin: tx.origin, 65 | blockNumber: uint32(block.number), 66 | transferFrom: _transferFrom 67 | }); 68 | require (last.origin != allow.origin || last.blockNumber != allow.blockNumber || last.transferFrom != allow.transferFrom, "Liquidity is locked (Please try again next block)"); 69 | balanceAllowed = allow; 70 | } 71 | 72 | function transfer(address recipient, uint256 amount) public virtual override returns (bool) 73 | { 74 | if (liquidityPairLocked[IUniswapV2Pair(address(msg.sender))]) { 75 | allowBalance(false); 76 | } 77 | else { 78 | balanceAllowed = CallRecord({ origin: address(0), blockNumber: 0, transferFrom: false }); 79 | } 80 | return super.transfer(recipient, amount); 81 | } 82 | 83 | function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) 84 | { 85 | if (liquidityPairLocked[IUniswapV2Pair(recipient)]) { 86 | allowBalance(true); 87 | } 88 | else { 89 | balanceAllowed = CallRecord({ origin: address(0), blockNumber: 0, transferFrom: false }); 90 | } 91 | return super.transferFrom(sender, recipient, amount); 92 | } 93 | } -------------------------------------------------------------------------------- /contracts/Owned.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | Provides ownerOnly() modifier 6 | Allows for ownership transfer but requires the new 7 | owner to claim (accept) ownership 8 | Safer because no accidental transfers or renouncing 9 | */ 10 | 11 | import "./IOwned.sol"; 12 | 13 | abstract contract Owned is IOwned 14 | { 15 | address public override owner = msg.sender; 16 | address internal pendingOwner; 17 | 18 | modifier ownerOnly() 19 | { 20 | require (msg.sender == owner, "Owner only"); 21 | _; 22 | } 23 | 24 | function transferOwnership(address newOwner) public override ownerOnly() 25 | { 26 | pendingOwner = newOwner; 27 | } 28 | 29 | function claimOwnership() public override 30 | { 31 | require (pendingOwner == msg.sender); 32 | pendingOwner = address(0); 33 | emit OwnershipTransferred(owner, msg.sender); 34 | owner = msg.sender; 35 | } 36 | } -------------------------------------------------------------------------------- /contracts/RootKit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | RootKit 6 | Because my suggestions of WootKit and GrootKit were overruled 7 | */ 8 | 9 | import "./GatedERC20.sol"; 10 | 11 | contract RootKit is GatedERC20("RootKit", "ROOT") 12 | { 13 | constructor() 14 | { 15 | _mint(msg.sender, 10000 ether); 16 | } 17 | } -------------------------------------------------------------------------------- /contracts/RootKitDirect.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./TokensRecoverable.sol"; 5 | import "./Owned.sol"; 6 | import "./KETH.sol"; 7 | import "./RootKitTransferGate.sol"; 8 | import "./UniswapV2Library.sol"; 9 | import "./IUniswapV2Factory.sol"; 10 | 11 | contract RootKitDirect is TokensRecoverable 12 | { 13 | KETH immutable keth; 14 | RootKit immutable rootKit; 15 | IUniswapV2Router02 immutable uniswapV2Router; 16 | IUniswapV2Factory immutable uniswapV2Factory; 17 | 18 | constructor(KETH _keth, RootKit _rootKit, IUniswapV2Router02 _uniswapV2Router) 19 | { 20 | keth = _keth; 21 | rootKit = _rootKit; 22 | uniswapV2Router = _uniswapV2Router; 23 | 24 | uniswapV2Factory = IUniswapV2Factory(_uniswapV2Router.factory()); 25 | 26 | _keth.approve(address(_uniswapV2Router), uint256(-1)); 27 | _rootKit.approve(address(_uniswapV2Router), uint256(-1)); 28 | } 29 | 30 | receive() external payable 31 | { 32 | require (msg.sender == address(keth)); 33 | } 34 | 35 | function estimateBuy(uint256 ethAmountIn) public view returns (uint256 rootKitAmount) 36 | { 37 | address[] memory path = new address[](2); 38 | path[0] = address(keth); 39 | path[1] = address(rootKit); 40 | (uint256[] memory amounts) = UniswapV2Library.getAmountsOut(address(uniswapV2Factory), ethAmountIn, path); 41 | return amounts[1]; 42 | } 43 | 44 | function estimateSell(uint256 rootKitAmountIn) public view returns (uint256 ethAmount) 45 | { 46 | address[] memory path = new address[](2); 47 | path[0] = address(rootKit); 48 | path[1] = address(keth); 49 | (uint256[] memory amounts) = UniswapV2Library.getAmountsOut(address(uniswapV2Factory), rootKitAmountIn, path); 50 | return amounts[1]; 51 | } 52 | 53 | function easyBuy() public payable returns (uint256 rootKitAmount) 54 | { 55 | return buy(estimateBuy(msg.value) * 98 / 100); 56 | } 57 | 58 | function easySell(uint256 rootKitAmountIn) public returns (uint256 ethAmount) 59 | { 60 | return sell(rootKitAmountIn, estimateSell(rootKitAmountIn) * 98 / 100); 61 | } 62 | 63 | function buy(uint256 amountOutMin) public payable returns (uint256 rootKitAmount) 64 | { 65 | uint256 amount = msg.value; 66 | require (amount > 0, "Send ETH to buy"); 67 | keth.deposit{ value: amount }(); 68 | address[] memory path = new address[](2); 69 | path[0] = address(keth); 70 | path[1] = address(rootKit); 71 | (uint256[] memory amounts) = uniswapV2Router.swapExactTokensForTokens(amount, amountOutMin, path, msg.sender, block.timestamp); 72 | return amounts[1]; 73 | } 74 | 75 | function sell(uint256 rootKitAmountIn, uint256 amountOutMin) public returns (uint256 ethAmount) 76 | { 77 | require (rootKitAmountIn > 0, "Nothing to sell"); 78 | RootKitTransferGate gate = RootKitTransferGate(address(rootKit.transferGate())); 79 | 80 | // to avoid double taxation 81 | gate.setUnrestricted(true); 82 | rootKit.transferFrom(msg.sender, address(this), rootKitAmountIn); 83 | gate.setUnrestricted(false); 84 | 85 | address[] memory path = new address[](2); 86 | path[0] = address(rootKit); 87 | path[1] = address(keth); 88 | (uint256[] memory amounts) = uniswapV2Router.swapExactTokensForTokens(rootKitAmountIn, amountOutMin, path, address(this), block.timestamp); 89 | keth.withdraw(amounts[1]); 90 | (bool success,) = msg.sender.call{ value: amounts[1] }(""); 91 | require (success, "Transfer failed"); 92 | return amounts[1]; 93 | } 94 | } -------------------------------------------------------------------------------- /contracts/RootKitFloorCalculator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | A floor calculator (to use with ERC31337) for RootKit uniswap pairs 6 | Ensures 100% of accessible funds are backed at all times 7 | */ 8 | 9 | import "./IFloorCalculator.sol"; 10 | import "./RootKit.sol"; 11 | import "./SafeMath.sol"; 12 | import "./UniswapV2Library.sol"; 13 | import "./IUniswapV2Factory.sol"; 14 | import "./TokensRecoverable.sol"; 15 | 16 | contract RootKitFloorCalculator is IFloorCalculator, TokensRecoverable 17 | { 18 | using SafeMath for uint256; 19 | 20 | RootKit immutable rootKit; 21 | IUniswapV2Factory immutable uniswapV2Factory; 22 | 23 | constructor(RootKit _rootKit, IUniswapV2Factory _uniswapV2Factory) 24 | { 25 | rootKit = _rootKit; 26 | uniswapV2Factory = _uniswapV2Factory; 27 | } 28 | 29 | function calculateSubFloor(IERC20 wrappedToken, IERC20 backingToken) public override view returns (uint256) 30 | { 31 | address pair = UniswapV2Library.pairFor(address(uniswapV2Factory), address(rootKit), address(backingToken)); 32 | uint256 freeRootKit = rootKit.totalSupply().sub(rootKit.balanceOf(pair)); 33 | uint256 sellAllProceeds = 0; 34 | if (freeRootKit > 0) { 35 | address[] memory path = new address[](2); 36 | path[0] = address(rootKit); 37 | path[1] = address(backingToken); 38 | uint256[] memory amountsOut = UniswapV2Library.getAmountsOut(address(uniswapV2Factory), freeRootKit, path); 39 | sellAllProceeds = amountsOut[1]; 40 | } 41 | uint256 backingInPool = backingToken.balanceOf(pair); 42 | if (backingInPool <= sellAllProceeds) { return 0; } 43 | uint256 excessInPool = backingInPool - sellAllProceeds; 44 | 45 | uint256 requiredBacking = backingToken.totalSupply().sub(excessInPool); 46 | uint256 currentBacking = wrappedToken.balanceOf(address(backingToken)); 47 | if (requiredBacking >= currentBacking) { return 0; } 48 | return currentBacking - requiredBacking; 49 | } 50 | } -------------------------------------------------------------------------------- /contracts/RootKitLiquidity.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | A wrapper for liquidity tokens so they can be distributed 6 | but not allowing for removal of liquidity 7 | */ 8 | 9 | import "./ERC31337.sol"; 10 | import "./IUniswapV2Pair.sol"; 11 | import "./IERC20.sol"; 12 | 13 | contract RootKitLiquidity is ERC31337 14 | { 15 | constructor(IUniswapV2Pair _pair, string memory _name, string memory _symbol) 16 | ERC31337(IERC20(address(_pair)), _name, _symbol) 17 | { 18 | } 19 | 20 | function _beforeWithdrawTokens(uint256) internal override pure 21 | { 22 | revert("RootKit liquidity is locked"); 23 | } 24 | } -------------------------------------------------------------------------------- /contracts/RootKitLiquidityGeneration.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | import "./RootKit.sol"; 6 | import "./IRootKitDistribution.sol"; 7 | import "./TokensRecoverable.sol"; 8 | 9 | contract RootKitLiquidityGeneration is TokensRecoverable 10 | { 11 | mapping (address => uint256) public contribution; 12 | address[] public contributors; 13 | 14 | bool public isActive; 15 | 16 | RootKit immutable rootKit; 17 | IRootKitDistribution public rootKitDistribution; 18 | uint256 refundsAllowedUntil; 19 | 20 | constructor (RootKit _rootKit) 21 | { 22 | rootKit = _rootKit; 23 | } 24 | 25 | modifier active() 26 | { 27 | require (isActive, "Distribution not active"); 28 | _; 29 | } 30 | 31 | function contributorsCount() public view returns (uint256) { return contributors.length; } 32 | 33 | function activate(IRootKitDistribution _rootKitDistribution) public ownerOnly() 34 | { 35 | require (!isActive && contributors.length == 0 && block.timestamp >= refundsAllowedUntil, "Already activated"); 36 | require (rootKit.balanceOf(address(this)) == rootKit.totalSupply(), "Missing supply"); 37 | require (address(_rootKitDistribution) != address(0)); 38 | rootKitDistribution = _rootKitDistribution; 39 | isActive = true; 40 | } 41 | 42 | function setRootKitDistribution(IRootKitDistribution _rootKitDistribution) public ownerOnly() active() 43 | { 44 | require (address(_rootKitDistribution) != address(0)); 45 | if (_rootKitDistribution == rootKitDistribution) { return; } 46 | rootKitDistribution = _rootKitDistribution; 47 | 48 | // Give everyone 1 day to claim refunds if they don't approve of the new distributor 49 | refundsAllowedUntil = block.timestamp + 86400; 50 | } 51 | 52 | function complete() public ownerOnly() active() 53 | { 54 | require (block.timestamp >= refundsAllowedUntil, "Refund period is still active"); 55 | isActive = false; 56 | if (address(this).balance == 0) { return; } 57 | rootKit.approve(address(rootKitDistribution), uint256(-1)); 58 | rootKitDistribution.distribute{ value: address(this).balance }(); 59 | } 60 | 61 | function allowRefunds() public ownerOnly() active() 62 | { 63 | isActive = false; 64 | refundsAllowedUntil = uint256(-1); 65 | } 66 | 67 | function claim() public 68 | { 69 | uint256 amount = contribution[msg.sender]; 70 | require (amount > 0, "Nothing to claim"); 71 | contribution[msg.sender] = 0; 72 | if (refundsAllowedUntil > block.timestamp) { 73 | (bool success,) = msg.sender.call{ value: amount }(""); 74 | require (success, "Transfer failed"); 75 | } 76 | else { 77 | rootKitDistribution.claim(msg.sender, amount); 78 | } 79 | } 80 | 81 | receive() external payable active() 82 | { 83 | uint256 oldContribution = contribution[msg.sender]; 84 | uint256 newContribution = oldContribution + msg.value; 85 | if (oldContribution == 0 && newContribution > 0) { 86 | contributors.push(msg.sender); 87 | } 88 | contribution[msg.sender] = newContribution; 89 | } 90 | } -------------------------------------------------------------------------------- /contracts/RootKitLiquidityMatching.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./RootKit.sol"; 5 | import "./IUniswapV2Router02.sol"; 6 | import "./IWrappedERC20.sol"; 7 | import "./IERC20.sol"; 8 | import "./IUniswapV2Pair.sol"; 9 | import "./IUniswapV2Factory.sol"; 10 | import "./Owned.sol"; 11 | import "./TokensRecoverable.sol"; 12 | import "./KETH.sol"; 13 | import "./SafeMath.sol"; 14 | import "./IWETH.sol"; 15 | 16 | /* ROOTKIT: 17 | This receives RootKit from whereever 18 | You can add ETH or KETH and we'll match it with RootKit from here for you 19 | Then you get the liquidity tokens back 20 | All in one shot 21 | Ready for staking 22 | Cheaper than buying first! 23 | */ 24 | 25 | contract RootKitLiquidityMatching is TokensRecoverable 26 | { 27 | using SafeMath for uint256; 28 | 29 | RootKit immutable rootKit; 30 | IUniswapV2Router02 immutable uniswapV2Router; 31 | IWrappedERC20 immutable liquidityTokenWrapper; 32 | KETH immutable keth; 33 | IWETH immutable weth; 34 | 35 | uint16 public liquidityPercentForUser = 5000; // 100% = 10000 36 | 37 | constructor(RootKit _rootKit, IUniswapV2Router02 _uniswapV2Router, IWrappedERC20 _liquidityTokenWrapper, KETH _keth) 38 | { 39 | rootKit = _rootKit; 40 | uniswapV2Router = _uniswapV2Router; 41 | liquidityTokenWrapper = _liquidityTokenWrapper; 42 | keth = _keth; 43 | 44 | IWETH _weth = IWETH(_uniswapV2Router.WETH()); 45 | weth = _weth; 46 | 47 | IERC20 _liquidityToken = _liquidityTokenWrapper.wrappedToken(); 48 | _liquidityToken.approve(address(_liquidityTokenWrapper), uint256(-1)); 49 | _rootKit.approve(address(_uniswapV2Router), uint256(-1)); 50 | _keth.approve(address(_uniswapV2Router), uint256(-1)); 51 | _weth.approve(address(_uniswapV2Router), uint256(-1)); 52 | _weth.approve(address(_keth), uint256(-1)); 53 | 54 | require (IUniswapV2Factory(_uniswapV2Router.factory()).getPair(address(_rootKit), address(_keth)) == address(_liquidityToken), "Sanity"); 55 | } 56 | 57 | receive() external payable 58 | { 59 | require (msg.sender == address(keth)); 60 | } 61 | 62 | function setLiquidityPercentForUser(uint16 _liquidityPercentForUser) public ownerOnly() 63 | { 64 | require (_liquidityPercentForUser <= 10000); 65 | 66 | liquidityPercentForUser = _liquidityPercentForUser; 67 | } 68 | 69 | function addLiquidityETH() public payable 70 | { 71 | uint256 amount = msg.value; 72 | require (amount > 0, "Zero amount"); 73 | keth.deposit{ value: amount }(); 74 | 75 | uint256 remainingKeth = addKethToLiquidity(amount); 76 | 77 | if (remainingKeth > 0) { 78 | keth.withdraw(remainingKeth); 79 | (bool success,) = msg.sender.call{ value: remainingKeth }(""); 80 | require (success, "Transfer failed"); 81 | } 82 | } 83 | 84 | function addLiquidityWETH(uint256 amount) public 85 | { 86 | require (amount > 0, "Zero amount"); 87 | weth.transferFrom(msg.sender, address(this), amount); 88 | keth.depositTokens(amount); 89 | 90 | uint256 remainingKeth = addKethToLiquidity(amount); 91 | 92 | if (remainingKeth > 0) { 93 | keth.withdrawTokens(remainingKeth); 94 | weth.transfer(msg.sender, remainingKeth); 95 | } 96 | } 97 | 98 | function addLiquidityKETH(uint256 amount) public 99 | { 100 | require (amount > 0, "Zero amount"); 101 | keth.transferFrom(msg.sender, address(this), amount); 102 | 103 | uint256 remainingKeth = addKethToLiquidity(amount); 104 | 105 | if (remainingKeth > 0) { 106 | keth.transfer(msg.sender, remainingKeth); 107 | } 108 | } 109 | 110 | function addKethToLiquidity(uint256 amount) private returns (uint256 remainingKeth) 111 | { 112 | (,,uint256 liquidity) = uniswapV2Router.addLiquidity(address(rootKit), address(keth), rootKit.balanceOf(address(this)), amount, 0, 0, address(this), block.timestamp); 113 | require (liquidity > 0, "No liquidity created (no available RootKit?)"); 114 | liquidity = liquidity.mul(liquidityPercentForUser) / 10000; 115 | liquidityTokenWrapper.depositTokens(liquidity); 116 | liquidityTokenWrapper.transfer(msg.sender, liquidity); 117 | return keth.balanceOf(address(this)); 118 | } 119 | } -------------------------------------------------------------------------------- /contracts/RootKitRuggableFloorCalculator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | A floor calculator (to use with ERC31337) 6 | This one is for liquidity tokens 7 | So finally 8 | WE CAN PLAY JENGA 9 | */ 10 | 11 | import "./IFloorCalculator.sol"; 12 | import "./TokensRecoverable.sol"; 13 | 14 | contract RootKitRuggableFloorCalculator is IFloorCalculator, TokensRecoverable 15 | { 16 | uint256 subFloor; 17 | 18 | function setSubFloor(uint256 _subFloor) public ownerOnly() 19 | { 20 | subFloor = _subFloor; 21 | } 22 | 23 | function calculateSubFloor(IERC20, IERC20) public override view returns (uint256) 24 | { 25 | return subFloor; 26 | } 27 | } -------------------------------------------------------------------------------- /contracts/RootKitVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | import "./SafeERC20.sol"; 6 | import "./IERC20.sol"; 7 | 8 | contract RootKitVault is Owned 9 | { 10 | using SafeERC20 for IERC20; 11 | 12 | receive() external payable { } 13 | 14 | function sendEther(address payable _to, uint256 _amount) public ownerOnly() 15 | { 16 | (bool success,) = _to.call{ value: _amount }(""); 17 | require (success, "Transfer failed"); 18 | } 19 | 20 | function sendToken(IERC20 _token, address _to, uint256 _amount) public ownerOnly() 21 | { 22 | _token.safeTransfer(_to, _amount); 23 | } 24 | } -------------------------------------------------------------------------------- /contracts/RootWethZapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | import "./IUniswapV2Router02.sol"; 6 | import "./IWETH.sol"; 7 | import "./RootKit.sol"; 8 | import "./RootKitTransferGate.sol"; 9 | import "./TokensRecoverable.sol"; 10 | 11 | contract RootWethZapper is TokensRecoverable 12 | { 13 | function go(IWETH weth, RootKit rootKit, uint256 wethAmount, uint256 rootKitAmount, IUniswapV2Router02 uniswapV2Router) 14 | public ownerOnly() 15 | { 16 | RootKitTransferGate gate = RootKitTransferGate(address(rootKit.transferGate())); 17 | gate.setUnrestricted(true); 18 | weth.transferFrom(msg.sender, address(this), wethAmount); 19 | rootKit.transferFrom(msg.sender, address(this), rootKitAmount); 20 | weth.approve(address(uniswapV2Router), wethAmount); 21 | rootKit.approve(address(uniswapV2Router), rootKitAmount); 22 | uniswapV2Router.addLiquidity(address(weth), address(rootKit), wethAmount, rootKitAmount, wethAmount, rootKitAmount, msg.sender, block.timestamp); 23 | gate.setUnrestricted(false); 24 | } 25 | } -------------------------------------------------------------------------------- /contracts/RootkitTwoPoolCalculator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | A floor calculator (to use with ERC31337) for RootKit uniswap pairs 6 | Ensures 100% of accessible funds are backed at all times 7 | */ 8 | 9 | import "./IFloorCalculator.sol"; 10 | import "./RootKit.sol"; 11 | import "./SafeMath.sol"; 12 | import "./UniswapV2Library.sol"; 13 | import "./IUniswapV2Factory.sol"; 14 | import "./IUniswapV2Router02.sol"; 15 | import "./TokensRecoverable.sol"; 16 | import "./EnumerableSet.sol"; 17 | 18 | contract RootKitTwoPoolCalculator is IFloorCalculator, TokensRecoverable 19 | { 20 | using SafeMath for uint256; 21 | using EnumerableSet for EnumerableSet.AddressSet; 22 | 23 | IERC20 immutable rootKit; 24 | IERC20 immutable keth; 25 | IERC20 immutable weth; 26 | address public immutable wethPair; 27 | address public immutable kethPair; 28 | IUniswapV2Factory immutable uniswapV2Factory; 29 | IUniswapV2Router02 immutable uniswapV2Router; 30 | EnumerableSet.AddressSet ignoredAddresses; 31 | 32 | constructor(IERC20 _rootKit, IERC20 _keth, IERC20 _weth, IUniswapV2Factory _uniswapV2Factory, IUniswapV2Router02 _uniswapV2Router) 33 | { 34 | rootKit = _rootKit; 35 | keth = _keth; 36 | weth = _weth; 37 | uniswapV2Factory = _uniswapV2Factory; 38 | uniswapV2Router = _uniswapV2Router; 39 | 40 | kethPair = _uniswapV2Factory.getPair(address(_keth), address(_rootKit)); 41 | wethPair = _uniswapV2Factory.getPair(address(_weth), address(_rootKit)); 42 | } 43 | 44 | function setIgnoredAddress(address ignoredAddress, bool add) public ownerOnly() 45 | { 46 | if (add) 47 | { 48 | ignoredAddresses.add(ignoredAddress); 49 | } 50 | else 51 | { 52 | ignoredAddresses.remove(ignoredAddress); 53 | } 54 | } 55 | 56 | function isIgnoredAddress(address ignoredAddress) public view returns (bool) 57 | { 58 | return ignoredAddresses.contains(ignoredAddress); 59 | } 60 | 61 | function ignoredAddressCount() public view returns (uint256) 62 | { 63 | return ignoredAddresses.length(); 64 | } 65 | 66 | function ignoredAddressAt(uint256 index) public view returns (address) 67 | { 68 | return ignoredAddresses.at(index); 69 | } 70 | 71 | function ignoredAddressesTotalBalance() public view returns (uint256) 72 | { 73 | uint256 total = 0; 74 | for (uint i = 0; i < ignoredAddresses.length(); i++) { 75 | total = total.add(rootKit.balanceOf(ignoredAddresses.at(i))); 76 | } 77 | 78 | return total; 79 | } 80 | 81 | // returns the amount currently available to be swept 82 | function calculateSubFloor(IERC20 wrappedToken, IERC20 backingToken) public override view returns (uint256) // backing token = keth 83 | { 84 | uint256 totalRootInPairs = rootKit.balanceOf(kethPair).add(rootKit.balanceOf(wethPair)); 85 | uint256 totalBaseAndEliteInPairs = backingToken.balanceOf(kethPair).add(wrappedToken.balanceOf(wethPair)); 86 | uint256 rootKitCirculatingSupply = rootKit.totalSupply().sub(totalRootInPairs).sub(ignoredAddressesTotalBalance()); 87 | 88 | uint256 amountUntilFloor = uniswapV2Router.getAmountOut(rootKitCirculatingSupply, totalRootInPairs, totalBaseAndEliteInPairs) * 100 / 94; //includes burn 89 | uint256 totalExcessInPools = totalBaseAndEliteInPairs.sub(amountUntilFloor); 90 | uint256 previouslySwept = backingToken.totalSupply().sub(wrappedToken.balanceOf(address(backingToken))); 91 | 92 | if (previouslySwept >= totalExcessInPools) { return 0; } 93 | 94 | return totalExcessInPools.sub(previouslySwept); 95 | } 96 | 97 | 98 | function getAbsoluteFloorPrice() public view returns (uint256) 99 | { 100 | uint256 totalRootInPairs = rootKit.balanceOf(kethPair).add(rootKit.balanceOf(wethPair)); 101 | uint256 totalBaseAndEliteInPairs = keth.balanceOf(kethPair).add(weth.balanceOf(wethPair)); 102 | uint256 rootKitCirculatingSupply = rootKit.totalSupply().sub(totalRootInPairs).sub(ignoredAddressesTotalBalance()); 103 | 104 | uint256 amountUntilFloor = uniswapV2Router.getAmountOut(rootKitCirculatingSupply, totalRootInPairs, totalBaseAndEliteInPairs) * 100 / 94; 105 | uint256 totalExcessInPools = totalBaseAndEliteInPairs.sub(amountUntilFloor); 106 | uint256 newTotalRootInPairs = totalRootInPairs + rootKitCirculatingSupply * 100 / 94; 107 | 108 | uint256 priceForOneRootIfZeroHolders = uniswapV2Router.getAmountIn(1e18, totalExcessInPools, newTotalRootInPairs); 109 | 110 | return priceForOneRootIfZeroHolders; 111 | } 112 | } -------------------------------------------------------------------------------- /contracts/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | Modified to remove some junk 6 | Also modified to remove silly restrictions (traps!) within safeApprove 7 | */ 8 | 9 | import "./IERC20.sol"; 10 | import "./SafeMath.sol"; 11 | import "./Address.sol"; 12 | 13 | /** 14 | * @title SafeERC20 15 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 16 | * contract returns false). Tokens that return no value (and instead revert or 17 | * throw on failure) are also supported, non-reverting calls are assumed to be 18 | * successful. 19 | * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, 20 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 21 | */ 22 | library SafeERC20 { 23 | using SafeMath for uint256; 24 | using Address for address; 25 | 26 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 27 | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 28 | } 29 | 30 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 31 | _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 32 | } 33 | 34 | /** 35 | * @dev Deprecated. This function has issues similar to the ones found in 36 | * {IERC20-approve}, and its usage is discouraged. 37 | * 38 | * Whenever possible, use {safeIncreaseAllowance} and 39 | * {safeDecreaseAllowance} instead. 40 | */ 41 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 42 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 43 | } 44 | 45 | /** 46 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 47 | * on the return value: the return value is optional (but if data is returned, it must not be false). 48 | * @param token The token targeted by the call. 49 | * @param data The call data (encoded using abi.encode or one of its variants). 50 | */ 51 | function _callOptionalReturn(IERC20 token, bytes memory data) private { 52 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 53 | // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that 54 | // the target address contains contract code and also asserts for success in the low-level call. 55 | 56 | bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 57 | if (returndata.length > 0) { // Return data is optional 58 | // solhint-disable-next-line max-line-length 59 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /contracts/SafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | O wherefore art thou 8 point O 6 | */ 7 | 8 | library SafeMath 9 | { 10 | function add(uint256 a, uint256 b) internal pure returns (uint256) 11 | { 12 | uint256 c = a + b; 13 | require(c >= a, "SafeMath: addition overflow"); 14 | return c; 15 | } 16 | 17 | function sub(uint256 a, uint256 b) internal pure returns (uint256) 18 | { 19 | return sub(a, b, "SafeMath: subtraction overflow"); 20 | } 21 | 22 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) 23 | { 24 | require(b <= a, errorMessage); 25 | uint256 c = a - b; 26 | return c; 27 | } 28 | 29 | function mul(uint256 a, uint256 b) internal pure returns (uint256) 30 | { 31 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 32 | // benefit is lost if 'b' is also tested. 33 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 34 | if (a == 0) 35 | { 36 | return 0; 37 | } 38 | 39 | uint256 c = a * b; 40 | require(c / a == b, "SafeMath: multiplication overflow"); 41 | return c; 42 | } 43 | 44 | function div(uint256 a, uint256 b) internal pure returns (uint256) 45 | { 46 | return div(a, b, "SafeMath: division by zero"); 47 | } 48 | 49 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) 50 | { 51 | require(b > 0, errorMessage); 52 | uint256 c = a / b; 53 | return c; 54 | } 55 | 56 | function mod(uint256 a, uint256 b) internal pure returns (uint256) 57 | { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | 61 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) 62 | { 63 | require(b != 0, errorMessage); 64 | return a % b; 65 | } 66 | } -------------------------------------------------------------------------------- /contracts/SingleSideLiquidityAdder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./TokensRecoverable.sol"; 5 | import "./RootKitTransferGate.sol"; 6 | 7 | // Contract to add 1 sided liquidty after buys via 8 | // selling and setting the "to" address as the pool 9 | 10 | contract SingleSideLiquidityAdder is TokensRecoverable { 11 | address public bot; 12 | IUniswapV2Router02 public immutable uniswapRouter; 13 | RootKitTransferGate immutable private gate; 14 | IERC20 immutable private rooted; 15 | address immutable private base; 16 | address immutable private pool; 17 | 18 | constructor (address _base, IERC20 _rooted, address _pool, RootKitTransferGate _gate, IUniswapV2Router02 _uniswapRouter) { 19 | base = _base; 20 | rooted = _rooted; 21 | pool = _pool; 22 | gate = _gate; 23 | uniswapRouter = _uniswapRouter; 24 | _rooted.approve(address(_uniswapRouter), uint(-1)); 25 | } 26 | 27 | function setBot(address _bot) public ownerOnly() { 28 | bot = _bot; 29 | } 30 | 31 | function addSingleSideLiquidity(uint256 amount, uint256 minAmountOut) public { 32 | require(msg.sender == bot, "Bot only"); 33 | require(rooted.balanceOf(address(this)) >= amount, "Not enough upToken Balance"); 34 | 35 | gate.setUnrestricted(true); 36 | 37 | address[] memory path = new address[](2); 38 | path[0] = address(rooted); 39 | path[1] = base; 40 | uniswapRouter.swapExactTokensForTokens(amount, minAmountOut, path, pool, block.timestamp); 41 | 42 | gate.setUnrestricted(false); 43 | } 44 | } -------------------------------------------------------------------------------- /contracts/Stoneface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | pragma experimental ABIEncoderV2; 4 | 5 | /* ROOTKIT: 6 | Stoneface will protect you 7 | Stoneface will hold stuff 8 | Like KETH 9 | But it doesn't know anything 10 | So it can't call setFloorCalculator 11 | Or setSweeper 12 | Or anything, really 13 | It's pretty stupid 14 | But it'll give stuff back if we want 15 | And if we're patient enough 16 | Cus it takes a while 17 | Unless we tell it to watch the distribution 18 | Then he wont give it back at all 19 | Unless the distribution is complete 20 | Stoneface is slow 21 | */ 22 | 23 | import "./Owned.sol"; 24 | import "./TokensRecoverable.sol"; 25 | import "./IStoneface.sol"; 26 | import "./IRootKitDistribution.sol"; 27 | 28 | contract Stoneface is TokensRecoverable, IStoneface 29 | { 30 | uint256 public immutable override delay; 31 | 32 | IRootKitDistribution public override rootKitDistribution; 33 | 34 | TransferOwnership[] _pendingTransferOwnership; 35 | function pendingTransferOwnership(uint256 index) public override view returns (TransferOwnership memory) { return _pendingTransferOwnership[index]; } 36 | function pendingTransferOwnershipCount() public override view returns (uint256) { return _pendingTransferOwnership.length; } 37 | 38 | constructor(uint256 _delay) 39 | { 40 | delay = _delay; 41 | } 42 | 43 | function watchDistribution(IRootKitDistribution _rootKitDistribution) public override ownerOnly() 44 | { 45 | require (address(rootKitDistribution) == address(0), "Can only be set once"); 46 | rootKitDistribution = _rootKitDistribution; 47 | } 48 | 49 | function callTransferOwnership(IOwned target, address newOwner) public override ownerOnly() 50 | { 51 | TransferOwnership memory pending; 52 | pending.target = target; 53 | pending.newOwner = newOwner; 54 | pending.when = block.timestamp + delay; 55 | _pendingTransferOwnership.push(pending); 56 | emit PendingOwnershipTransfer(target, newOwner, pending.when); 57 | } 58 | 59 | function callTransferOwnershipNow(uint256 index) public override ownerOnly() 60 | { 61 | require (_pendingTransferOwnership[index].when <= block.timestamp, "Too early"); 62 | require (address(rootKitDistribution) == address(0) || rootKitDistribution.distributionComplete(), "Distribution not yet complete"); 63 | _pendingTransferOwnership[index].target.transferOwnership(_pendingTransferOwnership[index].newOwner); 64 | _pendingTransferOwnership[index] = _pendingTransferOwnership[_pendingTransferOwnership.length - 1]; 65 | _pendingTransferOwnership.pop(); 66 | } 67 | 68 | function callClaimOwnership(IOwned target) public override ownerOnly() 69 | { 70 | target.claimOwnership(); 71 | } 72 | } -------------------------------------------------------------------------------- /contracts/TokensRecoverable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | Allows recovery of unexpected tokens (airdrops, etc) 6 | Inheriters can customize logic by overriding canRecoverTokens 7 | */ 8 | 9 | import "./IERC20.sol"; 10 | import "./SafeERC20.sol"; 11 | import "./Owned.sol"; 12 | import "./ITokensRecoverable.sol"; 13 | 14 | abstract contract TokensRecoverable is Owned, ITokensRecoverable 15 | { 16 | using SafeERC20 for IERC20; 17 | 18 | function recoverTokens(IERC20 token) public override ownerOnly() 19 | { 20 | require (canRecoverTokens(token)); 21 | token.safeTransfer(msg.sender, token.balanceOf(address(this))); 22 | } 23 | 24 | function canRecoverTokens(IERC20 token) internal virtual view returns (bool) 25 | { 26 | return address(token) != address(this); 27 | } 28 | } -------------------------------------------------------------------------------- /contracts/UniswapV2Library.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IUniswapV2Pair.sol"; 5 | import "./SafeMath.sol"; 6 | 7 | library UniswapV2Library { 8 | using SafeMath for uint; 9 | 10 | // returns sorted token addresses, used to handle return values from pairs sorted in this order 11 | function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { 12 | require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); 13 | (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 14 | require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); 15 | } 16 | 17 | // calculates the CREATE2 address for a pair without making any external calls 18 | function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { 19 | (address token0, address token1) = sortTokens(tokenA, tokenB); 20 | pair = address(uint(keccak256(abi.encodePacked( 21 | hex'ff', 22 | factory, 23 | keccak256(abi.encodePacked(token0, token1)), 24 | hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash 25 | )))); 26 | } 27 | 28 | // fetches and sorts the reserves for a pair 29 | function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { 30 | (address token0,) = sortTokens(tokenA, tokenB); 31 | (uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); 32 | (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); 33 | } 34 | 35 | // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 36 | function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { 37 | require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); 38 | require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 39 | amountB = amountA.mul(reserveB) / reserveA; 40 | } 41 | 42 | // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 43 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { 44 | require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); 45 | require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 46 | uint amountInWithFee = amountIn.mul(997); 47 | uint numerator = amountInWithFee.mul(reserveOut); 48 | uint denominator = reserveIn.mul(1000).add(amountInWithFee); 49 | amountOut = numerator / denominator; 50 | } 51 | 52 | // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 53 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { 54 | require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT'); 55 | require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 56 | uint numerator = reserveIn.mul(amountOut).mul(1000); 57 | uint denominator = reserveOut.sub(amountOut).mul(997); 58 | amountIn = (numerator / denominator).add(1); 59 | } 60 | 61 | // performs chained getAmountOut calculations on any number of pairs 62 | function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { 63 | require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); 64 | amounts = new uint[](path.length); 65 | amounts[0] = amountIn; 66 | for (uint i; i < path.length - 1; i++) { 67 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); 68 | amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 69 | } 70 | } 71 | 72 | // performs chained getAmountIn calculations on any number of pairs 73 | function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { 74 | require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); 75 | amounts = new uint[](path.length); 76 | amounts[amounts.length - 1] = amountOut; 77 | for (uint i = path.length - 1; i > 0; i--) { 78 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); 79 | amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /contracts/WETH9.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./IWETH.sol"; 5 | 6 | contract WETH9 is IWETH 7 | { 8 | string public override name = "Wrapped Ether"; 9 | string public override symbol = "WETH"; 10 | uint8 public override decimals = 18; 11 | 12 | mapping (address => uint) public override balanceOf; 13 | mapping (address => mapping (address => uint)) public override allowance; 14 | 15 | receive() external payable { 16 | deposit(); 17 | } 18 | function deposit() public payable override { 19 | balanceOf[msg.sender] += msg.value; 20 | emit Deposit(msg.sender, msg.value); 21 | } 22 | function withdraw(uint wad) public override { 23 | require(balanceOf[msg.sender] >= wad, "weth a: not enough balance"); 24 | balanceOf[msg.sender] -= wad; 25 | msg.sender.transfer(wad); 26 | emit Withdrawal(msg.sender, wad); 27 | } 28 | 29 | function totalSupply() public override view returns (uint) { 30 | return address(this).balance; 31 | } 32 | 33 | function approve(address guy, uint wad) public override returns (bool) { 34 | allowance[msg.sender][guy] = wad; 35 | emit Approval(msg.sender, guy, wad); 36 | return true; 37 | } 38 | 39 | function transfer(address dst, uint wad) public override returns (bool) { 40 | return transferFrom(msg.sender, dst, wad); 41 | } 42 | 43 | function transferFrom(address src, address dst, uint wad) 44 | public 45 | override 46 | returns (bool) 47 | { 48 | require(balanceOf[src] >= wad, "weth b: not enough balance"); 49 | 50 | if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { 51 | require(allowance[src][msg.sender] >= wad, "weth c: not enough allowance"); 52 | allowance[src][msg.sender] -= wad; 53 | } 54 | 55 | balanceOf[src] -= wad; 56 | balanceOf[dst] += wad; 57 | 58 | emit Transfer(src, dst, wad); 59 | 60 | return true; 61 | } 62 | } -------------------------------------------------------------------------------- /contracts/WbtcToWethLiquidityZapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | import "./TokensRecoverable.sol"; 6 | import "./RootKit.sol"; 7 | import "./IERC31337.sol"; 8 | import "./IUniswapV2Router02.sol"; 9 | import "./IWETH.sol"; 10 | import "./IUniswapV2Pair.sol"; 11 | import "./IERC20.sol"; 12 | import "./RootKitTransferGate.sol"; 13 | 14 | import "./UniswapV2Library.sol"; 15 | 16 | contract WbtcToWethLiquidityZapper is TokensRecoverable 17 | { 18 | IUniswapV2Router02 immutable uniswapV2Router; 19 | IERC31337 immutable wrappedWbtcRootKit; 20 | IUniswapV2Pair wbtcRootKit; 21 | IUniswapV2Pair wethRootKit; 22 | RootKit immutable rootKit; 23 | IWETH immutable weth; 24 | IERC20 immutable wbtc; 25 | 26 | constructor(IUniswapV2Router02 _uniswapV2Router, IERC31337 _wrappedWbtcRootKit, RootKit _rootKit) 27 | { 28 | uniswapV2Router = _uniswapV2Router; 29 | wrappedWbtcRootKit = _wrappedWbtcRootKit; 30 | rootKit = _rootKit; 31 | 32 | IUniswapV2Pair _wbtcRootKit = IUniswapV2Pair(address(_wrappedWbtcRootKit.wrappedToken())); 33 | wbtcRootKit = _wbtcRootKit; 34 | 35 | IWETH _weth = IWETH(_uniswapV2Router.WETH()); 36 | weth = _weth; 37 | 38 | IERC20 _wbtc = IERC20(_wbtcRootKit.token0() == address(_rootKit) ? _wbtcRootKit.token1() : _wbtcRootKit.token0()); 39 | wbtc = _wbtc; 40 | 41 | wethRootKit = IUniswapV2Pair(IUniswapV2Factory(_uniswapV2Router.factory()).getPair(address(_weth), address(_rootKit))); 42 | 43 | _wbtcRootKit.approve(address(_uniswapV2Router), uint256(-1)); 44 | _wbtc.approve(address(_uniswapV2Router), uint256(-1)); 45 | _weth.approve(address(_uniswapV2Router), uint256(-1)); 46 | _rootKit.approve(address(_uniswapV2Router), uint256(-1)); 47 | 48 | require (_wbtcRootKit.token0() == address(_rootKit) || _wbtcRootKit.token1() == address(_rootKit), "Sanity"); 49 | require (_wbtcRootKit.token0() != address(_weth) && _wbtcRootKit.token1() != address(_weth), "Sanity"); 50 | } 51 | 52 | function go() public ownerOnly() 53 | { 54 | wrappedWbtcRootKit.sweepFloor(address(this)); 55 | uint256 liquidity = wbtcRootKit.balanceOf(address(this)); 56 | require (liquidity > 0, "Nothing unwrapped"); 57 | RootKitTransferGate gate = RootKitTransferGate(address(rootKit.transferGate())); 58 | gate.setUnrestricted(true); 59 | (uint256 amountRootKit, uint256 amountWbtc) = uniswapV2Router.removeLiquidity(address(rootKit), address(wbtc), liquidity, 0, 0, address(this), block.timestamp); 60 | address[] memory path = new address[](2); 61 | path[0] = address(wbtc); 62 | path[1] = address(weth); 63 | (uint256[] memory amounts) = uniswapV2Router.swapExactTokensForTokens(amountWbtc, 0, path, address(this), block.timestamp); 64 | (,,liquidity) = uniswapV2Router.addLiquidity(address(rootKit), address(weth), amountRootKit, amounts[1], 0, 0, address(this), block.timestamp); 65 | require (liquidity > 0, "Nothing wrapped"); 66 | wethRootKit.transfer(msg.sender, liquidity); 67 | uint256 balance = weth.balanceOf(address(this)); 68 | if (balance > 0) { weth.transfer(msg.sender, balance ); } 69 | balance = wbtc.balanceOf(address(this)); 70 | if (balance > 0) { wbtc.transfer(msg.sender, balance ); } 71 | balance = rootKit.balanceOf(address(this)); 72 | if (balance > 0) { rootKit.transfer(msg.sender, balance ); } 73 | gate.setUnrestricted(false); 74 | } 75 | } -------------------------------------------------------------------------------- /contracts/WethToKethLiquidityZapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "./Owned.sol"; 5 | import "./TokensRecoverable.sol"; 6 | import "./RootKit.sol"; 7 | import "./IERC31337.sol"; 8 | import "./IUniswapV2Router02.sol"; 9 | import "./IWETH.sol"; 10 | import "./IUniswapV2Pair.sol"; 11 | import "./IERC20.sol"; 12 | import "./RootKitTransferGate.sol"; 13 | import "./UniswapV2Library.sol"; 14 | import "./KETH.sol"; 15 | 16 | contract WethToKethLiquidityZapper is TokensRecoverable 17 | { 18 | IUniswapV2Router02 immutable uniswapV2Router; 19 | IERC31337 immutable wrappedWethRootKit; 20 | IUniswapV2Pair kethRootKit; 21 | IUniswapV2Pair wethRootKit; 22 | RootKit immutable rootKit; 23 | IWETH immutable weth; 24 | KETH immutable keth; 25 | 26 | constructor(IUniswapV2Router02 _uniswapV2Router, IERC31337 _wrappedWethRootKit, KETH _keth, RootKit _rootKit) 27 | { 28 | uniswapV2Router = _uniswapV2Router; 29 | wrappedWethRootKit = _wrappedWethRootKit; 30 | keth = _keth; 31 | rootKit = _rootKit; 32 | 33 | IUniswapV2Pair _wethRootKit = IUniswapV2Pair(address(_wrappedWethRootKit.wrappedToken())); 34 | wethRootKit = _wethRootKit; 35 | 36 | IWETH _weth = IWETH(_uniswapV2Router.WETH()); 37 | weth = _weth; 38 | 39 | kethRootKit = IUniswapV2Pair(IUniswapV2Factory(_uniswapV2Router.factory()).getPair(address(_keth), address(_rootKit))); 40 | 41 | _wethRootKit.approve(address(_uniswapV2Router), uint256(-1)); 42 | _keth.approve(address(_uniswapV2Router), uint256(-1)); 43 | _weth.approve(address(_keth), uint256(-1)); 44 | _weth.approve(address(_uniswapV2Router), uint256(-1)); 45 | _rootKit.approve(address(_uniswapV2Router), uint256(-1)); 46 | 47 | require (_wethRootKit.token0() == address(_rootKit) || _wethRootKit.token1() == address(_rootKit), "Sanity"); 48 | require (_wethRootKit.token0() == address(_weth) || _wethRootKit.token1() == address(_weth), "Sanity"); 49 | } 50 | 51 | function WethToKeth() public ownerOnly() 52 | { 53 | wrappedWethRootKit.sweepFloor(address(this)); 54 | uint256 liquidity = wethRootKit.balanceOf(address(this)); 55 | require (liquidity > 0, "Nothing unwrapped"); 56 | RootKitTransferGate gate = RootKitTransferGate(address(rootKit.transferGate())); 57 | gate.setUnrestricted(true); 58 | (uint256 amountRootKit, uint256 amountWeth) = uniswapV2Router.removeLiquidity(address(rootKit), address(weth), liquidity, 0, 0, address(this), block.timestamp); 59 | keth.depositTokens(amountWeth); 60 | (,,liquidity) = uniswapV2Router.addLiquidity(address(rootKit), address(keth), amountRootKit, amountWeth, 0, 0, address(this), block.timestamp); 61 | require (liquidity > 0, "Nothing wrapped"); 62 | kethRootKit.transfer(msg.sender, liquidity); 63 | uint256 balance = weth.balanceOf(address(this)); 64 | if (balance > 0) { weth.transfer(msg.sender, balance ); } 65 | balance = keth.balanceOf(address(this)); 66 | if (balance > 0) { keth.transfer(msg.sender, balance ); } 67 | balance = rootKit.balanceOf(address(this)); 68 | if (balance > 0) { rootKit.transfer(msg.sender, balance ); } 69 | gate.setUnrestricted(false); 70 | } 71 | } -------------------------------------------------------------------------------- /contracts/WrappedERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | /* ROOTKIT: 5 | Wraps any ERC20 6 | Similar to WETH except for ERC20 tokens instead of ETH 7 | depositTokens/withdrawTokens are like deposit/withdraw in WETH 8 | Inheriters can hook into depositTokens and withdrawTokens 9 | by overriding _beforeDepositTokens and _beforeWithdrawTokens 10 | */ 11 | 12 | import "./IERC20.sol"; 13 | import "./ERC20.sol"; 14 | import "./IWrappedERC20.sol"; 15 | import "./TokensRecoverable.sol"; 16 | import "./SafeERC20.sol"; 17 | import "./SafeMath.sol"; 18 | 19 | contract WrappedERC20 is ERC20, IWrappedERC20, TokensRecoverable 20 | { 21 | using SafeERC20 for IERC20; 22 | using SafeMath for uint256; 23 | 24 | IERC20 public immutable override wrappedToken; 25 | 26 | constructor (IERC20 _wrappedToken, string memory _name, string memory _symbol) 27 | ERC20(_name, _symbol) 28 | { 29 | if (_wrappedToken.decimals() != 18) { 30 | _setupDecimals(_wrappedToken.decimals()); 31 | } 32 | wrappedToken = _wrappedToken; 33 | } 34 | 35 | function depositTokens(uint256 _amount) public override 36 | { 37 | _beforeDepositTokens(_amount); 38 | uint256 myBalance = wrappedToken.balanceOf(address(this)); 39 | wrappedToken.safeTransferFrom(msg.sender, address(this), _amount); 40 | uint256 received = wrappedToken.balanceOf(address(this)).sub(myBalance); 41 | _mint(msg.sender, received); 42 | emit Deposit(msg.sender, _amount); 43 | } 44 | 45 | function withdrawTokens(uint256 _amount) public override 46 | { 47 | _beforeWithdrawTokens(_amount); 48 | _burn(msg.sender, _amount); 49 | uint256 myBalance = wrappedToken.balanceOf(address(this)); 50 | wrappedToken.safeTransfer(msg.sender, _amount); 51 | require (wrappedToken.balanceOf(address(this)) == myBalance.sub(_amount), "Transfer not exact"); 52 | emit Withdrawal(msg.sender, _amount); 53 | } 54 | 55 | function canRecoverTokens(IERC20 token) internal virtual override view returns (bool) 56 | { 57 | return token != this && token != wrappedToken; 58 | } 59 | 60 | function _beforeDepositTokens(uint256 _amount) internal virtual view { } 61 | function _beforeWithdrawTokens(uint256 _amount) internal virtual view { } 62 | } -------------------------------------------------------------------------------- /contracts/json/UniswapV2Library.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [], 3 | "evm": { 4 | "bytecode": { 5 | "linkReferences": {}, 6 | "object": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122002d585132f8f3cd6197b79c2909d7f0c7c3324b181da08b820cbd9778395385a64736f6c63430006060033", 7 | "opcodes": "PUSH1 0x56 PUSH1 0x23 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH1 0x0 BYTE PUSH1 0x73 EQ PUSH1 0x16 JUMPI INVALID JUMPDEST ADDRESS PUSH1 0x0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 MUL 0xD5 DUP6 SGT 0x2F DUP16 EXTCODECOPY 0xD6 NOT PUSH28 0x79C2909D7F0C7C3324B181DA08B820CBD9778395385A64736F6C6343 STOP MOD MOD STOP CALLER ", 8 | "sourceMap": "120:4333:21:-:0;;132:2:-1;166:7;155:9;146:7;137:37;255:7;249:14;246:1;241:23;235:4;232:33;222:2;;269:9;222:2;293:9;290:1;283:20;323:4;314:7;306:22;347:7;338;331:24" 9 | }, 10 | "deployedBytecode": { 11 | "immutableReferences": {}, 12 | "linkReferences": {}, 13 | "object": "73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122002d585132f8f3cd6197b79c2909d7f0c7c3324b181da08b820cbd9778395385a64736f6c63430006060033", 14 | "opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 MUL 0xD5 DUP6 SGT 0x2F DUP16 EXTCODECOPY 0xD6 NOT PUSH28 0x79C2909D7F0C7C3324B181DA08B820CBD9778395385A64736F6C6343 STOP MOD MOD STOP CALLER ", 15 | "sourceMap": "120:4333:21:-:0;;;;;;12:1:-1;9;2:12" 16 | } 17 | }, 18 | "interface": [], 19 | "bytecode": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122002d585132f8f3cd6197b79c2909d7f0c7c3324b181da08b820cbd9778395385a64736f6c63430006060033" 20 | } -------------------------------------------------------------------------------- /contracts/json/UniswapV2OracleLibrary.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [], 3 | "evm": { 4 | "bytecode": { 5 | "linkReferences": {}, 6 | "object": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212205db364475eacba5c9e980efad00907bab321721a9511692deb58a12dbf020f5364736f6c63430006060033", 7 | "opcodes": "PUSH1 0x56 PUSH1 0x23 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH1 0x0 BYTE PUSH1 0x73 EQ PUSH1 0x16 JUMPI INVALID JUMPDEST ADDRESS PUSH1 0x0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0x5D 0xB3 PUSH5 0x475EACBA5C SWAP15 SWAP9 0xE STATICCALL 0xD0 MULMOD SMOD 0xBA 0xB3 0x21 PUSH19 0x1A9511692DEB58A12DBF020F5364736F6C6343 STOP MOD MOD STOP CALLER ", 8 | "sourceMap": "244:1444:22:-:0;;132:2:-1;166:7;155:9;146:7;137:37;255:7;249:14;246:1;241:23;235:4;232:33;222:2;;269:9;222:2;293:9;290:1;283:20;323:4;314:7;306:22;347:7;338;331:24" 9 | }, 10 | "deployedBytecode": { 11 | "immutableReferences": {}, 12 | "linkReferences": {}, 13 | "object": "73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212205db364475eacba5c9e980efad00907bab321721a9511692deb58a12dbf020f5364736f6c63430006060033", 14 | "opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0x5D 0xB3 PUSH5 0x475EACBA5C SWAP15 SWAP9 0xE STATICCALL 0xD0 MULMOD SMOD 0xBA 0xB3 0x21 PUSH19 0x1A9511692DEB58A12DBF020F5364736F6C6343 STOP MOD MOD STOP CALLER ", 15 | "sourceMap": "244:1444:22:-:0;;;;;;12:1:-1;9;2:12" 16 | } 17 | }, 18 | "interface": [], 19 | "bytecode": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212205db364475eacba5c9e980efad00907bab321721a9511692deb58a12dbf020f5364736f6c63430006060033" 20 | } -------------------------------------------------------------------------------- /contracts/test/ERC20Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "../ERC20.sol"; 5 | 6 | contract ERC20Test is ERC20("Test", "TST") 7 | { 8 | constructor() 9 | { 10 | _mint(msg.sender, 100 ether); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/test/GatedERC20Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "../GatedERC20.sol"; 5 | 6 | contract GatedERC20Test is GatedERC20("Test", "TST") 7 | { 8 | constructor() 9 | { 10 | _mint(msg.sender, 100 ether); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/test/LiquidityLockedERC20Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "../LiquidityLockedERC20.sol"; 5 | 6 | contract LiquidityLockedERC20Test is LiquidityLockedERC20("test", "TEST") 7 | { 8 | constructor() 9 | { 10 | _mint(msg.sender, 100 ether); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/test/OwnedTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "../Owned.sol"; 5 | 6 | contract OwnedTest is Owned { } -------------------------------------------------------------------------------- /contracts/test/RootKitDistributionTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "../IRootKitDistribution.sol"; 5 | import "../RootKit.sol"; 6 | 7 | contract RootKitDistributionTest is IRootKitDistribution 8 | { 9 | RootKit immutable rootKit; 10 | mapping (address => uint256) public claimCallAmount; 11 | bool public override distributionComplete; 12 | 13 | constructor(RootKit _rootKit) 14 | { 15 | rootKit = _rootKit; 16 | } 17 | 18 | function distribute() public override payable 19 | { 20 | require (!distributionComplete, "Already complete"); 21 | rootKit.transferFrom(msg.sender, address(this), rootKit.totalSupply()); 22 | distributionComplete = true; 23 | } 24 | 25 | function claim(address _to, uint256 _amount) public override 26 | { 27 | require (distributionComplete, "Not complete"); 28 | claimCallAmount[_to] = _amount; 29 | } 30 | } -------------------------------------------------------------------------------- /contracts/test/TokensRecoverableTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | 4 | import "../TokensRecoverable.sol"; 5 | 6 | contract TokensRecoverableTest is TokensRecoverable 7 | { 8 | bool canRecover; 9 | 10 | function setCanRecover(bool can) public 11 | { 12 | canRecover = can; 13 | } 14 | 15 | function canRecoverTokens(IERC20) internal override view returns (bool) { 16 | return canRecover; 17 | } 18 | } -------------------------------------------------------------------------------- /contracts/test/TransferGateTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: J-J-J-JENGA!!! 2 | pragma solidity ^0.7.4; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "../ITransferGate.sol"; 6 | 7 | contract TransferGateTest is ITransferGate 8 | { 9 | address sendAddr1; 10 | address sendAddr2; 11 | uint256 burnAmount; 12 | uint256 addr1Amount; 13 | uint256 addr2Amount; 14 | 15 | function setParams(uint256 _burnAmount, address _addr1, uint256 _addr1Amount, address _addr2, uint256 _addr2Amount) public 16 | { 17 | sendAddr1 = _addr1; 18 | sendAddr2 = _addr2; 19 | burnAmount = _burnAmount; 20 | addr1Amount = _addr1Amount; 21 | addr2Amount = _addr2Amount; 22 | } 23 | 24 | function handleTransfer(address, address, address, uint256) external override view 25 | returns (uint256 burn, TransferGateTarget[] memory targets) 26 | { 27 | burn = burnAmount; 28 | 29 | uint8 count = (addr1Amount > 0 ? 1 : 0) + (addr2Amount > 0 ? 1 : 0); 30 | targets = new TransferGateTarget[](count); 31 | 32 | if (addr1Amount > 0) { 33 | targets[--count].destination = sendAddr1; 34 | targets[count].amount = addr1Amount; 35 | } 36 | if (addr2Amount > 0) { 37 | targets[--count].destination = sendAddr2; 38 | targets[count].amount = addr2Amount; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /data/abi/DevSplitter.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address[]", 6 | "name": "payees", 7 | "type": "address[]" 8 | }, 9 | { 10 | "internalType": "uint256[]", 11 | "name": "shares", 12 | "type": "uint256[]" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "inputs": [ 20 | { 21 | "internalType": "contract IERC20", 22 | "name": "token", 23 | "type": "address" 24 | }, 25 | { 26 | "internalType": "address", 27 | "name": "payee", 28 | "type": "address" 29 | } 30 | ], 31 | "name": "owed", 32 | "outputs": [ 33 | { 34 | "internalType": "uint256", 35 | "name": "", 36 | "type": "uint256" 37 | } 38 | ], 39 | "stateMutability": "view", 40 | "type": "function" 41 | }, 42 | { 43 | "inputs": [ 44 | { 45 | "internalType": "contract IERC20", 46 | "name": "token", 47 | "type": "address" 48 | }, 49 | { 50 | "internalType": "address payable", 51 | "name": "payee", 52 | "type": "address" 53 | } 54 | ], 55 | "name": "pay", 56 | "outputs": [], 57 | "stateMutability": "nonpayable", 58 | "type": "function" 59 | }, 60 | { 61 | "inputs": [ 62 | { 63 | "internalType": "address", 64 | "name": "", 65 | "type": "address" 66 | } 67 | ], 68 | "name": "share", 69 | "outputs": [ 70 | { 71 | "internalType": "uint256", 72 | "name": "", 73 | "type": "uint256" 74 | } 75 | ], 76 | "stateMutability": "view", 77 | "type": "function" 78 | }, 79 | { 80 | "inputs": [ 81 | { 82 | "internalType": "contract IERC20", 83 | "name": "", 84 | "type": "address" 85 | } 86 | ], 87 | "name": "totalPaid", 88 | "outputs": [ 89 | { 90 | "internalType": "uint256", 91 | "name": "", 92 | "type": "uint256" 93 | } 94 | ], 95 | "stateMutability": "view", 96 | "type": "function" 97 | }, 98 | { 99 | "inputs": [ 100 | { 101 | "internalType": "contract IERC20", 102 | "name": "", 103 | "type": "address" 104 | }, 105 | { 106 | "internalType": "address", 107 | "name": "", 108 | "type": "address" 109 | } 110 | ], 111 | "name": "totalPaidToPayee", 112 | "outputs": [ 113 | { 114 | "internalType": "uint256", 115 | "name": "", 116 | "type": "uint256" 117 | } 118 | ], 119 | "stateMutability": "view", 120 | "type": "function" 121 | }, 122 | { 123 | "inputs": [], 124 | "name": "totalShares", 125 | "outputs": [ 126 | { 127 | "internalType": "uint256", 128 | "name": "", 129 | "type": "uint256" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "stateMutability": "payable", 137 | "type": "receive" 138 | } 139 | ] 140 | -------------------------------------------------------------------------------- /data/abi/GrootGrower.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract GrootKit", 6 | "name": "_grootKit", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract IERC20", 11 | "name": "_otherToken", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "contract IUniswapV2Router02", 16 | "name": "_uniswapV2Router", 17 | "type": "address" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "anonymous": false, 25 | "inputs": [ 26 | { 27 | "indexed": true, 28 | "internalType": "address", 29 | "name": "previousOwner", 30 | "type": "address" 31 | }, 32 | { 33 | "indexed": true, 34 | "internalType": "address", 35 | "name": "newOwner", 36 | "type": "address" 37 | } 38 | ], 39 | "name": "OwnershipTransferred", 40 | "type": "event" 41 | }, 42 | { 43 | "inputs": [], 44 | "name": "claimOwnership", 45 | "outputs": [], 46 | "stateMutability": "nonpayable", 47 | "type": "function" 48 | }, 49 | { 50 | "inputs": [], 51 | "name": "grow", 52 | "outputs": [], 53 | "stateMutability": "nonpayable", 54 | "type": "function" 55 | }, 56 | { 57 | "inputs": [], 58 | "name": "owner", 59 | "outputs": [ 60 | { 61 | "internalType": "address", 62 | "name": "", 63 | "type": "address" 64 | } 65 | ], 66 | "stateMutability": "view", 67 | "type": "function" 68 | }, 69 | { 70 | "inputs": [], 71 | "name": "parameters", 72 | "outputs": [ 73 | { 74 | "internalType": "uint32", 75 | "name": "nextGrowTimestamp", 76 | "type": "uint32" 77 | }, 78 | { 79 | "internalType": "uint32", 80 | "name": "growInterval", 81 | "type": "uint32" 82 | }, 83 | { 84 | "internalType": "uint16", 85 | "name": "redeemPercent", 86 | "type": "uint16" 87 | }, 88 | { 89 | "internalType": "uint16", 90 | "name": "buyPercent", 91 | "type": "uint16" 92 | } 93 | ], 94 | "stateMutability": "view", 95 | "type": "function" 96 | }, 97 | { 98 | "inputs": [], 99 | "name": "pricePerGroot", 100 | "outputs": [ 101 | { 102 | "internalType": "uint256", 103 | "name": "", 104 | "type": "uint256" 105 | } 106 | ], 107 | "stateMutability": "view", 108 | "type": "function" 109 | }, 110 | { 111 | "inputs": [ 112 | { 113 | "internalType": "contract IERC20", 114 | "name": "token", 115 | "type": "address" 116 | } 117 | ], 118 | "name": "recoverTokens", 119 | "outputs": [], 120 | "stateMutability": "nonpayable", 121 | "type": "function" 122 | }, 123 | { 124 | "inputs": [ 125 | { 126 | "internalType": "uint32", 127 | "name": "_growInterval", 128 | "type": "uint32" 129 | }, 130 | { 131 | "internalType": "uint16", 132 | "name": "_redeemPercent", 133 | "type": "uint16" 134 | }, 135 | { 136 | "internalType": "uint16", 137 | "name": "_buyPercent", 138 | "type": "uint16" 139 | } 140 | ], 141 | "name": "setParameters", 142 | "outputs": [], 143 | "stateMutability": "nonpayable", 144 | "type": "function" 145 | }, 146 | { 147 | "inputs": [ 148 | { 149 | "internalType": "address", 150 | "name": "newOwner", 151 | "type": "address" 152 | } 153 | ], 154 | "name": "transferOwnership", 155 | "outputs": [], 156 | "stateMutability": "nonpayable", 157 | "type": "function" 158 | } 159 | ] 160 | -------------------------------------------------------------------------------- /data/abi/IERC20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "_owner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "_spender", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "uint256", 20 | "name": "_value", 21 | "type": "uint256" 22 | } 23 | ], 24 | "name": "Approval", 25 | "type": "event" 26 | }, 27 | { 28 | "anonymous": false, 29 | "inputs": [ 30 | { 31 | "indexed": true, 32 | "internalType": "address", 33 | "name": "_from", 34 | "type": "address" 35 | }, 36 | { 37 | "indexed": true, 38 | "internalType": "address", 39 | "name": "_to", 40 | "type": "address" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "uint256", 45 | "name": "_value", 46 | "type": "uint256" 47 | } 48 | ], 49 | "name": "Transfer", 50 | "type": "event" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "_owner", 57 | "type": "address" 58 | }, 59 | { 60 | "internalType": "address", 61 | "name": "_spender", 62 | "type": "address" 63 | } 64 | ], 65 | "name": "allowance", 66 | "outputs": [ 67 | { 68 | "internalType": "uint256", 69 | "name": "", 70 | "type": "uint256" 71 | } 72 | ], 73 | "stateMutability": "view", 74 | "type": "function" 75 | }, 76 | { 77 | "inputs": [ 78 | { 79 | "internalType": "address", 80 | "name": "_spender", 81 | "type": "address" 82 | }, 83 | { 84 | "internalType": "uint256", 85 | "name": "_amount", 86 | "type": "uint256" 87 | } 88 | ], 89 | "name": "approve", 90 | "outputs": [ 91 | { 92 | "internalType": "bool", 93 | "name": "", 94 | "type": "bool" 95 | } 96 | ], 97 | "stateMutability": "nonpayable", 98 | "type": "function" 99 | }, 100 | { 101 | "inputs": [ 102 | { 103 | "internalType": "address", 104 | "name": "_account", 105 | "type": "address" 106 | } 107 | ], 108 | "name": "balanceOf", 109 | "outputs": [ 110 | { 111 | "internalType": "uint256", 112 | "name": "", 113 | "type": "uint256" 114 | } 115 | ], 116 | "stateMutability": "view", 117 | "type": "function" 118 | }, 119 | { 120 | "inputs": [], 121 | "name": "decimals", 122 | "outputs": [ 123 | { 124 | "internalType": "uint8", 125 | "name": "", 126 | "type": "uint8" 127 | } 128 | ], 129 | "stateMutability": "view", 130 | "type": "function" 131 | }, 132 | { 133 | "inputs": [], 134 | "name": "name", 135 | "outputs": [ 136 | { 137 | "internalType": "string", 138 | "name": "", 139 | "type": "string" 140 | } 141 | ], 142 | "stateMutability": "view", 143 | "type": "function" 144 | }, 145 | { 146 | "inputs": [], 147 | "name": "symbol", 148 | "outputs": [ 149 | { 150 | "internalType": "string", 151 | "name": "", 152 | "type": "string" 153 | } 154 | ], 155 | "stateMutability": "view", 156 | "type": "function" 157 | }, 158 | { 159 | "inputs": [], 160 | "name": "totalSupply", 161 | "outputs": [ 162 | { 163 | "internalType": "uint256", 164 | "name": "", 165 | "type": "uint256" 166 | } 167 | ], 168 | "stateMutability": "view", 169 | "type": "function" 170 | }, 171 | { 172 | "inputs": [ 173 | { 174 | "internalType": "address", 175 | "name": "_recipient", 176 | "type": "address" 177 | }, 178 | { 179 | "internalType": "uint256", 180 | "name": "_amount", 181 | "type": "uint256" 182 | } 183 | ], 184 | "name": "transfer", 185 | "outputs": [ 186 | { 187 | "internalType": "bool", 188 | "name": "", 189 | "type": "bool" 190 | } 191 | ], 192 | "stateMutability": "nonpayable", 193 | "type": "function" 194 | }, 195 | { 196 | "inputs": [ 197 | { 198 | "internalType": "address", 199 | "name": "_sender", 200 | "type": "address" 201 | }, 202 | { 203 | "internalType": "address", 204 | "name": "_recipient", 205 | "type": "address" 206 | }, 207 | { 208 | "internalType": "uint256", 209 | "name": "_amount", 210 | "type": "uint256" 211 | } 212 | ], 213 | "name": "transferFrom", 214 | "outputs": [ 215 | { 216 | "internalType": "bool", 217 | "name": "", 218 | "type": "bool" 219 | } 220 | ], 221 | "stateMutability": "nonpayable", 222 | "type": "function" 223 | } 224 | ] 225 | -------------------------------------------------------------------------------- /data/abi/IFloorCalculator.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IERC20", 6 | "name": "wrappedToken", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract IERC20", 11 | "name": "backingToken", 12 | "type": "address" 13 | } 14 | ], 15 | "name": "calculateSubFloor", 16 | "outputs": [ 17 | { 18 | "internalType": "uint256", 19 | "name": "", 20 | "type": "uint256" 21 | } 22 | ], 23 | "stateMutability": "view", 24 | "type": "function" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /data/abi/IOwned.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "claimOwnership", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "owner", 31 | "outputs": [ 32 | { 33 | "internalType": "address", 34 | "name": "", 35 | "type": "address" 36 | } 37 | ], 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "address", 45 | "name": "newOwner", 46 | "type": "address" 47 | } 48 | ], 49 | "name": "transferOwnership", 50 | "outputs": [], 51 | "stateMutability": "nonpayable", 52 | "type": "function" 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /data/abi/IRootKitDistribution.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_to", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "_contribution", 12 | "type": "uint256" 13 | } 14 | ], 15 | "name": "claim", 16 | "outputs": [], 17 | "stateMutability": "nonpayable", 18 | "type": "function" 19 | }, 20 | { 21 | "inputs": [], 22 | "name": "distribute", 23 | "outputs": [], 24 | "stateMutability": "payable", 25 | "type": "function" 26 | }, 27 | { 28 | "inputs": [], 29 | "name": "distributionComplete", 30 | "outputs": [ 31 | { 32 | "internalType": "bool", 33 | "name": "", 34 | "type": "bool" 35 | } 36 | ], 37 | "stateMutability": "view", 38 | "type": "function" 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /data/abi/IStoneface.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "contract IOwned", 8 | "name": "target", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "uint256", 20 | "name": "when", 21 | "type": "uint256" 22 | } 23 | ], 24 | "name": "PendingOwnershipTransfer", 25 | "type": "event" 26 | }, 27 | { 28 | "inputs": [ 29 | { 30 | "internalType": "contract IOwned", 31 | "name": "target", 32 | "type": "address" 33 | } 34 | ], 35 | "name": "callClaimOwnership", 36 | "outputs": [], 37 | "stateMutability": "nonpayable", 38 | "type": "function" 39 | }, 40 | { 41 | "inputs": [ 42 | { 43 | "internalType": "contract IOwned", 44 | "name": "target", 45 | "type": "address" 46 | }, 47 | { 48 | "internalType": "address", 49 | "name": "newOwner", 50 | "type": "address" 51 | } 52 | ], 53 | "name": "callTransferOwnership", 54 | "outputs": [], 55 | "stateMutability": "nonpayable", 56 | "type": "function" 57 | }, 58 | { 59 | "inputs": [ 60 | { 61 | "internalType": "uint256", 62 | "name": "index", 63 | "type": "uint256" 64 | } 65 | ], 66 | "name": "callTransferOwnershipNow", 67 | "outputs": [], 68 | "stateMutability": "nonpayable", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [], 73 | "name": "delay", 74 | "outputs": [ 75 | { 76 | "internalType": "uint256", 77 | "name": "", 78 | "type": "uint256" 79 | } 80 | ], 81 | "stateMutability": "view", 82 | "type": "function" 83 | }, 84 | { 85 | "inputs": [ 86 | { 87 | "internalType": "uint256", 88 | "name": "index", 89 | "type": "uint256" 90 | } 91 | ], 92 | "name": "pendingTransferOwnership", 93 | "outputs": [ 94 | { 95 | "components": [ 96 | { 97 | "internalType": "uint256", 98 | "name": "when", 99 | "type": "uint256" 100 | }, 101 | { 102 | "internalType": "contract IOwned", 103 | "name": "target", 104 | "type": "address" 105 | }, 106 | { 107 | "internalType": "address", 108 | "name": "newOwner", 109 | "type": "address" 110 | } 111 | ], 112 | "internalType": "struct IStoneface.TransferOwnership", 113 | "name": "", 114 | "type": "tuple" 115 | } 116 | ], 117 | "stateMutability": "view", 118 | "type": "function" 119 | }, 120 | { 121 | "inputs": [], 122 | "name": "pendingTransferOwnershipCount", 123 | "outputs": [ 124 | { 125 | "internalType": "uint256", 126 | "name": "", 127 | "type": "uint256" 128 | } 129 | ], 130 | "stateMutability": "view", 131 | "type": "function" 132 | }, 133 | { 134 | "inputs": [], 135 | "name": "rootKitDistribution", 136 | "outputs": [ 137 | { 138 | "internalType": "contract IRootKitDistribution", 139 | "name": "", 140 | "type": "address" 141 | } 142 | ], 143 | "stateMutability": "view", 144 | "type": "function" 145 | }, 146 | { 147 | "inputs": [ 148 | { 149 | "internalType": "contract IRootKitDistribution", 150 | "name": "_rootKitDistribution", 151 | "type": "address" 152 | } 153 | ], 154 | "name": "watchDistribution", 155 | "outputs": [], 156 | "stateMutability": "nonpayable", 157 | "type": "function" 158 | } 159 | ] 160 | -------------------------------------------------------------------------------- /data/abi/ITokensRecoverable.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IERC20", 6 | "name": "token", 7 | "type": "address" 8 | } 9 | ], 10 | "name": "recoverTokens", 11 | "outputs": [], 12 | "stateMutability": "nonpayable", 13 | "type": "function" 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /data/abi/ITransferGate.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "msgSender", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "from", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "to", 17 | "type": "address" 18 | }, 19 | { 20 | "internalType": "uint256", 21 | "name": "amount", 22 | "type": "uint256" 23 | } 24 | ], 25 | "name": "handleTransfer", 26 | "outputs": [ 27 | { 28 | "internalType": "uint256", 29 | "name": "burn", 30 | "type": "uint256" 31 | }, 32 | { 33 | "components": [ 34 | { 35 | "internalType": "address", 36 | "name": "destination", 37 | "type": "address" 38 | }, 39 | { 40 | "internalType": "uint256", 41 | "name": "amount", 42 | "type": "uint256" 43 | } 44 | ], 45 | "internalType": "struct TransferGateTarget[]", 46 | "name": "targets", 47 | "type": "tuple[]" 48 | } 49 | ], 50 | "stateMutability": "nonpayable", 51 | "type": "function" 52 | } 53 | ] 54 | -------------------------------------------------------------------------------- /data/abi/IUniswapV2Factory.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "token0", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "token1", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "address", 20 | "name": "pair", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": false, 25 | "internalType": "uint256", 26 | "name": "", 27 | "type": "uint256" 28 | } 29 | ], 30 | "name": "PairCreated", 31 | "type": "event" 32 | }, 33 | { 34 | "inputs": [ 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "allPairs", 42 | "outputs": [ 43 | { 44 | "internalType": "address", 45 | "name": "pair", 46 | "type": "address" 47 | } 48 | ], 49 | "stateMutability": "view", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [], 54 | "name": "allPairsLength", 55 | "outputs": [ 56 | { 57 | "internalType": "uint256", 58 | "name": "", 59 | "type": "uint256" 60 | } 61 | ], 62 | "stateMutability": "view", 63 | "type": "function" 64 | }, 65 | { 66 | "inputs": [ 67 | { 68 | "internalType": "address", 69 | "name": "tokenA", 70 | "type": "address" 71 | }, 72 | { 73 | "internalType": "address", 74 | "name": "tokenB", 75 | "type": "address" 76 | } 77 | ], 78 | "name": "createPair", 79 | "outputs": [ 80 | { 81 | "internalType": "address", 82 | "name": "pair", 83 | "type": "address" 84 | } 85 | ], 86 | "stateMutability": "nonpayable", 87 | "type": "function" 88 | }, 89 | { 90 | "inputs": [], 91 | "name": "feeTo", 92 | "outputs": [ 93 | { 94 | "internalType": "address", 95 | "name": "", 96 | "type": "address" 97 | } 98 | ], 99 | "stateMutability": "view", 100 | "type": "function" 101 | }, 102 | { 103 | "inputs": [], 104 | "name": "feeToSetter", 105 | "outputs": [ 106 | { 107 | "internalType": "address", 108 | "name": "", 109 | "type": "address" 110 | } 111 | ], 112 | "stateMutability": "view", 113 | "type": "function" 114 | }, 115 | { 116 | "inputs": [ 117 | { 118 | "internalType": "address", 119 | "name": "tokenA", 120 | "type": "address" 121 | }, 122 | { 123 | "internalType": "address", 124 | "name": "tokenB", 125 | "type": "address" 126 | } 127 | ], 128 | "name": "getPair", 129 | "outputs": [ 130 | { 131 | "internalType": "address", 132 | "name": "pair", 133 | "type": "address" 134 | } 135 | ], 136 | "stateMutability": "view", 137 | "type": "function" 138 | }, 139 | { 140 | "inputs": [ 141 | { 142 | "internalType": "address", 143 | "name": "", 144 | "type": "address" 145 | } 146 | ], 147 | "name": "setFeeTo", 148 | "outputs": [], 149 | "stateMutability": "nonpayable", 150 | "type": "function" 151 | }, 152 | { 153 | "inputs": [ 154 | { 155 | "internalType": "address", 156 | "name": "", 157 | "type": "address" 158 | } 159 | ], 160 | "name": "setFeeToSetter", 161 | "outputs": [], 162 | "stateMutability": "nonpayable", 163 | "type": "function" 164 | } 165 | ] 166 | -------------------------------------------------------------------------------- /data/abi/IWrappedERC20Events.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "from", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "uint256", 14 | "name": "amount", 15 | "type": "uint256" 16 | } 17 | ], 18 | "name": "Deposit", 19 | "type": "event" 20 | }, 21 | { 22 | "anonymous": false, 23 | "inputs": [ 24 | { 25 | "indexed": true, 26 | "internalType": "address", 27 | "name": "to", 28 | "type": "address" 29 | }, 30 | { 31 | "indexed": false, 32 | "internalType": "uint256", 33 | "name": "amount", 34 | "type": "uint256" 35 | } 36 | ], 37 | "name": "Withdrawal", 38 | "type": "event" 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /data/abi/Owned.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "claimOwnership", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "owner", 31 | "outputs": [ 32 | { 33 | "internalType": "address", 34 | "name": "", 35 | "type": "address" 36 | } 37 | ], 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "address", 45 | "name": "newOwner", 46 | "type": "address" 47 | } 48 | ], 49 | "name": "transferOwnership", 50 | "outputs": [], 51 | "stateMutability": "nonpayable", 52 | "type": "function" 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /data/abi/OwnedTest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "claimOwnership", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "owner", 31 | "outputs": [ 32 | { 33 | "internalType": "address", 34 | "name": "", 35 | "type": "address" 36 | } 37 | ], 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "address", 45 | "name": "newOwner", 46 | "type": "address" 47 | } 48 | ], 49 | "name": "transferOwnership", 50 | "outputs": [], 51 | "stateMutability": "nonpayable", 52 | "type": "function" 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /data/abi/RootKitDirect.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract KETH", 6 | "name": "_keth", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract RootKit", 11 | "name": "_rootKit", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "contract IUniswapV2Router02", 16 | "name": "_uniswapV2Router", 17 | "type": "address" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "anonymous": false, 25 | "inputs": [ 26 | { 27 | "indexed": true, 28 | "internalType": "address", 29 | "name": "previousOwner", 30 | "type": "address" 31 | }, 32 | { 33 | "indexed": true, 34 | "internalType": "address", 35 | "name": "newOwner", 36 | "type": "address" 37 | } 38 | ], 39 | "name": "OwnershipTransferred", 40 | "type": "event" 41 | }, 42 | { 43 | "inputs": [ 44 | { 45 | "internalType": "uint256", 46 | "name": "amountOutMin", 47 | "type": "uint256" 48 | } 49 | ], 50 | "name": "buy", 51 | "outputs": [ 52 | { 53 | "internalType": "uint256", 54 | "name": "rootKitAmount", 55 | "type": "uint256" 56 | } 57 | ], 58 | "stateMutability": "payable", 59 | "type": "function" 60 | }, 61 | { 62 | "inputs": [], 63 | "name": "claimOwnership", 64 | "outputs": [], 65 | "stateMutability": "nonpayable", 66 | "type": "function" 67 | }, 68 | { 69 | "inputs": [], 70 | "name": "easyBuy", 71 | "outputs": [ 72 | { 73 | "internalType": "uint256", 74 | "name": "rootKitAmount", 75 | "type": "uint256" 76 | } 77 | ], 78 | "stateMutability": "payable", 79 | "type": "function" 80 | }, 81 | { 82 | "inputs": [ 83 | { 84 | "internalType": "uint256", 85 | "name": "rootKitAmountIn", 86 | "type": "uint256" 87 | } 88 | ], 89 | "name": "easySell", 90 | "outputs": [ 91 | { 92 | "internalType": "uint256", 93 | "name": "ethAmount", 94 | "type": "uint256" 95 | } 96 | ], 97 | "stateMutability": "nonpayable", 98 | "type": "function" 99 | }, 100 | { 101 | "inputs": [ 102 | { 103 | "internalType": "uint256", 104 | "name": "ethAmountIn", 105 | "type": "uint256" 106 | } 107 | ], 108 | "name": "estimateBuy", 109 | "outputs": [ 110 | { 111 | "internalType": "uint256", 112 | "name": "rootKitAmount", 113 | "type": "uint256" 114 | } 115 | ], 116 | "stateMutability": "view", 117 | "type": "function" 118 | }, 119 | { 120 | "inputs": [ 121 | { 122 | "internalType": "uint256", 123 | "name": "rootKitAmountIn", 124 | "type": "uint256" 125 | } 126 | ], 127 | "name": "estimateSell", 128 | "outputs": [ 129 | { 130 | "internalType": "uint256", 131 | "name": "ethAmount", 132 | "type": "uint256" 133 | } 134 | ], 135 | "stateMutability": "view", 136 | "type": "function" 137 | }, 138 | { 139 | "inputs": [], 140 | "name": "owner", 141 | "outputs": [ 142 | { 143 | "internalType": "address", 144 | "name": "", 145 | "type": "address" 146 | } 147 | ], 148 | "stateMutability": "view", 149 | "type": "function" 150 | }, 151 | { 152 | "inputs": [ 153 | { 154 | "internalType": "contract IERC20", 155 | "name": "token", 156 | "type": "address" 157 | } 158 | ], 159 | "name": "recoverTokens", 160 | "outputs": [], 161 | "stateMutability": "nonpayable", 162 | "type": "function" 163 | }, 164 | { 165 | "inputs": [ 166 | { 167 | "internalType": "uint256", 168 | "name": "rootKitAmountIn", 169 | "type": "uint256" 170 | }, 171 | { 172 | "internalType": "uint256", 173 | "name": "amountOutMin", 174 | "type": "uint256" 175 | } 176 | ], 177 | "name": "sell", 178 | "outputs": [ 179 | { 180 | "internalType": "uint256", 181 | "name": "ethAmount", 182 | "type": "uint256" 183 | } 184 | ], 185 | "stateMutability": "nonpayable", 186 | "type": "function" 187 | }, 188 | { 189 | "inputs": [ 190 | { 191 | "internalType": "address", 192 | "name": "newOwner", 193 | "type": "address" 194 | } 195 | ], 196 | "name": "transferOwnership", 197 | "outputs": [], 198 | "stateMutability": "nonpayable", 199 | "type": "function" 200 | }, 201 | { 202 | "stateMutability": "payable", 203 | "type": "receive" 204 | } 205 | ] 206 | -------------------------------------------------------------------------------- /data/abi/RootKitDistributionTest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract RootKit", 6 | "name": "_rootKit", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "inputs": [ 15 | { 16 | "internalType": "address", 17 | "name": "_to", 18 | "type": "address" 19 | }, 20 | { 21 | "internalType": "uint256", 22 | "name": "_amount", 23 | "type": "uint256" 24 | } 25 | ], 26 | "name": "claim", 27 | "outputs": [], 28 | "stateMutability": "nonpayable", 29 | "type": "function" 30 | }, 31 | { 32 | "inputs": [ 33 | { 34 | "internalType": "address", 35 | "name": "", 36 | "type": "address" 37 | } 38 | ], 39 | "name": "claimCallAmount", 40 | "outputs": [ 41 | { 42 | "internalType": "uint256", 43 | "name": "", 44 | "type": "uint256" 45 | } 46 | ], 47 | "stateMutability": "view", 48 | "type": "function" 49 | }, 50 | { 51 | "inputs": [], 52 | "name": "distribute", 53 | "outputs": [], 54 | "stateMutability": "payable", 55 | "type": "function" 56 | }, 57 | { 58 | "inputs": [], 59 | "name": "distributionComplete", 60 | "outputs": [ 61 | { 62 | "internalType": "bool", 63 | "name": "", 64 | "type": "bool" 65 | } 66 | ], 67 | "stateMutability": "view", 68 | "type": "function" 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /data/abi/RootKitFloorCalculator.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract RootKit", 6 | "name": "_rootKit", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract IUniswapV2Factory", 11 | "name": "_uniswapV2Factory", 12 | "type": "address" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "anonymous": false, 20 | "inputs": [ 21 | { 22 | "indexed": true, 23 | "internalType": "address", 24 | "name": "previousOwner", 25 | "type": "address" 26 | }, 27 | { 28 | "indexed": true, 29 | "internalType": "address", 30 | "name": "newOwner", 31 | "type": "address" 32 | } 33 | ], 34 | "name": "OwnershipTransferred", 35 | "type": "event" 36 | }, 37 | { 38 | "inputs": [ 39 | { 40 | "internalType": "contract IERC20", 41 | "name": "wrappedToken", 42 | "type": "address" 43 | }, 44 | { 45 | "internalType": "contract IERC20", 46 | "name": "backingToken", 47 | "type": "address" 48 | } 49 | ], 50 | "name": "calculateSubFloor", 51 | "outputs": [ 52 | { 53 | "internalType": "uint256", 54 | "name": "", 55 | "type": "uint256" 56 | } 57 | ], 58 | "stateMutability": "view", 59 | "type": "function" 60 | }, 61 | { 62 | "inputs": [], 63 | "name": "claimOwnership", 64 | "outputs": [], 65 | "stateMutability": "nonpayable", 66 | "type": "function" 67 | }, 68 | { 69 | "inputs": [], 70 | "name": "owner", 71 | "outputs": [ 72 | { 73 | "internalType": "address", 74 | "name": "", 75 | "type": "address" 76 | } 77 | ], 78 | "stateMutability": "view", 79 | "type": "function" 80 | }, 81 | { 82 | "inputs": [ 83 | { 84 | "internalType": "contract IERC20", 85 | "name": "token", 86 | "type": "address" 87 | } 88 | ], 89 | "name": "recoverTokens", 90 | "outputs": [], 91 | "stateMutability": "nonpayable", 92 | "type": "function" 93 | }, 94 | { 95 | "inputs": [ 96 | { 97 | "internalType": "address", 98 | "name": "newOwner", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "transferOwnership", 103 | "outputs": [], 104 | "stateMutability": "nonpayable", 105 | "type": "function" 106 | } 107 | ] 108 | -------------------------------------------------------------------------------- /data/abi/RootKitLiquidityGeneration.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract RootKit", 6 | "name": "_rootKit", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "anonymous": false, 15 | "inputs": [ 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "previousOwner", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": true, 24 | "internalType": "address", 25 | "name": "newOwner", 26 | "type": "address" 27 | } 28 | ], 29 | "name": "OwnershipTransferred", 30 | "type": "event" 31 | }, 32 | { 33 | "inputs": [ 34 | { 35 | "internalType": "contract IRootKitDistribution", 36 | "name": "_rootKitDistribution", 37 | "type": "address" 38 | } 39 | ], 40 | "name": "activate", 41 | "outputs": [], 42 | "stateMutability": "nonpayable", 43 | "type": "function" 44 | }, 45 | { 46 | "inputs": [], 47 | "name": "allowRefunds", 48 | "outputs": [], 49 | "stateMutability": "nonpayable", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [], 54 | "name": "claim", 55 | "outputs": [], 56 | "stateMutability": "nonpayable", 57 | "type": "function" 58 | }, 59 | { 60 | "inputs": [], 61 | "name": "claimOwnership", 62 | "outputs": [], 63 | "stateMutability": "nonpayable", 64 | "type": "function" 65 | }, 66 | { 67 | "inputs": [], 68 | "name": "complete", 69 | "outputs": [], 70 | "stateMutability": "nonpayable", 71 | "type": "function" 72 | }, 73 | { 74 | "inputs": [ 75 | { 76 | "internalType": "address", 77 | "name": "", 78 | "type": "address" 79 | } 80 | ], 81 | "name": "contribution", 82 | "outputs": [ 83 | { 84 | "internalType": "uint256", 85 | "name": "", 86 | "type": "uint256" 87 | } 88 | ], 89 | "stateMutability": "view", 90 | "type": "function" 91 | }, 92 | { 93 | "inputs": [ 94 | { 95 | "internalType": "uint256", 96 | "name": "", 97 | "type": "uint256" 98 | } 99 | ], 100 | "name": "contributors", 101 | "outputs": [ 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | } 107 | ], 108 | "stateMutability": "view", 109 | "type": "function" 110 | }, 111 | { 112 | "inputs": [], 113 | "name": "contributorsCount", 114 | "outputs": [ 115 | { 116 | "internalType": "uint256", 117 | "name": "", 118 | "type": "uint256" 119 | } 120 | ], 121 | "stateMutability": "view", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [], 126 | "name": "isActive", 127 | "outputs": [ 128 | { 129 | "internalType": "bool", 130 | "name": "", 131 | "type": "bool" 132 | } 133 | ], 134 | "stateMutability": "view", 135 | "type": "function" 136 | }, 137 | { 138 | "inputs": [], 139 | "name": "owner", 140 | "outputs": [ 141 | { 142 | "internalType": "address", 143 | "name": "", 144 | "type": "address" 145 | } 146 | ], 147 | "stateMutability": "view", 148 | "type": "function" 149 | }, 150 | { 151 | "inputs": [ 152 | { 153 | "internalType": "contract IERC20", 154 | "name": "token", 155 | "type": "address" 156 | } 157 | ], 158 | "name": "recoverTokens", 159 | "outputs": [], 160 | "stateMutability": "nonpayable", 161 | "type": "function" 162 | }, 163 | { 164 | "inputs": [], 165 | "name": "rootKitDistribution", 166 | "outputs": [ 167 | { 168 | "internalType": "contract IRootKitDistribution", 169 | "name": "", 170 | "type": "address" 171 | } 172 | ], 173 | "stateMutability": "view", 174 | "type": "function" 175 | }, 176 | { 177 | "inputs": [ 178 | { 179 | "internalType": "contract IRootKitDistribution", 180 | "name": "_rootKitDistribution", 181 | "type": "address" 182 | } 183 | ], 184 | "name": "setRootKitDistribution", 185 | "outputs": [], 186 | "stateMutability": "nonpayable", 187 | "type": "function" 188 | }, 189 | { 190 | "inputs": [ 191 | { 192 | "internalType": "address", 193 | "name": "newOwner", 194 | "type": "address" 195 | } 196 | ], 197 | "name": "transferOwnership", 198 | "outputs": [], 199 | "stateMutability": "nonpayable", 200 | "type": "function" 201 | }, 202 | { 203 | "stateMutability": "payable", 204 | "type": "receive" 205 | } 206 | ] 207 | -------------------------------------------------------------------------------- /data/abi/RootKitLiquidityMatching.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract RootKit", 6 | "name": "_rootKit", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract IUniswapV2Router02", 11 | "name": "_uniswapV2Router", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "contract IWrappedERC20", 16 | "name": "_liquidityTokenWrapper", 17 | "type": "address" 18 | }, 19 | { 20 | "internalType": "contract KETH", 21 | "name": "_keth", 22 | "type": "address" 23 | } 24 | ], 25 | "stateMutability": "nonpayable", 26 | "type": "constructor" 27 | }, 28 | { 29 | "anonymous": false, 30 | "inputs": [ 31 | { 32 | "indexed": true, 33 | "internalType": "address", 34 | "name": "previousOwner", 35 | "type": "address" 36 | }, 37 | { 38 | "indexed": true, 39 | "internalType": "address", 40 | "name": "newOwner", 41 | "type": "address" 42 | } 43 | ], 44 | "name": "OwnershipTransferred", 45 | "type": "event" 46 | }, 47 | { 48 | "inputs": [], 49 | "name": "addLiquidityETH", 50 | "outputs": [], 51 | "stateMutability": "payable", 52 | "type": "function" 53 | }, 54 | { 55 | "inputs": [ 56 | { 57 | "internalType": "uint256", 58 | "name": "amount", 59 | "type": "uint256" 60 | } 61 | ], 62 | "name": "addLiquidityKETH", 63 | "outputs": [], 64 | "stateMutability": "nonpayable", 65 | "type": "function" 66 | }, 67 | { 68 | "inputs": [ 69 | { 70 | "internalType": "uint256", 71 | "name": "amount", 72 | "type": "uint256" 73 | } 74 | ], 75 | "name": "addLiquidityWETH", 76 | "outputs": [], 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "inputs": [], 82 | "name": "claimOwnership", 83 | "outputs": [], 84 | "stateMutability": "nonpayable", 85 | "type": "function" 86 | }, 87 | { 88 | "inputs": [], 89 | "name": "liquidityPercentForUser", 90 | "outputs": [ 91 | { 92 | "internalType": "uint16", 93 | "name": "", 94 | "type": "uint16" 95 | } 96 | ], 97 | "stateMutability": "view", 98 | "type": "function" 99 | }, 100 | { 101 | "inputs": [], 102 | "name": "owner", 103 | "outputs": [ 104 | { 105 | "internalType": "address", 106 | "name": "", 107 | "type": "address" 108 | } 109 | ], 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "inputs": [ 115 | { 116 | "internalType": "contract IERC20", 117 | "name": "token", 118 | "type": "address" 119 | } 120 | ], 121 | "name": "recoverTokens", 122 | "outputs": [], 123 | "stateMutability": "nonpayable", 124 | "type": "function" 125 | }, 126 | { 127 | "inputs": [ 128 | { 129 | "internalType": "uint16", 130 | "name": "_liquidityPercentForUser", 131 | "type": "uint16" 132 | } 133 | ], 134 | "name": "setLiquidityPercentForUser", 135 | "outputs": [], 136 | "stateMutability": "nonpayable", 137 | "type": "function" 138 | }, 139 | { 140 | "inputs": [ 141 | { 142 | "internalType": "address", 143 | "name": "newOwner", 144 | "type": "address" 145 | } 146 | ], 147 | "name": "transferOwnership", 148 | "outputs": [], 149 | "stateMutability": "nonpayable", 150 | "type": "function" 151 | }, 152 | { 153 | "stateMutability": "payable", 154 | "type": "receive" 155 | } 156 | ] 157 | -------------------------------------------------------------------------------- /data/abi/RootKitMoneyButton.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IUniswapV2Router02", 6 | "name": "_uniswapV2Router", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract KETH", 11 | "name": "_keth", 12 | "type": "address" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "anonymous": false, 20 | "inputs": [ 21 | { 22 | "indexed": true, 23 | "internalType": "address", 24 | "name": "previousOwner", 25 | "type": "address" 26 | }, 27 | { 28 | "indexed": true, 29 | "internalType": "address", 30 | "name": "newOwner", 31 | "type": "address" 32 | } 33 | ], 34 | "name": "OwnershipTransferred", 35 | "type": "event" 36 | }, 37 | { 38 | "inputs": [], 39 | "name": "claimOwnership", 40 | "outputs": [], 41 | "stateMutability": "nonpayable", 42 | "type": "function" 43 | }, 44 | { 45 | "inputs": [ 46 | { 47 | "internalType": "address", 48 | "name": "_vault", 49 | "type": "address" 50 | }, 51 | { 52 | "internalType": "uint16", 53 | "name": "_percentToVault", 54 | "type": "uint16" 55 | } 56 | ], 57 | "name": "configure", 58 | "outputs": [], 59 | "stateMutability": "nonpayable", 60 | "type": "function" 61 | }, 62 | { 63 | "inputs": [ 64 | { 65 | "internalType": "address[]", 66 | "name": "_fullPath", 67 | "type": "address[]" 68 | }, 69 | { 70 | "internalType": "uint256", 71 | "name": "_amountIn", 72 | "type": "uint256" 73 | } 74 | ], 75 | "name": "estimateProfit", 76 | "outputs": [ 77 | { 78 | "internalType": "uint256", 79 | "name": "", 80 | "type": "uint256" 81 | } 82 | ], 83 | "stateMutability": "view", 84 | "type": "function" 85 | }, 86 | { 87 | "inputs": [ 88 | { 89 | "internalType": "address[]", 90 | "name": "_fullPath", 91 | "type": "address[]" 92 | }, 93 | { 94 | "internalType": "uint256", 95 | "name": "_amountIn", 96 | "type": "uint256" 97 | }, 98 | { 99 | "internalType": "uint256", 100 | "name": "_minProfit", 101 | "type": "uint256" 102 | } 103 | ], 104 | "name": "gimmeMoney", 105 | "outputs": [], 106 | "stateMutability": "payable", 107 | "type": "function" 108 | }, 109 | { 110 | "inputs": [], 111 | "name": "owner", 112 | "outputs": [ 113 | { 114 | "internalType": "address", 115 | "name": "", 116 | "type": "address" 117 | } 118 | ], 119 | "stateMutability": "view", 120 | "type": "function" 121 | }, 122 | { 123 | "inputs": [], 124 | "name": "percentToVault", 125 | "outputs": [ 126 | { 127 | "internalType": "uint16", 128 | "name": "", 129 | "type": "uint16" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [ 137 | { 138 | "internalType": "contract IERC20", 139 | "name": "token", 140 | "type": "address" 141 | } 142 | ], 143 | "name": "recoverTokens", 144 | "outputs": [], 145 | "stateMutability": "nonpayable", 146 | "type": "function" 147 | }, 148 | { 149 | "inputs": [ 150 | { 151 | "internalType": "address", 152 | "name": "newOwner", 153 | "type": "address" 154 | } 155 | ], 156 | "name": "transferOwnership", 157 | "outputs": [], 158 | "stateMutability": "nonpayable", 159 | "type": "function" 160 | }, 161 | { 162 | "inputs": [], 163 | "name": "vault", 164 | "outputs": [ 165 | { 166 | "internalType": "address", 167 | "name": "", 168 | "type": "address" 169 | } 170 | ], 171 | "stateMutability": "view", 172 | "type": "function" 173 | }, 174 | { 175 | "stateMutability": "payable", 176 | "type": "receive" 177 | } 178 | ] 179 | -------------------------------------------------------------------------------- /data/abi/RootKitRuggableFloorCalculator.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [ 23 | { 24 | "internalType": "contract IERC20", 25 | "name": "", 26 | "type": "address" 27 | }, 28 | { 29 | "internalType": "contract IERC20", 30 | "name": "", 31 | "type": "address" 32 | } 33 | ], 34 | "name": "calculateSubFloor", 35 | "outputs": [ 36 | { 37 | "internalType": "uint256", 38 | "name": "", 39 | "type": "uint256" 40 | } 41 | ], 42 | "stateMutability": "view", 43 | "type": "function" 44 | }, 45 | { 46 | "inputs": [], 47 | "name": "claimOwnership", 48 | "outputs": [], 49 | "stateMutability": "nonpayable", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [], 54 | "name": "owner", 55 | "outputs": [ 56 | { 57 | "internalType": "address", 58 | "name": "", 59 | "type": "address" 60 | } 61 | ], 62 | "stateMutability": "view", 63 | "type": "function" 64 | }, 65 | { 66 | "inputs": [ 67 | { 68 | "internalType": "contract IERC20", 69 | "name": "token", 70 | "type": "address" 71 | } 72 | ], 73 | "name": "recoverTokens", 74 | "outputs": [], 75 | "stateMutability": "nonpayable", 76 | "type": "function" 77 | }, 78 | { 79 | "inputs": [ 80 | { 81 | "internalType": "uint256", 82 | "name": "_subFloor", 83 | "type": "uint256" 84 | } 85 | ], 86 | "name": "setSubFloor", 87 | "outputs": [], 88 | "stateMutability": "nonpayable", 89 | "type": "function" 90 | }, 91 | { 92 | "inputs": [ 93 | { 94 | "internalType": "address", 95 | "name": "newOwner", 96 | "type": "address" 97 | } 98 | ], 99 | "name": "transferOwnership", 100 | "outputs": [], 101 | "stateMutability": "nonpayable", 102 | "type": "function" 103 | } 104 | ] 105 | -------------------------------------------------------------------------------- /data/abi/RootKitVault.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "claimOwnership", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "owner", 31 | "outputs": [ 32 | { 33 | "internalType": "address", 34 | "name": "", 35 | "type": "address" 36 | } 37 | ], 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "address payable", 45 | "name": "_to", 46 | "type": "address" 47 | }, 48 | { 49 | "internalType": "uint256", 50 | "name": "_amount", 51 | "type": "uint256" 52 | } 53 | ], 54 | "name": "sendEther", 55 | "outputs": [], 56 | "stateMutability": "nonpayable", 57 | "type": "function" 58 | }, 59 | { 60 | "inputs": [ 61 | { 62 | "internalType": "contract IERC20", 63 | "name": "_token", 64 | "type": "address" 65 | }, 66 | { 67 | "internalType": "address", 68 | "name": "_to", 69 | "type": "address" 70 | }, 71 | { 72 | "internalType": "uint256", 73 | "name": "_amount", 74 | "type": "uint256" 75 | } 76 | ], 77 | "name": "sendToken", 78 | "outputs": [], 79 | "stateMutability": "nonpayable", 80 | "type": "function" 81 | }, 82 | { 83 | "inputs": [ 84 | { 85 | "internalType": "address", 86 | "name": "newOwner", 87 | "type": "address" 88 | } 89 | ], 90 | "name": "transferOwnership", 91 | "outputs": [], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "stateMutability": "payable", 97 | "type": "receive" 98 | } 99 | ] 100 | -------------------------------------------------------------------------------- /data/abi/RootWethZapper.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "claimOwnership", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "contract IWETH", 32 | "name": "weth", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "contract RootKit", 37 | "name": "rootKit", 38 | "type": "address" 39 | }, 40 | { 41 | "internalType": "uint256", 42 | "name": "wethAmount", 43 | "type": "uint256" 44 | }, 45 | { 46 | "internalType": "uint256", 47 | "name": "rootKitAmount", 48 | "type": "uint256" 49 | }, 50 | { 51 | "internalType": "contract IUniswapV2Router02", 52 | "name": "uniswapV2Router", 53 | "type": "address" 54 | } 55 | ], 56 | "name": "go", 57 | "outputs": [], 58 | "stateMutability": "nonpayable", 59 | "type": "function" 60 | }, 61 | { 62 | "inputs": [], 63 | "name": "owner", 64 | "outputs": [ 65 | { 66 | "internalType": "address", 67 | "name": "", 68 | "type": "address" 69 | } 70 | ], 71 | "stateMutability": "view", 72 | "type": "function" 73 | }, 74 | { 75 | "inputs": [ 76 | { 77 | "internalType": "contract IERC20", 78 | "name": "token", 79 | "type": "address" 80 | } 81 | ], 82 | "name": "recoverTokens", 83 | "outputs": [], 84 | "stateMutability": "nonpayable", 85 | "type": "function" 86 | }, 87 | { 88 | "inputs": [ 89 | { 90 | "internalType": "address", 91 | "name": "newOwner", 92 | "type": "address" 93 | } 94 | ], 95 | "name": "transferOwnership", 96 | "outputs": [], 97 | "stateMutability": "nonpayable", 98 | "type": "function" 99 | } 100 | ] 101 | -------------------------------------------------------------------------------- /data/abi/Stoneface.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "_delay", 7 | "type": "uint256" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "anonymous": false, 15 | "inputs": [ 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "previousOwner", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": true, 24 | "internalType": "address", 25 | "name": "newOwner", 26 | "type": "address" 27 | } 28 | ], 29 | "name": "OwnershipTransferred", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": false, 37 | "internalType": "contract IOwned", 38 | "name": "target", 39 | "type": "address" 40 | }, 41 | { 42 | "indexed": false, 43 | "internalType": "address", 44 | "name": "newOwner", 45 | "type": "address" 46 | }, 47 | { 48 | "indexed": false, 49 | "internalType": "uint256", 50 | "name": "when", 51 | "type": "uint256" 52 | } 53 | ], 54 | "name": "PendingOwnershipTransfer", 55 | "type": "event" 56 | }, 57 | { 58 | "inputs": [ 59 | { 60 | "internalType": "contract IOwned", 61 | "name": "target", 62 | "type": "address" 63 | } 64 | ], 65 | "name": "callClaimOwnership", 66 | "outputs": [], 67 | "stateMutability": "nonpayable", 68 | "type": "function" 69 | }, 70 | { 71 | "inputs": [ 72 | { 73 | "internalType": "contract IOwned", 74 | "name": "target", 75 | "type": "address" 76 | }, 77 | { 78 | "internalType": "address", 79 | "name": "newOwner", 80 | "type": "address" 81 | } 82 | ], 83 | "name": "callTransferOwnership", 84 | "outputs": [], 85 | "stateMutability": "nonpayable", 86 | "type": "function" 87 | }, 88 | { 89 | "inputs": [ 90 | { 91 | "internalType": "uint256", 92 | "name": "index", 93 | "type": "uint256" 94 | } 95 | ], 96 | "name": "callTransferOwnershipNow", 97 | "outputs": [], 98 | "stateMutability": "nonpayable", 99 | "type": "function" 100 | }, 101 | { 102 | "inputs": [], 103 | "name": "claimOwnership", 104 | "outputs": [], 105 | "stateMutability": "nonpayable", 106 | "type": "function" 107 | }, 108 | { 109 | "inputs": [], 110 | "name": "delay", 111 | "outputs": [ 112 | { 113 | "internalType": "uint256", 114 | "name": "", 115 | "type": "uint256" 116 | } 117 | ], 118 | "stateMutability": "view", 119 | "type": "function" 120 | }, 121 | { 122 | "inputs": [], 123 | "name": "owner", 124 | "outputs": [ 125 | { 126 | "internalType": "address", 127 | "name": "", 128 | "type": "address" 129 | } 130 | ], 131 | "stateMutability": "view", 132 | "type": "function" 133 | }, 134 | { 135 | "inputs": [ 136 | { 137 | "internalType": "uint256", 138 | "name": "index", 139 | "type": "uint256" 140 | } 141 | ], 142 | "name": "pendingTransferOwnership", 143 | "outputs": [ 144 | { 145 | "components": [ 146 | { 147 | "internalType": "uint256", 148 | "name": "when", 149 | "type": "uint256" 150 | }, 151 | { 152 | "internalType": "contract IOwned", 153 | "name": "target", 154 | "type": "address" 155 | }, 156 | { 157 | "internalType": "address", 158 | "name": "newOwner", 159 | "type": "address" 160 | } 161 | ], 162 | "internalType": "struct IStoneface.TransferOwnership", 163 | "name": "", 164 | "type": "tuple" 165 | } 166 | ], 167 | "stateMutability": "view", 168 | "type": "function" 169 | }, 170 | { 171 | "inputs": [], 172 | "name": "pendingTransferOwnershipCount", 173 | "outputs": [ 174 | { 175 | "internalType": "uint256", 176 | "name": "", 177 | "type": "uint256" 178 | } 179 | ], 180 | "stateMutability": "view", 181 | "type": "function" 182 | }, 183 | { 184 | "inputs": [ 185 | { 186 | "internalType": "contract IERC20", 187 | "name": "token", 188 | "type": "address" 189 | } 190 | ], 191 | "name": "recoverTokens", 192 | "outputs": [], 193 | "stateMutability": "nonpayable", 194 | "type": "function" 195 | }, 196 | { 197 | "inputs": [], 198 | "name": "rootKitDistribution", 199 | "outputs": [ 200 | { 201 | "internalType": "contract IRootKitDistribution", 202 | "name": "", 203 | "type": "address" 204 | } 205 | ], 206 | "stateMutability": "view", 207 | "type": "function" 208 | }, 209 | { 210 | "inputs": [ 211 | { 212 | "internalType": "address", 213 | "name": "newOwner", 214 | "type": "address" 215 | } 216 | ], 217 | "name": "transferOwnership", 218 | "outputs": [], 219 | "stateMutability": "nonpayable", 220 | "type": "function" 221 | }, 222 | { 223 | "inputs": [ 224 | { 225 | "internalType": "contract IRootKitDistribution", 226 | "name": "_rootKitDistribution", 227 | "type": "address" 228 | } 229 | ], 230 | "name": "watchDistribution", 231 | "outputs": [], 232 | "stateMutability": "nonpayable", 233 | "type": "function" 234 | } 235 | ] 236 | -------------------------------------------------------------------------------- /data/abi/TokensRecoverable.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "claimOwnership", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "owner", 31 | "outputs": [ 32 | { 33 | "internalType": "address", 34 | "name": "", 35 | "type": "address" 36 | } 37 | ], 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "contract IERC20", 45 | "name": "token", 46 | "type": "address" 47 | } 48 | ], 49 | "name": "recoverTokens", 50 | "outputs": [], 51 | "stateMutability": "nonpayable", 52 | "type": "function" 53 | }, 54 | { 55 | "inputs": [ 56 | { 57 | "internalType": "address", 58 | "name": "newOwner", 59 | "type": "address" 60 | } 61 | ], 62 | "name": "transferOwnership", 63 | "outputs": [], 64 | "stateMutability": "nonpayable", 65 | "type": "function" 66 | } 67 | ] 68 | -------------------------------------------------------------------------------- /data/abi/TokensRecoverableTest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "claimOwnership", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "owner", 31 | "outputs": [ 32 | { 33 | "internalType": "address", 34 | "name": "", 35 | "type": "address" 36 | } 37 | ], 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "contract IERC20", 45 | "name": "token", 46 | "type": "address" 47 | } 48 | ], 49 | "name": "recoverTokens", 50 | "outputs": [], 51 | "stateMutability": "nonpayable", 52 | "type": "function" 53 | }, 54 | { 55 | "inputs": [ 56 | { 57 | "internalType": "bool", 58 | "name": "can", 59 | "type": "bool" 60 | } 61 | ], 62 | "name": "setCanRecover", 63 | "outputs": [], 64 | "stateMutability": "nonpayable", 65 | "type": "function" 66 | }, 67 | { 68 | "inputs": [ 69 | { 70 | "internalType": "address", 71 | "name": "newOwner", 72 | "type": "address" 73 | } 74 | ], 75 | "name": "transferOwnership", 76 | "outputs": [], 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | } 80 | ] 81 | -------------------------------------------------------------------------------- /data/abi/TransferGateTest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "", 17 | "type": "address" 18 | }, 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "name": "handleTransfer", 26 | "outputs": [ 27 | { 28 | "internalType": "uint256", 29 | "name": "burn", 30 | "type": "uint256" 31 | }, 32 | { 33 | "components": [ 34 | { 35 | "internalType": "address", 36 | "name": "destination", 37 | "type": "address" 38 | }, 39 | { 40 | "internalType": "uint256", 41 | "name": "amount", 42 | "type": "uint256" 43 | } 44 | ], 45 | "internalType": "struct TransferGateTarget[]", 46 | "name": "targets", 47 | "type": "tuple[]" 48 | } 49 | ], 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "inputs": [ 55 | { 56 | "internalType": "uint256", 57 | "name": "_burnAmount", 58 | "type": "uint256" 59 | }, 60 | { 61 | "internalType": "address", 62 | "name": "_addr1", 63 | "type": "address" 64 | }, 65 | { 66 | "internalType": "uint256", 67 | "name": "_addr1Amount", 68 | "type": "uint256" 69 | }, 70 | { 71 | "internalType": "address", 72 | "name": "_addr2", 73 | "type": "address" 74 | }, 75 | { 76 | "internalType": "uint256", 77 | "name": "_addr2Amount", 78 | "type": "uint256" 79 | } 80 | ], 81 | "name": "setParams", 82 | "outputs": [], 83 | "stateMutability": "nonpayable", 84 | "type": "function" 85 | } 86 | ] 87 | -------------------------------------------------------------------------------- /data/abi/WbtcToWethLiquidityZapper.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IUniswapV2Router02", 6 | "name": "_uniswapV2Router", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract IERC31337", 11 | "name": "_wrappedWbtcRootKit", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "contract RootKit", 16 | "name": "_rootKit", 17 | "type": "address" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "anonymous": false, 25 | "inputs": [ 26 | { 27 | "indexed": true, 28 | "internalType": "address", 29 | "name": "previousOwner", 30 | "type": "address" 31 | }, 32 | { 33 | "indexed": true, 34 | "internalType": "address", 35 | "name": "newOwner", 36 | "type": "address" 37 | } 38 | ], 39 | "name": "OwnershipTransferred", 40 | "type": "event" 41 | }, 42 | { 43 | "inputs": [], 44 | "name": "claimOwnership", 45 | "outputs": [], 46 | "stateMutability": "nonpayable", 47 | "type": "function" 48 | }, 49 | { 50 | "inputs": [], 51 | "name": "go", 52 | "outputs": [], 53 | "stateMutability": "nonpayable", 54 | "type": "function" 55 | }, 56 | { 57 | "inputs": [], 58 | "name": "owner", 59 | "outputs": [ 60 | { 61 | "internalType": "address", 62 | "name": "", 63 | "type": "address" 64 | } 65 | ], 66 | "stateMutability": "view", 67 | "type": "function" 68 | }, 69 | { 70 | "inputs": [ 71 | { 72 | "internalType": "contract IERC20", 73 | "name": "token", 74 | "type": "address" 75 | } 76 | ], 77 | "name": "recoverTokens", 78 | "outputs": [], 79 | "stateMutability": "nonpayable", 80 | "type": "function" 81 | }, 82 | { 83 | "inputs": [ 84 | { 85 | "internalType": "address", 86 | "name": "newOwner", 87 | "type": "address" 88 | } 89 | ], 90 | "name": "transferOwnership", 91 | "outputs": [], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | } 95 | ] 96 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomiclabs/hardhat-waffle"); 2 | 3 | /** 4 | * @type import('hardhat/config').HardhatUserConfig 5 | */ 6 | module.exports = { 7 | solidity: "0.7.4", 8 | networks: { 9 | hardhat: { 10 | accounts: { 11 | accountsBalance: "100000000000000000000000" 12 | }, 13 | chainId: 1, 14 | gas: 1, 15 | gasPrice: 152525256960 16 | } 17 | } 18 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rootkit", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npx hardhat test" 8 | }, 9 | "author": "", 10 | "devDependencies": { 11 | "@nomiclabs/hardhat-ethers": "^2.0.2", 12 | "@nomiclabs/hardhat-waffle": "^2.0.0", 13 | "chai": "^4.3.4", 14 | "ethereum-waffle": "^3.4.0", 15 | "ethers": "^5.5.1", 16 | "hardhat": "^2.6.6", 17 | "mocha": "^8.4.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/ERC20.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { ethers } = require("hardhat"); 3 | const { constants, BigNumber, utils } = require("ethers"); 4 | 5 | describe("ERC20", function() { 6 | let erc20, user1, user2; 7 | 8 | beforeEach(async function() { 9 | [user1, user2] = await ethers.getSigners(); 10 | const erc20Factory = await ethers.getContractFactory("ERC20Test"); 11 | erc20 = await erc20Factory.connect(user1).deploy(); 12 | }) 13 | 14 | it("init params as expected", async function() { 15 | expect(await erc20.name()).to.equal("Test"); 16 | expect(await erc20.symbol()).to.equal("TST"); 17 | expect(await erc20.decimals()).to.equal(18); 18 | expect(await erc20.totalSupply()).to.equal(utils.parseEther("100")); 19 | expect(await erc20.balanceOf(user1.address)).to.equal(utils.parseEther("100")); 20 | expect(await erc20.balanceOf(user2.address)).to.equal(0); 21 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(0); 22 | expect(await erc20.allowance(user2.address, user1.address)).to.equal(0); 23 | }) 24 | 25 | describe("transfer", function() { 26 | it("fails with insufficient balance", async function() { 27 | await expect(erc20.connect(user1).transfer(user2.address, utils.parseEther("101"))).to.be.revertedWith("ERC20: transfer amount exceeds balance"); 28 | }) 29 | 30 | it("works as expected", async function() { 31 | await erc20.connect(user1).transfer(user2.address, utils.parseEther("5")); 32 | 33 | expect(await erc20.totalSupply()).to.equal(utils.parseEther("100")); 34 | expect(await erc20.balanceOf(user1.address)).to.equal(utils.parseEther("95")); 35 | expect(await erc20.balanceOf(user2.address)).to.equal(utils.parseEther("5")); 36 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(0); 37 | expect(await erc20.allowance(user2.address, user1.address)).to.equal(0); 38 | }) 39 | }) 40 | 41 | it("approve works as expected", async function() { 42 | await erc20.connect(user1).approve(user2.address, utils.parseEther("5000")); 43 | 44 | expect(await erc20.balanceOf(user1.address)).to.equal(utils.parseEther("100")); 45 | expect(await erc20.balanceOf(user2.address)).to.equal(0); 46 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(utils.parseEther("5000")); 47 | expect(await erc20.allowance(user2.address, user1.address)).to.equal(0); 48 | }) 49 | 50 | describe("transferFrom", function() { 51 | it("Fails with insufficient approval", async function() { 52 | await expect(erc20.transferFrom(user1.address, user2.address, 1)).to.be.revertedWith("ERC20: transfer amount exceeds allowance"); 53 | }) 54 | 55 | it("works as expected", async function() { 56 | await erc20.connect(user1).approve(user2.address, utils.parseEther("5")); 57 | await erc20.connect(user2).transferFrom(user1.address, user2.address, utils.parseEther("5")); 58 | 59 | expect(await erc20.totalSupply()).to.equal(utils.parseEther("100")); 60 | expect(await erc20.balanceOf(user1.address)).to.equal(utils.parseEther("95")); 61 | expect(await erc20.balanceOf(user2.address)).to.equal(utils.parseEther("5")); 62 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(0); 63 | expect(await erc20.allowance(user2.address, user1.address)).to.equal(0); 64 | }) 65 | 66 | it("doesn't adjust allowance if allowance is max", async function() { 67 | await erc20.connect(user1).approve(user2.address, constants.MaxUint256); 68 | await erc20.connect(user2).transferFrom(user1.address, user2.address, utils.parseEther("5")); 69 | 70 | expect(await erc20.totalSupply()).to.equal(utils.parseEther("100")); 71 | expect(await erc20.balanceOf(user1.address)).to.equal(utils.parseEther("95")); 72 | expect(await erc20.balanceOf(user2.address)).to.equal(utils.parseEther("5")); 73 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(constants.MaxUint256); 74 | expect(await erc20.allowance(user2.address, user1.address)).to.equal(0); 75 | }) 76 | }) 77 | 78 | it("increaseAllowance works as expected", async function() { 79 | await erc20.connect(user1).increaseAllowance(user2.address, 5); 80 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(5); 81 | await erc20.connect(user1).increaseAllowance(user2.address, 6); 82 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(11); 83 | await expect(erc20.connect(user1).increaseAllowance(user2.address, constants.MaxUint256)).to.be.revertedWith("SafeMath: addition overflow"); 84 | }) 85 | 86 | it("decreaseAllowance works as expected", async function() { 87 | await erc20.connect(user1).approve(user2.address, 11); 88 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(11); 89 | await erc20.connect(user1).decreaseAllowance(user2.address, 6); 90 | expect(await erc20.allowance(user1.address, user2.address)).to.equal(5); 91 | await expect(erc20.connect(user1).decreaseAllowance(user2.address, 6)).to.be.revertedWith("ERC20: decreased allowance below zero"); 92 | }) 93 | }) -------------------------------------------------------------------------------- /test/ERC31337.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { ethers } = require("hardhat"); 3 | const { createWETH, createUniswap } = require("./helpers"); 4 | const { utils, constants } = require("ethers"); 5 | 6 | describe("ERC31337", function() { 7 | let erc20, owner, erc31337, user1, rootKit, uniswap, user2; 8 | 9 | beforeEach(async function() { 10 | [owner, user1, user2] = await ethers.getSigners(); 11 | var erc20Factory = await ethers.getContractFactory("ERC20Test"); 12 | erc20 = await erc20Factory.connect(owner).deploy(); 13 | var erc31337Factory = await ethers.getContractFactory("ERC31337"); 14 | const rootKitFactory = await ethers.getContractFactory("RootKit"); 15 | rootKit = await rootKitFactory.deploy(); 16 | erc31337 = await erc31337Factory.deploy(erc20.address, "RootKit [Test]", "RK:TST"); 17 | const weth = await createWETH(); 18 | uniswap = await createUniswap(owner, weth); 19 | }); 20 | 21 | it("initializes as expected", async function() { 22 | expect(await erc31337.name()).to.equal("RootKit [Test]"); 23 | expect(await erc31337.symbol()).to.equal("RK:TST"); 24 | expect(await erc31337.decimals()).to.equal(18); 25 | expect(await erc31337.totalSupply()).to.equal(0); 26 | expect(await erc31337.floorCalculator()).to.equal(constants.AddressZero); 27 | }) 28 | 29 | it("deposit and withdrawal work as expected", async function() { 30 | await erc20.connect(owner).approve(erc31337.address, utils.parseEther("5")); 31 | await erc31337.connect(owner).depositTokens(utils.parseEther("5")); 32 | expect(await erc20.balanceOf(owner.address)).to.equal(utils.parseEther("95")); 33 | expect(await erc31337.balanceOf(owner.address)).to.equal(utils.parseEther("5")); 34 | expect(await erc31337.totalSupply()).to.equal(utils.parseEther("5")); 35 | 36 | await erc31337.connect(owner).transfer(user1.address, utils.parseEther("3")); 37 | await erc31337.connect(user1).withdrawTokens(utils.parseEther("3")); 38 | expect(await erc20.balanceOf(owner.address)).to.equal(utils.parseEther("95")); 39 | expect(await erc20.balanceOf(user1.address)).to.equal(utils.parseEther("3")); 40 | expect(await erc31337.balanceOf(owner.address)).to.equal(utils.parseEther("2")); 41 | expect(await erc31337.totalSupply()).to.equal(utils.parseEther("2")); 42 | }) 43 | 44 | it("setFloorCalculator doesn't work for non-owner", async function() { 45 | await expect(erc31337.connect(user1).setFloorCalculator(owner.address)).to.be.revertedWith("Owner only"); 46 | }) 47 | 48 | it("sweepFloor doesn't work for non-sweeper", async function() { 49 | await expect(erc31337.connect(user1).sweepFloor(owner.address)).to.be.revertedWith("Sweepers only"); 50 | await expect(erc31337.connect(owner).sweepFloor(owner.address)).to.be.revertedWith("Sweepers only"); 51 | }) 52 | 53 | it("setSweeper doesn't work for non-owner", async function() { 54 | await expect(erc31337.connect(user1).setSweeper(owner.address, true)).to.be.revertedWith("Owner only"); 55 | }) 56 | 57 | describe("setFloorCalculator(RootKitFloorCalculator)", function() { 58 | let rootKitFloorCalculator; 59 | 60 | beforeEach(async function() { 61 | const rootKitFloorCalculatorFactory = await ethers.getContractFactory("RootKitFloorCalculator"); 62 | rootKitFloorCalculator = await rootKitFloorCalculatorFactory.connect(owner).deploy(rootKit.address, uniswap.factory.address); 63 | await erc31337.connect(owner).setFloorCalculator(rootKitFloorCalculator.address); 64 | await erc31337.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 65 | await rootKit.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 66 | await erc20.connect(owner).approve(erc31337.address, constants.MaxUint256); 67 | await erc31337.connect(owner).depositTokens(utils.parseEther("1")); 68 | await uniswap.router.connect(owner).addLiquidity(erc31337.address, rootKit.address, utils.parseEther("1"), utils.parseEther("5000"), utils.parseEther("1"), utils.parseEther("5000"), owner.address, 2e9); 69 | }) 70 | 71 | it("initializes correctly", async function() { 72 | expect(await erc31337.floorCalculator()).to.equal(rootKitFloorCalculator.address); 73 | }) 74 | 75 | it("sweepFloor works", async function() { 76 | await erc31337.connect(owner).setSweeper(owner.address, true); 77 | await erc31337.connect(owner).sweepFloor(user2.address); 78 | const erc20Balance = await erc20.balanceOf(user2.address); 79 | await erc31337.connect(owner).sweepFloor(user2.address); 80 | const erc20Balance2 = await erc20.balanceOf(user2.address); 81 | expect(erc20Balance).to.equal("500751126690035053"); 82 | expect(erc20Balance).to.equal(erc20Balance2); 83 | }) 84 | }) 85 | }); -------------------------------------------------------------------------------- /test/GrootGrower.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { utils, constants } = require("ethers"); 3 | const { parseEther } = require("ethers/lib/utils"); 4 | const { ethers } = require("hardhat"); 5 | const { createWETH, createUniswap } = require("./helpers"); 6 | 7 | describe("GrootGrower", function() { 8 | let owner, user1; 9 | let uniswap, weth, grootKit, grootGrower, wethGroot; 10 | 11 | beforeEach(async function() { 12 | [owner, user1] = await ethers.getSigners(); 13 | weth = await createWETH(); 14 | uniswap = await createUniswap(owner, weth); 15 | const grootKitFactory = await ethers.getContractFactory("GrootKit"); 16 | grootKit = await grootKitFactory.connect(owner).deploy(); 17 | await uniswap.factory.createPair(grootKit.address, weth.address); 18 | const grootGrowerFactory = await ethers.getContractFactory("GrootGrower"); 19 | grootGrower = await grootGrowerFactory.connect(owner).deploy(grootKit.address, weth.address, uniswap.router.address); 20 | wethGroot = uniswap.pairFor(await uniswap.factory.getPair(grootKit.address, weth.address)); 21 | await grootKit.connect(owner).setLiquidityController(owner.address, true); 22 | await grootKit.connect(owner).setLiquidityController(grootGrower.address, true); 23 | }) 24 | 25 | it("initializes correctly", async function() { 26 | const parameters = await grootGrower.parameters(); 27 | expect(parameters.nextGrowTimestamp).to.equal(0); 28 | expect(parameters.growInterval).to.equal(0); 29 | expect(parameters.redeemPercent).to.equal(0); 30 | expect(parameters.buyPercent).to.equal(0); 31 | }) 32 | 33 | it("owner-only functions can't be called by non-owner", async function() { 34 | await expect(grootGrower.connect(user1).setParameters(0,0,0)).to.be.revertedWith("Owner only"); 35 | }); 36 | 37 | describe("Liquidity added, sent to groot grower", function() { 38 | const startingWeth = utils.parseEther("10"); 39 | const startingGroot = utils.parseEther("1000000"); 40 | beforeEach(async function() { 41 | await weth.connect(owner).deposit({ value: startingWeth }); 42 | await weth.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 43 | await grootKit.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 44 | await uniswap.router.connect(owner).addLiquidity(weth.address, grootKit.address, startingWeth, startingGroot, 0, 0, grootGrower.address, 2e9); 45 | await grootKit.connect(owner).setLiquidityLock(wethGroot.address, true); 46 | }) 47 | 48 | describe("setParameters(1, 9900, 260)", function() { 49 | beforeEach(async function() { 50 | await grootGrower.connect(owner).setParameters(1, 9900, 260); 51 | }) 52 | 53 | it("initializes correctly", async function() { 54 | const parameters = await grootGrower.parameters(); 55 | expect(parameters.nextGrowTimestamp).not.to.equal(0); 56 | expect(parameters.growInterval).to.equal(1); 57 | expect(parameters.redeemPercent).to.equal(9900); 58 | expect(parameters.buyPercent).to.equal(260); 59 | }) 60 | 61 | it("grow() works", async function() { 62 | await grootGrower.connect(user1).grow(); 63 | await grootGrower.connect(user1).grow(); 64 | await grootGrower.connect(user1).grow(); 65 | await grootGrower.connect(user1).grow(); 66 | await grootGrower.connect(user1).grow(); 67 | await grootGrower.connect(user1).grow(); 68 | await grootGrower.connect(user1).grow(); 69 | console.log("WETH: " + utils.formatEther(await weth.balanceOf(grootGrower.address))); 70 | console.log("Groot: " + utils.formatEther(await grootKit.balanceOf(grootGrower.address))); 71 | }) 72 | }) 73 | 74 | describe("setParameters(100, 9900, 260)", function() { 75 | beforeEach(async function() { 76 | await grootGrower.connect(owner).setParameters(100, 9900, 260); 77 | }) 78 | 79 | it("initializes correctly", async function() { 80 | const parameters = await grootGrower.parameters(); 81 | expect(parameters.nextGrowTimestamp).not.to.equal(0); 82 | expect(parameters.growInterval).to.equal(100); 83 | expect(parameters.redeemPercent).to.equal(9900); 84 | expect(parameters.buyPercent).to.equal(260); 85 | }) 86 | 87 | it("grow() doesn't work until enough time has passed", async function() { 88 | await expect(grootGrower.connect(user1).grow()).to.be.revertedWith("Too early to grow"); 89 | await ethers.provider.send("evm_increaseTime", [100]); 90 | await grootGrower.connect(user1).grow(); 91 | await expect(grootGrower.connect(user1).grow()).to.be.revertedWith("Too early to grow"); 92 | await ethers.provider.send("evm_increaseTime", [100]); 93 | await grootGrower.connect(user1).grow(); 94 | await expect(grootGrower.connect(user1).grow()).to.be.revertedWith("Too early to grow"); 95 | await ethers.provider.send("evm_increaseTime", [100]); 96 | await grootGrower.connect(user1).grow(); 97 | await expect(grootGrower.connect(user1).grow()).to.be.revertedWith("Too early to grow"); 98 | }) 99 | }) 100 | }) 101 | }) -------------------------------------------------------------------------------- /test/GrootKit.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { utils } = require("ethers"); 3 | const { expect } = require("chai"); 4 | 5 | describe("GrootKit", function() { 6 | let grootKit, owner; 7 | 8 | beforeEach(async function() { 9 | [owner] = await ethers.getSigners(); 10 | const grootKitFactory = await ethers.getContractFactory("GrootKit"); 11 | grootKit = await grootKitFactory.connect(owner).deploy(); 12 | }) 13 | 14 | it("initialized correctly", async function() { 15 | expect(await grootKit.name()).to.equal("GrootKit"); 16 | expect(await grootKit.symbol()).to.equal("GROOT"); 17 | expect(await grootKit.decimals()).to.equal(18); 18 | expect(await grootKit.totalSupply()).to.equal(utils.parseEther("1000000")); 19 | expect(await grootKit.balanceOf(owner.address)).to.equal(utils.parseEther("1000000")); 20 | }) 21 | }); -------------------------------------------------------------------------------- /test/KETH.js: -------------------------------------------------------------------------------- 1 | const { createWETH, createUniswap } = require("./helpers.js"); 2 | const { ethers } = require("hardhat"); 3 | const { expect } = require("chai"); 4 | 5 | 6 | describe("KETH", function() { 7 | let weth, keth, owner; 8 | 9 | beforeEach(async function() { 10 | [owner] = await ethers.getSigners(); 11 | weth = await createWETH(); 12 | const kethFactory = await ethers.getContractFactory("KETH"); 13 | keth = await kethFactory.deploy(weth.address); 14 | }) 15 | 16 | it("can deposit and withdraw ETH", async function() { 17 | await owner.sendTransaction({ to: keth.address, value: 5 }); 18 | expect(await keth.balanceOf(owner.address)).to.equal(5); 19 | expect(await keth.totalSupply()).to.equal(5); 20 | 21 | await keth.connect(owner).deposit({ value: 6 }); 22 | expect(await keth.balanceOf(owner.address)).to.equal(11); 23 | expect(await keth.totalSupply()).to.equal(11); 24 | 25 | await weth.connect(owner).deposit({ value: 7 }); 26 | expect(await weth.balanceOf(owner.address)).to.equal(7); 27 | await expect(keth.depositTokens(7)).to.be.revertedWith("weth c: not enough allowance"); 28 | await weth.approve(keth.address, 7); 29 | await keth.depositTokens(7); 30 | expect(await weth.balanceOf(owner.address)).to.equal(0); 31 | expect(await keth.balanceOf(owner.address)).to.equal(18); 32 | expect(await keth.totalSupply()).to.equal(18); 33 | 34 | await keth.connect(owner).withdrawTokens(3); 35 | expect(await weth.balanceOf(owner.address)).to.equal(3); 36 | expect(await keth.balanceOf(owner.address)).to.equal(15); 37 | expect(await keth.totalSupply()).to.equal(15); 38 | 39 | await keth.connect(owner).withdraw(4); 40 | expect(await weth.balanceOf(owner.address)).to.equal(3); 41 | expect(await keth.balanceOf(owner.address)).to.equal(11); 42 | expect(await keth.totalSupply()).to.equal(11); 43 | 44 | await expect(keth.connect(owner).withdraw(12)).to.be.revertedWith("ERC20: burn amount exceeds balance"); 45 | }); 46 | }) -------------------------------------------------------------------------------- /test/Owned.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { expect } = require("chai"); 3 | 4 | describe("Owned", function() { 5 | let owned, owner, user1; 6 | 7 | beforeEach(async function() { 8 | [owner, user1] = await ethers.getSigners(); 9 | const ownedFactory = await ethers.getContractFactory("OwnedTest"); 10 | owned = await ownedFactory.connect(owner).deploy(); 11 | }) 12 | 13 | it("owner starts as creator", async function() { 14 | expect(await owned.owner()).to.equal(owner.address); 15 | }) 16 | 17 | it("transferOwnership works", async function() { 18 | await owned.connect(owner).transferOwnership(user1.address); 19 | }) 20 | it("transferOwnership fails for non-owner", async function() { 21 | await expect(owned.connect(user1).transferOwnership(user1.address)).to.be.revertedWith("Owner only"); 22 | }) 23 | 24 | describe("transferOwnership(user1)", function() { 25 | beforeEach(async function() { 26 | await owned.connect(owner).transferOwnership(user1.address); 27 | }) 28 | 29 | it("claimOwnership from non-user1 fails", async function() { 30 | await expect(owned.connect(owner).claimOwnership()).to.be.revertedWith(); 31 | }) 32 | 33 | it("claimOwnership for user1 makes user1 owner", async function() { 34 | await owned.connect(user1).claimOwnership(); 35 | expect(await owned.owner()).to.equal(user1.address); 36 | }) 37 | 38 | it("claimOwnership emits OwnedshipTransferred", async function() { 39 | await expect(owned.connect(user1).claimOwnership()).to.emit(owned, "OwnershipTransferred").withArgs(owner.address, user1.address); 40 | }) 41 | }) 42 | }) -------------------------------------------------------------------------------- /test/RootKit.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { utils } = require("ethers"); 3 | const { expect } = require("chai"); 4 | 5 | describe("RootKit", function() { 6 | let rootKit, owner; 7 | 8 | beforeEach(async function() { 9 | [owner] = await ethers.getSigners(); 10 | const rootKitFactory = await ethers.getContractFactory("RootKit"); 11 | rootKit = await rootKitFactory.connect(owner).deploy(); 12 | }) 13 | 14 | it("initialized correctly", async function() { 15 | expect(await rootKit.name()).to.equal("RootKit"); 16 | expect(await rootKit.symbol()).to.equal("ROOT"); 17 | expect(await rootKit.decimals()).to.equal(18); 18 | expect(await rootKit.totalSupply()).to.equal(utils.parseEther("10000")); 19 | expect(await rootKit.balanceOf(owner.address)).to.equal(utils.parseEther("10000")); 20 | }) 21 | }); -------------------------------------------------------------------------------- /test/RootKitDirect.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { utils, constants, BigNumber } = require("ethers"); 3 | const { ethers } = require("hardhat"); 4 | const { createWETH, createUniswap } = require("./helpers"); 5 | 6 | describe("RootKitDirect", function() { 7 | let owner, user1, user2, vault; 8 | let rootKit, keth, rootKitLiquidityGeneration, rootKitDistribution, uniswap, rootKitDirect; 9 | 10 | beforeEach(async function() { 11 | [owner, user1, user2, vault] = await ethers.getSigners(); 12 | const weth = await createWETH(); 13 | uniswap = await createUniswap(owner, weth); 14 | const rootKitFactory = await ethers.getContractFactory("RootKit"); 15 | const rootKitLiquidityGenerationFactory = await ethers.getContractFactory("RootKitLiquidityGeneration"); 16 | const rootKitDistributionFactory = await ethers.getContractFactory("RootKitDistribution"); 17 | rootKit = await rootKitFactory.connect(owner).deploy(); 18 | const kethFactory = await ethers.getContractFactory("KETH"); 19 | keth = await kethFactory.connect(owner).deploy(weth.address); 20 | rootKitLiquidityGeneration = await rootKitLiquidityGenerationFactory.connect(owner).deploy(rootKit.address); 21 | rootKitDistribution = await rootKitDistributionFactory.connect(owner).deploy(rootKit.address, uniswap.router.address, keth.address, uniswap.wbtc.address, vault.address); 22 | await rootKitDistribution.connect(owner).setupKethRootKit(); 23 | await rootKitDistribution.connect(owner).setupWbtcRootKit(); 24 | const rootKitLiquidityFactory = await ethers.getContractFactory("RootKitLiquidity"); 25 | const kethRootKit = uniswap.pairFor(await uniswap.factory.getPair(keth.address, rootKit.address)); 26 | const wbtcRootKit = uniswap.pairFor(await uniswap.factory.getPair(uniswap.wbtc.address, rootKit.address)); 27 | const wrappedKethRootKit = await rootKitLiquidityFactory.connect(owner).deploy(kethRootKit.address, "a", "b"); 28 | const wrappedWbtcRootKit = await rootKitLiquidityFactory.connect(owner).deploy(wbtcRootKit.address, "a", "b"); 29 | await rootKitDistribution.connect(owner).setupKethRootKit(); 30 | await rootKitDistribution.connect(owner).completeSetup(wrappedKethRootKit.address, wrappedWbtcRootKit.address); 31 | await rootKit.connect(owner).transfer(rootKitLiquidityGeneration.address, await rootKit.totalSupply()); 32 | await rootKitLiquidityGeneration.connect(owner).activate(rootKitDistribution.address); 33 | await user1.sendTransaction({ to: rootKitLiquidityGeneration.address, value: utils.parseEther("1") }); 34 | const rootKitTransferGateFactory = await ethers.getContractFactory("RootKitTransferGate"); 35 | const rootKitTransferGate = await rootKitTransferGateFactory.connect(owner).deploy(rootKit.address, uniswap.router.address); 36 | await rootKit.connect(owner).setTransferGate(rootKitTransferGate.address); 37 | const rootKitFloorCalculatorFactory = await ethers.getContractFactory("RootKitFloorCalculator"); 38 | const rootKitFloorCalculator = await rootKitFloorCalculatorFactory.connect(owner).deploy(rootKit.address, uniswap.factory.address); 39 | await keth.setSweeper(rootKitDistribution.address, true); 40 | await rootKitTransferGate.connect(owner).setUnrestrictedController(rootKitDistribution.address, true); 41 | await keth.connect(owner).setFloorCalculator(rootKitFloorCalculator.address); 42 | await rootKitLiquidityGeneration.connect(owner).complete(); 43 | await rootKitLiquidityGeneration.connect(user1).claim(); 44 | const rootKitDirectFactory = await ethers.getContractFactory("RootKitDirect"); 45 | rootKitDirect = await rootKitDirectFactory.connect(owner).deploy(keth.address, rootKit.address, uniswap.router.address); 46 | await rootKitTransferGate.allowPool(keth.address); 47 | await rootKit.connect(user1).approve(rootKitDirect.address, constants.MaxUint256); 48 | await rootKitTransferGate.setUnrestrictedController(rootKitDirect.address, true); 49 | }) 50 | 51 | it("buy", async function() { 52 | await rootKitDirect.connect(user2).buy(0, { value: utils.parseEther("1") }); 53 | expect(await rootKit.balanceOf(user2.address)).not.to.equal("0"); 54 | }) 55 | 56 | it("easyBuy", async function() { 57 | await rootKitDirect.connect(user2).easyBuy({ value: utils.parseEther("1") }); 58 | expect(await rootKit.balanceOf(user2.address)).not.to.equal("0"); 59 | }) 60 | 61 | it("sell", async function() { 62 | const oldBalance = BigNumber.from(await ethers.provider.getBalance(user1.address)); 63 | await rootKitDirect.connect(user1).sell(utils.parseEther("1"), 0, { gasPrice: 0 }); 64 | const newBalance = BigNumber.from(await ethers.provider.getBalance(user1.address)); 65 | expect(newBalance.gt(oldBalance)).to.equal(true); 66 | }) 67 | 68 | it("easySell", async function() { 69 | const oldBalance = BigNumber.from(await ethers.provider.getBalance(user1.address)); 70 | await rootKitDirect.connect(user1).easySell(utils.parseEther("1"), { gasPrice: 0 }); 71 | const newBalance = BigNumber.from(await ethers.provider.getBalance(user1.address)); 72 | expect(newBalance.gt(oldBalance)).to.equal(true); 73 | }) 74 | }) -------------------------------------------------------------------------------- /test/RootKitFloorCalculator.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { utils, constants, BigNumber } = require("ethers"); 3 | const { ethers } = require("hardhat"); 4 | const { createWETH, createUniswap } = require("./helpers"); 5 | 6 | describe("RootKitFloorCalculator", function() { 7 | let uniswap, rootKit, owner, weth, keth, rootKitFloorCalculator; 8 | 9 | beforeEach(async function() { 10 | [owner] = await ethers.getSigners(); 11 | weth = await createWETH(); 12 | uniswap = await createUniswap(owner, weth); 13 | const rootKitFactory = await ethers.getContractFactory("RootKit"); 14 | rootKit = await rootKitFactory.connect(owner).deploy(); 15 | const rootKitFloorCalculatorFactory = await ethers.getContractFactory("RootKitFloorCalculator"); 16 | rootKitFloorCalculator = await rootKitFloorCalculatorFactory.deploy(rootKit.address, uniswap.factory.address); 17 | const kethFactory = await ethers.getContractFactory("KETH"); 18 | keth = await kethFactory.connect(owner).deploy(weth.address); 19 | }) 20 | 21 | describe("pair has 5000 ROOT & 1 KETH", function() { 22 | beforeEach(async function() { 23 | await keth.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 24 | await rootKit.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 25 | await owner.sendTransaction({ to: keth.address, value: utils.parseEther("1") }); 26 | await uniswap.router.connect(owner).addLiquidity(rootKit.address, keth.address, utils.parseEther("5000"), utils.parseEther("1"), utils.parseEther("100"), utils.parseEther("1"), owner.address, 2e9); 27 | }) 28 | 29 | it("subfloor is approx 0.5", async function() { 30 | const subFloor = BigNumber.from(await rootKitFloorCalculator.calculateSubFloor(weth.address, keth.address)); 31 | expect(subFloor).to.equal("500751126690035053"); 32 | }) 33 | }) 34 | }); -------------------------------------------------------------------------------- /test/RootKitRuggableFloorCalculator.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { constants } = require("ethers"); 3 | const { ethers } = require("hardhat"); 4 | 5 | describe("RootKitRuggableFloorCalculator", function() { 6 | let owner, user1; 7 | let rootKitRuggableFloorCalculator; 8 | 9 | beforeEach(async function() { 10 | [owner, user1] = await ethers.getSigners(); 11 | const rootKitRuggableFloorCalculatorFactory = await ethers.getContractFactory("RootKitRuggableFloorCalculator"); 12 | rootKitRuggableFloorCalculator = await rootKitRuggableFloorCalculatorFactory.connect(owner).deploy(); 13 | }) 14 | 15 | it("owner-only functions don't work for non-owner", async function() { 16 | await expect(rootKitRuggableFloorCalculator.connect(user1).setSubFloor(0)).to.be.revertedWith("Owner only"); 17 | }) 18 | 19 | it("calculateSubFloor returns whatever setSubFloor sets", async function() { 20 | expect(await rootKitRuggableFloorCalculator.calculateSubFloor(constants.AddressZero, constants.AddressZero)).to.equal(0); 21 | await rootKitRuggableFloorCalculator.connect(owner).setSubFloor(1); 22 | expect(await rootKitRuggableFloorCalculator.calculateSubFloor(constants.AddressZero, constants.AddressZero)).to.equal(1); 23 | await rootKitRuggableFloorCalculator.connect(owner).setSubFloor(3); 24 | expect(await rootKitRuggableFloorCalculator.calculateSubFloor(constants.AddressZero, constants.AddressZero)).to.equal(3); 25 | }) 26 | }) -------------------------------------------------------------------------------- /test/RootKitVault.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { utils, BigNumber } = require("ethers"); 3 | const { ethers } = require("hardhat"); 4 | 5 | describe("RootKitVault", function() { 6 | let owner, user1, rootKitVault, erc20; 7 | 8 | beforeEach(async function() { 9 | [owner, user1] = await ethers.getSigners(); 10 | const rootKitVaultFactory = await ethers.getContractFactory("RootKitVault"); 11 | rootKitVault = await rootKitVaultFactory.connect(owner).deploy(); 12 | const erc20Factory = await ethers.getContractFactory("ERC20Test"); 13 | erc20 = await erc20Factory.connect(owner).deploy(); 14 | 15 | await owner.sendTransaction({ to: rootKitVault.address, value: utils.parseEther("2") }); 16 | await erc20.connect(owner).transfer(rootKitVault.address, utils.parseEther("2")); 17 | }) 18 | 19 | it("Can't send ETH or tokens from non-owner", async function() { 20 | await expect(rootKitVault.connect(user1).sendEther(user1.address, 1)).to.be.revertedWith("Owner only"); 21 | await expect(rootKitVault.connect(user1).sendToken(erc20.address, user1.address, 1)).to.be.revertedWith("Owner only"); 22 | }) 23 | 24 | it("Can send ETH", async function() { 25 | const balance = BigNumber.from(await ethers.provider.getBalance(user1.address)); 26 | await rootKitVault.connect(owner).sendEther(user1.address, 1); 27 | expect(BigNumber.from(await ethers.provider.getBalance(user1.address)).toString()).to.equal(balance.add(1).toString()); 28 | }) 29 | 30 | it("Can send tokens", async function() { 31 | await rootKitVault.connect(owner).sendToken(erc20.address, user1.address, 1); 32 | expect(await erc20.balanceOf(user1.address)).to.equal("1"); 33 | }) 34 | }) -------------------------------------------------------------------------------- /test/RootWethZapper.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { utils, constants, BigNumber } = require("ethers"); 3 | const { ethers } = require("hardhat"); 4 | const { createWETH, createUniswap } = require("./helpers"); 5 | 6 | describe("RootWethZapper", function() { 7 | let owner, user1, user2, vault; 8 | let rootKit, weth, keth, rootKitLiquidityGeneration, rootKitDistribution, uniswap, rootWethZapper; 9 | 10 | beforeEach(async function() { 11 | [owner, user1, user2, vault] = await ethers.getSigners(); 12 | weth = await createWETH(); 13 | uniswap = await createUniswap(owner, weth); 14 | const rootKitFactory = await ethers.getContractFactory("RootKit"); 15 | const rootKitLiquidityGenerationFactory = await ethers.getContractFactory("RootKitLiquidityGeneration"); 16 | const rootKitDistributionFactory = await ethers.getContractFactory("RootKitDistribution"); 17 | rootKit = await rootKitFactory.connect(owner).deploy(); 18 | const kethFactory = await ethers.getContractFactory("KETH"); 19 | keth = await kethFactory.connect(owner).deploy(weth.address); 20 | rootKitLiquidityGeneration = await rootKitLiquidityGenerationFactory.connect(owner).deploy(rootKit.address); 21 | rootKitDistribution = await rootKitDistributionFactory.connect(owner).deploy(rootKit.address, uniswap.router.address, keth.address, uniswap.wbtc.address, vault.address); 22 | await rootKitDistribution.connect(owner).setupKethRootKit(); 23 | await rootKitDistribution.connect(owner).setupWbtcRootKit(); 24 | const rootKitLiquidityFactory = await ethers.getContractFactory("RootKitLiquidity"); 25 | const kethRootKit = uniswap.pairFor(await uniswap.factory.getPair(keth.address, rootKit.address)); 26 | const wbtcRootKit = uniswap.pairFor(await uniswap.factory.getPair(uniswap.wbtc.address, rootKit.address)); 27 | const wrappedKethRootKit = await rootKitLiquidityFactory.connect(owner).deploy(kethRootKit.address, "a", "b"); 28 | const wrappedWbtcRootKit = await rootKitLiquidityFactory.connect(owner).deploy(wbtcRootKit.address, "a", "b"); 29 | await rootKitDistribution.connect(owner).setupKethRootKit(); 30 | await rootKitDistribution.connect(owner).completeSetup(wrappedKethRootKit.address, wrappedWbtcRootKit.address); 31 | await rootKit.connect(owner).transfer(rootKitLiquidityGeneration.address, await rootKit.totalSupply()); 32 | await rootKitLiquidityGeneration.connect(owner).activate(rootKitDistribution.address); 33 | await user1.sendTransaction({ to: rootKitLiquidityGeneration.address, value: utils.parseEther("1") }); 34 | const rootKitTransferGateFactory = await ethers.getContractFactory("RootKitTransferGate"); 35 | const rootKitTransferGate = await rootKitTransferGateFactory.connect(owner).deploy(rootKit.address, uniswap.router.address); 36 | await rootKit.connect(owner).setTransferGate(rootKitTransferGate.address); 37 | const rootKitFloorCalculatorFactory = await ethers.getContractFactory("RootKitFloorCalculator"); 38 | const rootKitFloorCalculator = await rootKitFloorCalculatorFactory.connect(owner).deploy(rootKit.address, uniswap.factory.address); 39 | await keth.setSweeper(rootKitDistribution.address, true); 40 | await rootKitTransferGate.connect(owner).setUnrestrictedController(rootKitDistribution.address, true); 41 | await keth.connect(owner).setFloorCalculator(rootKitFloorCalculator.address); 42 | await rootKitLiquidityGeneration.connect(owner).complete(); 43 | await rootKitLiquidityGeneration.connect(user1).claim(); 44 | const rootWethZapperFactory = await ethers.getContractFactory("RootWethZapper"); 45 | rootWethZapper = await rootWethZapperFactory.connect(owner).deploy(); 46 | await rootKitTransferGate.connect(owner).setUnrestrictedController(rootWethZapper.address, true); 47 | await rootKit.connect(user1).transfer(owner.address, utils.parseEther("3")); 48 | }) 49 | 50 | it("go", async function() { 51 | const wethAmount = utils.parseEther("1"); 52 | const rootKitAmount = utils.parseEther("2"); 53 | await owner.sendTransaction({ to: weth.address, value: wethAmount }); 54 | await weth.connect(owner).approve(rootWethZapper.address, wethAmount); 55 | await rootKit.connect(owner).approve(rootWethZapper.address, rootKitAmount); 56 | await rootWethZapper.connect(owner).go(weth.address, rootKit.address, wethAmount, rootKitAmount, uniswap.router.address); 57 | const wethRootKit = uniswap.pairFor(await uniswap.factory.getPair(weth.address, rootKit.address)); 58 | }) 59 | 60 | }) -------------------------------------------------------------------------------- /test/TokensRecoverable.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { ethers } = require("hardhat"); 3 | 4 | describe("TokensRecoverable", function() { 5 | let owner, user1, tokensRecoverable, erc20; 6 | 7 | beforeEach(async function() { 8 | [owner, user1] = await ethers.getSigners(); 9 | const erc20Factory = await ethers.getContractFactory("ERC20Test"); 10 | const tokensRecoverableFactory = await ethers.getContractFactory("TokensRecoverableTest"); 11 | erc20 = await erc20Factory.connect(owner).deploy(); 12 | tokensRecoverable = await tokensRecoverableFactory.connect(owner).deploy(); 13 | await erc20.connect(owner).transfer(tokensRecoverable.address, 10000); 14 | }) 15 | 16 | it("Fails when canRecover is false", async function() { 17 | await tokensRecoverable.setCanRecover(false); 18 | await expect(tokensRecoverable.connect(owner).recoverTokens(erc20.address)).to.be.revertedWith(); 19 | await expect(tokensRecoverable.connect(user1).recoverTokens(erc20.address)).to.be.revertedWith("Owner only"); 20 | }) 21 | 22 | it("Succeeds when canRecover is true", async function() { 23 | await tokensRecoverable.setCanRecover(true); 24 | await expect(tokensRecoverable.connect(user1).recoverTokens(erc20.address)).to.be.revertedWith("Owner only"); 25 | await tokensRecoverable.connect(owner).recoverTokens(erc20.address); 26 | expect(await erc20.balanceOf(tokensRecoverable.address)).to.equal(0); 27 | expect(await erc20.balanceOf(owner.address)).to.equal(await erc20.totalSupply()); 28 | await tokensRecoverable.connect(owner).recoverTokens(erc20.address); 29 | }) 30 | 31 | }) -------------------------------------------------------------------------------- /test/WbtcToWethLiquidityZapper.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { utils, constants, BigNumber } = require("ethers"); 3 | const { ethers } = require("hardhat"); 4 | const { createWETH, createUniswap } = require("./helpers.js"); 5 | 6 | describe("WbtcToWethLiquidityZapper", function() { 7 | let owner, user1; 8 | let wbtcToWethLiquidityZapper, uniswap, weth, rootKit, wbtcRootKit, wethRootKit, wrappedWbtcRootKit, wrappedWethRootKit, rootKitRuggableFloorCalculator; 9 | 10 | beforeEach(async function() { 11 | [owner, user1] = await ethers.getSigners(); 12 | const rootKitFactory = await ethers.getContractFactory("RootKit"); 13 | rootKit = await rootKitFactory.connect(owner).deploy(); 14 | weth = await createWETH(); 15 | uniswap = await createUniswap(owner, weth); 16 | await uniswap.factory.createPair(uniswap.wbtc.address, rootKit.address); 17 | await uniswap.factory.createPair(weth.address, rootKit.address); 18 | wbtcRootKit = uniswap.pairFor(await uniswap.factory.getPair(uniswap.wbtc.address, rootKit.address)); 19 | wethRootKit = uniswap.pairFor(await uniswap.factory.getPair(weth.address, rootKit.address)); 20 | const rootKitLiquidityFactory = await ethers.getContractFactory("RootKitLiquidity"); 21 | wrappedWbtcRootKit = await rootKitLiquidityFactory.connect(owner).deploy(wbtcRootKit.address, "a", "b"); 22 | wrappedWethRootKit = await rootKitLiquidityFactory.connect(owner).deploy(wethRootKit.address, "c", "d"); 23 | const wbtcToWethLiquidityZapperFactory = await ethers.getContractFactory("WbtcToWethLiquidityZapper"); 24 | wbtcToWethLiquidityZapper = await wbtcToWethLiquidityZapperFactory.connect(owner).deploy(uniswap.router.address, wrappedWbtcRootKit.address, rootKit.address); 25 | const rootKitRuggableFloorCalculatorFactory = await ethers.getContractFactory("RootKitRuggableFloorCalculator"); 26 | rootKitRuggableFloorCalculator = await rootKitRuggableFloorCalculatorFactory.connect(owner).deploy(); 27 | await wrappedWbtcRootKit.connect(owner).setFloorCalculator(rootKitRuggableFloorCalculator.address); 28 | await wrappedWbtcRootKit.connect(owner).setSweeper(wbtcToWethLiquidityZapper.address, true); 29 | const rootKitTransferGateFactory = await ethers.getContractFactory("RootKitTransferGate"); 30 | rootKitTransferGate = await rootKitTransferGateFactory.connect(owner).deploy(rootKit.address, uniswap.router.address); 31 | await rootKit.connect(owner).setTransferGate(rootKitTransferGate.address); 32 | await rootKitTransferGate.connect(owner).allowPool(weth.address); 33 | await rootKitTransferGate.connect(owner).allowPool(uniswap.wbtc.address); 34 | await rootKitTransferGate.connect(owner).setUnrestrictedController(wbtcToWethLiquidityZapper.address, true); 35 | 36 | const amt = utils.parseEther("10"); 37 | await rootKit.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 38 | await uniswap.wbtc.connect(owner).approve(uniswap.router.address, constants.MaxUint256); 39 | await wbtcRootKit.connect(owner).approve(wrappedWbtcRootKit.address, constants.MaxUint256); 40 | await uniswap.router.connect(owner).addLiquidity(rootKit.address, uniswap.wbtc.address, amt, amt, amt, amt, owner.address, 2e9); 41 | await wrappedWbtcRootKit.connect(owner).depositTokens(await wbtcRootKit.balanceOf(owner.address)); 42 | }) 43 | 44 | it("go() fails when nothing below floor", async function() { 45 | await expect(wbtcToWethLiquidityZapper.connect(owner).go()).to.be.revertedWith("Nothing unwrapped"); 46 | }) 47 | 48 | it("go() works", async function() { 49 | const wrappedWbtcRootKitSupply = BigNumber.from(await wrappedWbtcRootKit.totalSupply()); 50 | const wbtcRootKitRedeemed = wrappedWbtcRootKitSupply.div(2); 51 | await rootKitRuggableFloorCalculator.connect(owner).setSubFloor(wbtcRootKitRedeemed); 52 | await wbtcToWethLiquidityZapper.connect(owner).go(); 53 | }) 54 | }) -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { utils } = require("ethers"); 3 | 4 | const UniswapV2PairJson = require('../contracts/json/UniswapV2Pair.json'); 5 | const UniswapV2FactoryJson = require('../contracts/json/UniswapV2Factory.json'); 6 | const UniswapV2Router02Json = require('../contracts/json/UniswapV2Router02.json'); 7 | const UniswapV2LibraryJson = require('../contracts/json/UniswapV2Library.json'); 8 | 9 | exports.createWETH = async function() { 10 | const wethFactory = await ethers.getContractFactory("WETH9"); 11 | return await wethFactory.deploy(); 12 | } 13 | exports.createUniswap = async function(owner, weth) { 14 | const erc20Factory = await ethers.getContractFactory("ERC20Test"); 15 | const wbtc = await erc20Factory.connect(owner).deploy(); 16 | const factory = await new ethers.ContractFactory(UniswapV2FactoryJson.abi, UniswapV2FactoryJson.bytecode, owner).deploy(owner.address); 17 | const router = await new ethers.ContractFactory(UniswapV2Router02Json.abi, UniswapV2Router02Json.bytecode, owner).deploy(factory.address, weth.address); 18 | const library = await new ethers.ContractFactory(UniswapV2LibraryJson.abi, UniswapV2LibraryJson.bytecode, owner).deploy(); 19 | const amt = utils.parseEther("10"); 20 | await owner.sendTransaction({ to: weth.address, value: amt }); 21 | await weth.connect(owner).approve(router.address, amt); 22 | await wbtc.connect(owner).approve(router.address, amt); 23 | await router.connect(owner).addLiquidity(wbtc.address, weth.address, amt, amt, amt, amt, owner.address, 2e9); 24 | return { 25 | factory, 26 | router, 27 | library, 28 | wbtc, 29 | pairFor: address => new ethers.Contract(address, UniswapV2PairJson.abi, owner) 30 | }; 31 | } -------------------------------------------------------------------------------- /transferOwnership.js: -------------------------------------------------------------------------------- 1 | // 1. Double check addresses 2 | // 2. In the REMIX compile IOwned 3 | // 3. Right click on the script name and hit "Run" to execute 4 | (async () => { 5 | try { 6 | const newOwner = "0x50A73495b844195D510D41509D50F195bCfa371C"; 7 | const arbitrage = "0xcf53281777CeBcD2D2646E12Ca9e8fAeA0e1a3aF"; 8 | const calculator = "0xA12C55637E642C0e79C5923125cd7eeb8be3a53F"; 9 | const elite = "0x93747501F46Ae40b8A4B8F1a1529696AE24ea04e"; 10 | const rooted = "0xCb5f72d37685C3D5aD0bB5F982443BC8FcdF570E" 11 | const singleSideLiquidityAdder = "0x75013Cbfc60fda02c7B18cD1066d7B6C46970D25" 12 | const stakingToken = "0x39E9fB78b543748950827BF4c606F58724b67a80" 13 | const transferGate = "0x105E66f0bfD5b3b1E386D0dC6EC00F3342EF3fF6"; 14 | const vault = "0xc547D2bc0C3606602a4C9A530BFadDBc07A7f06F"; 15 | const fiatInitialSupplyMinter = "0x5a0748f8d40b7884e182fc4994d8d4a115a8cbf7" 16 | 17 | const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(); 18 | 19 | const ownedMetadata = JSON.parse(await remix.call('fileManager', 'getFile', `browser/artifacts/IOwned.json`)); 20 | const ownedFactory = new ethers.ContractFactory(ownedMetadata.abi, ownedMetadata.data.bytecode.object, signer); 21 | const owned = [ 22 | arbitrage, 23 | calculator, 24 | elite, 25 | rooted, 26 | singleSideLiquidityAdder, 27 | stakingToken, 28 | transferGate, 29 | vault, 30 | fiatInitialSupplyMinter 31 | ]; 32 | 33 | const arbitrageContract = await ownedFactory.attach(arbitrage); 34 | const gas = await arbitrageContract.estimateGas.transferOwnership(newOwner); 35 | const increasedGas = gas.toNumber() * 1.5; 36 | 37 | for (var i = 0; i < owned.length; i++) { 38 | const contract = await ownedFactory.attach(owned[i]); 39 | contract.transferOwnership(newOwner, { gasLimit: increasedGas }); 40 | } 41 | 42 | console.log('Done!'); 43 | } 44 | catch (e) { 45 | console.log(e) 46 | } 47 | })() --------------------------------------------------------------------------------