From 9873dfc76b1f05bc43eed0f1287afc2a9e871d73 Mon Sep 17 00:00:00 2001 From: yellow <8539006+yellowBirdy@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:37:40 +0200 Subject: [PATCH 01/19] constructor --- README.md | 15 ++++++++------- script/RaidGeld.s.sol | 6 ++++-- src/Constants.sol | 8 ++++++++ src/RaidGeld.sol | 8 +++++++- test/RaidGeld.t.sol | 5 +++-- test/RaidGeldUtils.t.sol | 2 +- 6 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 src/Constants.sol diff --git a/README.md b/README.md index 7f86c36..ead054e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ Idle game & shitcoin advanture dedicated to cohort VII of Raid Guild. ## Set up for local DEV -### 1. Run `anvil` to setup local RPC +### 1. Run `anvil` to setup local RPC as a fork of base mainnet +anvil --rpc-url ### 2. Deploy contract @@ -14,14 +15,14 @@ Either use `./deploy_contract.sh` script (!! change contract values and set priv Move to `app` dir, install deps via `npm install` and run `npm run dev` to start the dev server. -#### 3. 1. Run `cast rpc anvil_mine` +#### 3. 1. Point Metamask to Anvil network for local dev -This is so time gets set on the local chain, otherwise you will start at 0 time and first mint will give you bajillion GELD. - -#### 3. 2. Point Metamask to Anvil network for local dev - -#### 3. 3. Change `app/contract_address.ts` to match your program address if needed +#### 3. 2. Change `app/contract_address.ts` to match your program address if needed ### 4. Local development requires mining blocks by hand Call `cast rpc anvil_mine` to mine next block, otherwise it wont ever progress and time "stands still" as far as the game is concerned + + +### 5. Fork tests +forge test --rpc-url diff --git a/script/RaidGeld.s.sol b/script/RaidGeld.s.sol index ea5f87c..851b83d 100644 --- a/script/RaidGeld.s.sol +++ b/script/RaidGeld.s.sol @@ -4,14 +4,16 @@ pragma solidity ^0.8.13; import {Script, console} from "forge-std/Script.sol"; import {RaidGeld} from "../src/RaidGeld.sol"; -contract RaidGeldScript is Script { +import {Constants} from "../src/Constants.sol"; + +contract RaidGeldScript is Script, Constants { RaidGeld public raidgeld; function setUp() public {} function run() public { vm.startBroadcast(); - raidgeld = new RaidGeld(); + raidgeld = new RaidGeld(DAO_TOKEN, POOL); vm.stopBroadcast(); } } diff --git a/src/Constants.sol b/src/Constants.sol new file mode 100644 index 0000000..b31ade5 --- /dev/null +++ b/src/Constants.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +contract Constants { + //base addresses + address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8; + address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926; +} \ No newline at end of file diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 52c96a4..30e6350 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -16,13 +16,19 @@ contract RaidGeld is ERC20, Ownable { mapping(address => Player) private players; mapping(address => Army) private armies; + ERC20 public daoToken; + address public pool; + // Modifier for functions that should only be available to registered players modifier onlyPlayer() { require(players[msg.sender].created_at != 0, "Not an initiated player"); _; } - constructor() ERC20("Raid Geld", "GELD") Ownable(msg.sender) {} + constructor(address _daoToken, address _pool) ERC20("Raid Geld", "GELD") Ownable(msg.sender) { + daoToken = ERC20(_daoToken); + pool = _pool; + } // This effectively registers the user function register() external payable { diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 375fb31..8a00a7b 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.13; import {Test, console} from "forge-std/Test.sol"; import {RaidGeld, Army, Player} from "../src/RaidGeld.sol"; import "../src/RaidGeldUtils.sol"; +import {Constants} from "../src/Constants.sol"; -contract raid_geldTest is Test { +contract raid_geldTest is Test, Constants { RaidGeld public raid_geld; address public player1; address public player2; @@ -17,7 +18,7 @@ contract raid_geldTest is Test { vm.deal(owner, 10 ether); vm.deal(player1, 10 ether); vm.prank(owner); - raid_geld = new RaidGeld(); + raid_geld = new RaidGeld(DAO_TOKEN, POOL); } function registerPlayer() private { diff --git a/test/RaidGeldUtils.t.sol b/test/RaidGeldUtils.t.sol index 8de1385..c6b5b24 100644 --- a/test/RaidGeldUtils.t.sol +++ b/test/RaidGeldUtils.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.13; import {Test, console} from "forge-std/Test.sol"; -import {Army, Raider} from "../src/RaidGeld.sol"; +import {Army, Raider} from "../src/RaidGeldStructs.sol"; import "../src/RaidGeldUtils.sol"; contract raid_geldTest is Test { From 5b0d24ccbae1fe3b97d45ce72e6521ec1bec99fb Mon Sep 17 00:00:00 2001 From: yellow <8539006+yellowBirdy@users.noreply.github.com> Date: Fri, 25 Oct 2024 23:10:40 +0200 Subject: [PATCH 02/19] registration with dao token --- README.md | 4 +++- src/RaidGeld.sol | 12 ++++++++++- test/RaidGeld.t.sol | 52 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ead054e..03e38c0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ Idle game & shitcoin advanture dedicated to cohort VII of Raid Guild. ## Set up for local DEV ### 1. Run `anvil` to setup local RPC as a fork of base mainnet -anvil --rpc-url +`anvil --rpc-url ` + +you can get a free rpc url by registering with https://alchemy.com and creating and app ### 2. Deploy contract diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 30e6350..71cab5a 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -6,10 +6,13 @@ import "@openzeppelin/contracts/access/Ownable.sol"; import {RaidGeldUtils} from "../src/RaidGeldUtils.sol"; import {Army, Player, Raider} from "../src/RaidGeldStructs.sol"; + contract RaidGeld is ERC20, Ownable { uint256 public constant MANTISSA = 1e4; uint256 public constant BUY_IN_AMOUNT = 0.00005 ether; + uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT; + uint256 public constant INITIAL_GELD = 50 * MANTISSA; uint256 public constant RAID_WAIT = 15 seconds; @@ -28,12 +31,19 @@ contract RaidGeld is ERC20, Ownable { constructor(address _daoToken, address _pool) ERC20("Raid Geld", "GELD") Ownable(msg.sender) { daoToken = ERC20(_daoToken); pool = _pool; + BUY_IN_DAO_TOKEN_AMOUNT = 50 * 10 ** daoToken.decimals(); } // This effectively registers the user function register() external payable { require(players[msg.sender].created_at == 0, "Whoops, player already exists :)"); - require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount"); + if (msg.value != 0) { + require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount"); + } else { + //@notice this is not safe for arbitrary tokens, which may not follow the interface eg. USDT + //@notice but should be fine for the DAO token + require(daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), "Failed to transfer DAO tokens"); + } // Mint some starting tokens to the player _mint(msg.sender, INITIAL_GELD); diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 8a00a7b..aeea89d 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -2,11 +2,16 @@ pragma solidity ^0.8.13; import {Test, console} from "forge-std/Test.sol"; +import {stdStorage, StdStorage} from "forge-std/Test.sol"; + import {RaidGeld, Army, Player} from "../src/RaidGeld.sol"; import "../src/RaidGeldUtils.sol"; import {Constants} from "../src/Constants.sol"; contract raid_geldTest is Test, Constants { + + using stdStorage for StdStorage; + RaidGeld public raid_geld; address public player1; address public player2; @@ -16,14 +21,28 @@ contract raid_geldTest is Test, Constants { owner = address(0x126); player1 = address(0x123); vm.deal(owner, 10 ether); - vm.deal(player1, 10 ether); + fundAccount(player1); vm.prank(owner); raid_geld = new RaidGeld(DAO_TOKEN, POOL); } + function fundAccount(address _acc) private { + vm.deal(_acc, 10 ether); + stdstore + .target(DAO_TOKEN) + .sig("balanceOf(address)") + .with_key(_acc) + .checked_write(100 ether); + + } function registerPlayer() private { raid_geld.register{value: raid_geld.BUY_IN_AMOUNT()}(); } + function registerPlayerWithDaoToken() private { + raid_geld.daoToken().approve(address(raid_geld), raid_geld.BUY_IN_DAO_TOKEN_AMOUNT()); + raid_geld.register(); + } + function test_00_no_fallback() public { vm.expectRevert(); @@ -37,7 +56,7 @@ contract raid_geldTest is Test, Constants { payable(address(raid_geld)).transfer(0.1 ether); } - function test_02_registration() public { + function test_02_1_registrationWithEth() public { vm.startPrank(player1); uint256 initialBalance = address(raid_geld).balance; @@ -65,6 +84,35 @@ contract raid_geldTest is Test, Constants { assertEq(army.champion.level, 0); } + function test_02_2_registrationWithDaoToken() public { + vm.startPrank(player1); + + uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); + + // Send registration fee ETH to the contract + registerPlayerWithDaoToken(); + + // Check that initialraid_geld.is received by the player + assertEq(raid_geld.balanceOf(player1), raid_geld.INITIAL_GELD()); + + // Verify the contract dao token balance is updated + assertEq(raid_geld.daoToken().balanceOf(address(raid_geld)), initialBalance + raid_geld.BUY_IN_DAO_TOKEN_AMOUNT()); + + // Verify player is set initially + Player memory player = raid_geld.getPlayer(player1); + assertEq(player.total_minted, raid_geld.INITIAL_GELD()); + assertEq(player.created_at, block.timestamp); + assertEq(player.last_raided_at, block.timestamp); + + Army memory army = raid_geld.getArmy(player1); + + assertEq(army.moloch_denier.level, 0); + assertEq(army.apprentice.level, 0); + assertEq(army.anointed.level, 0); + assertEq(army.champion.level, 0); + } + + function test_03_funds_can_be_withdrawn() public { uint256 initialBalance = owner.balance; From 7b9661bda7640dd58029c11f5cf6149a7cd64361 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Sun, 27 Oct 2024 11:52:26 +0100 Subject: [PATCH 03/19] Allows withdrawal of DAO tokens back to owner() account --- README.md | 13 ++-- app/contract_address.ts | 2 +- .../RaidGeld.s.sol/8453/run-1729970220.json | 68 +++++++++++++++++++ broadcast/RaidGeld.s.sol/8453/run-latest.json | 68 +++++++++++++++++++ src/Constants.sol | 2 +- src/RaidGeld.sol | 13 +++- test/RaidGeld.t.sol | 41 +++++++---- 7 files changed, 182 insertions(+), 25 deletions(-) create mode 100644 broadcast/RaidGeld.s.sol/8453/run-1729970220.json create mode 100644 broadcast/RaidGeld.s.sol/8453/run-latest.json diff --git a/README.md b/README.md index 03e38c0..f044f0b 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,10 @@ Idle game & shitcoin advanture dedicated to cohort VII of Raid Guild. ## Set up for local DEV ### 1. Run `anvil` to setup local RPC as a fork of base mainnet -`anvil --rpc-url ` -you can get a free rpc url by registering with https://alchemy.com and creating and app +`anvil --block-time 5 --rpc-url ` + +You can get a free rpc url by registering with https://alchemy.com and creating and app ### 2. Deploy contract @@ -21,10 +22,6 @@ Move to `app` dir, install deps via `npm install` and run `npm run dev` to start #### 3. 2. Change `app/contract_address.ts` to match your program address if needed -### 4. Local development requires mining blocks by hand +### 4. Fork tests -Call `cast rpc anvil_mine` to mine next block, otherwise it wont ever progress and time "stands still" as far as the game is concerned - - -### 5. Fork tests -forge test --rpc-url +forge test --rpc-url diff --git a/app/contract_address.ts b/app/contract_address.ts index 712d987..5eaa84e 100644 --- a/app/contract_address.ts +++ b/app/contract_address.ts @@ -1,4 +1,4 @@ -const contractAddress = "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66"; +const contractAddress = "0xb2fc8F28aD37290245241C6cb0E411c9fff6A1d7"; export default contractAddress diff --git a/broadcast/RaidGeld.s.sol/8453/run-1729970220.json b/broadcast/RaidGeld.s.sol/8453/run-1729970220.json new file mode 100644 index 0000000..da935d1 --- /dev/null +++ b/broadcast/RaidGeld.s.sol/8453/run-1729970220.json @@ -0,0 +1,68 @@ +{ + "transactions": [ + { + "hash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", + "transactionType": "CREATE", + "contractName": "RaidGeld", + "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", + "function": null, + "arguments": [ + "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8", + "0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926" + ], + "transaction": { + "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", + "gas": "0x1e142b", + "value": "0x0", + "input": "0x60a060405234801561001057600080fd5b50604051611ccd380380611ccd83398101604081905261002f916101e2565b336040518060400160405280600981526020016814985a590811d95b1960ba1b8152506040518060400160405280600481526020016311d1531160e21b815250816003908161007e91906102b4565b50600461008b82826102b4565b5050506001600160a01b0381166100bc57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100c581610174565b50600880546001600160a01b038085166001600160a01b0319928316811790935560098054918516919092161790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801561012f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101539190610372565b61015e90600a61049b565b6101699060326104aa565b608052506104c19050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146101dd57600080fd5b919050565b600080604083850312156101f557600080fd5b6101fe836101c6565b915061020c602084016101c6565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061023f57607f821691505b60208210810361025f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102af57806000526020600020601f840160051c8101602085101561028c5750805b601f840160051c820191505b818110156102ac5760008155600101610298565b50505b505050565b81516001600160401b038111156102cd576102cd610215565b6102e1816102db845461022b565b84610265565b6020601f82116001811461031557600083156102fd5750848201515b600019600385901b1c1916600184901b1784556102ac565b600084815260208120601f198516915b828110156103455787850151825560209485019460019092019101610325565b50848210156103635786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b60006020828403121561038457600080fd5b815160ff8116811461039557600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b6001815b60018411156103ed578085048111156103d1576103d161039c565b60018416156103df57908102905b60019390931c9280026103b6565b935093915050565b60008261040457506001610495565b8161041157506000610495565b816001811461042757600281146104315761044d565b6001915050610495565b60ff8411156104425761044261039c565b50506001821b610495565b5060208310610133831016604e8410600b8410161715610470575081810a610495565b61047d60001984846103b2565b80600019048211156104915761049161039c565b0290505b92915050565b600061039560ff8416836103f5565b80820281158282048414176104955761049561039c565b6080516117ea6104e360003960008181610677015261088901526117ea6000f3fe6080604052600436106101855760003560e01c80635c12cd4b116100d1578063a7db742f1161008a578063c861dcb111610064578063c861dcb114610650578063db4d0d2714610665578063dd62ed3e14610699578063f2fde38b146106df576101fd565b8063a7db742f146105e0578063a9059cbb146105f5578063c3c5a54714610615576101fd565b80635c12cd4b1461050057806370a0823114610542578063715018a61461057857806385ed706d1461058d5780638da5cb5b146105ad57806395d89b41146105cb576101fd565b806323b872dd1161013e5780633ccfd60b116101185780633ccfd60b1461036c57806347d1e46e146103815780634914b0301461039b57806353d7da60146103bb576101fd565b806323b872dd1461031a5780632703984c1461033a578063313ce56714610350576101fd565b806306fdde0314610245578063095ea7b31461027057806313820ba7146102a057806316f0115b146102c357806318160ddd146102fb5780631aa3a00814610310576101fd565b366101fd5760405162461bcd60e51b815260206004820152603f60248201527f4e6f20706c61696e2045746865722061636365707465642c207573652072656760448201527f697374657228292066756e6374696f6e20746f20636865636b20696e203a290060648201526084015b60405180910390fd5b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2066616c6c6261636b2063616c6c7320616363657074656400000000000060448201526064016101f4565b34801561025157600080fd5b5061025a6106ff565b6040516102679190611544565b60405180910390f35b34801561027c57600080fd5b5061029061028b3660046115ae565b610791565b6040519015158152602001610267565b3480156102ac57600080fd5b506102b5600f81565b604051908152602001610267565b3480156102cf57600080fd5b506009546102e3906001600160a01b031681565b6040516001600160a01b039091168152602001610267565b34801561030757600080fd5b506002546102b5565b6103186107ab565b005b34801561032657600080fd5b506102906103353660046115d8565b610a6c565b34801561034657600080fd5b506102b561271081565b34801561035c57600080fd5b5060405160048152602001610267565b34801561037857600080fd5b50610318610a90565b34801561038d57600080fd5b506102b5652d79883d200081565b3480156103a757600080fd5b506008546102e3906001600160a01b031681565b3480156103c757600080fd5b506104aa6103d6366004611615565b6040805160c081018252600060a082018181528252825160208082018552828252808401919091528351808201855282815283850152835190810190935280835260608201929092526080810191909152506001600160a01b0316600090815260076020908152604091829020825160c081018452815461ffff90811660a08301908152825284518085018652600184015482168152828501528451808501865260028401548216815282860152845193840190945260038201549093168252606083019190915260040154608082015290565b6040516102679190600060a08201905061ffff83515116825261ffff60208401515116602083015261ffff60408401515116604083015261ffff6060840151511660608301526080830151608083015292915050565b34801561050c57600080fd5b5061052061051b366004611615565b610ad4565b6040805182518152602080840151908201529181015190820152606001610267565b34801561054e57600080fd5b506102b561055d366004611615565b6001600160a01b031660009081526020819052604090205490565b34801561058457600080fd5b50610318610b3a565b34801561059957600080fd5b506103186105a8366004611637565b610b4e565b3480156105b957600080fd5b506005546001600160a01b03166102e3565b3480156105d757600080fd5b5061025a610e2d565b3480156105ec57600080fd5b50610318610e3c565b34801561060157600080fd5b506102906106103660046115ae565b610f07565b34801561062157600080fd5b50610290610630366004611615565b6001600160a01b0316600090815260066020526040902060010154151590565b34801561065c57600080fd5b506102b5610f15565b34801561067157600080fd5b506102b57f000000000000000000000000000000000000000000000000000000000000000081565b3480156106a557600080fd5b506102b56106b436600461167d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156106eb57600080fd5b506103186106fa366004611615565b610f25565b60606003805461070e906116b0565b80601f016020809104026020016040519081016040528092919081815260200182805461073a906116b0565b80156107875780601f1061075c57610100808354040283529160200191610787565b820191906000526020600020905b81548152906001019060200180831161076a57829003601f168201915b5050505050905090565b60003361079f818585610f60565b60019150505b92915050565b336000908152600660205260409020600101541561080b5760405162461bcd60e51b815260206004820181905260248201527f57686f6f70732c20706c6179657220616c726561647920657869737473203a2960448201526064016101f4565b341561086b57652d79883d200034146108665760405162461bcd60e51b815260206004820152601760248201527f496e636f72726563742062757920696e20616d6f756e7400000000000000000060448201526064016101f4565b610951565b6008546040516323b872dd60e01b81523360048201523060248201527f000000000000000000000000000000000000000000000000000000000000000060448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090591906116ea565b6109515760405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f207472616e736665722044414f20746f6b656e7300000060448201526064016101f4565b610967336109626127106032611722565b610f72565b604051806060016040528061271060326109819190611722565b815242602080830182905260409283019190915233600081815260068352838120855181558584015160018083019190915595850151600291820155845160c08101865260a0810183815281528551808601875283815281860190815286518087018852848152828801908152875180880189528581526060840190815260808401868152968652600790975296909320905151815461ffff1990811661ffff92831617835593515197820180548516988216989098179097559451519085018054831691871691909117905591515160038401805490931694169390931790559051600490910155565b600033610a7a858285610fac565b610a8585858561102a565b506001949350505050565b610a98611089565b6005546040516001600160a01b03909116904780156108fc02916000818181858888f19350505050158015610ad1573d6000803e3d6000fd5b50565b610af860405180606001604052806000815260200160008152602001600081525090565b506001600160a01b0316600090815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b610b42611089565b610b4c60006110b6565b565b336000908152600660205260408120600101549003610ba95760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b60038260ff161115610bec5760405162461bcd60e51b815260206004820152600c60248201526b155b9adb9bdddb881d5b9a5d60a21b60448201526064016101f4565b3360009081526007602052604081209060ff84168103610c125750805461ffff16610c5c565b8360ff16600103610c2c5750600181015461ffff16610c5c565b8360ff16600203610c465750600281015461ffff16610c5c565b8360ff16600303610c5c5750600381015461ffff165b6000610c69858386611108565b9050610c74336111d5565b336000908152602081905260409020548110610cd25760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682047454c4420746f206164642074686973206d75636860448201526064016101f4565b610cdc3382611258565b8460ff16600003610d1e57825484908490600090610cff90849061ffff16611739565b92506101000a81548161ffff021916908361ffff160217905550610dab565b8460ff16600103610d4457600183018054859190600090610cff90849061ffff16611739565b8460ff16600203610d6a57600283018054859190600090610cff90849061ffff16611739565b8460ff16600303610dab57600383018054859190600090610d9090849061ffff16611739565b92506101000a81548161ffff021916908361ffff1602179055505b6040805160c081018252845461ffff90811660a08301908152825282516020818101855260018801548316825280840191909152835180820185526002880154831681528385015283519081019093526003860154168252606081019190915260048401546080820152610e1e9061128e565b83600401819055505050505050565b60606004805461070e906116b0565b336000908152600660205260408120600101549003610e975760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b33600090815260066020526040902060020154610eb690600f90611753565b421015610efe5760405162461bcd60e51b81526020600482015260166024820152752a3934b2b21036b4b73a34b733903a37b79039b7b7b760511b60448201526064016101f4565b610b4c336111d5565b60003361079f81858561102a565b610f226127106032611722565b81565b610f2d611089565b6001600160a01b038116610f5757604051631e4fbdf760e01b8152600060048201526024016101f4565b610ad1816110b6565b610f6d8383836001611345565b505050565b6001600160a01b038216610f9c5760405163ec442f0560e01b8152600060048201526024016101f4565b610fa86000838361141a565b5050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611024578181101561101557604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016101f4565b61102484848484036000611345565b50505050565b6001600160a01b03831661105457604051634b637e8f60e11b8152600060048201526024016101f4565b6001600160a01b03821661107e5760405163ec442f0560e01b8152600060048201526024016101f4565b610f6d83838361141a565b6005546001600160a01b03163314610b4c5760405163118cdaa760e01b81523360048201526024016101f4565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060038460ff1611156111575760405162461bcd60e51b8152602060048201526016602482015275139bc81b585d18da1a5b99c81d5b9a5d08199bdd5b9960521b60448201526064016101f4565b60006205cc60611168866001611766565b60ff166111759190611722565b90508060015b6111858587611739565b61ffff168110156111cb5761271061119f612cec85611722565b6111a9919061177f565b92508561ffff1681106111c3576111c08383611753565b91505b60010161117b565b5095945050505050565b6001600160a01b0381166000908152600660205260408120600201546111fb90426117a1565b6001600160a01b03831660009081526007602052604081206004015491925090611226908390611722565b90506112328382610f72565b6001600160a01b0390921660009081526006602052604090204260028201559190915550565b6001600160a01b03821661128257604051634b637e8f60e11b8152600060048201526024016101f4565b610fa88260008361141a565b80515160009081906112a7906127109061ffff16611722565b9050600061ee4884602001516000015161ffff166112c59190611722565b905060006205dc0085604001516000015161ffff166112e49190611722565b905060006127106112fb8165ede50bb9800061177f565b611305919061177f565b606087015151611319919061ffff16611722565b905080826113278587611753565b6113319190611753565b61133b9190611753565b9695505050505050565b6001600160a01b03841661136f5760405163e602df0560e01b8152600060048201526024016101f4565b6001600160a01b03831661139957604051634a1406b160e11b8152600060048201526024016101f4565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561102457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161140c91815260200190565b60405180910390a350505050565b6001600160a01b03831661144557806002600082825461143a9190611753565b909155506114b79050565b6001600160a01b038316600090815260208190526040902054818110156114985760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016101f4565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166114d3576002805482900390556114f2565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161153791815260200190565b60405180910390a3505050565b602081526000825180602084015260005b818110156115725760208186018101516040868401015201611555565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b03811681146115a957600080fd5b919050565b600080604083850312156115c157600080fd5b6115ca83611592565b946020939093013593505050565b6000806000606084860312156115ed57600080fd5b6115f684611592565b925061160460208501611592565b929592945050506040919091013590565b60006020828403121561162757600080fd5b61163082611592565b9392505050565b6000806040838503121561164a57600080fd5b823560ff8116811461165b57600080fd5b9150602083013561ffff8116811461167257600080fd5b809150509250929050565b6000806040838503121561169057600080fd5b61169983611592565b91506116a760208401611592565b90509250929050565b600181811c908216806116c457607f821691505b6020821081036116e457634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156116fc57600080fd5b8151801515811461163057600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176107a5576107a561170c565b61ffff81811683821601908111156107a5576107a561170c565b808201808211156107a5576107a561170c565b60ff81811683821601908111156107a5576107a561170c565b60008261179c57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156107a5576107a561170c56fea2646970667358221220e6bad70680fdee5fb985ae5e884c4471f46d5febec4efc3ccebe2e1ee82de75764736f6c634300081c003300000000000000000000000011dc980faf34a1d082ae8a6a883db3a950a3c6e800000000000000000000000027004f6d0c1bb7979367d32ba9d6df6d61a18926", + "nonce": "0x1", + "chainId": "0x2105" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x172507", + "logs": [ + { + "address": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000003295cca2d922c637d35b258fc6c9c7e471803b45" + ], + "data": "0x", + "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", + "blockNumber": "0x1497119", + "blockTimestamp": "0x671d402a", + "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000008000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000010000000000000001000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", + "transactionIndex": "0x0", + "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", + "blockNumber": "0x1497119", + "gasUsed": "0x172507", + "effectiveGasPrice": "0x2b", + "blobGasPrice": "0x1", + "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", + "to": null, + "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", + "root": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1729970220, + "chain": 8453, + "commit": "5b0d24c" +} \ No newline at end of file diff --git a/broadcast/RaidGeld.s.sol/8453/run-latest.json b/broadcast/RaidGeld.s.sol/8453/run-latest.json new file mode 100644 index 0000000..da935d1 --- /dev/null +++ b/broadcast/RaidGeld.s.sol/8453/run-latest.json @@ -0,0 +1,68 @@ +{ + "transactions": [ + { + "hash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", + "transactionType": "CREATE", + "contractName": "RaidGeld", + "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", + "function": null, + "arguments": [ + "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8", + "0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926" + ], + "transaction": { + "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", + "gas": "0x1e142b", + "value": "0x0", + "input": "0x60a060405234801561001057600080fd5b50604051611ccd380380611ccd83398101604081905261002f916101e2565b336040518060400160405280600981526020016814985a590811d95b1960ba1b8152506040518060400160405280600481526020016311d1531160e21b815250816003908161007e91906102b4565b50600461008b82826102b4565b5050506001600160a01b0381166100bc57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100c581610174565b50600880546001600160a01b038085166001600160a01b0319928316811790935560098054918516919092161790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801561012f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101539190610372565b61015e90600a61049b565b6101699060326104aa565b608052506104c19050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146101dd57600080fd5b919050565b600080604083850312156101f557600080fd5b6101fe836101c6565b915061020c602084016101c6565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061023f57607f821691505b60208210810361025f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102af57806000526020600020601f840160051c8101602085101561028c5750805b601f840160051c820191505b818110156102ac5760008155600101610298565b50505b505050565b81516001600160401b038111156102cd576102cd610215565b6102e1816102db845461022b565b84610265565b6020601f82116001811461031557600083156102fd5750848201515b600019600385901b1c1916600184901b1784556102ac565b600084815260208120601f198516915b828110156103455787850151825560209485019460019092019101610325565b50848210156103635786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b60006020828403121561038457600080fd5b815160ff8116811461039557600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b6001815b60018411156103ed578085048111156103d1576103d161039c565b60018416156103df57908102905b60019390931c9280026103b6565b935093915050565b60008261040457506001610495565b8161041157506000610495565b816001811461042757600281146104315761044d565b6001915050610495565b60ff8411156104425761044261039c565b50506001821b610495565b5060208310610133831016604e8410600b8410161715610470575081810a610495565b61047d60001984846103b2565b80600019048211156104915761049161039c565b0290505b92915050565b600061039560ff8416836103f5565b80820281158282048414176104955761049561039c565b6080516117ea6104e360003960008181610677015261088901526117ea6000f3fe6080604052600436106101855760003560e01c80635c12cd4b116100d1578063a7db742f1161008a578063c861dcb111610064578063c861dcb114610650578063db4d0d2714610665578063dd62ed3e14610699578063f2fde38b146106df576101fd565b8063a7db742f146105e0578063a9059cbb146105f5578063c3c5a54714610615576101fd565b80635c12cd4b1461050057806370a0823114610542578063715018a61461057857806385ed706d1461058d5780638da5cb5b146105ad57806395d89b41146105cb576101fd565b806323b872dd1161013e5780633ccfd60b116101185780633ccfd60b1461036c57806347d1e46e146103815780634914b0301461039b57806353d7da60146103bb576101fd565b806323b872dd1461031a5780632703984c1461033a578063313ce56714610350576101fd565b806306fdde0314610245578063095ea7b31461027057806313820ba7146102a057806316f0115b146102c357806318160ddd146102fb5780631aa3a00814610310576101fd565b366101fd5760405162461bcd60e51b815260206004820152603f60248201527f4e6f20706c61696e2045746865722061636365707465642c207573652072656760448201527f697374657228292066756e6374696f6e20746f20636865636b20696e203a290060648201526084015b60405180910390fd5b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2066616c6c6261636b2063616c6c7320616363657074656400000000000060448201526064016101f4565b34801561025157600080fd5b5061025a6106ff565b6040516102679190611544565b60405180910390f35b34801561027c57600080fd5b5061029061028b3660046115ae565b610791565b6040519015158152602001610267565b3480156102ac57600080fd5b506102b5600f81565b604051908152602001610267565b3480156102cf57600080fd5b506009546102e3906001600160a01b031681565b6040516001600160a01b039091168152602001610267565b34801561030757600080fd5b506002546102b5565b6103186107ab565b005b34801561032657600080fd5b506102906103353660046115d8565b610a6c565b34801561034657600080fd5b506102b561271081565b34801561035c57600080fd5b5060405160048152602001610267565b34801561037857600080fd5b50610318610a90565b34801561038d57600080fd5b506102b5652d79883d200081565b3480156103a757600080fd5b506008546102e3906001600160a01b031681565b3480156103c757600080fd5b506104aa6103d6366004611615565b6040805160c081018252600060a082018181528252825160208082018552828252808401919091528351808201855282815283850152835190810190935280835260608201929092526080810191909152506001600160a01b0316600090815260076020908152604091829020825160c081018452815461ffff90811660a08301908152825284518085018652600184015482168152828501528451808501865260028401548216815282860152845193840190945260038201549093168252606083019190915260040154608082015290565b6040516102679190600060a08201905061ffff83515116825261ffff60208401515116602083015261ffff60408401515116604083015261ffff6060840151511660608301526080830151608083015292915050565b34801561050c57600080fd5b5061052061051b366004611615565b610ad4565b6040805182518152602080840151908201529181015190820152606001610267565b34801561054e57600080fd5b506102b561055d366004611615565b6001600160a01b031660009081526020819052604090205490565b34801561058457600080fd5b50610318610b3a565b34801561059957600080fd5b506103186105a8366004611637565b610b4e565b3480156105b957600080fd5b506005546001600160a01b03166102e3565b3480156105d757600080fd5b5061025a610e2d565b3480156105ec57600080fd5b50610318610e3c565b34801561060157600080fd5b506102906106103660046115ae565b610f07565b34801561062157600080fd5b50610290610630366004611615565b6001600160a01b0316600090815260066020526040902060010154151590565b34801561065c57600080fd5b506102b5610f15565b34801561067157600080fd5b506102b57f000000000000000000000000000000000000000000000000000000000000000081565b3480156106a557600080fd5b506102b56106b436600461167d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156106eb57600080fd5b506103186106fa366004611615565b610f25565b60606003805461070e906116b0565b80601f016020809104026020016040519081016040528092919081815260200182805461073a906116b0565b80156107875780601f1061075c57610100808354040283529160200191610787565b820191906000526020600020905b81548152906001019060200180831161076a57829003601f168201915b5050505050905090565b60003361079f818585610f60565b60019150505b92915050565b336000908152600660205260409020600101541561080b5760405162461bcd60e51b815260206004820181905260248201527f57686f6f70732c20706c6179657220616c726561647920657869737473203a2960448201526064016101f4565b341561086b57652d79883d200034146108665760405162461bcd60e51b815260206004820152601760248201527f496e636f72726563742062757920696e20616d6f756e7400000000000000000060448201526064016101f4565b610951565b6008546040516323b872dd60e01b81523360048201523060248201527f000000000000000000000000000000000000000000000000000000000000000060448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090591906116ea565b6109515760405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f207472616e736665722044414f20746f6b656e7300000060448201526064016101f4565b610967336109626127106032611722565b610f72565b604051806060016040528061271060326109819190611722565b815242602080830182905260409283019190915233600081815260068352838120855181558584015160018083019190915595850151600291820155845160c08101865260a0810183815281528551808601875283815281860190815286518087018852848152828801908152875180880189528581526060840190815260808401868152968652600790975296909320905151815461ffff1990811661ffff92831617835593515197820180548516988216989098179097559451519085018054831691871691909117905591515160038401805490931694169390931790559051600490910155565b600033610a7a858285610fac565b610a8585858561102a565b506001949350505050565b610a98611089565b6005546040516001600160a01b03909116904780156108fc02916000818181858888f19350505050158015610ad1573d6000803e3d6000fd5b50565b610af860405180606001604052806000815260200160008152602001600081525090565b506001600160a01b0316600090815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b610b42611089565b610b4c60006110b6565b565b336000908152600660205260408120600101549003610ba95760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b60038260ff161115610bec5760405162461bcd60e51b815260206004820152600c60248201526b155b9adb9bdddb881d5b9a5d60a21b60448201526064016101f4565b3360009081526007602052604081209060ff84168103610c125750805461ffff16610c5c565b8360ff16600103610c2c5750600181015461ffff16610c5c565b8360ff16600203610c465750600281015461ffff16610c5c565b8360ff16600303610c5c5750600381015461ffff165b6000610c69858386611108565b9050610c74336111d5565b336000908152602081905260409020548110610cd25760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682047454c4420746f206164642074686973206d75636860448201526064016101f4565b610cdc3382611258565b8460ff16600003610d1e57825484908490600090610cff90849061ffff16611739565b92506101000a81548161ffff021916908361ffff160217905550610dab565b8460ff16600103610d4457600183018054859190600090610cff90849061ffff16611739565b8460ff16600203610d6a57600283018054859190600090610cff90849061ffff16611739565b8460ff16600303610dab57600383018054859190600090610d9090849061ffff16611739565b92506101000a81548161ffff021916908361ffff1602179055505b6040805160c081018252845461ffff90811660a08301908152825282516020818101855260018801548316825280840191909152835180820185526002880154831681528385015283519081019093526003860154168252606081019190915260048401546080820152610e1e9061128e565b83600401819055505050505050565b60606004805461070e906116b0565b336000908152600660205260408120600101549003610e975760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b33600090815260066020526040902060020154610eb690600f90611753565b421015610efe5760405162461bcd60e51b81526020600482015260166024820152752a3934b2b21036b4b73a34b733903a37b79039b7b7b760511b60448201526064016101f4565b610b4c336111d5565b60003361079f81858561102a565b610f226127106032611722565b81565b610f2d611089565b6001600160a01b038116610f5757604051631e4fbdf760e01b8152600060048201526024016101f4565b610ad1816110b6565b610f6d8383836001611345565b505050565b6001600160a01b038216610f9c5760405163ec442f0560e01b8152600060048201526024016101f4565b610fa86000838361141a565b5050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611024578181101561101557604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016101f4565b61102484848484036000611345565b50505050565b6001600160a01b03831661105457604051634b637e8f60e11b8152600060048201526024016101f4565b6001600160a01b03821661107e5760405163ec442f0560e01b8152600060048201526024016101f4565b610f6d83838361141a565b6005546001600160a01b03163314610b4c5760405163118cdaa760e01b81523360048201526024016101f4565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060038460ff1611156111575760405162461bcd60e51b8152602060048201526016602482015275139bc81b585d18da1a5b99c81d5b9a5d08199bdd5b9960521b60448201526064016101f4565b60006205cc60611168866001611766565b60ff166111759190611722565b90508060015b6111858587611739565b61ffff168110156111cb5761271061119f612cec85611722565b6111a9919061177f565b92508561ffff1681106111c3576111c08383611753565b91505b60010161117b565b5095945050505050565b6001600160a01b0381166000908152600660205260408120600201546111fb90426117a1565b6001600160a01b03831660009081526007602052604081206004015491925090611226908390611722565b90506112328382610f72565b6001600160a01b0390921660009081526006602052604090204260028201559190915550565b6001600160a01b03821661128257604051634b637e8f60e11b8152600060048201526024016101f4565b610fa88260008361141a565b80515160009081906112a7906127109061ffff16611722565b9050600061ee4884602001516000015161ffff166112c59190611722565b905060006205dc0085604001516000015161ffff166112e49190611722565b905060006127106112fb8165ede50bb9800061177f565b611305919061177f565b606087015151611319919061ffff16611722565b905080826113278587611753565b6113319190611753565b61133b9190611753565b9695505050505050565b6001600160a01b03841661136f5760405163e602df0560e01b8152600060048201526024016101f4565b6001600160a01b03831661139957604051634a1406b160e11b8152600060048201526024016101f4565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561102457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161140c91815260200190565b60405180910390a350505050565b6001600160a01b03831661144557806002600082825461143a9190611753565b909155506114b79050565b6001600160a01b038316600090815260208190526040902054818110156114985760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016101f4565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166114d3576002805482900390556114f2565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161153791815260200190565b60405180910390a3505050565b602081526000825180602084015260005b818110156115725760208186018101516040868401015201611555565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b03811681146115a957600080fd5b919050565b600080604083850312156115c157600080fd5b6115ca83611592565b946020939093013593505050565b6000806000606084860312156115ed57600080fd5b6115f684611592565b925061160460208501611592565b929592945050506040919091013590565b60006020828403121561162757600080fd5b61163082611592565b9392505050565b6000806040838503121561164a57600080fd5b823560ff8116811461165b57600080fd5b9150602083013561ffff8116811461167257600080fd5b809150509250929050565b6000806040838503121561169057600080fd5b61169983611592565b91506116a760208401611592565b90509250929050565b600181811c908216806116c457607f821691505b6020821081036116e457634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156116fc57600080fd5b8151801515811461163057600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176107a5576107a561170c565b61ffff81811683821601908111156107a5576107a561170c565b808201808211156107a5576107a561170c565b60ff81811683821601908111156107a5576107a561170c565b60008261179c57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156107a5576107a561170c56fea2646970667358221220e6bad70680fdee5fb985ae5e884c4471f46d5febec4efc3ccebe2e1ee82de75764736f6c634300081c003300000000000000000000000011dc980faf34a1d082ae8a6a883db3a950a3c6e800000000000000000000000027004f6d0c1bb7979367d32ba9d6df6d61a18926", + "nonce": "0x1", + "chainId": "0x2105" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x172507", + "logs": [ + { + "address": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000003295cca2d922c637d35b258fc6c9c7e471803b45" + ], + "data": "0x", + "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", + "blockNumber": "0x1497119", + "blockTimestamp": "0x671d402a", + "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000008000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000010000000000000001000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", + "transactionIndex": "0x0", + "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", + "blockNumber": "0x1497119", + "gasUsed": "0x172507", + "effectiveGasPrice": "0x2b", + "blobGasPrice": "0x1", + "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", + "to": null, + "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", + "root": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1729970220, + "chain": 8453, + "commit": "5b0d24c" +} \ No newline at end of file diff --git a/src/Constants.sol b/src/Constants.sol index b31ade5..dca2613 100644 --- a/src/Constants.sol +++ b/src/Constants.sol @@ -5,4 +5,4 @@ contract Constants { //base addresses address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8; address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926; -} \ No newline at end of file +} diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 71cab5a..4116719 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -6,7 +6,6 @@ import "@openzeppelin/contracts/access/Ownable.sol"; import {RaidGeldUtils} from "../src/RaidGeldUtils.sol"; import {Army, Player, Raider} from "../src/RaidGeldStructs.sol"; - contract RaidGeld is ERC20, Ownable { uint256 public constant MANTISSA = 1e4; @@ -42,7 +41,10 @@ contract RaidGeld is ERC20, Ownable { } else { //@notice this is not safe for arbitrary tokens, which may not follow the interface eg. USDT //@notice but should be fine for the DAO token - require(daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), "Failed to transfer DAO tokens"); + require( + daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), + "Failed to transfer DAO tokens" + ); } // Mint some starting tokens to the player @@ -70,6 +72,13 @@ contract RaidGeld is ERC20, Ownable { payable(owner()).transfer(address(this).balance); } + // Allows the owner to withdraw DAO tokens + function withdraw_dao() external onlyOwner { + uint256 amount = daoToken.balanceOf(address(this)); + daoToken.approve(address(this), amount); + daoToken.transferFrom(address(this), owner(), amount); + } + // Manual minting for itchy fingers function raid() external onlyPlayer { require(block.timestamp >= players[msg.sender].last_raided_at + RAID_WAIT, "Tried minting too soon"); diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index aeea89d..0d68681 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -2,14 +2,13 @@ pragma solidity ^0.8.13; import {Test, console} from "forge-std/Test.sol"; -import {stdStorage, StdStorage} from "forge-std/Test.sol"; +import {stdStorage, StdStorage} from "forge-std/Test.sol"; import {RaidGeld, Army, Player} from "../src/RaidGeld.sol"; import "../src/RaidGeldUtils.sol"; import {Constants} from "../src/Constants.sol"; contract raid_geldTest is Test, Constants { - using stdStorage for StdStorage; RaidGeld public raid_geld; @@ -25,25 +24,21 @@ contract raid_geldTest is Test, Constants { vm.prank(owner); raid_geld = new RaidGeld(DAO_TOKEN, POOL); } + function fundAccount(address _acc) private { vm.deal(_acc, 10 ether); - stdstore - .target(DAO_TOKEN) - .sig("balanceOf(address)") - .with_key(_acc) - .checked_write(100 ether); - + stdstore.target(DAO_TOKEN).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether); } function registerPlayer() private { raid_geld.register{value: raid_geld.BUY_IN_AMOUNT()}(); } + function registerPlayerWithDaoToken() private { raid_geld.daoToken().approve(address(raid_geld), raid_geld.BUY_IN_DAO_TOKEN_AMOUNT()); raid_geld.register(); } - function test_00_no_fallback() public { vm.expectRevert(); // Send Ether with some data to trigger fallback @@ -92,11 +87,13 @@ contract raid_geldTest is Test, Constants { // Send registration fee ETH to the contract registerPlayerWithDaoToken(); - // Check that initialraid_geld.is received by the player + // Check that initial raid_geld is received by the player assertEq(raid_geld.balanceOf(player1), raid_geld.INITIAL_GELD()); // Verify the contract dao token balance is updated - assertEq(raid_geld.daoToken().balanceOf(address(raid_geld)), initialBalance + raid_geld.BUY_IN_DAO_TOKEN_AMOUNT()); + assertEq( + raid_geld.daoToken().balanceOf(address(raid_geld)), initialBalance + raid_geld.BUY_IN_DAO_TOKEN_AMOUNT() + ); // Verify player is set initially Player memory player = raid_geld.getPlayer(player1); @@ -112,8 +109,7 @@ contract raid_geldTest is Test, Constants { assertEq(army.champion.level, 0); } - - function test_03_funds_can_be_withdrawn() public { + function test_03_01_ETH_funds_can_be_withdrawn() public { uint256 initialBalance = owner.balance; // Switch to Player 1 and register it @@ -132,6 +128,25 @@ contract raid_geldTest is Test, Constants { assertEq(newBalance, initialBalance + raid_geld.BUY_IN_AMOUNT()); } + function test_03_02_RGCVII_funds_can_be_withdrawn() public { + uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); + + // Switch to Player 1 and register it + vm.startPrank(player1); + registerPlayerWithDaoToken(); + + // Switch back to owner and withdraw funds + vm.startPrank(owner); + raid_geld.withdraw_dao(); + uint256 newBalance = raid_geld.daoToken().balanceOf(address(owner)); + uint256 newContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); + + // contract balance should be empty + assertEq(newContractBalance, 0); + // owner should have the extra funds + assertGt(newBalance, initialBalance); + } + function test_04_only_owner_can_withdraw() public { // Register player 1 vm.startPrank(player1); From d197935faee72c47d795a75fdc78de4df2348b7b Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Sun, 27 Oct 2024 12:57:05 +0100 Subject: [PATCH 04/19] Prepping uniswap of received ETH -> RGCVII --- app/src/providers/PlayerProvider.tsx | 2 +- src/Constants.sol | 2 + src/RaidGeld.sol | 70 +++++++++++++++++++--------- test/RaidGeld.t.sol | 4 +- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/app/src/providers/PlayerProvider.tsx b/app/src/providers/PlayerProvider.tsx index 7f44202..824cce3 100644 --- a/app/src/providers/PlayerProvider.tsx +++ b/app/src/providers/PlayerProvider.tsx @@ -100,7 +100,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { abi, address: contractAddress, functionName: 'register', - value: parseEther("0.00005"), + value: parseEther("0.0005"), }) }, [writeContract]) diff --git a/src/Constants.sol b/src/Constants.sol index dca2613..82c37e3 100644 --- a/src/Constants.sol +++ b/src/Constants.sol @@ -5,4 +5,6 @@ contract Constants { //base addresses address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8; address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926; + address public constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address public constant SWAP_ROUTER_02 = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45; } diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 67119c9..941597e 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -3,28 +3,39 @@ pragma solidity ^0.8.13; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; +import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol'; +import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol'; import {RaidGeldUtils} from "../src/RaidGeldUtils.sol"; import {Army, Player, Raider} from "../src/RaidGeldStructs.sol"; contract RaidGeld is ERC20, Ownable { + uint256 public constant MANTISSA = 1e4; - - uint256 public constant BUY_IN_AMOUNT = 0.00005 ether; + uint256 public constant BUY_IN_AMOUNT = 0.0005 ether; uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT; - uint256 public constant INITIAL_GELD = 50 * MANTISSA; - mapping(address => Player) private players; mapping(address => Army) private armies; + // WETH + IERC20 private constant weth = IERC20(Constants.WETH); + // RGCVII token ERC20 public daoToken; + // RGCVII pool address public pool; + // Uniswap + ISwapRouter02 private constant router = ISwapRouter02(Constants.SWAP_ROUTER_02); // Modifier for functions that should only be available to registered players modifier onlyPlayer() { require(players[msg.sender].created_at != 0, "Not an initiated player"); _; } + // Modifier for functions that should only be available to non initialized players + modifier newPlayer() { + require(players[msg.sender].created_at == 0, "Whoops, player already exists :)"); + _; + } constructor(address _daoToken, address _pool) ERC20("Raid Geld", "GELD") Ownable(msg.sender) { daoToken = ERC20(_daoToken); @@ -32,27 +43,14 @@ contract RaidGeld is ERC20, Ownable { BUY_IN_DAO_TOKEN_AMOUNT = 50 * 10 ** daoToken.decimals(); } - // This effectively registers the user - function register() external payable { - require(players[msg.sender].created_at == 0, "Whoops, player already exists :)"); - if (msg.value != 0) { - require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount"); - } else { - //@notice this is not safe for arbitrary tokens, which may not follow the interface eg. USDT - //@notice but should be fine for the DAO token - require( - daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), - "Failed to transfer DAO tokens" - ); - } - + function init_player(address player) private { // Mint some starting tokens to the player - _mint(msg.sender, INITIAL_GELD); + _mint(player, INITIAL_GELD); // Set initial states - players[msg.sender] = + players[player] = Player({total_minted: INITIAL_GELD, created_at: block.timestamp, last_raided_at: block.timestamp}); - armies[msg.sender] = Army({ + armies[player] = Army({ moloch_denier: Raider({level: 0}), apprentice: Raider({level: 0}), anointed: Raider({level: 0}), @@ -61,6 +59,36 @@ contract RaidGeld is ERC20, Ownable { }); } + // New player want to register with ETH + function register_eth() external payable newPlayer { + require(weth.transferFrom(msg.sender, address(this), BUY_IN_AMOUNT), "Make sure to send exactly 0.0005 eth"); + weth.approve(address(router), amountIn); + ISwapRouter02.ExactInputSingleParams memory params = ISwapRouter02 + .ExactInputSingleParams({ + tokenIn: WETH, + tokenOut: DAI, + fee: 3000, + recipient: msg.sender, + amountIn: amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + }); + router.exactInputSingle(params); + init_player(); + } + + // New player wants to register with dao + function register_dao() external payable newPlayer { + //@notice this is not safe for arbitrary tokens, which may not follow the interface eg. USDT + //@notice but should be fine for the DAO token + require( + daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), + "Failed to transfer DAO tokens" + ); + // Init player + init_player(msg.sender); + } + // Override for default number of decimals function decimals() public view virtual override returns (uint8) { return 4; diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 2488f89..057b219 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -31,12 +31,12 @@ contract raid_geldTest is Test, Constants { } function registerPlayer() private { - raid_geld.register{value: raid_geld.BUY_IN_AMOUNT()}(); + raid_geld.register_eth{value: raid_geld.BUY_IN_AMOUNT()}(); } function registerPlayerWithDaoToken() private { raid_geld.daoToken().approve(address(raid_geld), raid_geld.BUY_IN_DAO_TOKEN_AMOUNT()); - raid_geld.register(); + raid_geld.register_dao(); } function test_00_no_fallback() public { From 8b35e86904cf08c081779490456b2e94b4cf7ad8 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Sun, 27 Oct 2024 12:57:15 +0100 Subject: [PATCH 05/19] forge install: v3-periphery v1.3.0 --- .gitmodules | 3 +++ lib/v3-periphery | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/v3-periphery diff --git a/.gitmodules b/.gitmodules index 690924b..67763b2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/openzeppelin-contracts"] path = lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "lib/v3-periphery"] + path = lib/v3-periphery + url = https://github.com/uniswap/v3-periphery diff --git a/lib/v3-periphery b/lib/v3-periphery new file mode 160000 index 0000000..80f26c8 --- /dev/null +++ b/lib/v3-periphery @@ -0,0 +1 @@ +Subproject commit 80f26c86c57b8a5e4b913f42844d4c8bd274d058 From a4be82cbd936fc63a642d3cea95a8202013a261c Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Sun, 27 Oct 2024 13:37:15 +0100 Subject: [PATCH 06/19] Added v3-periphery and remappings --- remappings.txt | 1 + test/RaidGeld.t.sol | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/remappings.txt b/remappings.txt index 6fdbafd..69a18fc 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1 +1,2 @@ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ +@uniswap/v3-periphery/contracts/=lib/v3-periphery/contracts diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 057b219..726965c 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.13; import {Test, console} from "forge-std/Test.sol"; import {stdStorage, StdStorage} from "forge-std/Test.sol"; - import {RaidGeld, Army, Player} from "../src/RaidGeld.sol"; import "../src/RaidGeldUtils.sol"; import {Constants} from "../src/Constants.sol"; From d28e33612ea8c020be2057c8a39eaf9b1a066ef8 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Sun, 27 Oct 2024 13:37:24 +0100 Subject: [PATCH 07/19] forge install: v3-core v1.0.0 --- .gitmodules | 3 +++ lib/v3-core | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/v3-core diff --git a/.gitmodules b/.gitmodules index 67763b2..1ddc652 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "lib/v3-periphery"] path = lib/v3-periphery url = https://github.com/uniswap/v3-periphery +[submodule "lib/v3-core"] + path = lib/v3-core + url = https://github.com/uniswap/v3-core diff --git a/lib/v3-core b/lib/v3-core new file mode 160000 index 0000000..e3589b1 --- /dev/null +++ b/lib/v3-core @@ -0,0 +1 @@ +Subproject commit e3589b192d0be27e100cd0daaf6c97204fdb1899 From aaf1c0fd4649f939a433aff8ef334d6d142baea5 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Sun, 27 Oct 2024 21:20:38 +0100 Subject: [PATCH 08/19] Swapping WETH -> RGCVII --- remappings.txt | 1 + script/RaidGeld.s.sol | 1 - src/Constants.sol | 4 ++-- src/RaidGeld.sol | 26 +++++++++++++------------- test/RaidGeld.t.sol | 16 +++++++++++++--- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/remappings.txt b/remappings.txt index 69a18fc..dc7d2c1 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,2 +1,3 @@ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ @uniswap/v3-periphery/contracts/=lib/v3-periphery/contracts +@uniswap/v3-core/contracts/=lib/v3-core/contracts diff --git a/script/RaidGeld.s.sol b/script/RaidGeld.s.sol index 851b83d..1cce4ee 100644 --- a/script/RaidGeld.s.sol +++ b/script/RaidGeld.s.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.13; import {Script, console} from "forge-std/Script.sol"; import {RaidGeld} from "../src/RaidGeld.sol"; - import {Constants} from "../src/Constants.sol"; contract RaidGeldScript is Script, Constants { diff --git a/src/Constants.sol b/src/Constants.sol index 82c37e3..0b65467 100644 --- a/src/Constants.sol +++ b/src/Constants.sol @@ -5,6 +5,6 @@ contract Constants { //base addresses address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8; address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926; - address public constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; - address public constant SWAP_ROUTER_02 = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45; + address public constant WETH = 0x4200000000000000000000000000000000000006; + address public constant SWAP_ROUTER = 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD; } diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 941597e..802da7c 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -7,8 +7,9 @@ import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol'; import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol'; import {RaidGeldUtils} from "../src/RaidGeldUtils.sol"; import {Army, Player, Raider} from "../src/RaidGeldStructs.sol"; +import "../src/Constants.sol"; -contract RaidGeld is ERC20, Ownable { +contract RaidGeld is ERC20, Ownable, Constants { uint256 public constant MANTISSA = 1e4; uint256 public constant BUY_IN_AMOUNT = 0.0005 ether; @@ -18,13 +19,13 @@ contract RaidGeld is ERC20, Ownable { mapping(address => Army) private armies; // WETH - IERC20 private constant weth = IERC20(Constants.WETH); + IERC20 public immutable weth = IERC20(WETH); // RGCVII token ERC20 public daoToken; // RGCVII pool address public pool; // Uniswap - ISwapRouter02 private constant router = ISwapRouter02(Constants.SWAP_ROUTER_02); + ISwapRouter private constant router = ISwapRouter(SWAP_ROUTER); // Modifier for functions that should only be available to registered players modifier onlyPlayer() { @@ -46,7 +47,6 @@ contract RaidGeld is ERC20, Ownable { function init_player(address player) private { // Mint some starting tokens to the player _mint(player, INITIAL_GELD); - // Set initial states players[player] = Player({total_minted: INITIAL_GELD, created_at: block.timestamp, last_raided_at: block.timestamp}); @@ -62,19 +62,19 @@ contract RaidGeld is ERC20, Ownable { // New player want to register with ETH function register_eth() external payable newPlayer { require(weth.transferFrom(msg.sender, address(this), BUY_IN_AMOUNT), "Make sure to send exactly 0.0005 eth"); - weth.approve(address(router), amountIn); - ISwapRouter02.ExactInputSingleParams memory params = ISwapRouter02 - .ExactInputSingleParams({ + TransferHelper.safeApprove(WETH, address(router), BUY_IN_AMOUNT); + ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({ tokenIn: WETH, - tokenOut: DAI, - fee: 3000, - recipient: msg.sender, - amountIn: amountIn, - amountOutMinimum: amountOutMin, + tokenOut: DAO_TOKEN, + fee: 10000, + recipient: address(this), + deadline: block.timestamp, + amountIn: BUY_IN_AMOUNT, + amountOutMinimum: 0, sqrtPriceLimitX96: 0 }); router.exactInputSingle(params); - init_player(); + init_player(msg.sender); } // New player wants to register with dao diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 726965c..2a6066f 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -6,8 +6,10 @@ import {stdStorage, StdStorage} from "forge-std/Test.sol"; import {RaidGeld, Army, Player} from "../src/RaidGeld.sol"; import "../src/RaidGeldUtils.sol"; import {Constants} from "../src/Constants.sol"; +import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; contract raid_geldTest is Test, Constants { + using stdStorage for StdStorage; RaidGeld public raid_geld; @@ -27,10 +29,18 @@ contract raid_geldTest is Test, Constants { function fundAccount(address _acc) private { vm.deal(_acc, 10 ether); stdstore.target(DAO_TOKEN).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether); + stdstore.target(WETH).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether); + } + + function getPoolLiquidity() public view { + IUniswapV3Pool pool = IUniswapV3Pool(POOL); + console.log(pool.liquidity()); } function registerPlayer() private { - raid_geld.register_eth{value: raid_geld.BUY_IN_AMOUNT()}(); + getPoolLiquidity(); + raid_geld.weth().approve(address(raid_geld), raid_geld.BUY_IN_AMOUNT()); + raid_geld.register_eth(); } function registerPlayerWithDaoToken() private { @@ -129,7 +139,7 @@ contract raid_geldTest is Test, Constants { function test_03_02_RGCVII_funds_can_be_withdrawn() public { uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); - + // Switch to Player 1 and register it vm.startPrank(player1); registerPlayerWithDaoToken(); @@ -138,7 +148,7 @@ contract raid_geldTest is Test, Constants { vm.startPrank(owner); raid_geld.withdraw_dao(); uint256 newBalance = raid_geld.daoToken().balanceOf(address(owner)); - uint256 newContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); + uint256 newContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); // contract balance should be empty assertEq(newContractBalance, 0); From 98050890ed3ae3952d3c4627a48fca0ccb7f328d Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Sun, 27 Oct 2024 23:18:54 +0100 Subject: [PATCH 09/19] Removed uni v3 --- .gitmodules | 6 ------ lib/v3-core | 1 - lib/v3-periphery | 1 - test/RaidGeld.t.sol | 1 + 4 files changed, 1 insertion(+), 8 deletions(-) delete mode 160000 lib/v3-core delete mode 160000 lib/v3-periphery diff --git a/.gitmodules b/.gitmodules index 1ddc652..690924b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,3 @@ [submodule "lib/openzeppelin-contracts"] path = lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts -[submodule "lib/v3-periphery"] - path = lib/v3-periphery - url = https://github.com/uniswap/v3-periphery -[submodule "lib/v3-core"] - path = lib/v3-core - url = https://github.com/uniswap/v3-core diff --git a/lib/v3-core b/lib/v3-core deleted file mode 160000 index e3589b1..0000000 --- a/lib/v3-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e3589b192d0be27e100cd0daaf6c97204fdb1899 diff --git a/lib/v3-periphery b/lib/v3-periphery deleted file mode 160000 index 80f26c8..0000000 --- a/lib/v3-periphery +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 80f26c86c57b8a5e4b913f42844d4c8bd274d058 diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 2a6066f..8084e7c 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -24,6 +24,7 @@ contract raid_geldTest is Test, Constants { fundAccount(player1); vm.prank(owner); raid_geld = new RaidGeld(DAO_TOKEN, POOL); + raid_geld.weth().deposit{ value: 5 ether }(); } function fundAccount(address _acc) private { From f086e9bac410f3d5e18f3ff3edac6190083f7894 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Mon, 28 Oct 2024 00:25:24 +0100 Subject: [PATCH 10/19] Added uniswap router contracts --- lib/swap-router-contracts/.gitattributes | 1 + .../.github/workflows/lint.yml | 33 + .../.github/workflows/release.yml | 45 + .../.github/workflows/tests.yml | 41 + lib/swap-router-contracts/.gitignore | 7 + lib/swap-router-contracts/.prettierignore | 1 + lib/swap-router-contracts/.prettierrc | 5 + lib/swap-router-contracts/.solhint.json | 6 + lib/swap-router-contracts/.yarnrc | 1 + lib/swap-router-contracts/LICENSE | 339 + lib/swap-router-contracts/README.md | 65 + lib/swap-router-contracts/bug-bounty.md | 80 + .../contracts/SwapRouter02.sol | 22 + .../contracts/V2SwapRouter.sol | 94 + .../contracts/V3SwapRouter.sol | 238 + .../contracts/base/ApproveAndCall.sol | 126 + .../contracts/base/ImmutableState.sol | 18 + .../contracts/base/MulticallExtended.sol | 34 + .../contracts/base/OracleSlippage.sol | 171 + .../base/PeripheryPaymentsExtended.sol | 29 + .../base/PeripheryPaymentsWithFeeExtended.sol | 32 + .../base/PeripheryValidationExtended.sol | 11 + .../contracts/interfaces/IApproveAndCall.sol | 63 + .../contracts/interfaces/IImmutableState.sol | 12 + .../interfaces/IMixedRouteQuoterV1.sol | 72 + .../interfaces/IMulticallExtended.sol | 26 + .../contracts/interfaces/IOracleSlippage.sol | 31 + .../interfaces/IPeripheryPaymentsExtended.sol | 29 + .../IPeripheryPaymentsWithFeeExtended.sol | 29 + .../contracts/interfaces/IQuoter.sol | 51 + .../contracts/interfaces/IQuoterV2.sol | 98 + .../contracts/interfaces/ISwapRouter02.sol | 15 + .../contracts/interfaces/ITokenValidator.sol | 50 + .../contracts/interfaces/IV2SwapRouter.sol | 35 + .../contracts/interfaces/IV3SwapRouter.sol | 69 + .../contracts/interfaces/IWETH.sol | 10 + .../contracts/lens/MixedRouteQuoterV1.sol | 237 + .../contracts/lens/Quoter.sol | 170 + .../contracts/lens/QuoterV2.sol | 273 + .../contracts/lens/README.md | 4 + .../contracts/lens/TokenValidator.sol | 159 + .../contracts/libraries/Constants.sol | 15 + .../contracts/libraries/PoolTicksCounter.sol | 96 + .../contracts/libraries/UniswapV2Library.sol | 90 + .../contracts/test/ImmutableStateTest.sol | 8 + .../contracts/test/MockObservations.sol | 77 + .../contracts/test/MockTimeSwapRouter.sol | 24 + .../contracts/test/OracleSlippageTest.sol | 62 + .../contracts/test/PoolTicksCounterTest.sol | 18 + .../contracts/test/TestERC20.sol | 10 + .../contracts/test/TestMulticallExtended.sol | 26 + .../contracts/test/TestUniswapV3Callee.sol | 62 + lib/swap-router-contracts/hardhat.config.ts | 70 + lib/swap-router-contracts/package.json | 68 + .../test/ApproveAndCall.spec.ts | 388 + .../test/ImmutableState.spec.ts | 58 + .../test/MixedRouteQuoterV1.integ.ts | 184 + .../test/MixedRouteQuoterV1.spec.ts | 460 + .../test/MulticallExtended.spec.ts | 50 + .../test/OracleSlippage.spec.ts | 447 + .../test/PeripheryPaymentsExtended.spec.ts | 50 + .../test/PoolTicksCounter.spec.ts | 280 + lib/swap-router-contracts/test/Quoter.spec.ts | 201 + .../test/QuoterV2.spec.ts | 578 ++ .../test/SwapRouter.gas.spec.ts | 470 + .../test/SwapRouter.spec.ts | 1623 ++++ .../test/TokenValidator.spec.ts | 158 + .../__snapshots__/ImmutableState.spec.ts.snap | 3 + .../MixedRouteQuoterV1.spec.ts.snap | 27 + .../test/__snapshots__/Multicall.spec.ts.snap | 5 + .../test/__snapshots__/Path.spec.ts.snap | 3 + .../__snapshots__/PoolAddress.spec.ts.snap | 5 + .../test/__snapshots__/QuoterV2.spec.ts.snap | 51 + .../__snapshots__/SwapRouter.gas.spec.ts.snap | 37 + .../__snapshots__/SwapRouter.spec.ts.snap | 3 + .../test/contracts/WETH9.json | 156 + .../test/shared/completeFixture.ts | 36 + .../test/shared/computePoolAddress.ts | 22 + .../test/shared/constants.ts | 21 + .../test/shared/encodePriceSqrt.ts | 16 + .../test/shared/expandTo18Decimals.ts | 9 + .../test/shared/expect.ts | 8 + .../test/shared/externalFixtures.ts | 76 + lib/swap-router-contracts/test/shared/path.ts | 61 + .../test/shared/quoter.ts | 160 + .../test/shared/snapshotGasCost.ts | 27 + .../test/shared/ticks.ts | 2 + lib/swap-router-contracts/tsconfig.json | 14 + lib/swap-router-contracts/yarn.lock | 8128 +++++++++++++++++ 89 files changed, 17275 insertions(+) create mode 100644 lib/swap-router-contracts/.gitattributes create mode 100644 lib/swap-router-contracts/.github/workflows/lint.yml create mode 100644 lib/swap-router-contracts/.github/workflows/release.yml create mode 100644 lib/swap-router-contracts/.github/workflows/tests.yml create mode 100644 lib/swap-router-contracts/.gitignore create mode 100644 lib/swap-router-contracts/.prettierignore create mode 100644 lib/swap-router-contracts/.prettierrc create mode 100644 lib/swap-router-contracts/.solhint.json create mode 100644 lib/swap-router-contracts/.yarnrc create mode 100644 lib/swap-router-contracts/LICENSE create mode 100644 lib/swap-router-contracts/README.md create mode 100644 lib/swap-router-contracts/bug-bounty.md create mode 100644 lib/swap-router-contracts/contracts/SwapRouter02.sol create mode 100644 lib/swap-router-contracts/contracts/V2SwapRouter.sol create mode 100644 lib/swap-router-contracts/contracts/V3SwapRouter.sol create mode 100644 lib/swap-router-contracts/contracts/base/ApproveAndCall.sol create mode 100644 lib/swap-router-contracts/contracts/base/ImmutableState.sol create mode 100644 lib/swap-router-contracts/contracts/base/MulticallExtended.sol create mode 100644 lib/swap-router-contracts/contracts/base/OracleSlippage.sol create mode 100644 lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol create mode 100644 lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol create mode 100644 lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IQuoter.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol create mode 100644 lib/swap-router-contracts/contracts/interfaces/IWETH.sol create mode 100644 lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol create mode 100644 lib/swap-router-contracts/contracts/lens/Quoter.sol create mode 100644 lib/swap-router-contracts/contracts/lens/QuoterV2.sol create mode 100644 lib/swap-router-contracts/contracts/lens/README.md create mode 100644 lib/swap-router-contracts/contracts/lens/TokenValidator.sol create mode 100644 lib/swap-router-contracts/contracts/libraries/Constants.sol create mode 100644 lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol create mode 100644 lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol create mode 100644 lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol create mode 100644 lib/swap-router-contracts/contracts/test/MockObservations.sol create mode 100644 lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol create mode 100644 lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol create mode 100644 lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol create mode 100644 lib/swap-router-contracts/contracts/test/TestERC20.sol create mode 100644 lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol create mode 100644 lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol create mode 100644 lib/swap-router-contracts/hardhat.config.ts create mode 100644 lib/swap-router-contracts/package.json create mode 100644 lib/swap-router-contracts/test/ApproveAndCall.spec.ts create mode 100644 lib/swap-router-contracts/test/ImmutableState.spec.ts create mode 100644 lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts create mode 100644 lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts create mode 100644 lib/swap-router-contracts/test/MulticallExtended.spec.ts create mode 100644 lib/swap-router-contracts/test/OracleSlippage.spec.ts create mode 100644 lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts create mode 100644 lib/swap-router-contracts/test/PoolTicksCounter.spec.ts create mode 100644 lib/swap-router-contracts/test/Quoter.spec.ts create mode 100644 lib/swap-router-contracts/test/QuoterV2.spec.ts create mode 100644 lib/swap-router-contracts/test/SwapRouter.gas.spec.ts create mode 100644 lib/swap-router-contracts/test/SwapRouter.spec.ts create mode 100644 lib/swap-router-contracts/test/TokenValidator.spec.ts create mode 100644 lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap create mode 100644 lib/swap-router-contracts/test/contracts/WETH9.json create mode 100644 lib/swap-router-contracts/test/shared/completeFixture.ts create mode 100644 lib/swap-router-contracts/test/shared/computePoolAddress.ts create mode 100644 lib/swap-router-contracts/test/shared/constants.ts create mode 100644 lib/swap-router-contracts/test/shared/encodePriceSqrt.ts create mode 100644 lib/swap-router-contracts/test/shared/expandTo18Decimals.ts create mode 100644 lib/swap-router-contracts/test/shared/expect.ts create mode 100644 lib/swap-router-contracts/test/shared/externalFixtures.ts create mode 100644 lib/swap-router-contracts/test/shared/path.ts create mode 100644 lib/swap-router-contracts/test/shared/quoter.ts create mode 100644 lib/swap-router-contracts/test/shared/snapshotGasCost.ts create mode 100644 lib/swap-router-contracts/test/shared/ticks.ts create mode 100644 lib/swap-router-contracts/tsconfig.json create mode 100644 lib/swap-router-contracts/yarn.lock diff --git a/lib/swap-router-contracts/.gitattributes b/lib/swap-router-contracts/.gitattributes new file mode 100644 index 0000000..7cc88f0 --- /dev/null +++ b/lib/swap-router-contracts/.gitattributes @@ -0,0 +1 @@ +*.sol linguist-language=Solidity \ No newline at end of file diff --git a/lib/swap-router-contracts/.github/workflows/lint.yml b/lib/swap-router-contracts/.github/workflows/lint.yml new file mode 100644 index 0000000..2f78834 --- /dev/null +++ b/lib/swap-router-contracts/.github/workflows/lint.yml @@ -0,0 +1,33 @@ +name: Lint + +on: + push: + branches: + - main + pull_request: + +jobs: + run-linters: + name: Run linters + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v2 + + - name: Set up node + uses: actions/setup-node@v1 + with: + node-version: 12.x + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Run linters + uses: wearerequired/lint-action@a8497ddb33fb1205941fd40452ca9fff07e0770d + with: + github_token: ${{ secrets.github_token }} + prettier: true + auto_fix: true + prettier_extensions: 'css,html,js,json,jsx,md,sass,scss,ts,tsx,vue,yaml,yml,sol' diff --git a/lib/swap-router-contracts/.github/workflows/release.yml b/lib/swap-router-contracts/.github/workflows/release.yml new file mode 100644 index 0000000..238720e --- /dev/null +++ b/lib/swap-router-contracts/.github/workflows/release.yml @@ -0,0 +1,45 @@ +name: Release + +on: workflow_dispatch # TODO set this on a deploy schedule + +jobs: + release: + name: Release + environment: + name: release + runs-on: + group: npm-deploy + steps: + - name: Load Secrets + uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0 + with: + # Export loaded secrets as environment variables + export-env: true + env: + OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} + NPM_TOKEN: op://npm-deploy/npm-runner-token/secret + + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: "true" + fetch-depth: 2 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 18 + registry-url: 'https://registry.npmjs.org' + # Defaults to the user or organization that owns the workflow file + scope: '@uniswap' + + - name: Setup CI + run: npm ci + + - name: Build + run: npm run build + + - name: Publish + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }} diff --git a/lib/swap-router-contracts/.github/workflows/tests.yml b/lib/swap-router-contracts/.github/workflows/tests.yml new file mode 100644 index 0000000..3b969f7 --- /dev/null +++ b/lib/swap-router-contracts/.github/workflows/tests.yml @@ -0,0 +1,41 @@ +name: Tests + +on: + push: + branches: + - main + pull_request: + +jobs: + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: 12.x + registry-url: https://registry.npmjs.org + + - id: yarn-cache + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v1 + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + yarn- + + - name: Install dependencies + run: yarn install --frozen-lockfile + + # This is required separately from yarn test because it generates the typechain definitions + - name: Compile + run: yarn compile + + - name: Run unit tests + run: yarn test + env: # Or as an environment variable + ARCHIVE_RPC_URL: ${{ secrets.ARCHIVE_RPC_URL }} diff --git a/lib/swap-router-contracts/.gitignore b/lib/swap-router-contracts/.gitignore new file mode 100644 index 0000000..bde9d13 --- /dev/null +++ b/lib/swap-router-contracts/.gitignore @@ -0,0 +1,7 @@ +artifacts/ +cache/ +crytic-export/ +node_modules/ +typechain/ +.env +.vscode \ No newline at end of file diff --git a/lib/swap-router-contracts/.prettierignore b/lib/swap-router-contracts/.prettierignore new file mode 100644 index 0000000..821c19d --- /dev/null +++ b/lib/swap-router-contracts/.prettierignore @@ -0,0 +1 @@ +.github \ No newline at end of file diff --git a/lib/swap-router-contracts/.prettierrc b/lib/swap-router-contracts/.prettierrc new file mode 100644 index 0000000..31ba22d --- /dev/null +++ b/lib/swap-router-contracts/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "printWidth": 120 +} diff --git a/lib/swap-router-contracts/.solhint.json b/lib/swap-router-contracts/.solhint.json new file mode 100644 index 0000000..11b3647 --- /dev/null +++ b/lib/swap-router-contracts/.solhint.json @@ -0,0 +1,6 @@ +{ + "plugins": ["prettier"], + "rules": { + "prettier/prettier": "error" + } +} diff --git a/lib/swap-router-contracts/.yarnrc b/lib/swap-router-contracts/.yarnrc new file mode 100644 index 0000000..5455c6c --- /dev/null +++ b/lib/swap-router-contracts/.yarnrc @@ -0,0 +1 @@ +ignore-scripts true diff --git a/lib/swap-router-contracts/LICENSE b/lib/swap-router-contracts/LICENSE new file mode 100644 index 0000000..ecbc059 --- /dev/null +++ b/lib/swap-router-contracts/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file diff --git a/lib/swap-router-contracts/README.md b/lib/swap-router-contracts/README.md new file mode 100644 index 0000000..9260c3f --- /dev/null +++ b/lib/swap-router-contracts/README.md @@ -0,0 +1,65 @@ +# Uniswap Swap Router + +[![Tests](https://github.com/Uniswap/swap-router-contracts/workflows/Tests/badge.svg)](https://github.com/Uniswap/swap-router-contracts/actions?query=workflow%3ATests) +[![Lint](https://github.com/Uniswap/swap-router-contracts/workflows/Lint/badge.svg)](https://github.com/Uniswap/swap-router-contracts/actions?query=workflow%3ALint) + +This repository contains smart contracts for swapping on the Uniswap V2 and V3 protocols. + +## Bug bounty + +This repository is subject to the Uniswap V3 bug bounty program, +per the terms defined [here](./bug-bounty.md). + +## Local deployment + +In order to deploy this code to a local testnet, you should install the npm package +`@uniswap/swap-router-contracts` +and import bytecode imported from artifacts located at +`@uniswap/swap-router-contracts/artifacts/contracts/*/*.json`. +For example: + +```typescript +import { + abi as SWAP_ROUTER_ABI, + bytecode as SWAP_ROUTER_BYTECODE, +} from '@uniswap/swap-router-contracts/artifacts/contracts/SwapRouter02.sol/SwapRouter02.json' + +// deploy the bytecode +``` + +This will ensure that you are testing against the same bytecode that is deployed to +mainnet and public testnets, and all Uniswap code will correctly interoperate with +your local deployment. + +## Using solidity interfaces + +The swap router contract interfaces are available for import into solidity smart contracts +via the npm artifact `@uniswap/swap-router-contracts`, e.g.: + +```solidity +import '@uniswap/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol'; + +contract MyContract { + ISwapRouter02 router; + + function doSomethingWithSwapRouter() { + // router.exactInput(...); + } +} + +``` + +## Tests + +Some tests use Hardhat mainnet forking and therefore require an archive node. +Either create a `.env` file in the workspace root containing: + +``` +ARCHIVE_RPC_URL='...' +``` + +Or set the variable when running tests: + +``` +export ARCHIVE_RPC_URL='...' && npm run test +``` diff --git a/lib/swap-router-contracts/bug-bounty.md b/lib/swap-router-contracts/bug-bounty.md new file mode 100644 index 0000000..7ac66d4 --- /dev/null +++ b/lib/swap-router-contracts/bug-bounty.md @@ -0,0 +1,80 @@ +# Uniswap V3 Bug Bounty + +## Overview + +Starting on September 16th, 2021, the [swap-router-contracts](https://github.com/Uniswap/swap-router-contracts) repository is +subject to the Uniswap V3 Bug Bounty (the “Program”) to incentivize responsible bug disclosure. + +We are limiting the scope of the Program to critical and high severity bugs, and are offering a reward of up to $500,000. Happy hunting! + +## Scope + +The scope of the Program is limited to bugs that result in the loss of user funds. + +The following are not within the scope of the Program: + +- Any contract located under [contracts/test](./contracts/test) or [contracts/lens](./contracts/lens). +- Bugs in any third party contract or platform. +- Vulnerabilities already reported and/or discovered in contracts built by third parties. +- Any already-reported bugs. + +Vulnerabilities contingent upon the occurrence of any of the following also are outside the scope of this Program: + +- Frontend bugs +- DDOS attacks +- Spamming +- Phishing +- Automated tools (Github Actions, AWS, etc.) +- Compromise or misuse of third party systems or services + +## Assumptions + +Uniswap V3 was developed with the following assumptions, and thus any bug must also adhere to the following assumptions +to be eligible for the bug bounty: + +- The total supply of any token does not exceed 2128 - 1, i.e. `type(uint128).max`. +- The `transfer` and `transferFrom` methods of any token strictly decrease the balance of the token sender by the transfer amount and increases the balance of token recipient by the transfer amount, i.e. fee on transfer tokens are excluded. +- The token balance of an address can only change due to a call to `transfer` by the sender or `transferFrom` by an approved address, i.e. rebase tokens and interest bearing tokens are excluded. + +## Rewards + +Rewards will be allocated based on the severity of the bug disclosed and will be evaluated and rewarded at the discretion of the Uniswap Labs team. +For critical bugs that lead to loss of user funds (more than 1% or user specified slippage tolerance), +rewards of up to $500,000 will be granted. Lower severity bugs will be rewarded at the discretion of the team. +In addition, all vulnerabilities disclosed prior to the mainnet launch date will be subject to receive higher rewards. + +## Disclosure + +Any vulnerability or bug discovered must be reported only to the following email: [security@uniswap.org](mailto:security@uniswap.org). + +The vulnerability must not be disclosed publicly or to any other person, entity or email address before Uniswap Labs has been notified, has fixed the issue, and has granted permission for public disclosure. In addition, disclosure must be made within 24 hours following discovery of the vulnerability. + +A detailed report of a vulnerability increases the likelihood of a reward and may increase the reward amount. Please provide as much information about the vulnerability as possible, including: + +- The conditions on which reproducing the bug is contingent. +- The steps needed to reproduce the bug or, preferably, a proof of concept. +- The potential implications of the vulnerability being abused. + +Anyone who reports a unique, previously-unreported vulnerability that results in a change to the code or a configuration change and who keeps such vulnerability confidential until it has been resolved by our engineers will be recognized publicly for their contribution if they so choose. + +## Eligibility + +To be eligible for a reward under this Program, you must: + +- Discover a previously unreported, non-public vulnerability that would result in a loss of and/or lock on any ERC-20 token on Uniswap V2 or V3 (but not on any third party platform) and that is within the scope of this Program. Vulnerabilities must be distinct from the issues covered in the Trail of Bits or ABDK audits. +- Be the first to disclose the unique vulnerability to [security@uniswap.org](mailto:security@uniswap.org), in compliance with the disclosure requirements above. If similar vulnerabilities are reported within the same 24 hour period, rewards will be split at the discretion of Uniswap Labs. +- Provide sufficient information to enable our engineers to reproduce and fix the vulnerability. +- Not engage in any unlawful conduct when disclosing the bug, including through threats, demands, or any other coercive tactics. +- Not exploit the vulnerability in any way, including through making it public or by obtaining a profit (other than a reward under this Program). +- Make a good faith effort to avoid privacy violations, destruction of data, interruption or degradation of Uniswap V2 or V3. +- Submit only one vulnerability per submission, unless you need to chain vulnerabilities to provide impact regarding any of the vulnerabilities. +- Not submit a vulnerability caused by an underlying issue that is the same as an issue on which a reward has been paid under this Program. +- Not be one of our current or former employees, vendors, or contractors or an employee of any of those vendors or contractors. +- Not be subject to US sanctions or reside in a US-embargoed country. +- Be at least 18 years of age or, if younger, submit your vulnerability with the consent of your parent or guardian. + +## Other Terms + +By submitting your report, you grant Uniswap Labs any and all rights, including intellectual property rights, needed to validate, mitigate, and disclose the vulnerability. All reward decisions, including eligibility for and amounts of the rewards and the manner in which such rewards will be paid, are made at our sole discretion. + +The terms and conditions of this Program may be altered at any time. diff --git a/lib/swap-router-contracts/contracts/SwapRouter02.sol b/lib/swap-router-contracts/contracts/SwapRouter02.sol new file mode 100644 index 0000000..afef66f --- /dev/null +++ b/lib/swap-router-contracts/contracts/SwapRouter02.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@uniswap/v3-periphery/contracts/base/SelfPermit.sol'; +import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; + +import './interfaces/ISwapRouter02.sol'; +import './V2SwapRouter.sol'; +import './V3SwapRouter.sol'; +import './base/ApproveAndCall.sol'; +import './base/MulticallExtended.sol'; + +/// @title Uniswap V2 and V3 Swap Router +contract SwapRouter02 is ISwapRouter02, V2SwapRouter, V3SwapRouter, ApproveAndCall, MulticallExtended, SelfPermit { + constructor( + address _factoryV2, + address factoryV3, + address _positionManager, + address _WETH9 + ) ImmutableState(_factoryV2, _positionManager) PeripheryImmutableState(factoryV3, _WETH9) {} +} diff --git a/lib/swap-router-contracts/contracts/V2SwapRouter.sol b/lib/swap-router-contracts/contracts/V2SwapRouter.sol new file mode 100644 index 0000000..5738bd5 --- /dev/null +++ b/lib/swap-router-contracts/contracts/V2SwapRouter.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol'; +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; + +import './interfaces/IV2SwapRouter.sol'; +import './base/ImmutableState.sol'; +import './base/PeripheryPaymentsWithFeeExtended.sol'; +import './libraries/Constants.sol'; +import './libraries/UniswapV2Library.sol'; + +/// @title Uniswap V2 Swap Router +/// @notice Router for stateless execution of swaps against Uniswap V2 +abstract contract V2SwapRouter is IV2SwapRouter, ImmutableState, PeripheryPaymentsWithFeeExtended { + using LowGasSafeMath for uint256; + + // supports fee-on-transfer tokens + // requires the initial amount to have already been sent to the first pair + function _swap(address[] memory path, address _to) private { + for (uint256 i; i < path.length - 1; i++) { + (address input, address output) = (path[i], path[i + 1]); + (address token0, ) = UniswapV2Library.sortTokens(input, output); + IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factoryV2, input, output)); + uint256 amountInput; + uint256 amountOutput; + // scope to avoid stack too deep errors + { + (uint256 reserve0, uint256 reserve1, ) = pair.getReserves(); + (uint256 reserveInput, uint256 reserveOutput) = + input == token0 ? (reserve0, reserve1) : (reserve1, reserve0); + amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput); + amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput); + } + (uint256 amount0Out, uint256 amount1Out) = + input == token0 ? (uint256(0), amountOutput) : (amountOutput, uint256(0)); + address to = i < path.length - 2 ? UniswapV2Library.pairFor(factoryV2, output, path[i + 2]) : _to; + pair.swap(amount0Out, amount1Out, to, new bytes(0)); + } + } + + /// @inheritdoc IV2SwapRouter + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to + ) external payable override returns (uint256 amountOut) { + // use amountIn == Constants.CONTRACT_BALANCE as a flag to swap the entire balance of the contract + bool hasAlreadyPaid; + if (amountIn == Constants.CONTRACT_BALANCE) { + hasAlreadyPaid = true; + amountIn = IERC20(path[0]).balanceOf(address(this)); + } + + pay( + path[0], + hasAlreadyPaid ? address(this) : msg.sender, + UniswapV2Library.pairFor(factoryV2, path[0], path[1]), + amountIn + ); + + // find and replace to addresses + if (to == Constants.MSG_SENDER) to = msg.sender; + else if (to == Constants.ADDRESS_THIS) to = address(this); + + uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); + + _swap(path, to); + + amountOut = IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore); + require(amountOut >= amountOutMin, 'Too little received'); + } + + /// @inheritdoc IV2SwapRouter + function swapTokensForExactTokens( + uint256 amountOut, + uint256 amountInMax, + address[] calldata path, + address to + ) external payable override returns (uint256 amountIn) { + amountIn = UniswapV2Library.getAmountsIn(factoryV2, amountOut, path)[0]; + require(amountIn <= amountInMax, 'Too much requested'); + + pay(path[0], msg.sender, UniswapV2Library.pairFor(factoryV2, path[0], path[1]), amountIn); + + // find and replace to addresses + if (to == Constants.MSG_SENDER) to = msg.sender; + else if (to == Constants.ADDRESS_THIS) to = address(this); + + _swap(path, to); + } +} diff --git a/lib/swap-router-contracts/contracts/V3SwapRouter.sol b/lib/swap-router-contracts/contracts/V3SwapRouter.sol new file mode 100644 index 0000000..5ffc42a --- /dev/null +++ b/lib/swap-router-contracts/contracts/V3SwapRouter.sol @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; +import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; +import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; +import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; +import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; + +import './interfaces/IV3SwapRouter.sol'; +import './base/PeripheryPaymentsWithFeeExtended.sol'; +import './base/OracleSlippage.sol'; +import './libraries/Constants.sol'; + +/// @title Uniswap V3 Swap Router +/// @notice Router for stateless execution of swaps against Uniswap V3 +abstract contract V3SwapRouter is IV3SwapRouter, PeripheryPaymentsWithFeeExtended, OracleSlippage { + using Path for bytes; + using SafeCast for uint256; + + /// @dev Used as the placeholder value for amountInCached, because the computed amount in for an exact output swap + /// can never actually be this value + uint256 private constant DEFAULT_AMOUNT_IN_CACHED = type(uint256).max; + + /// @dev Transient storage variable used for returning the computed amount in for an exact output swap. + uint256 private amountInCached = DEFAULT_AMOUNT_IN_CACHED; + + /// @dev Returns the pool for the given token pair and fee. The pool contract may or may not exist. + function getPool( + address tokenA, + address tokenB, + uint24 fee + ) private view returns (IUniswapV3Pool) { + return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); + } + + struct SwapCallbackData { + bytes path; + address payer; + } + + /// @inheritdoc IUniswapV3SwapCallback + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata _data + ) external override { + require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported + SwapCallbackData memory data = abi.decode(_data, (SwapCallbackData)); + (address tokenIn, address tokenOut, uint24 fee) = data.path.decodeFirstPool(); + CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); + + (bool isExactInput, uint256 amountToPay) = + amount0Delta > 0 + ? (tokenIn < tokenOut, uint256(amount0Delta)) + : (tokenOut < tokenIn, uint256(amount1Delta)); + + if (isExactInput) { + pay(tokenIn, data.payer, msg.sender, amountToPay); + } else { + // either initiate the next swap or pay + if (data.path.hasMultiplePools()) { + data.path = data.path.skipToken(); + exactOutputInternal(amountToPay, msg.sender, 0, data); + } else { + amountInCached = amountToPay; + // note that because exact output swaps are executed in reverse order, tokenOut is actually tokenIn + pay(tokenOut, data.payer, msg.sender, amountToPay); + } + } + } + + /// @dev Performs a single exact input swap + function exactInputInternal( + uint256 amountIn, + address recipient, + uint160 sqrtPriceLimitX96, + SwapCallbackData memory data + ) private returns (uint256 amountOut) { + // find and replace recipient addresses + if (recipient == Constants.MSG_SENDER) recipient = msg.sender; + else if (recipient == Constants.ADDRESS_THIS) recipient = address(this); + + (address tokenIn, address tokenOut, uint24 fee) = data.path.decodeFirstPool(); + + bool zeroForOne = tokenIn < tokenOut; + + (int256 amount0, int256 amount1) = + getPool(tokenIn, tokenOut, fee).swap( + recipient, + zeroForOne, + amountIn.toInt256(), + sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : sqrtPriceLimitX96, + abi.encode(data) + ); + + return uint256(-(zeroForOne ? amount1 : amount0)); + } + + /// @inheritdoc IV3SwapRouter + function exactInputSingle(ExactInputSingleParams memory params) + external + payable + override + returns (uint256 amountOut) + { + // use amountIn == Constants.CONTRACT_BALANCE as a flag to swap the entire balance of the contract + bool hasAlreadyPaid; + if (params.amountIn == Constants.CONTRACT_BALANCE) { + hasAlreadyPaid = true; + params.amountIn = IERC20(params.tokenIn).balanceOf(address(this)); + } + + amountOut = exactInputInternal( + params.amountIn, + params.recipient, + params.sqrtPriceLimitX96, + SwapCallbackData({ + path: abi.encodePacked(params.tokenIn, params.fee, params.tokenOut), + payer: hasAlreadyPaid ? address(this) : msg.sender + }) + ); + require(amountOut >= params.amountOutMinimum, 'Too little received'); + } + + /// @inheritdoc IV3SwapRouter + function exactInput(ExactInputParams memory params) external payable override returns (uint256 amountOut) { + // use amountIn == Constants.CONTRACT_BALANCE as a flag to swap the entire balance of the contract + bool hasAlreadyPaid; + if (params.amountIn == Constants.CONTRACT_BALANCE) { + hasAlreadyPaid = true; + (address tokenIn, , ) = params.path.decodeFirstPool(); + params.amountIn = IERC20(tokenIn).balanceOf(address(this)); + } + + address payer = hasAlreadyPaid ? address(this) : msg.sender; + + while (true) { + bool hasMultiplePools = params.path.hasMultiplePools(); + + // the outputs of prior swaps become the inputs to subsequent ones + params.amountIn = exactInputInternal( + params.amountIn, + hasMultiplePools ? address(this) : params.recipient, // for intermediate swaps, this contract custodies + 0, + SwapCallbackData({ + path: params.path.getFirstPool(), // only the first pool in the path is necessary + payer: payer + }) + ); + + // decide whether to continue or terminate + if (hasMultiplePools) { + payer = address(this); + params.path = params.path.skipToken(); + } else { + amountOut = params.amountIn; + break; + } + } + + require(amountOut >= params.amountOutMinimum, 'Too little received'); + } + + /// @dev Performs a single exact output swap + function exactOutputInternal( + uint256 amountOut, + address recipient, + uint160 sqrtPriceLimitX96, + SwapCallbackData memory data + ) private returns (uint256 amountIn) { + // find and replace recipient addresses + if (recipient == Constants.MSG_SENDER) recipient = msg.sender; + else if (recipient == Constants.ADDRESS_THIS) recipient = address(this); + + (address tokenOut, address tokenIn, uint24 fee) = data.path.decodeFirstPool(); + + bool zeroForOne = tokenIn < tokenOut; + + (int256 amount0Delta, int256 amount1Delta) = + getPool(tokenIn, tokenOut, fee).swap( + recipient, + zeroForOne, + -amountOut.toInt256(), + sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : sqrtPriceLimitX96, + abi.encode(data) + ); + + uint256 amountOutReceived; + (amountIn, amountOutReceived) = zeroForOne + ? (uint256(amount0Delta), uint256(-amount1Delta)) + : (uint256(amount1Delta), uint256(-amount0Delta)); + // it's technically possible to not receive the full output amount, + // so if no price limit has been specified, require this possibility away + if (sqrtPriceLimitX96 == 0) require(amountOutReceived == amountOut); + } + + /// @inheritdoc IV3SwapRouter + function exactOutputSingle(ExactOutputSingleParams calldata params) + external + payable + override + returns (uint256 amountIn) + { + // avoid an SLOAD by using the swap return data + amountIn = exactOutputInternal( + params.amountOut, + params.recipient, + params.sqrtPriceLimitX96, + SwapCallbackData({path: abi.encodePacked(params.tokenOut, params.fee, params.tokenIn), payer: msg.sender}) + ); + + require(amountIn <= params.amountInMaximum, 'Too much requested'); + // has to be reset even though we don't use it in the single hop case + amountInCached = DEFAULT_AMOUNT_IN_CACHED; + } + + /// @inheritdoc IV3SwapRouter + function exactOutput(ExactOutputParams calldata params) external payable override returns (uint256 amountIn) { + exactOutputInternal( + params.amountOut, + params.recipient, + 0, + SwapCallbackData({path: params.path, payer: msg.sender}) + ); + + amountIn = amountInCached; + require(amountIn <= params.amountInMaximum, 'Too much requested'); + amountInCached = DEFAULT_AMOUNT_IN_CACHED; + } +} diff --git a/lib/swap-router-contracts/contracts/base/ApproveAndCall.sol b/lib/swap-router-contracts/contracts/base/ApproveAndCall.sol new file mode 100644 index 0000000..fdb8859 --- /dev/null +++ b/lib/swap-router-contracts/contracts/base/ApproveAndCall.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import '@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol'; + +import '../interfaces/IApproveAndCall.sol'; +import './ImmutableState.sol'; + +/// @title Approve and Call +/// @notice Allows callers to approve the Uniswap V3 position manager from this contract, +/// for any token, and then make calls into the position manager +abstract contract ApproveAndCall is IApproveAndCall, ImmutableState { + function tryApprove(address token, uint256 amount) private returns (bool) { + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(IERC20.approve.selector, positionManager, amount)); + return success && (data.length == 0 || abi.decode(data, (bool))); + } + + /// @inheritdoc IApproveAndCall + function getApprovalType(address token, uint256 amount) external override returns (ApprovalType) { + // check existing approval + if (IERC20(token).allowance(address(this), positionManager) >= amount) return ApprovalType.NOT_REQUIRED; + + // try type(uint256).max / type(uint256).max - 1 + if (tryApprove(token, type(uint256).max)) return ApprovalType.MAX; + if (tryApprove(token, type(uint256).max - 1)) return ApprovalType.MAX_MINUS_ONE; + + // set approval to 0 (must succeed) + require(tryApprove(token, 0)); + + // try type(uint256).max / type(uint256).max - 1 + if (tryApprove(token, type(uint256).max)) return ApprovalType.ZERO_THEN_MAX; + if (tryApprove(token, type(uint256).max - 1)) return ApprovalType.ZERO_THEN_MAX_MINUS_ONE; + + revert(); + } + + /// @inheritdoc IApproveAndCall + function approveMax(address token) external payable override { + require(tryApprove(token, type(uint256).max)); + } + + /// @inheritdoc IApproveAndCall + function approveMaxMinusOne(address token) external payable override { + require(tryApprove(token, type(uint256).max - 1)); + } + + /// @inheritdoc IApproveAndCall + function approveZeroThenMax(address token) external payable override { + require(tryApprove(token, 0)); + require(tryApprove(token, type(uint256).max)); + } + + /// @inheritdoc IApproveAndCall + function approveZeroThenMaxMinusOne(address token) external payable override { + require(tryApprove(token, 0)); + require(tryApprove(token, type(uint256).max - 1)); + } + + /// @inheritdoc IApproveAndCall + function callPositionManager(bytes memory data) public payable override returns (bytes memory result) { + bool success; + (success, result) = positionManager.call(data); + + if (!success) { + // Next 5 lines from https://ethereum.stackexchange.com/a/83577 + if (result.length < 68) revert(); + assembly { + result := add(result, 0x04) + } + revert(abi.decode(result, (string))); + } + } + + function balanceOf(address token) private view returns (uint256) { + return IERC20(token).balanceOf(address(this)); + } + + /// @inheritdoc IApproveAndCall + function mint(MintParams calldata params) external payable override returns (bytes memory result) { + return + callPositionManager( + abi.encodeWithSelector( + INonfungiblePositionManager.mint.selector, + INonfungiblePositionManager.MintParams({ + token0: params.token0, + token1: params.token1, + fee: params.fee, + tickLower: params.tickLower, + tickUpper: params.tickUpper, + amount0Desired: balanceOf(params.token0), + amount1Desired: balanceOf(params.token1), + amount0Min: params.amount0Min, + amount1Min: params.amount1Min, + recipient: params.recipient, + deadline: type(uint256).max // deadline should be checked via multicall + }) + ) + ); + } + + /// @inheritdoc IApproveAndCall + function increaseLiquidity(IncreaseLiquidityParams calldata params) + external + payable + override + returns (bytes memory result) + { + return + callPositionManager( + abi.encodeWithSelector( + INonfungiblePositionManager.increaseLiquidity.selector, + INonfungiblePositionManager.IncreaseLiquidityParams({ + tokenId: params.tokenId, + amount0Desired: balanceOf(params.token0), + amount1Desired: balanceOf(params.token1), + amount0Min: params.amount0Min, + amount1Min: params.amount1Min, + deadline: type(uint256).max // deadline should be checked via multicall + }) + ) + ); + } +} diff --git a/lib/swap-router-contracts/contracts/base/ImmutableState.sol b/lib/swap-router-contracts/contracts/base/ImmutableState.sol new file mode 100644 index 0000000..8ba7929 --- /dev/null +++ b/lib/swap-router-contracts/contracts/base/ImmutableState.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; + +import '../interfaces/IImmutableState.sol'; + +/// @title Immutable state +/// @notice Immutable state used by the swap router +abstract contract ImmutableState is IImmutableState { + /// @inheritdoc IImmutableState + address public immutable override factoryV2; + /// @inheritdoc IImmutableState + address public immutable override positionManager; + + constructor(address _factoryV2, address _positionManager) { + factoryV2 = _factoryV2; + positionManager = _positionManager; + } +} diff --git a/lib/swap-router-contracts/contracts/base/MulticallExtended.sol b/lib/swap-router-contracts/contracts/base/MulticallExtended.sol new file mode 100644 index 0000000..fe32ef6 --- /dev/null +++ b/lib/swap-router-contracts/contracts/base/MulticallExtended.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@uniswap/v3-periphery/contracts/base/Multicall.sol'; + +import '../interfaces/IMulticallExtended.sol'; +import '../base/PeripheryValidationExtended.sol'; + +/// @title Multicall +/// @notice Enables calling multiple methods in a single call to the contract +abstract contract MulticallExtended is IMulticallExtended, Multicall, PeripheryValidationExtended { + /// @inheritdoc IMulticallExtended + function multicall(uint256 deadline, bytes[] calldata data) + external + payable + override + checkDeadline(deadline) + returns (bytes[] memory) + { + return multicall(data); + } + + /// @inheritdoc IMulticallExtended + function multicall(bytes32 previousBlockhash, bytes[] calldata data) + external + payable + override + checkPreviousBlockhash(previousBlockhash) + returns (bytes[] memory) + { + return multicall(data); + } +} diff --git a/lib/swap-router-contracts/contracts/base/OracleSlippage.sol b/lib/swap-router-contracts/contracts/base/OracleSlippage.sol new file mode 100644 index 0000000..4a1424b --- /dev/null +++ b/lib/swap-router-contracts/contracts/base/OracleSlippage.sol @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '../interfaces/IOracleSlippage.sol'; + +import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; +import '@uniswap/v3-periphery/contracts/base/BlockTimestamp.sol'; +import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; +import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; +import '@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol'; + +abstract contract OracleSlippage is IOracleSlippage, PeripheryImmutableState, BlockTimestamp { + using Path for bytes; + + /// @dev Returns the tick as of the beginning of the current block, and as of right now, for the given pool. + function getBlockStartingAndCurrentTick(IUniswapV3Pool pool) + internal + view + returns (int24 blockStartingTick, int24 currentTick) + { + uint16 observationIndex; + uint16 observationCardinality; + (, currentTick, observationIndex, observationCardinality, , , ) = pool.slot0(); + + // 2 observations are needed to reliably calculate the block starting tick + require(observationCardinality > 1, 'NEO'); + + // If the latest observation occurred in the past, then no tick-changing trades have happened in this block + // therefore the tick in `slot0` is the same as at the beginning of the current block. + // We don't need to check if this observation is initialized - it is guaranteed to be. + (uint32 observationTimestamp, int56 tickCumulative, , ) = pool.observations(observationIndex); + if (observationTimestamp != uint32(_blockTimestamp())) { + blockStartingTick = currentTick; + } else { + uint256 prevIndex = (uint256(observationIndex) + observationCardinality - 1) % observationCardinality; + (uint32 prevObservationTimestamp, int56 prevTickCumulative, , bool prevInitialized) = + pool.observations(prevIndex); + + require(prevInitialized, 'ONI'); + + uint32 delta = observationTimestamp - prevObservationTimestamp; + blockStartingTick = int24((tickCumulative - prevTickCumulative) / delta); + } + } + + /// @dev Virtual function to get pool addresses that can be overridden in tests. + function getPoolAddress( + address tokenA, + address tokenB, + uint24 fee + ) internal view virtual returns (IUniswapV3Pool pool) { + pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); + } + + /// @dev Returns the synthetic time-weighted average tick as of secondsAgo, as well as the current tick, + /// for the given path. Returned synthetic ticks always represent tokenOut/tokenIn prices, + /// meaning lower ticks are worse. + function getSyntheticTicks(bytes memory path, uint32 secondsAgo) + internal + view + returns (int256 syntheticAverageTick, int256 syntheticCurrentTick) + { + bool lowerTicksAreWorse; + + uint256 numPools = path.numPools(); + address previousTokenIn; + for (uint256 i = 0; i < numPools; i++) { + // this assumes the path is sorted in swap order + (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); + IUniswapV3Pool pool = getPoolAddress(tokenIn, tokenOut, fee); + + // get the average and current ticks for the current pool + int256 averageTick; + int256 currentTick; + if (secondsAgo == 0) { + // we optimize for the secondsAgo == 0 case, i.e. since the beginning of the block + (averageTick, currentTick) = getBlockStartingAndCurrentTick(pool); + } else { + (averageTick, ) = OracleLibrary.consult(address(pool), secondsAgo); + (, currentTick, , , , , ) = IUniswapV3Pool(pool).slot0(); + } + + if (i == numPools - 1) { + // if we're here, this is the last pool in the path, meaning tokenOut represents the + // destination token. so, if tokenIn < tokenOut, then tokenIn is token0 of the last pool, + // meaning the current running ticks are going to represent tokenOut/tokenIn prices. + // so, the lower these prices get, the worse of a price the swap will get + lowerTicksAreWorse = tokenIn < tokenOut; + } else { + // if we're here, we need to iterate over the next pool in the path + path = path.skipToken(); + previousTokenIn = tokenIn; + } + + // accumulate the ticks derived from the current pool into the running synthetic ticks, + // ensuring that intermediate tokens "cancel out" + bool add = (i == 0) || (previousTokenIn < tokenIn ? tokenIn < tokenOut : tokenOut < tokenIn); + if (add) { + syntheticAverageTick += averageTick; + syntheticCurrentTick += currentTick; + } else { + syntheticAverageTick -= averageTick; + syntheticCurrentTick -= currentTick; + } + } + + // flip the sign of the ticks if necessary, to ensure that the lower ticks are always worse + if (!lowerTicksAreWorse) { + syntheticAverageTick *= -1; + syntheticCurrentTick *= -1; + } + } + + /// @dev Cast a int256 to a int24, revert on overflow or underflow + function toInt24(int256 y) private pure returns (int24 z) { + require((z = int24(y)) == y); + } + + /// @dev For each passed path, fetches the synthetic time-weighted average tick as of secondsAgo, + /// as well as the current tick. Then, synthetic ticks from all paths are subjected to a weighted + /// average, where the weights are the fraction of the total input amount allocated to each path. + /// Returned synthetic ticks always represent tokenOut/tokenIn prices, meaning lower ticks are worse. + /// Paths must all start and end in the same token. + function getSyntheticTicks( + bytes[] memory paths, + uint128[] memory amounts, + uint32 secondsAgo + ) internal view returns (int256 averageSyntheticAverageTick, int256 averageSyntheticCurrentTick) { + require(paths.length == amounts.length); + + OracleLibrary.WeightedTickData[] memory weightedSyntheticAverageTicks = + new OracleLibrary.WeightedTickData[](paths.length); + OracleLibrary.WeightedTickData[] memory weightedSyntheticCurrentTicks = + new OracleLibrary.WeightedTickData[](paths.length); + + for (uint256 i = 0; i < paths.length; i++) { + (int256 syntheticAverageTick, int256 syntheticCurrentTick) = getSyntheticTicks(paths[i], secondsAgo); + weightedSyntheticAverageTicks[i].tick = toInt24(syntheticAverageTick); + weightedSyntheticCurrentTicks[i].tick = toInt24(syntheticCurrentTick); + weightedSyntheticAverageTicks[i].weight = amounts[i]; + weightedSyntheticCurrentTicks[i].weight = amounts[i]; + } + + averageSyntheticAverageTick = OracleLibrary.getWeightedArithmeticMeanTick(weightedSyntheticAverageTicks); + averageSyntheticCurrentTick = OracleLibrary.getWeightedArithmeticMeanTick(weightedSyntheticCurrentTicks); + } + + /// @inheritdoc IOracleSlippage + function checkOracleSlippage( + bytes memory path, + uint24 maximumTickDivergence, + uint32 secondsAgo + ) external view override { + (int256 syntheticAverageTick, int256 syntheticCurrentTick) = getSyntheticTicks(path, secondsAgo); + require(syntheticAverageTick - syntheticCurrentTick < maximumTickDivergence, 'TD'); + } + + /// @inheritdoc IOracleSlippage + function checkOracleSlippage( + bytes[] memory paths, + uint128[] memory amounts, + uint24 maximumTickDivergence, + uint32 secondsAgo + ) external view override { + (int256 averageSyntheticAverageTick, int256 averageSyntheticCurrentTick) = + getSyntheticTicks(paths, amounts, secondsAgo); + require(averageSyntheticAverageTick - averageSyntheticCurrentTick < maximumTickDivergence, 'TD'); + } +} diff --git a/lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol b/lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol new file mode 100644 index 0000000..08877ac --- /dev/null +++ b/lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; + +import '@uniswap/v3-periphery/contracts/base/PeripheryPayments.sol'; +import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol'; + +import '../interfaces/IPeripheryPaymentsExtended.sol'; + +abstract contract PeripheryPaymentsExtended is IPeripheryPaymentsExtended, PeripheryPayments { + /// @inheritdoc IPeripheryPaymentsExtended + function unwrapWETH9(uint256 amountMinimum) external payable override { + unwrapWETH9(amountMinimum, msg.sender); + } + + /// @inheritdoc IPeripheryPaymentsExtended + function wrapETH(uint256 value) external payable override { + IWETH9(WETH9).deposit{value: value}(); + } + + /// @inheritdoc IPeripheryPaymentsExtended + function sweepToken(address token, uint256 amountMinimum) external payable override { + sweepToken(token, amountMinimum, msg.sender); + } + + /// @inheritdoc IPeripheryPaymentsExtended + function pull(address token, uint256 value) external payable override { + TransferHelper.safeTransferFrom(token, msg.sender, address(this), value); + } +} diff --git a/lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol b/lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol new file mode 100644 index 0000000..f4a9e42 --- /dev/null +++ b/lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; + +import '@uniswap/v3-periphery/contracts/base/PeripheryPaymentsWithFee.sol'; + +import '../interfaces/IPeripheryPaymentsWithFeeExtended.sol'; +import './PeripheryPaymentsExtended.sol'; + +abstract contract PeripheryPaymentsWithFeeExtended is + IPeripheryPaymentsWithFeeExtended, + PeripheryPaymentsExtended, + PeripheryPaymentsWithFee +{ + /// @inheritdoc IPeripheryPaymentsWithFeeExtended + function unwrapWETH9WithFee( + uint256 amountMinimum, + uint256 feeBips, + address feeRecipient + ) external payable override { + unwrapWETH9WithFee(amountMinimum, msg.sender, feeBips, feeRecipient); + } + + /// @inheritdoc IPeripheryPaymentsWithFeeExtended + function sweepTokenWithFee( + address token, + uint256 amountMinimum, + uint256 feeBips, + address feeRecipient + ) external payable override { + sweepTokenWithFee(token, amountMinimum, msg.sender, feeBips, feeRecipient); + } +} diff --git a/lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol b/lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol new file mode 100644 index 0000000..17afbf2 --- /dev/null +++ b/lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; + +import '@uniswap/v3-periphery/contracts/base/PeripheryValidation.sol'; + +abstract contract PeripheryValidationExtended is PeripheryValidation { + modifier checkPreviousBlockhash(bytes32 previousBlockhash) { + require(blockhash(block.number - 1) == previousBlockhash, 'Blockhash'); + _; + } +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol b/lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol new file mode 100644 index 0000000..6e50dd0 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +interface IApproveAndCall { + enum ApprovalType {NOT_REQUIRED, MAX, MAX_MINUS_ONE, ZERO_THEN_MAX, ZERO_THEN_MAX_MINUS_ONE} + + /// @dev Lens to be called off-chain to determine which (if any) of the relevant approval functions should be called + /// @param token The token to approve + /// @param amount The amount to approve + /// @return The required approval type + function getApprovalType(address token, uint256 amount) external returns (ApprovalType); + + /// @notice Approves a token for the maximum possible amount + /// @param token The token to approve + function approveMax(address token) external payable; + + /// @notice Approves a token for the maximum possible amount minus one + /// @param token The token to approve + function approveMaxMinusOne(address token) external payable; + + /// @notice Approves a token for zero, then the maximum possible amount + /// @param token The token to approve + function approveZeroThenMax(address token) external payable; + + /// @notice Approves a token for zero, then the maximum possible amount minus one + /// @param token The token to approve + function approveZeroThenMaxMinusOne(address token) external payable; + + /// @notice Calls the position manager with arbitrary calldata + /// @param data Calldata to pass along to the position manager + /// @return result The result from the call + function callPositionManager(bytes memory data) external payable returns (bytes memory result); + + struct MintParams { + address token0; + address token1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint256 amount0Min; + uint256 amount1Min; + address recipient; + } + + /// @notice Calls the position manager's mint function + /// @param params Calldata to pass along to the position manager + /// @return result The result from the call + function mint(MintParams calldata params) external payable returns (bytes memory result); + + struct IncreaseLiquidityParams { + address token0; + address token1; + uint256 tokenId; + uint256 amount0Min; + uint256 amount1Min; + } + + /// @notice Calls the position manager's increaseLiquidity function + /// @param params Calldata to pass along to the position manager + /// @return result The result from the call + function increaseLiquidity(IncreaseLiquidityParams calldata params) external payable returns (bytes memory result); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol b/lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol new file mode 100644 index 0000000..58120dd --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +/// @title Immutable state +/// @notice Functions that return immutable state of the router +interface IImmutableState { + /// @return Returns the address of the Uniswap V2 factory + function factoryV2() external view returns (address); + + /// @return Returns the address of Uniswap V3 NFT position manager + function positionManager() external view returns (address); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol b/lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol new file mode 100644 index 0000000..084f970 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +/// @title MixedRouteQuoterV1 Interface +/// @notice Supports quoting the calculated amounts for exact input swaps. Is specialized for routes containing a mix of V2 and V3 liquidity. +/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IMixedRouteQuoterV1 { + /// @notice Returns the amount out received for a given exact input swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + /// @return v3SqrtPriceX96AfterList List of the sqrt price after the swap for each v3 pool in the path, 0 for v2 pools + /// @return v3InitializedTicksCrossedList List of the initialized ticks that the swap crossed for each v3 pool in the path, 0 for v2 pools + /// @return v3SwapGasEstimate The estimate of the gas that the v3 swaps in the path consume + function quoteExactInput(bytes memory path, uint256 amountIn) + external + returns ( + uint256 amountOut, + uint160[] memory v3SqrtPriceX96AfterList, + uint32[] memory v3InitializedTicksCrossedList, + uint256 v3SwapGasEstimate + ); + + struct QuoteExactInputSingleV3Params { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + + struct QuoteExactInputSingleV2Params { + address tokenIn; + address tokenOut; + uint256 amountIn; + } + + /// @notice Returns the amount out received for a given exact input but for a swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// fee The fee of the token pool to consider for the pair + /// amountIn The desired input amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactInputSingleV3(QuoteExactInputSingleV3Params memory params) + external + returns ( + uint256 amountOut, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ); + + /// @notice Returns the amount out received for a given exact input but for a swap of a single V2 pool + /// @param params The params for the quote, encoded as `QuoteExactInputSingleV2Params` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// amountIn The desired input amount + /// @return amountOut The amount of `tokenOut` that would be received + function quoteExactInputSingleV2(QuoteExactInputSingleV2Params memory params) external returns (uint256 amountOut); + + /// @dev ExactOutput swaps are not supported by this new Quoter which is specialized for supporting routes + /// crossing both V2 liquidity pairs and V3 pools. + /// @deprecated quoteExactOutputSingle and exactOutput. Use QuoterV2 instead. +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol b/lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol new file mode 100644 index 0000000..1e1a2c4 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +import '@uniswap/v3-periphery/contracts/interfaces/IMulticall.sol'; + +/// @title MulticallExtended interface +/// @notice Enables calling multiple methods in a single call to the contract with optional validation +interface IMulticallExtended is IMulticall { + /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed + /// @dev The `msg.value` should not be trusted for any method callable from multicall. + /// @param deadline The time by which this function must be called before failing + /// @param data The encoded function data for each of the calls to make to this contract + /// @return results The results from each of the calls passed in via data + function multicall(uint256 deadline, bytes[] calldata data) external payable returns (bytes[] memory results); + + /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed + /// @dev The `msg.value` should not be trusted for any method callable from multicall. + /// @param previousBlockhash The expected parent blockHash + /// @param data The encoded function data for each of the calls to make to this contract + /// @return results The results from each of the calls passed in via data + function multicall(bytes32 previousBlockhash, bytes[] calldata data) + external + payable + returns (bytes[] memory results); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol b/lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol new file mode 100644 index 0000000..734fb33 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +/// @title OracleSlippage interface +/// @notice Enables slippage checks against oracle prices +interface IOracleSlippage { + /// @notice Ensures that the current (synthetic) tick over the path is no worse than + /// `maximumTickDivergence` ticks away from the average as of `secondsAgo` + /// @param path The path to fetch prices over + /// @param maximumTickDivergence The maximum number of ticks that the price can degrade by + /// @param secondsAgo The number of seconds ago to compute oracle prices against + function checkOracleSlippage( + bytes memory path, + uint24 maximumTickDivergence, + uint32 secondsAgo + ) external view; + + /// @notice Ensures that the weighted average current (synthetic) tick over the path is no + /// worse than `maximumTickDivergence` ticks away from the average as of `secondsAgo` + /// @param paths The paths to fetch prices over + /// @param amounts The weights for each entry in `paths` + /// @param maximumTickDivergence The maximum number of ticks that the price can degrade by + /// @param secondsAgo The number of seconds ago to compute oracle prices against + function checkOracleSlippage( + bytes[] memory paths, + uint128[] memory amounts, + uint24 maximumTickDivergence, + uint32 secondsAgo + ) external view; +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol b/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol new file mode 100644 index 0000000..53c026b --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; + +import '@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol'; + +/// @title Periphery Payments Extended +/// @notice Functions to ease deposits and withdrawals of ETH and tokens +interface IPeripheryPaymentsExtended is IPeripheryPayments { + /// @notice Unwraps the contract's WETH9 balance and sends it to msg.sender as ETH. + /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. + /// @param amountMinimum The minimum amount of WETH9 to unwrap + function unwrapWETH9(uint256 amountMinimum) external payable; + + /// @notice Wraps the contract's ETH balance into WETH9 + /// @dev The resulting WETH9 is custodied by the router, thus will require further distribution + /// @param value The amount of ETH to wrap + function wrapETH(uint256 value) external payable; + + /// @notice Transfers the full amount of a token held by this contract to msg.sender + /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users + /// @param token The contract address of the token which will be transferred to msg.sender + /// @param amountMinimum The minimum amount of token required for a transfer + function sweepToken(address token, uint256 amountMinimum) external payable; + + /// @notice Transfers the specified amount of a token from the msg.sender to address(this) + /// @param token The token to pull + /// @param value The amount to pay + function pull(address token, uint256 value) external payable; +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol b/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol new file mode 100644 index 0000000..fdbc461 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; + +import '@uniswap/v3-periphery/contracts/interfaces/IPeripheryPaymentsWithFee.sol'; + +import './IPeripheryPaymentsExtended.sol'; + +/// @title Periphery Payments With Fee Extended +/// @notice Functions to ease deposits and withdrawals of ETH +interface IPeripheryPaymentsWithFeeExtended is IPeripheryPaymentsExtended, IPeripheryPaymentsWithFee { + /// @notice Unwraps the contract's WETH9 balance and sends it to msg.sender as ETH, with a percentage between + /// 0 (exclusive), and 1 (inclusive) going to feeRecipient + /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. + function unwrapWETH9WithFee( + uint256 amountMinimum, + uint256 feeBips, + address feeRecipient + ) external payable; + + /// @notice Transfers the full amount of a token held by this contract to msg.sender, with a percentage between + /// 0 (exclusive) and 1 (inclusive) going to feeRecipient + /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users + function sweepTokenWithFee( + address token, + uint256 amountMinimum, + uint256 feeBips, + address feeRecipient + ) external payable; +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IQuoter.sol b/lib/swap-router-contracts/contracts/interfaces/IQuoter.sol new file mode 100644 index 0000000..3410e0c --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IQuoter.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +/// @title Quoter Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoter { + /// @notice Returns the amount out received for a given exact input swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut); + + /// @notice Returns the amount out received for a given exact input but for a swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountIn The desired input amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + function quoteExactInputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) external returns (uint256 amountOut); + + /// @notice Returns the amount in required for a given exact output swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn); + + /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountOut The desired output amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` + function quoteExactOutputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountOut, + uint160 sqrtPriceLimitX96 + ) external returns (uint256 amountIn); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol b/lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol new file mode 100644 index 0000000..3c2961b --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +/// @title QuoterV2 Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps. +/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoterV2 { + /// @notice Returns the amount out received for a given exact input swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactInput(bytes memory path, uint256 amountIn) + external + returns ( + uint256 amountOut, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ); + + struct QuoteExactInputSingleParams { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + + /// @notice Returns the amount out received for a given exact input but for a swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// fee The fee of the token pool to consider for the pair + /// amountIn The desired input amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactInputSingle(QuoteExactInputSingleParams memory params) + external + returns ( + uint256 amountOut, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ); + + /// @notice Returns the amount in required for a given exact output swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactOutput(bytes memory path, uint256 amountOut) + external + returns ( + uint256 amountIn, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ); + + struct QuoteExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint256 amount; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + + /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// fee The fee of the token pool to consider for the pair + /// amountOut The desired output amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactOutputSingle(QuoteExactOutputSingleParams memory params) + external + returns ( + uint256 amountIn, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol b/lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol new file mode 100644 index 0000000..688fc3d --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +import '@uniswap/v3-periphery/contracts/interfaces/ISelfPermit.sol'; + +import './IV2SwapRouter.sol'; +import './IV3SwapRouter.sol'; +import './IApproveAndCall.sol'; +import './IMulticallExtended.sol'; + +/// @title Router token swapping functionality +interface ISwapRouter02 is IV2SwapRouter, IV3SwapRouter, IApproveAndCall, IMulticallExtended, ISelfPermit { + +} diff --git a/lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol b/lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol new file mode 100644 index 0000000..a002188 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +/// @notice Validates tokens by flash borrowing from the token/ pool on V2. +/// @notice Returns +/// Status.FOT if we detected a fee is taken on transfer. +/// Status.STF if transfer failed for the token. +/// Status.UNKN if we did not detect any issues with the token. +/// @notice A return value of Status.UNKN does not mean the token is definitely not a fee on transfer token +/// or definitely has no problems with its transfer. It just means we cant say for sure that it has any +/// issues. +/// @dev We can not guarantee the result of this lens is correct for a few reasons: +/// @dev 1/ Some tokens take fees or allow transfers under specific conditions, for example some have an allowlist +/// @dev of addresses that do/dont require fees. Therefore the result is not guaranteed to be correct +/// @dev in all circumstances. +/// @dev 2/ It is possible that the token does not have any pools on V2 therefore we are not able to perform +/// @dev a flashloan to test the token. +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. +interface ITokenValidator { + // Status.FOT: detected a fee is taken on transfer. + // Status.STF: transfer failed for the token. + // Status.UNKN: no issues found with the token. + enum Status {UNKN, FOT, STF} + + /// @notice Validates a token by detecting if its transferable or takes a fee on transfer + /// @param token The address of the token to check for fee on transfer + /// @param baseTokens The addresses of the tokens to try pairing with + /// token when looking for a pool to flash loan from. + /// @param amountToBorrow The amount to try flash borrowing from the pools + /// @return The status of the token + function validate( + address token, + address[] calldata baseTokens, + uint256 amountToBorrow + ) external returns (Status); + + /// @notice Validates each token by detecting if its transferable or takes a fee on transfer + /// @param tokens The addresses of the tokens to check for fee on transfer + /// @param baseTokens The addresses of the tokens to try pairing with + /// token when looking for a pool to flash loan from. + /// @param amountToBorrow The amount to try flash borrowing from the pools + /// @return The status of the token + function batchValidate( + address[] calldata tokens, + address[] calldata baseTokens, + uint256 amountToBorrow + ) external returns (Status[] memory); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol b/lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol new file mode 100644 index 0000000..0d1ded3 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V2 +interface IV2SwapRouter { + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, + /// and swap the entire amount, enabling contracts to send tokens before calling this function. + /// @param amountIn The amount of token to swap + /// @param amountOutMin The minimum amount of output that must be received + /// @param path The ordered list of tokens to swap through + /// @param to The recipient address + /// @return amountOut The amount of the received token + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to + ) external payable returns (uint256 amountOut); + + /// @notice Swaps as little as possible of one token for an exact amount of another token + /// @param amountOut The amount of token to swap for + /// @param amountInMax The maximum amount of input that the caller will pay + /// @param path The ordered list of tokens to swap through + /// @param to The recipient address + /// @return amountIn The amount of token to pay + function swapTokensForExactTokens( + uint256 amountOut, + uint256 amountInMax, + address[] calldata path, + address to + ) external payable returns (uint256 amountIn); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol b/lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol new file mode 100644 index 0000000..f5d6459 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V3 +interface IV3SwapRouter is IUniswapV3SwapCallback { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, + /// and swap the entire amount, enabling contracts to send tokens before calling this function. + /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata + /// @return amountOut The amount of the received token + function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); + + struct ExactInputParams { + bytes path; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path + /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, + /// and swap the entire amount, enabling contracts to send tokens before calling this function. + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata + /// @return amountOut The amount of the received token + function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); + + struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another token + /// that may remain in the router after the swap. + /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata + /// @return amountIn The amount of the input token + function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); + + struct ExactOutputParams { + bytes path; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) + /// that may remain in the router after the swap. + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata + /// @return amountIn The amount of the input token + function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); +} diff --git a/lib/swap-router-contracts/contracts/interfaces/IWETH.sol b/lib/swap-router-contracts/contracts/interfaces/IWETH.sol new file mode 100644 index 0000000..24cbe47 --- /dev/null +++ b/lib/swap-router-contracts/contracts/interfaces/IWETH.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +interface IWETH { + function deposit() external payable; + + function transfer(address to, uint256 value) external returns (bool); + + function withdraw(uint256) external; +} diff --git a/lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol b/lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol new file mode 100644 index 0000000..b2beb08 --- /dev/null +++ b/lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; +import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; +import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; +import '@uniswap/v3-core/contracts/libraries/TickBitmap.sol'; +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; +import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; +import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; +import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; +import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; +import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; + +import '../base/ImmutableState.sol'; +import '../interfaces/IMixedRouteQuoterV1.sol'; +import '../libraries/PoolTicksCounter.sol'; +import '../libraries/UniswapV2Library.sol'; + +/// @title Provides on chain quotes for V3, V2, and MixedRoute exact input swaps +/// @notice Allows getting the expected amount out for a given swap without executing the swap +/// @notice Does not support exact output swaps since using the contract balance between exactOut swaps is not supported +/// @dev These functions are not gas efficient and should _not_ be called on chain. Instead, optimistically execute +/// the swap and check the amounts in the callback. +contract MixedRouteQuoterV1 is IMixedRouteQuoterV1, IUniswapV3SwapCallback, PeripheryImmutableState { + using Path for bytes; + using SafeCast for uint256; + using PoolTicksCounter for IUniswapV3Pool; + address public immutable factoryV2; + /// @dev Value to bit mask with path fee to determine if V2 or V3 route + // max V3 fee: 000011110100001001000000 (24 bits) + // mask: 1 << 23 = 100000000000000000000000 = decimal value 8388608 + uint24 private constant flagBitmask = 8388608; + + /// @dev Transient storage variable used to check a safety condition in exact output swaps. + uint256 private amountOutCached; + + constructor( + address _factory, + address _factoryV2, + address _WETH9 + ) PeripheryImmutableState(_factory, _WETH9) { + factoryV2 = _factoryV2; + } + + function getPool( + address tokenA, + address tokenB, + uint24 fee + ) private view returns (IUniswapV3Pool) { + return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); + } + + /// @dev Given an amountIn, fetch the reserves of the V2 pair and get the amountOut + function getPairAmountOut( + uint256 amountIn, + address tokenIn, + address tokenOut + ) private view returns (uint256) { + (uint256 reserveIn, uint256 reserveOut) = UniswapV2Library.getReserves(factoryV2, tokenIn, tokenOut); + return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut); + } + + /// @inheritdoc IUniswapV3SwapCallback + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes memory path + ) external view override { + require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported + (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); + CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); + + (bool isExactInput, uint256 amountReceived) = + amount0Delta > 0 + ? (tokenIn < tokenOut, uint256(-amount1Delta)) + : (tokenOut < tokenIn, uint256(-amount0Delta)); + + IUniswapV3Pool pool = getPool(tokenIn, tokenOut, fee); + (uint160 v3SqrtPriceX96After, int24 tickAfter, , , , , ) = pool.slot0(); + + if (isExactInput) { + assembly { + let ptr := mload(0x40) + mstore(ptr, amountReceived) + mstore(add(ptr, 0x20), v3SqrtPriceX96After) + mstore(add(ptr, 0x40), tickAfter) + revert(ptr, 0x60) + } + } else { + /// since we don't support exactOutput, revert here + revert('Exact output quote not supported'); + } + } + + /// @dev Parses a revert reason that should contain the numeric quote + function parseRevertReason(bytes memory reason) + private + pure + returns ( + uint256 amount, + uint160 sqrtPriceX96After, + int24 tickAfter + ) + { + if (reason.length != 0x60) { + if (reason.length < 0x44) revert('Unexpected error'); + assembly { + reason := add(reason, 0x04) + } + revert(abi.decode(reason, (string))); + } + return abi.decode(reason, (uint256, uint160, int24)); + } + + function handleV3Revert( + bytes memory reason, + IUniswapV3Pool pool, + uint256 gasEstimate + ) + private + view + returns ( + uint256 amount, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 + ) + { + int24 tickBefore; + int24 tickAfter; + (, tickBefore, , , , , ) = pool.slot0(); + (amount, sqrtPriceX96After, tickAfter) = parseRevertReason(reason); + + initializedTicksCrossed = pool.countInitializedTicksCrossed(tickBefore, tickAfter); + + return (amount, sqrtPriceX96After, initializedTicksCrossed, gasEstimate); + } + + /// @dev Fetch an exactIn quote for a V3 Pool on chain + function quoteExactInputSingleV3(QuoteExactInputSingleV3Params memory params) + public + override + returns ( + uint256 amountOut, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ) + { + bool zeroForOne = params.tokenIn < params.tokenOut; + IUniswapV3Pool pool = getPool(params.tokenIn, params.tokenOut, params.fee); + + uint256 gasBefore = gasleft(); + try + pool.swap( + address(this), // address(0) might cause issues with some tokens + zeroForOne, + params.amountIn.toInt256(), + params.sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : params.sqrtPriceLimitX96, + abi.encodePacked(params.tokenIn, params.fee, params.tokenOut) + ) + {} catch (bytes memory reason) { + gasEstimate = gasBefore - gasleft(); + return handleV3Revert(reason, pool, gasEstimate); + } + } + + /// @dev Fetch an exactIn quote for a V2 pair on chain + function quoteExactInputSingleV2(QuoteExactInputSingleV2Params memory params) + public + view + override + returns (uint256 amountOut) + { + amountOut = getPairAmountOut(params.amountIn, params.tokenIn, params.tokenOut); + } + + /// @dev Get the quote for an exactIn swap between an array of V2 and/or V3 pools + /// @notice To encode a V2 pair within the path, use 0x800000 (hex value of 8388608) for the fee between the two token addresses + function quoteExactInput(bytes memory path, uint256 amountIn) + public + override + returns ( + uint256 amountOut, + uint160[] memory v3SqrtPriceX96AfterList, + uint32[] memory v3InitializedTicksCrossedList, + uint256 v3SwapGasEstimate + ) + { + v3SqrtPriceX96AfterList = new uint160[](path.numPools()); + v3InitializedTicksCrossedList = new uint32[](path.numPools()); + + uint256 i = 0; + while (true) { + (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); + + if (fee & flagBitmask != 0) { + amountIn = quoteExactInputSingleV2( + QuoteExactInputSingleV2Params({tokenIn: tokenIn, tokenOut: tokenOut, amountIn: amountIn}) + ); + } else { + /// the outputs of prior swaps become the inputs to subsequent ones + ( + uint256 _amountOut, + uint160 _sqrtPriceX96After, + uint32 _initializedTicksCrossed, + uint256 _gasEstimate + ) = + quoteExactInputSingleV3( + QuoteExactInputSingleV3Params({ + tokenIn: tokenIn, + tokenOut: tokenOut, + fee: fee, + amountIn: amountIn, + sqrtPriceLimitX96: 0 + }) + ); + v3SqrtPriceX96AfterList[i] = _sqrtPriceX96After; + v3InitializedTicksCrossedList[i] = _initializedTicksCrossed; + v3SwapGasEstimate += _gasEstimate; + amountIn = _amountOut; + } + i++; + + /// decide whether to continue or terminate + if (path.hasMultiplePools()) { + path = path.skipToken(); + } else { + return (amountIn, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList, v3SwapGasEstimate); + } + } + } +} diff --git a/lib/swap-router-contracts/contracts/lens/Quoter.sol b/lib/swap-router-contracts/contracts/lens/Quoter.sol new file mode 100644 index 0000000..e34d43d --- /dev/null +++ b/lib/swap-router-contracts/contracts/lens/Quoter.sol @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; +import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; +import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; +import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; +import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; +import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; +import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; + +import '../interfaces/IQuoter.sol'; + +/// @title Provides quotes for swaps +/// @notice Allows getting the expected amount out or amount in for a given swap without executing the swap +/// @dev These functions are not gas efficient and should _not_ be called on chain. Instead, optimistically execute +/// the swap and check the amounts in the callback. +contract Quoter is IQuoter, IUniswapV3SwapCallback, PeripheryImmutableState { + using Path for bytes; + using SafeCast for uint256; + + /// @dev Transient storage variable used to check a safety condition in exact output swaps. + uint256 private amountOutCached; + + constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} + + function getPool( + address tokenA, + address tokenB, + uint24 fee + ) private view returns (IUniswapV3Pool) { + return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); + } + + /// @inheritdoc IUniswapV3SwapCallback + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes memory path + ) external view override { + require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported + (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); + CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); + + (bool isExactInput, uint256 amountToPay, uint256 amountReceived) = + amount0Delta > 0 + ? (tokenIn < tokenOut, uint256(amount0Delta), uint256(-amount1Delta)) + : (tokenOut < tokenIn, uint256(amount1Delta), uint256(-amount0Delta)); + if (isExactInput) { + assembly { + let ptr := mload(0x40) + mstore(ptr, amountReceived) + revert(ptr, 32) + } + } else { + // if the cache has been populated, ensure that the full output amount has been received + if (amountOutCached != 0) require(amountReceived == amountOutCached); + assembly { + let ptr := mload(0x40) + mstore(ptr, amountToPay) + revert(ptr, 32) + } + } + } + + /// @dev Parses a revert reason that should contain the numeric quote + function parseRevertReason(bytes memory reason) private pure returns (uint256) { + if (reason.length != 32) { + if (reason.length < 68) revert('Unexpected error'); + assembly { + reason := add(reason, 0x04) + } + revert(abi.decode(reason, (string))); + } + return abi.decode(reason, (uint256)); + } + + /// @inheritdoc IQuoter + function quoteExactInputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) public override returns (uint256 amountOut) { + bool zeroForOne = tokenIn < tokenOut; + + try + getPool(tokenIn, tokenOut, fee).swap( + address(this), // address(0) might cause issues with some tokens + zeroForOne, + amountIn.toInt256(), + sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : sqrtPriceLimitX96, + abi.encodePacked(tokenIn, fee, tokenOut) + ) + {} catch (bytes memory reason) { + return parseRevertReason(reason); + } + } + + /// @inheritdoc IQuoter + function quoteExactInput(bytes memory path, uint256 amountIn) external override returns (uint256 amountOut) { + while (true) { + bool hasMultiplePools = path.hasMultiplePools(); + + (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); + + // the outputs of prior swaps become the inputs to subsequent ones + amountIn = quoteExactInputSingle(tokenIn, tokenOut, fee, amountIn, 0); + + // decide whether to continue or terminate + if (hasMultiplePools) { + path = path.skipToken(); + } else { + return amountIn; + } + } + } + + /// @inheritdoc IQuoter + function quoteExactOutputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountOut, + uint160 sqrtPriceLimitX96 + ) public override returns (uint256 amountIn) { + bool zeroForOne = tokenIn < tokenOut; + + // if no price limit has been specified, cache the output amount for comparison in the swap callback + if (sqrtPriceLimitX96 == 0) amountOutCached = amountOut; + try + getPool(tokenIn, tokenOut, fee).swap( + address(this), // address(0) might cause issues with some tokens + zeroForOne, + -amountOut.toInt256(), + sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : sqrtPriceLimitX96, + abi.encodePacked(tokenOut, fee, tokenIn) + ) + {} catch (bytes memory reason) { + if (sqrtPriceLimitX96 == 0) delete amountOutCached; // clear cache + return parseRevertReason(reason); + } + } + + /// @inheritdoc IQuoter + function quoteExactOutput(bytes memory path, uint256 amountOut) external override returns (uint256 amountIn) { + while (true) { + bool hasMultiplePools = path.hasMultiplePools(); + + (address tokenOut, address tokenIn, uint24 fee) = path.decodeFirstPool(); + + // the inputs of prior swaps become the outputs of subsequent ones + amountOut = quoteExactOutputSingle(tokenIn, tokenOut, fee, amountOut, 0); + + // decide whether to continue or terminate + if (hasMultiplePools) { + path = path.skipToken(); + } else { + return amountOut; + } + } + } +} diff --git a/lib/swap-router-contracts/contracts/lens/QuoterV2.sol b/lib/swap-router-contracts/contracts/lens/QuoterV2.sol new file mode 100644 index 0000000..9c17c17 --- /dev/null +++ b/lib/swap-router-contracts/contracts/lens/QuoterV2.sol @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; +import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; +import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; +import '@uniswap/v3-core/contracts/libraries/TickBitmap.sol'; +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; +import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; +import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; +import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; +import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; + +import '../interfaces/IQuoterV2.sol'; +import '../libraries/PoolTicksCounter.sol'; + +/// @title Provides quotes for swaps +/// @notice Allows getting the expected amount out or amount in for a given swap without executing the swap +/// @dev These functions are not gas efficient and should _not_ be called on chain. Instead, optimistically execute +/// the swap and check the amounts in the callback. +contract QuoterV2 is IQuoterV2, IUniswapV3SwapCallback, PeripheryImmutableState { + using Path for bytes; + using SafeCast for uint256; + using PoolTicksCounter for IUniswapV3Pool; + + /// @dev Transient storage variable used to check a safety condition in exact output swaps. + uint256 private amountOutCached; + + constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} + + function getPool( + address tokenA, + address tokenB, + uint24 fee + ) private view returns (IUniswapV3Pool) { + return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); + } + + /// @inheritdoc IUniswapV3SwapCallback + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes memory path + ) external view override { + require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported + (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); + CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); + + (bool isExactInput, uint256 amountToPay, uint256 amountReceived) = + amount0Delta > 0 + ? (tokenIn < tokenOut, uint256(amount0Delta), uint256(-amount1Delta)) + : (tokenOut < tokenIn, uint256(amount1Delta), uint256(-amount0Delta)); + + IUniswapV3Pool pool = getPool(tokenIn, tokenOut, fee); + (uint160 sqrtPriceX96After, int24 tickAfter, , , , , ) = pool.slot0(); + + if (isExactInput) { + assembly { + let ptr := mload(0x40) + mstore(ptr, amountReceived) + mstore(add(ptr, 0x20), sqrtPriceX96After) + mstore(add(ptr, 0x40), tickAfter) + revert(ptr, 96) + } + } else { + // if the cache has been populated, ensure that the full output amount has been received + if (amountOutCached != 0) require(amountReceived == amountOutCached); + assembly { + let ptr := mload(0x40) + mstore(ptr, amountToPay) + mstore(add(ptr, 0x20), sqrtPriceX96After) + mstore(add(ptr, 0x40), tickAfter) + revert(ptr, 96) + } + } + } + + /// @dev Parses a revert reason that should contain the numeric quote + function parseRevertReason(bytes memory reason) + private + pure + returns ( + uint256 amount, + uint160 sqrtPriceX96After, + int24 tickAfter + ) + { + if (reason.length != 96) { + if (reason.length < 68) revert('Unexpected error'); + assembly { + reason := add(reason, 0x04) + } + revert(abi.decode(reason, (string))); + } + return abi.decode(reason, (uint256, uint160, int24)); + } + + function handleRevert( + bytes memory reason, + IUniswapV3Pool pool, + uint256 gasEstimate + ) + private + view + returns ( + uint256 amount, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 + ) + { + int24 tickBefore; + int24 tickAfter; + (, tickBefore, , , , , ) = pool.slot0(); + (amount, sqrtPriceX96After, tickAfter) = parseRevertReason(reason); + + initializedTicksCrossed = pool.countInitializedTicksCrossed(tickBefore, tickAfter); + + return (amount, sqrtPriceX96After, initializedTicksCrossed, gasEstimate); + } + + function quoteExactInputSingle(QuoteExactInputSingleParams memory params) + public + override + returns ( + uint256 amountOut, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ) + { + bool zeroForOne = params.tokenIn < params.tokenOut; + IUniswapV3Pool pool = getPool(params.tokenIn, params.tokenOut, params.fee); + + uint256 gasBefore = gasleft(); + try + pool.swap( + address(this), // address(0) might cause issues with some tokens + zeroForOne, + params.amountIn.toInt256(), + params.sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : params.sqrtPriceLimitX96, + abi.encodePacked(params.tokenIn, params.fee, params.tokenOut) + ) + {} catch (bytes memory reason) { + gasEstimate = gasBefore - gasleft(); + return handleRevert(reason, pool, gasEstimate); + } + } + + function quoteExactInput(bytes memory path, uint256 amountIn) + public + override + returns ( + uint256 amountOut, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ) + { + sqrtPriceX96AfterList = new uint160[](path.numPools()); + initializedTicksCrossedList = new uint32[](path.numPools()); + + uint256 i = 0; + while (true) { + (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); + + // the outputs of prior swaps become the inputs to subsequent ones + (uint256 _amountOut, uint160 _sqrtPriceX96After, uint32 _initializedTicksCrossed, uint256 _gasEstimate) = + quoteExactInputSingle( + QuoteExactInputSingleParams({ + tokenIn: tokenIn, + tokenOut: tokenOut, + fee: fee, + amountIn: amountIn, + sqrtPriceLimitX96: 0 + }) + ); + + sqrtPriceX96AfterList[i] = _sqrtPriceX96After; + initializedTicksCrossedList[i] = _initializedTicksCrossed; + amountIn = _amountOut; + gasEstimate += _gasEstimate; + i++; + + // decide whether to continue or terminate + if (path.hasMultiplePools()) { + path = path.skipToken(); + } else { + return (amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate); + } + } + } + + function quoteExactOutputSingle(QuoteExactOutputSingleParams memory params) + public + override + returns ( + uint256 amountIn, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ) + { + bool zeroForOne = params.tokenIn < params.tokenOut; + IUniswapV3Pool pool = getPool(params.tokenIn, params.tokenOut, params.fee); + + // if no price limit has been specified, cache the output amount for comparison in the swap callback + if (params.sqrtPriceLimitX96 == 0) amountOutCached = params.amount; + uint256 gasBefore = gasleft(); + try + pool.swap( + address(this), // address(0) might cause issues with some tokens + zeroForOne, + -params.amount.toInt256(), + params.sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : params.sqrtPriceLimitX96, + abi.encodePacked(params.tokenOut, params.fee, params.tokenIn) + ) + {} catch (bytes memory reason) { + gasEstimate = gasBefore - gasleft(); + if (params.sqrtPriceLimitX96 == 0) delete amountOutCached; // clear cache + return handleRevert(reason, pool, gasEstimate); + } + } + + function quoteExactOutput(bytes memory path, uint256 amountOut) + public + override + returns ( + uint256 amountIn, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ) + { + sqrtPriceX96AfterList = new uint160[](path.numPools()); + initializedTicksCrossedList = new uint32[](path.numPools()); + + uint256 i = 0; + while (true) { + (address tokenOut, address tokenIn, uint24 fee) = path.decodeFirstPool(); + + // the inputs of prior swaps become the outputs of subsequent ones + (uint256 _amountIn, uint160 _sqrtPriceX96After, uint32 _initializedTicksCrossed, uint256 _gasEstimate) = + quoteExactOutputSingle( + QuoteExactOutputSingleParams({ + tokenIn: tokenIn, + tokenOut: tokenOut, + amount: amountOut, + fee: fee, + sqrtPriceLimitX96: 0 + }) + ); + + sqrtPriceX96AfterList[i] = _sqrtPriceX96After; + initializedTicksCrossedList[i] = _initializedTicksCrossed; + amountOut = _amountIn; + gasEstimate += _gasEstimate; + i++; + + // decide whether to continue or terminate + if (path.hasMultiplePools()) { + path = path.skipToken(); + } else { + return (amountOut, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate); + } + } + } +} diff --git a/lib/swap-router-contracts/contracts/lens/README.md b/lib/swap-router-contracts/contracts/lens/README.md new file mode 100644 index 0000000..8359711 --- /dev/null +++ b/lib/swap-router-contracts/contracts/lens/README.md @@ -0,0 +1,4 @@ +# lens + +These contracts are not designed to be called on-chain. They simplify +fetching on-chain data from off-chain. diff --git a/lib/swap-router-contracts/contracts/lens/TokenValidator.sol b/lib/swap-router-contracts/contracts/lens/TokenValidator.sol new file mode 100644 index 0000000..ba3afde --- /dev/null +++ b/lib/swap-router-contracts/contracts/lens/TokenValidator.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; +import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Callee.sol'; +import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; +import '../libraries/UniswapV2Library.sol'; +import '../interfaces/ISwapRouter02.sol'; +import '../interfaces/ITokenValidator.sol'; +import '../base/ImmutableState.sol'; + +/// @notice Validates tokens by flash borrowing from the token/ pool on V2. +/// @notice Returns +/// Status.FOT if we detected a fee is taken on transfer. +/// Status.STF if transfer failed for the token. +/// Status.UNKN if we did not detect any issues with the token. +/// @notice A return value of Status.UNKN does not mean the token is definitely not a fee on transfer token +/// or definitely has no problems with its transfer. It just means we cant say for sure that it has any +/// issues. +/// @dev We can not guarantee the result of this lens is correct for a few reasons: +/// @dev 1/ Some tokens take fees or allow transfers under specific conditions, for example some have an allowlist +/// @dev of addresses that do/dont require fees. Therefore the result is not guaranteed to be correct +/// @dev in all circumstances. +/// @dev 2/ It is possible that the token does not have any pools on V2 therefore we are not able to perform +/// @dev a flashloan to test the token. +contract TokenValidator is ITokenValidator, IUniswapV2Callee, ImmutableState { + string internal constant FOT_REVERT_STRING = 'FOT'; + // https://github.com/Uniswap/v2-core/blob/1136544ac842ff48ae0b1b939701436598d74075/contracts/UniswapV2Pair.sol#L46 + string internal constant STF_REVERT_STRING_SUFFIX = 'TRANSFER_FAILED'; + + constructor(address _factoryV2, address _positionManager) ImmutableState(_factoryV2, _positionManager) {} + + function batchValidate( + address[] calldata tokens, + address[] calldata baseTokens, + uint256 amountToBorrow + ) public override returns (Status[] memory isFotResults) { + isFotResults = new Status[](tokens.length); + for (uint256 i = 0; i < tokens.length; i++) { + isFotResults[i] = validate(tokens[i], baseTokens, amountToBorrow); + } + } + + function validate( + address token, + address[] calldata baseTokens, + uint256 amountToBorrow + ) public override returns (Status) { + for (uint256 i = 0; i < baseTokens.length; i++) { + Status result = _validate(token, baseTokens[i], amountToBorrow); + if (result == Status.FOT || result == Status.STF) { + return result; + } + } + return Status.UNKN; + } + + function _validate( + address token, + address baseToken, + uint256 amountToBorrow + ) internal returns (Status) { + if (token == baseToken) { + return Status.UNKN; + } + + address pairAddress = UniswapV2Library.pairFor(this.factoryV2(), token, baseToken); + + // If the token/baseToken pair exists, get token0. + // Must do low level call as try/catch does not support case where contract does not exist. + (, bytes memory returnData) = address(pairAddress).call(abi.encodeWithSelector(IUniswapV2Pair.token0.selector)); + + if (returnData.length == 0) { + return Status.UNKN; + } + + address token0Address = abi.decode(returnData, (address)); + + // Flash loan {amountToBorrow} + (uint256 amount0Out, uint256 amount1Out) = + token == token0Address ? (amountToBorrow, uint256(0)) : (uint256(0), amountToBorrow); + + uint256 balanceBeforeLoan = IERC20(token).balanceOf(address(this)); + + IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); + + try + pair.swap(amount0Out, amount1Out, address(this), abi.encode(balanceBeforeLoan, amountToBorrow)) + {} catch Error(string memory reason) { + if (isFotFailed(reason)) { + return Status.FOT; + } + + if (isTransferFailed(reason)) { + return Status.STF; + } + + return Status.UNKN; + } + + // Swap always reverts so should never reach. + revert('Unexpected error'); + } + + function isFotFailed(string memory reason) internal pure returns (bool) { + return keccak256(bytes(reason)) == keccak256(bytes(FOT_REVERT_STRING)); + } + + function isTransferFailed(string memory reason) internal pure returns (bool) { + // We check the suffix of the revert string so we can support forks that + // may have modified the prefix. + string memory stf = STF_REVERT_STRING_SUFFIX; + + uint256 reasonLength = bytes(reason).length; + uint256 suffixLength = bytes(stf).length; + if (reasonLength < suffixLength) { + return false; + } + + uint256 ptr; + uint256 offset = 32 + reasonLength - suffixLength; + bool transferFailed; + assembly { + ptr := add(reason, offset) + let suffixPtr := add(stf, 32) + transferFailed := eq(keccak256(ptr, suffixLength), keccak256(suffixPtr, suffixLength)) + } + + return transferFailed; + } + + function uniswapV2Call( + address, + uint256 amount0, + uint256, + bytes calldata data + ) external view override { + IUniswapV2Pair pair = IUniswapV2Pair(msg.sender); + (address token0, address token1) = (pair.token0(), pair.token1()); + + IERC20 tokenBorrowed = IERC20(amount0 > 0 ? token0 : token1); + + (uint256 balanceBeforeLoan, uint256 amountRequestedToBorrow) = abi.decode(data, (uint256, uint256)); + uint256 amountBorrowed = tokenBorrowed.balanceOf(address(this)) - balanceBeforeLoan; + + // If we received less token than we requested when we called swap, then a fee must have been taken + // by the token during transfer. + if (amountBorrowed != amountRequestedToBorrow) { + revert(FOT_REVERT_STRING); + } + + // Note: If we do not revert here, we would end up reverting in the pair's swap method anyway + // since for a flash borrow we need to transfer back the amount we borrowed + 0.3% fee, and we don't + // have funds to cover the fee. Revert early here to save gas/time. + revert('Unknown'); + } +} diff --git a/lib/swap-router-contracts/contracts/libraries/Constants.sol b/lib/swap-router-contracts/contracts/libraries/Constants.sol new file mode 100644 index 0000000..7428170 --- /dev/null +++ b/lib/swap-router-contracts/contracts/libraries/Constants.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; + +/// @title Constant state +/// @notice Constant state used by the swap router +library Constants { + /// @dev Used for identifying cases when this contract's balance of a token is to be used + uint256 internal constant CONTRACT_BALANCE = 0; + + /// @dev Used as a flag for identifying msg.sender, saves gas by sending more 0 bytes + address internal constant MSG_SENDER = address(1); + + /// @dev Used as a flag for identifying address(this), saves gas by sending more 0 bytes + address internal constant ADDRESS_THIS = address(2); +} diff --git a/lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol b/lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol new file mode 100644 index 0000000..fb0682f --- /dev/null +++ b/lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.0; + +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; + +library PoolTicksCounter { + /// @dev This function counts the number of initialized ticks that would incur a gas cost between tickBefore and tickAfter. + /// When tickBefore and/or tickAfter themselves are initialized, the logic over whether we should count them depends on the + /// direction of the swap. If we are swapping upwards (tickAfter > tickBefore) we don't want to count tickBefore but we do + /// want to count tickAfter. The opposite is true if we are swapping downwards. + function countInitializedTicksCrossed( + IUniswapV3Pool self, + int24 tickBefore, + int24 tickAfter + ) internal view returns (uint32 initializedTicksCrossed) { + int16 wordPosLower; + int16 wordPosHigher; + uint8 bitPosLower; + uint8 bitPosHigher; + bool tickBeforeInitialized; + bool tickAfterInitialized; + + { + // Get the key and offset in the tick bitmap of the active tick before and after the swap. + int16 wordPos = int16((tickBefore / self.tickSpacing()) >> 8); + uint8 bitPos = uint8((tickBefore / self.tickSpacing()) % 256); + + int16 wordPosAfter = int16((tickAfter / self.tickSpacing()) >> 8); + uint8 bitPosAfter = uint8((tickAfter / self.tickSpacing()) % 256); + + // In the case where tickAfter is initialized, we only want to count it if we are swapping downwards. + // If the initializable tick after the swap is initialized, our original tickAfter is a + // multiple of tick spacing, and we are swapping downwards we know that tickAfter is initialized + // and we shouldn't count it. + tickAfterInitialized = + ((self.tickBitmap(wordPosAfter) & (1 << bitPosAfter)) > 0) && + ((tickAfter % self.tickSpacing()) == 0) && + (tickBefore > tickAfter); + + // In the case where tickBefore is initialized, we only want to count it if we are swapping upwards. + // Use the same logic as above to decide whether we should count tickBefore or not. + tickBeforeInitialized = + ((self.tickBitmap(wordPos) & (1 << bitPos)) > 0) && + ((tickBefore % self.tickSpacing()) == 0) && + (tickBefore < tickAfter); + + if (wordPos < wordPosAfter || (wordPos == wordPosAfter && bitPos <= bitPosAfter)) { + wordPosLower = wordPos; + bitPosLower = bitPos; + wordPosHigher = wordPosAfter; + bitPosHigher = bitPosAfter; + } else { + wordPosLower = wordPosAfter; + bitPosLower = bitPosAfter; + wordPosHigher = wordPos; + bitPosHigher = bitPos; + } + } + + // Count the number of initialized ticks crossed by iterating through the tick bitmap. + // Our first mask should include the lower tick and everything to its left. + uint256 mask = type(uint256).max << bitPosLower; + while (wordPosLower <= wordPosHigher) { + // If we're on the final tick bitmap page, ensure we only count up to our + // ending tick. + if (wordPosLower == wordPosHigher) { + mask = mask & (type(uint256).max >> (255 - bitPosHigher)); + } + + uint256 masked = self.tickBitmap(wordPosLower) & mask; + initializedTicksCrossed += countOneBits(masked); + wordPosLower++; + // Reset our mask so we consider all bits on the next iteration. + mask = type(uint256).max; + } + + if (tickAfterInitialized) { + initializedTicksCrossed -= 1; + } + + if (tickBeforeInitialized) { + initializedTicksCrossed -= 1; + } + + return initializedTicksCrossed; + } + + function countOneBits(uint256 x) private pure returns (uint16) { + uint16 bits = 0; + while (x != 0) { + bits++; + x &= (x - 1); + } + return bits; + } +} diff --git a/lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol b/lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol new file mode 100644 index 0000000..a90b07e --- /dev/null +++ b/lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; +import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol'; + +library UniswapV2Library { + using LowGasSafeMath for uint256; + + // returns sorted token addresses, used to handle return values from pairs sorted in this order + function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { + require(tokenA != tokenB); + (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); + require(token0 != address(0)); + } + + // calculates the CREATE2 address for a pair without making any external calls + function pairFor( + address factory, + address tokenA, + address tokenB + ) internal pure returns (address pair) { + (address token0, address token1) = sortTokens(tokenA, tokenB); + pair = address( + uint256( + keccak256( + abi.encodePacked( + hex'ff', + factory, + keccak256(abi.encodePacked(token0, token1)), + hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash + ) + ) + ) + ); + } + + // fetches and sorts the reserves for a pair + function getReserves( + address factory, + address tokenA, + address tokenB + ) internal view returns (uint256 reserveA, uint256 reserveB) { + (address token0, ) = sortTokens(tokenA, tokenB); + (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); + (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); + } + + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut( + uint256 amountIn, + uint256 reserveIn, + uint256 reserveOut + ) internal pure returns (uint256 amountOut) { + require(amountIn > 0, 'INSUFFICIENT_INPUT_AMOUNT'); + require(reserveIn > 0 && reserveOut > 0); + uint256 amountInWithFee = amountIn.mul(997); + uint256 numerator = amountInWithFee.mul(reserveOut); + uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); + amountOut = numerator / denominator; + } + + // given an output amount of an asset and pair reserves, returns a required input amount of the other asset + function getAmountIn( + uint256 amountOut, + uint256 reserveIn, + uint256 reserveOut + ) internal pure returns (uint256 amountIn) { + require(amountOut > 0, 'INSUFFICIENT_OUTPUT_AMOUNT'); + require(reserveIn > 0 && reserveOut > 0); + uint256 numerator = reserveIn.mul(amountOut).mul(1000); + uint256 denominator = reserveOut.sub(amountOut).mul(997); + amountIn = (numerator / denominator).add(1); + } + + // performs chained getAmountIn calculations on any number of pairs + function getAmountsIn( + address factory, + uint256 amountOut, + address[] memory path + ) internal view returns (uint256[] memory amounts) { + require(path.length >= 2); + amounts = new uint256[](path.length); + amounts[amounts.length - 1] = amountOut; + for (uint256 i = path.length - 1; i > 0; i--) { + (uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i - 1], path[i]); + amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); + } + } +} diff --git a/lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol b/lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol new file mode 100644 index 0000000..0c55ca7 --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; + +import '../base/ImmutableState.sol'; + +contract ImmutableStateTest is ImmutableState { + constructor(address _factoryV2, address _positionManager) ImmutableState(_factoryV2, _positionManager) {} +} diff --git a/lib/swap-router-contracts/contracts/test/MockObservations.sol b/lib/swap-router-contracts/contracts/test/MockObservations.sol new file mode 100644 index 0000000..2d4edbe --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/MockObservations.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.7.6; + +import '@uniswap/v3-core/contracts/libraries/Oracle.sol'; + +contract MockObservations { + using Oracle for Oracle.Observation[65535]; + + // slot0 + int24 private slot0Tick; + uint16 private slot0ObservationCardinality; + uint16 private slot0ObservationIndex; + + // observations + Oracle.Observation[65535] public observations; + + // block timestamps always monotonic increasing from 0, cumulative ticks are calculated automatically + constructor( + uint32[3] memory blockTimestamps, + int24[3] memory ticks, + bool mockLowObservationCardinality + ) { + require(blockTimestamps[0] == 0, '0'); + require(blockTimestamps[1] > 0, '1'); + require(blockTimestamps[2] > blockTimestamps[1], '2'); + + int56 tickCumulative = 0; + for (uint256 i = 0; i < blockTimestamps.length; i++) { + if (i != 0) { + int24 tick = ticks[i - 1]; + uint32 delta = blockTimestamps[i] - blockTimestamps[i - 1]; + tickCumulative += int56(tick) * delta; + } + observations[i] = Oracle.Observation({ + blockTimestamp: blockTimestamps[i], + tickCumulative: tickCumulative, + secondsPerLiquidityCumulativeX128: uint160(i), + initialized: true + }); + } + slot0Tick = ticks[2]; + slot0ObservationCardinality = mockLowObservationCardinality ? 1 : 3; + slot0ObservationIndex = 2; + } + + function slot0() + external + view + returns ( + uint160, + int24, + uint16, + uint16, + uint16, + uint8, + bool + ) + { + return (0, slot0Tick, slot0ObservationIndex, slot0ObservationCardinality, 0, 0, false); + } + + function observe(uint32[] calldata secondsAgos) + external + view + returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) + { + return + observations.observe( + observations[2].blockTimestamp, + secondsAgos, + slot0Tick, + slot0ObservationIndex, + 0, + slot0ObservationCardinality + ); + } +} diff --git a/lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol b/lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol new file mode 100644 index 0000000..7e76c09 --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.7.6; +pragma abicoder v2; + +import '../SwapRouter02.sol'; + +contract MockTimeSwapRouter02 is SwapRouter02 { + uint256 time; + + constructor( + address _factoryV2, + address factoryV3, + address _positionManager, + address _WETH9 + ) SwapRouter02(_factoryV2, factoryV3, _positionManager, _WETH9) {} + + function _blockTimestamp() internal view override returns (uint256) { + return time; + } + + function setTime(uint256 _time) external { + time = _time; + } +} diff --git a/lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol b/lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol new file mode 100644 index 0000000..4d97120 --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity =0.7.6; +pragma abicoder v2; + +import '../base/OracleSlippage.sol'; + +contract OracleSlippageTest is OracleSlippage { + mapping(address => mapping(address => mapping(uint24 => IUniswapV3Pool))) private pools; + uint256 internal time; + + constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} + + function setTime(uint256 _time) external { + time = _time; + } + + function _blockTimestamp() internal view override returns (uint256) { + return time; + } + + function registerPool( + IUniswapV3Pool pool, + address tokenIn, + address tokenOut, + uint24 fee + ) external { + pools[tokenIn][tokenOut][fee] = pool; + pools[tokenOut][tokenIn][fee] = pool; + } + + function getPoolAddress( + address tokenA, + address tokenB, + uint24 fee + ) internal view override returns (IUniswapV3Pool pool) { + pool = pools[tokenA][tokenB][fee]; + } + + function testGetBlockStartingAndCurrentTick(IUniswapV3Pool pool) + external + view + returns (int24 blockStartingTick, int24 currentTick) + { + return getBlockStartingAndCurrentTick(pool); + } + + function testGetSyntheticTicks(bytes memory path, uint32 secondsAgo) + external + view + returns (int256 syntheticAverageTick, int256 syntheticCurrentTick) + { + return getSyntheticTicks(path, secondsAgo); + } + + function testGetSyntheticTicks( + bytes[] memory paths, + uint128[] memory amounts, + uint32 secondsAgo + ) external view returns (int256 averageSyntheticAverageTick, int256 averageSyntheticCurrentTick) { + return getSyntheticTicks(paths, amounts, secondsAgo); + } +} diff --git a/lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol b/lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol new file mode 100644 index 0000000..3d47bf7 --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; + +pragma solidity >=0.6.0; + +import '../libraries/PoolTicksCounter.sol'; + +contract PoolTicksCounterTest { + using PoolTicksCounter for IUniswapV3Pool; + + function countInitializedTicksCrossed( + IUniswapV3Pool pool, + int24 tickBefore, + int24 tickAfter + ) external view returns (uint32 initializedTicksCrossed) { + return pool.countInitializedTicksCrossed(tickBefore, tickAfter); + } +} diff --git a/lib/swap-router-contracts/contracts/test/TestERC20.sol b/lib/swap-router-contracts/contracts/test/TestERC20.sol new file mode 100644 index 0000000..66ed4ac --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/TestERC20.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.7.6; + +import '@openzeppelin/contracts/drafts/ERC20Permit.sol'; + +contract TestERC20 is ERC20Permit { + constructor(uint256 amountToMint) ERC20('Test ERC20', 'TEST') ERC20Permit('Test ERC20') { + _mint(msg.sender, amountToMint); + } +} diff --git a/lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol b/lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol new file mode 100644 index 0000000..b32b54e --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.7.6; +pragma abicoder v2; + +import '../base/MulticallExtended.sol'; + +contract TestMulticallExtended is MulticallExtended { + uint256 time; + + function _blockTimestamp() internal view override returns (uint256) { + return time; + } + + function setTime(uint256 _time) external { + time = _time; + } + + struct Tuple { + uint256 a; + uint256 b; + } + + function functionThatReturnsTuple(uint256 a, uint256 b) external pure returns (Tuple memory tuple) { + tuple = Tuple({b: a, a: b}); + } +} diff --git a/lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol b/lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol new file mode 100644 index 0000000..1400bd6 --- /dev/null +++ b/lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.7.6; + +import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; +import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; +import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; + +contract TestUniswapV3Callee is IUniswapV3SwapCallback { + using SafeCast for uint256; + + function swapExact0For1( + address pool, + uint256 amount0In, + address recipient, + uint160 sqrtPriceLimitX96 + ) external { + IUniswapV3Pool(pool).swap(recipient, true, amount0In.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); + } + + function swap0ForExact1( + address pool, + uint256 amount1Out, + address recipient, + uint160 sqrtPriceLimitX96 + ) external { + IUniswapV3Pool(pool).swap(recipient, true, -amount1Out.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); + } + + function swapExact1For0( + address pool, + uint256 amount1In, + address recipient, + uint160 sqrtPriceLimitX96 + ) external { + IUniswapV3Pool(pool).swap(recipient, false, amount1In.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); + } + + function swap1ForExact0( + address pool, + uint256 amount0Out, + address recipient, + uint160 sqrtPriceLimitX96 + ) external { + IUniswapV3Pool(pool).swap(recipient, false, -amount0Out.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); + } + + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) external override { + address sender = abi.decode(data, (address)); + + if (amount0Delta > 0) { + IERC20(IUniswapV3Pool(msg.sender).token0()).transferFrom(sender, msg.sender, uint256(amount0Delta)); + } else { + assert(amount1Delta > 0); + IERC20(IUniswapV3Pool(msg.sender).token1()).transferFrom(sender, msg.sender, uint256(amount1Delta)); + } + } +} diff --git a/lib/swap-router-contracts/hardhat.config.ts b/lib/swap-router-contracts/hardhat.config.ts new file mode 100644 index 0000000..2afe809 --- /dev/null +++ b/lib/swap-router-contracts/hardhat.config.ts @@ -0,0 +1,70 @@ +import '@nomiclabs/hardhat-ethers' +import '@nomiclabs/hardhat-etherscan' +import '@nomiclabs/hardhat-waffle' +import 'hardhat-typechain' +import 'hardhat-watcher' +import 'dotenv/config' + +const DEFAULT_COMPILER_SETTINGS = { + version: '0.7.6', + settings: { + evmVersion: 'istanbul', + optimizer: { + enabled: true, + runs: 1_000_000, + }, + metadata: { + bytecodeHash: 'none', + }, + }, +} + +export default { + networks: { + hardhat: { + allowUnlimitedContractSize: false, + }, + mainnet: { + url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, + }, + ropsten: { + url: `https://ropsten.infura.io/v3/${process.env.INFURA_API_KEY}`, + }, + rinkeby: { + url: `https://rinkeby.infura.io/v3/${process.env.INFURA_API_KEY}`, + }, + goerli: { + url: `https://goerli.infura.io/v3/${process.env.INFURA_API_KEY}`, + }, + kovan: { + url: `https://kovan.infura.io/v3/${process.env.INFURA_API_KEY}`, + }, + arbitrumRinkeby: { + url: `https://rinkeby.arbitrum.io/rpc`, + }, + arbitrum: { + url: `https://arb1.arbitrum.io/rpc`, + }, + optimismKovan: { + url: `https://kovan.optimism.io`, + }, + optimism: { + url: `https://mainnet.optimism.io`, + }, + }, + etherscan: { + // Your API key for Etherscan + // Obtain one at https://etherscan.io/ + apiKey: process.env.ETHERSCAN_API_KEY, + }, + solidity: { + compilers: [DEFAULT_COMPILER_SETTINGS], + }, + watcher: { + test: { + tasks: [{ command: 'test', params: { testFiles: ['{path}'] } }], + files: ['./test/**/*'], + verbose: true, + }, + }, +} diff --git a/lib/swap-router-contracts/package.json b/lib/swap-router-contracts/package.json new file mode 100644 index 0000000..908cb25 --- /dev/null +++ b/lib/swap-router-contracts/package.json @@ -0,0 +1,68 @@ +{ + "name": "@uniswap/swap-router-contracts", + "description": "Smart contracts for swapping on Uniswap V2 and V3", + "license": "GPL-2.0-or-later", + "publishConfig": { + "access": "public" + }, + "version": "1.3.1", + "homepage": "https://uniswap.org", + "keywords": [ + "uniswap", + "v2", + "v3" + ], + "repository": { + "type": "git", + "url": "https://github.com/Uniswap/swap-router-contracts" + }, + "files": [ + "contracts/base", + "contracts/interfaces", + "contracts/libraries", + "artifacts/contracts/**/*.json", + "!artifacts/contracts/**/*.dbg.json", + "!artifacts/contracts/test/**/*", + "!artifacts/contracts/base/**/*" + ], + "engines": { + "node": ">=10" + }, + "dependencies": { + "@openzeppelin/contracts": "3.4.2-solc-0.7", + "@uniswap/v2-core": "^1.0.1", + "@uniswap/v3-core": "^1.0.0", + "@uniswap/v3-periphery": "^1.4.4", + "dotenv": "^14.2.0", + "hardhat-watcher": "^2.1.1" + }, + "devDependencies": { + "@nomiclabs/hardhat-ethers": "^2.0.2", + "@nomiclabs/hardhat-etherscan": "^2.1.8", + "@nomiclabs/hardhat-waffle": "^2.0.1", + "@typechain/ethers-v5": "^4.0.0", + "@types/chai": "^4.2.6", + "@types/mocha": "^5.2.7", + "chai": "^4.2.0", + "decimal.js": "^10.2.1", + "ethereum-waffle": "^3.0.2", + "ethers": "^5.0.8", + "hardhat": "^2.6.8", + "hardhat-typechain": "^0.3.5", + "is-svg": "^4.3.1", + "mocha": "^6.2.2", + "mocha-chai-jest-snapshot": "^1.1.0", + "prettier": "^2.0.5", + "prettier-plugin-solidity": "^1.0.0-beta.10", + "solhint": "^3.2.1", + "solhint-plugin-prettier": "^0.0.5", + "ts-generator": "^0.1.1", + "ts-node": "^8.5.4", + "typechain": "^4.0.0", + "typescript": "^3.7.3" + }, + "scripts": { + "compile": "hardhat compile", + "test": "hardhat test" + } +} diff --git a/lib/swap-router-contracts/test/ApproveAndCall.spec.ts b/lib/swap-router-contracts/test/ApproveAndCall.spec.ts new file mode 100644 index 0000000..1476b53 --- /dev/null +++ b/lib/swap-router-contracts/test/ApproveAndCall.spec.ts @@ -0,0 +1,388 @@ +import { defaultAbiCoder } from '@ethersproject/abi' +import { Fixture } from 'ethereum-waffle' +import { constants, Contract, ContractTransaction, Wallet } from 'ethers' +import { solidityPack } from 'ethers/lib/utils' +import { ethers, waffle } from 'hardhat' +import { MockTimeSwapRouter02, TestERC20 } from '../typechain' +import completeFixture from './shared/completeFixture' +import { ADDRESS_THIS, FeeAmount, TICK_SPACINGS } from './shared/constants' +import { encodePriceSqrt } from './shared/encodePriceSqrt' +import { expect } from './shared/expect' +import { encodePath } from './shared/path' +import { getMaxTick, getMinTick } from './shared/ticks' + +enum ApprovalType { + NOT_REQUIRED, + MAX, + MAX_MINUS_ONE, + ZERO_THEN_MAX, + ZERO_THEN_MAX_MINUS_ONE, +} + +describe('ApproveAndCall', function () { + this.timeout(40000) + let wallet: Wallet + let trader: Wallet + + const swapRouterFixture: Fixture<{ + factory: Contract + router: MockTimeSwapRouter02 + nft: Contract + tokens: [TestERC20, TestERC20, TestERC20] + }> = async (wallets, provider) => { + const { factory, router, tokens, nft } = await completeFixture(wallets, provider) + + // approve & fund wallets + for (const token of tokens) { + await token.approve(nft.address, constants.MaxUint256) + } + + return { + factory, + router, + tokens, + nft, + } + } + + let factory: Contract + let router: MockTimeSwapRouter02 + let nft: Contract + let tokens: [TestERC20, TestERC20, TestERC20] + + let loadFixture: ReturnType + + function encodeSweepToken(token: string, amount: number) { + const functionSignature = 'sweepToken(address,uint256)' + return solidityPack( + ['bytes4', 'bytes'], + [router.interface.getSighash(functionSignature), defaultAbiCoder.encode(['address', 'uint256'], [token, amount])] + ) + } + + before('create fixture loader', async () => { + ;[wallet, trader] = await (ethers as any).getSigners() + loadFixture = waffle.createFixtureLoader([wallet, trader]) + }) + + beforeEach('load fixture', async () => { + ;({ factory, router, tokens, nft } = await loadFixture(swapRouterFixture)) + }) + + describe('swap and add', () => { + async function createPool(tokenAddressA: string, tokenAddressB: string) { + if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) + [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] + + await nft.createAndInitializePoolIfNecessary( + tokenAddressA, + tokenAddressB, + FeeAmount.MEDIUM, + encodePriceSqrt(1, 1) + ) + + const liquidityParams = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: wallet.address, + amount0Desired: 1000000, + amount1Desired: 1000000, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + return nft.mint(liquidityParams) + } + + describe('approvals', () => { + it('#approveMax', async () => { + let approvalType = await router.callStatic.getApprovalType(tokens[0].address, 123) + expect(approvalType).to.be.eq(ApprovalType.MAX) + + await router.approveMax(tokens[0].address) + + approvalType = await router.callStatic.getApprovalType(tokens[0].address, 123) + expect(approvalType).to.be.eq(ApprovalType.NOT_REQUIRED) + }) + + it('#approveMax', async () => { + await router.approveMax(tokens[0].address) + }) + + it('#approveMaxMinusOne', async () => { + await router.approveMaxMinusOne(tokens[0].address) + }) + + describe('#approveZeroThenMax', async () => { + it('from 0', async () => { + await router.approveZeroThenMax(tokens[0].address) + }) + it('from max', async () => { + await router.approveMax(tokens[0].address) + await router.approveZeroThenMax(tokens[0].address) + }) + }) + + describe('#approveZeroThenMax', async () => { + it('from 0', async () => { + await router.approveZeroThenMaxMinusOne(tokens[0].address) + }) + it('from max', async () => { + await router.approveMax(tokens[0].address) + await router.approveZeroThenMaxMinusOne(tokens[0].address) + }) + }) + }) + + it('#mint and #increaseLiquidity', async () => { + await createPool(tokens[0].address, tokens[1].address) + const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) + + // approve in advance + await router.approveMax(tokens[0].address) + await router.approveMax(tokens[1].address) + + // send dummy amount of tokens to the pair in advance + const amount = 1000 + await tokens[0].transfer(router.address, amount) + await tokens[1].transfer(router.address, amount) + expect((await tokens[0].balanceOf(router.address)).toNumber()).to.be.eq(amount) + expect((await tokens[1].balanceOf(router.address)).toNumber()).to.be.eq(amount) + + let poolBalance0Before = await tokens[0].balanceOf(pool) + let poolBalance1Before = await tokens[1].balanceOf(pool) + + // perform the mint + await router.mint({ + token0: tokens[0].address, + token1: tokens[1].address, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: trader.address, + amount0Min: 0, + amount1Min: 0, + }) + + expect((await tokens[0].balanceOf(router.address)).toNumber()).to.be.eq(0) + expect((await tokens[1].balanceOf(router.address)).toNumber()).to.be.eq(0) + expect((await tokens[0].balanceOf(pool)).toNumber()).to.be.eq(poolBalance0Before.toNumber() + amount) + expect((await tokens[1].balanceOf(pool)).toNumber()).to.be.eq(poolBalance1Before.toNumber() + amount) + + expect((await nft.balanceOf(trader.address)).toNumber()).to.be.eq(1) + + // send more tokens + await tokens[0].transfer(router.address, amount) + await tokens[1].transfer(router.address, amount) + + // perform the increaseLiquidity + await router.increaseLiquidity({ + token0: tokens[0].address, + token1: tokens[1].address, + tokenId: 2, + amount0Min: 0, + amount1Min: 0, + }) + + expect((await tokens[0].balanceOf(router.address)).toNumber()).to.be.eq(0) + expect((await tokens[1].balanceOf(router.address)).toNumber()).to.be.eq(0) + expect((await tokens[0].balanceOf(pool)).toNumber()).to.be.eq(poolBalance0Before.toNumber() + amount * 2) + expect((await tokens[1].balanceOf(pool)).toNumber()).to.be.eq(poolBalance1Before.toNumber() + amount * 2) + + expect((await nft.balanceOf(trader.address)).toNumber()).to.be.eq(1) + }) + + describe('single-asset add', () => { + beforeEach('create 0-1 pool', async () => { + await createPool(tokens[0].address, tokens[1].address) + }) + + async function singleAssetAddExactInput( + tokenIn: string, + tokenOut: string, + amountIn: number, + amountOutMinimum: number + ): Promise { + // encode the exact input swap + const params = { + path: encodePath([tokenIn, tokenOut], [FeeAmount.MEDIUM]), + recipient: ADDRESS_THIS, // have to send to the router, as it will be adding liquidity for the caller + amountIn, + amountOutMinimum, + } + // ensure that the swap fails if the limit is any tighter + const amountOut = await router.connect(trader).callStatic.exactInput(params) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + const data = [router.interface.encodeFunctionData('exactInput', [params])] + + // encode the pull (we take the same as the amountOutMinimum, assuming a 50/50 range) + data.push(router.interface.encodeFunctionData('pull', [tokenIn, amountOutMinimum])) + + // encode the approves + data.push(router.interface.encodeFunctionData('approveMax', [tokenIn])) + data.push(router.interface.encodeFunctionData('approveMax', [tokenOut])) + + // encode the add liquidity + const [token0, token1] = + tokenIn.toLowerCase() < tokenOut.toLowerCase() ? [tokenIn, tokenOut] : [tokenOut, tokenIn] + const liquidityParams = { + token0, + token1, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: trader.address, + amount0Desired: amountOutMinimum, + amount1Desired: amountOutMinimum, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + data.push( + router.interface.encodeFunctionData('callPositionManager', [ + nft.interface.encodeFunctionData('mint', [liquidityParams]), + ]) + ) + + // encode the sweeps + data.push(encodeSweepToken(tokenIn, 0)) + data.push(encodeSweepToken(tokenOut, 0)) + + return router.connect(trader)['multicall(bytes[])'](data) + } + + it('0 -> 1', async () => { + const amountIn = 1000 + const amountOutMinimum = 996 + + // prep for the swap + add by sending tokens + await tokens[0].transfer(trader.address, amountIn + amountOutMinimum) + await tokens[0].connect(trader).approve(router.address, amountIn + amountOutMinimum) + + const traderToken0BalanceBefore = await tokens[0].balanceOf(trader.address) + const traderToken1BalanceBefore = await tokens[1].balanceOf(trader.address) + expect(traderToken0BalanceBefore.toNumber()).to.be.eq(amountIn + amountOutMinimum) + expect(traderToken1BalanceBefore.toNumber()).to.be.eq(0) + + const traderNFTBalanceBefore = await nft.balanceOf(trader.address) + expect(traderNFTBalanceBefore.toNumber()).to.be.eq(0) + + await singleAssetAddExactInput(tokens[0].address, tokens[1].address, amountIn, amountOutMinimum) + + const traderToken0BalanceAfter = await tokens[0].balanceOf(trader.address) + const traderToken1BalanceAfter = await tokens[1].balanceOf(trader.address) + expect(traderToken0BalanceAfter.toNumber()).to.be.eq(0) + expect(traderToken1BalanceAfter.toNumber()).to.be.eq(1) // dust + + const traderNFTBalanceAfter = await nft.balanceOf(trader.address) + expect(traderNFTBalanceAfter.toNumber()).to.be.eq(1) + }) + }) + + describe('any-asset add', () => { + beforeEach('create 0-1, 0-2, and 1-2 pools pools', async () => { + await createPool(tokens[0].address, tokens[1].address) + await createPool(tokens[0].address, tokens[2].address) + await createPool(tokens[1].address, tokens[2].address) + }) + + async function anyAssetAddExactInput( + tokenStart: string, + tokenA: string, + tokenB: string, + amountIn: number, + amountOutMinimum: number + ): Promise { + // encode the exact input swaps + let params = { + path: encodePath([tokenStart, tokenA], [FeeAmount.MEDIUM]), + recipient: ADDRESS_THIS, // have to send to the router, as it will be adding liquidity for the caller + amountIn, + amountOutMinimum, + } + // ensure that the swap fails if the limit is any tighter + let amountOut = await router.connect(trader).callStatic.exactInput(params) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + let data = [router.interface.encodeFunctionData('exactInput', [params])] + + // encode the exact input swaps + params = { + path: encodePath([tokenStart, tokenB], [FeeAmount.MEDIUM]), + recipient: ADDRESS_THIS, // have to send to the router, as it will be adding liquidity for the caller + amountIn, + amountOutMinimum, + } + // ensure that the swap fails if the limit is any tighter + amountOut = await router.connect(trader).callStatic.exactInput(params) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + data.push(router.interface.encodeFunctionData('exactInput', [params])) + + // encode the approves + data.push(router.interface.encodeFunctionData('approveMax', [tokenA])) + data.push(router.interface.encodeFunctionData('approveMax', [tokenB])) + + // encode the add liquidity + const [token0, token1] = tokenA.toLowerCase() < tokenB.toLowerCase() ? [tokenA, tokenB] : [tokenB, tokenA] + const liquidityParams = { + token0, + token1, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: trader.address, + amount0Desired: amountOutMinimum, + amount1Desired: amountOutMinimum, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + data.push( + router.interface.encodeFunctionData('callPositionManager', [ + nft.interface.encodeFunctionData('mint', [liquidityParams]), + ]) + ) + + // encode the sweeps + data.push(encodeSweepToken(tokenA, 0)) + data.push(encodeSweepToken(tokenB, 0)) + + return router.connect(trader)['multicall(bytes[])'](data) + } + + it('0 -> 1 and 0 -> 2', async () => { + const amountIn = 1000 + const amountOutMinimum = 996 + + // prep for the swap + add by sending tokens + await tokens[0].transfer(trader.address, amountIn * 2) + await tokens[0].connect(trader).approve(router.address, amountIn * 2) + + const traderToken0BalanceBefore = await tokens[0].balanceOf(trader.address) + const traderToken1BalanceBefore = await tokens[1].balanceOf(trader.address) + const traderToken2BalanceBefore = await tokens[2].balanceOf(trader.address) + expect(traderToken0BalanceBefore.toNumber()).to.be.eq(amountIn * 2) + expect(traderToken1BalanceBefore.toNumber()).to.be.eq(0) + expect(traderToken2BalanceBefore.toNumber()).to.be.eq(0) + + const traderNFTBalanceBefore = await nft.balanceOf(trader.address) + expect(traderNFTBalanceBefore.toNumber()).to.be.eq(0) + + await anyAssetAddExactInput(tokens[0].address, tokens[1].address, tokens[2].address, amountIn, amountOutMinimum) + + const traderToken0BalanceAfter = await tokens[0].balanceOf(trader.address) + const traderToken1BalanceAfter = await tokens[1].balanceOf(trader.address) + const traderToken2BalanceAfter = await tokens[2].balanceOf(trader.address) + expect(traderToken0BalanceAfter.toNumber()).to.be.eq(0) + expect(traderToken1BalanceAfter.toNumber()).to.be.eq(0) + expect(traderToken2BalanceAfter.toNumber()).to.be.eq(0) + + const traderNFTBalanceAfter = await nft.balanceOf(trader.address) + expect(traderNFTBalanceAfter.toNumber()).to.be.eq(1) + }) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/ImmutableState.spec.ts b/lib/swap-router-contracts/test/ImmutableState.spec.ts new file mode 100644 index 0000000..6bd642b --- /dev/null +++ b/lib/swap-router-contracts/test/ImmutableState.spec.ts @@ -0,0 +1,58 @@ +import { Contract } from 'ethers' +import { waffle, ethers } from 'hardhat' + +import { Fixture } from 'ethereum-waffle' +import { ImmutableStateTest } from '../typechain' +import { expect } from './shared/expect' +import completeFixture from './shared/completeFixture' +import { v2FactoryFixture } from './shared/externalFixtures' + +describe('ImmutableState', () => { + const fixture: Fixture<{ + factoryV2: Contract + nft: Contract + state: ImmutableStateTest + }> = async (wallets, provider) => { + const { factory: factoryV2 } = await v2FactoryFixture(wallets, provider) + const { nft } = await completeFixture(wallets, provider) + + const stateFactory = await ethers.getContractFactory('ImmutableStateTest') + const state = (await stateFactory.deploy(factoryV2.address, nft.address)) as ImmutableStateTest + + return { + nft, + factoryV2, + state, + } + } + + let factoryV2: Contract + let nft: Contract + let state: ImmutableStateTest + + let loadFixture: ReturnType + + before('create fixture loader', async () => { + loadFixture = waffle.createFixtureLoader(await (ethers as any).getSigners()) + }) + + beforeEach('load fixture', async () => { + ;({ factoryV2, nft, state } = await loadFixture(fixture)) + }) + + it('bytecode size', async () => { + expect(((await state.provider.getCode(state.address)).length - 2) / 2).to.matchSnapshot() + }) + + describe('#factoryV2', () => { + it('points to v2 core factory', async () => { + expect(await state.factoryV2()).to.eq(factoryV2.address) + }) + }) + + describe('#positionManager', () => { + it('points to NFT', async () => { + expect(await state.positionManager()).to.eq(nft.address) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts b/lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts new file mode 100644 index 0000000..a84b46f --- /dev/null +++ b/lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts @@ -0,0 +1,184 @@ +import { expect } from 'chai' +import { BigNumber } from 'ethers' +import { MixedRouteQuoterV1 } from '../typechain' + +import hre, { ethers } from 'hardhat' +import { encodePath } from './shared/path' +import { expandTo18Decimals, expandToNDecimals } from './shared/expandTo18Decimals' +import { FeeAmount, V2_FEE_PLACEHOLDER } from './shared/constants' + +const V3_FACTORY = '0x1F98431c8aD98523631AE4a59f267346ea31F984' +const V2_FACTORY = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' + +const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' +const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' +const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' +const UNI = '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984' +const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F' + +/// @dev basic V2 routes +const DAI_V2_UNI_V2_WETH = encodePath([DAI, UNI, WETH], [V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER]) +const USDC_V2_UNI_V2_WETH = encodePath([USDC, UNI, WETH], [V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER]) + +/// @dev basic V3 routes +const USDC_V3_USDT = encodePath([USDC, USDT], [FeeAmount.LOW]) +const UNI_V3_WETH = encodePath([UNI, WETH], [FeeAmount.MEDIUM]) + +/// @dev stablecoin IL routes +const USDT_V3_DAI_V2_USDC = encodePath([USDT, DAI, USDC], [FeeAmount.LOW, V2_FEE_PLACEHOLDER]) +const DAI_V3_USDC_V2_USDT = encodePath([DAI, USDC, USDT], [100, V2_FEE_PLACEHOLDER]) + +/// @dev erc20 IL routes +// V3 - V2 +const UNI_V3_WETH_V2_DAI = encodePath([UNI, WETH, DAI], [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER]) +const USDC_V3_UNI_V2_WETH = encodePath([USDC, UNI, WETH], [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER]) +// V2 - V3 +const UNI_V2_WETH_V3_DAI = encodePath([UNI, WETH, DAI], [V2_FEE_PLACEHOLDER, FeeAmount.MEDIUM]) + +/// @dev complex IL routes +// (use two V3 pools) +const DAI_V3_3000_UNI_V2_USDT_V3_3000_WETH = encodePath( + [DAI, UNI, USDT, WETH], + [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER, FeeAmount.MEDIUM] +) +// (use two V2 pools) +const DAI_V3_3000_UNI_V2_USDT_V2_WETH = encodePath( + [DAI, UNI, USDT, WETH], + [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER] +) + +describe('MixedRouteQuoterV1 integration tests', function () { + let mixedRouteQuoter: MixedRouteQuoterV1 + + this.timeout(100000) + + before(async function () { + if (!process.env.ARCHIVE_RPC_URL) { + this.skip() + } + + await hre.network.provider.request({ + method: 'hardhat_reset', + params: [ + { + forking: { + jsonRpcUrl: process.env.ARCHIVE_RPC_URL, + blockNumber: 14390000, + }, + }, + ], + }) + + const MixedRouteQuoterV1Factory = await ethers.getContractFactory('MixedRouteQuoterV1') + mixedRouteQuoter = (await MixedRouteQuoterV1Factory.deploy(V3_FACTORY, V2_FACTORY, WETH)) as MixedRouteQuoterV1 + }) + + after(async () => { + // Disable mainnet forking to avoid effecting other tests. + await hre.network.provider.request({ + method: 'hardhat_reset', + params: [], + }) + }) + + /** + * Test values only valid starting at block 14390000 + */ + it('sets block number correctly', async () => { + const blockNumber = BigNumber.from( + await hre.network.provider.request({ + method: 'eth_blockNumber', + params: [], + }) + ) + /// @dev +1 so 14390001 since we just requested + expect(blockNumber.eq(14390001)).to.be.true + }) + + describe('quotes stablecoin only paths correctly', () => { + /// @dev the amount must be expanded to the decimals of the first token in the path + it('V3-V2 stablecoin path with 6 decimal in start of path', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](USDT_V3_DAI_V2_USDC, expandToNDecimals(10000, 6)) + + expect(amountOut).eq(BigNumber.from('9966336832')) + expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x10c6727487c45717095f'))).to.be.true + }) + + it('V3-V2 stablecoin path with 6 decimal in middle of path', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](DAI_V3_USDC_V2_USDT, expandTo18Decimals(10000)) + + expect(amountOut).eq(BigNumber.from('9959354898')) + expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x10c715093f77e3073634'))).to.be.true + }) + }) + + describe('V2-V2 quotes', () => { + it('quotes V2-V2 correctly', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](DAI_V2_UNI_V2_WETH, expandTo18Decimals(10000)) + + expect(amountOut).eq(BigNumber.from('2035189623576328665')) + expect(v3SqrtPriceX96AfterList.every((el) => el.eq(0))).to.be.true + expect(v3InitializedTicksCrossedList.every((el) => el == 0)).to.be.true + }) + + it('quotes V2 (6 decimal stablecoin) -V2 correctly', async () => { + const { amountOut } = await mixedRouteQuoter.callStatic['quoteExactInput(bytes,uint256)']( + USDC_V2_UNI_V2_WETH, + expandToNDecimals(10000, 6) + ) + + expect(amountOut).eq(BigNumber.from('1989381322826753150')) + }) + }) + + it('quotes V3-V2 erc20s with mixed decimal scales correctly', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](USDC_V3_UNI_V2_WETH, expandToNDecimals(10000, 6)) + + expect(amountOut).eq(BigNumber.from('3801923847986895918')) // 3.801923847986895918 + expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x3110863ba621ac3915fd'))).to.be.true + }) + + it('quotes V3-V2 correctly', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](UNI_V3_WETH_V2_DAI, expandTo18Decimals(10000)) + + expect(amountOut).eq(BigNumber.from('80675538331724434694636')) + expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x0e83f285cb58c4cca14fb78b'))).to.be.true + }) + + it('quotes V3-V2-V3 correctly', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](DAI_V3_3000_UNI_V2_USDT_V3_3000_WETH, expandTo18Decimals(10000)) + + expect(amountOut).eq(BigNumber.from('886596560223108447')) + expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0xfffd8963efd1fc6a506488495d951d5263988d25'))).to.be.true + expect(v3SqrtPriceX96AfterList[2].eq(BigNumber.from('0x034b624fce51aba62a4722'))).to.be.true + }) + + it('quotes V2-V3 correctly', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](UNI_V2_WETH_V3_DAI, expandTo18Decimals(10000)) + + expect(amountOut).eq(BigNumber.from('81108655328627859394525')) + expect(v3SqrtPriceX96AfterList[1].eq(BigNumber.from('0x0518b75d40eb50192903493d'))).to.be.true + }) + + it('quotes only V3 correctly', async () => { + const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ + 'quoteExactInput(bytes,uint256)' + ](UNI_V3_WETH, expandTo18Decimals(10000)) + + expect(amountOut.eq(BigNumber.from('32215526370828998898'))).to.be.true + }) +}) diff --git a/lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts b/lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts new file mode 100644 index 0000000..f0b6ed4 --- /dev/null +++ b/lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts @@ -0,0 +1,460 @@ +import { Fixture } from 'ethereum-waffle' +import { constants, Wallet, Contract, BigNumber } from 'ethers' +import { ethers, waffle } from 'hardhat' +import { MixedRouteQuoterV1, TestERC20 } from '../typechain' +import completeFixture from './shared/completeFixture' +import { FeeAmount, V2_FEE_PLACEHOLDER } from './shared/constants' +import { encodePriceSqrt } from './shared/encodePriceSqrt' +import { expandTo18Decimals } from './shared/expandTo18Decimals' +import { expect } from './shared/expect' +import { encodePath } from './shared/path' +import { + createPair, + createPool, + createPoolWithMultiplePositions, + createPoolWithZeroTickInitialized, +} from './shared/quoter' +import snapshotGasCost from './shared/snapshotGasCost' + +import { abi as PAIR_V2_ABI } from '@uniswap/v2-core/build/UniswapV2Pair.json' + +const V3_MAX_FEE = 999999 // = 1_000_000 - 1 since must be < 1_000_000 + +describe('MixedRouteQuoterV1', function () { + this.timeout(40000) + let wallet: Wallet + let trader: Wallet + + const swapRouterFixture: Fixture<{ + nft: Contract + factoryV2: Contract + tokens: [TestERC20, TestERC20, TestERC20] + quoter: MixedRouteQuoterV1 + }> = async (wallets, provider) => { + const { weth9, factory, factoryV2, router, tokens, nft } = await completeFixture(wallets, provider) + + // approve & fund wallets + for (const token of tokens) { + await token.approve(router.address, constants.MaxUint256) + await token.approve(nft.address, constants.MaxUint256) + await token.connect(trader).approve(router.address, constants.MaxUint256) + await token.transfer(trader.address, expandTo18Decimals(1_000_000)) + } + + const quoterFactory = await ethers.getContractFactory('MixedRouteQuoterV1') + quoter = (await quoterFactory.deploy(factory.address, factoryV2.address, weth9.address)) as MixedRouteQuoterV1 + + return { + tokens, + nft, + factoryV2, + quoter, + } + } + + let nft: Contract + let factoryV2: Contract + let tokens: [TestERC20, TestERC20, TestERC20] + let quoter: MixedRouteQuoterV1 + + let pair01Address, pair02Address, pair12Address: string + + let loadFixture: ReturnType + + before('create fixture loader', async () => { + const wallets = await (ethers as any).getSigners() + ;[wallet, trader] = wallets + loadFixture = waffle.createFixtureLoader(wallets) + }) + + // helper for getting weth and token balances + beforeEach('load fixture', async () => { + ;({ tokens, nft, factoryV2, quoter } = await loadFixture(swapRouterFixture)) + }) + + const addLiquidityV2 = async ( + pairAddress: string, + token0: TestERC20, + token1: TestERC20, + amount0: string, + amount1: string + ) => { + const pair = new Contract(pairAddress, PAIR_V2_ABI, wallet) + expect(await pair.callStatic.token0()).to.equal(token0.address) + expect(await pair.callStatic.token1()).to.equal(token1.address) + // seed the pairs with liquidity + + const [reserve0Before, reserve1Before]: [BigNumber, BigNumber] = await pair.callStatic.getReserves() + + const token0BalanceBefore = await token0.balanceOf(pairAddress) + const token1BalanceBefore = await token1.balanceOf(pairAddress) + + await token0.transfer(pairAddress, ethers.utils.parseEther(amount0)) + await token1.transfer(pairAddress, ethers.utils.parseEther(amount1)) + + expect(await token0.balanceOf(pairAddress)).to.equal(token0BalanceBefore.add(ethers.utils.parseEther(amount0))) + expect(await token1.balanceOf(pairAddress)).to.equal(token1BalanceBefore.add(ethers.utils.parseEther(amount1))) + + await pair.mint(wallet.address) // update the reserves + + const [reserve0, reserve1] = await pair.callStatic.getReserves() + expect(reserve0).to.equal(reserve0Before.add(ethers.utils.parseEther(amount0))) + expect(reserve1).to.equal(reserve1Before.add(ethers.utils.parseEther(amount1))) + } + + describe('quotes', () => { + beforeEach(async () => { + await createPool(nft, wallet, tokens[0].address, tokens[1].address) + await createPool(nft, wallet, tokens[1].address, tokens[2].address) + await createPoolWithMultiplePositions(nft, wallet, tokens[0].address, tokens[2].address) + /// @dev Create V2 Pairs + pair01Address = await createPair(factoryV2, tokens[0].address, tokens[1].address) + pair12Address = await createPair(factoryV2, tokens[1].address, tokens[2].address) + pair02Address = await createPair(factoryV2, tokens[0].address, tokens[2].address) + + await addLiquidityV2(pair01Address, tokens[0], tokens[1], '1000000', '1000000') + await addLiquidityV2(pair12Address, tokens[1], tokens[2], '1000000', '1000000') + await addLiquidityV2(pair02Address, tokens[0], tokens[2], '1000000', '1000000') + }) + + /// @dev Test running the old suite on the new function but with protocolFlags only being V3[] + describe('#quoteExactInput V3 only', () => { + it('0 -> 2 cross 2 tick', async () => { + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 10000 + ) + + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') + expect(v3InitializedTicksCrossedList[0]).to.eq(2) + expect(amountOut).to.eq(9871) + await snapshotGasCost(v3SwapGasEstimate) + }) + + it('0 -> 2 cross 2 tick where after is initialized', async () => { + // The swap amount is set such that the active tick after the swap is -120. + // -120 is an initialized tick for this pool. We check that we don't count it. + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 6200 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('78757224507315167622282810783') + expect(v3InitializedTicksCrossedList.length).to.eq(1) + expect(v3InitializedTicksCrossedList[0]).to.eq(1) + expect(amountOut).to.eq(6143) + }) + + it('0 -> 2 cross 1 tick', async () => { + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 4000 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3InitializedTicksCrossedList[0]).to.eq(1) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('78926452400586371254602774705') + expect(amountOut).to.eq(3971) + }) + + it('0 -> 2 cross 0 tick, starting tick not initialized', async () => { + // Tick before 0, tick after -1. + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 10 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3InitializedTicksCrossedList[0]).to.eq(0) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('79227483487511329217250071027') + expect(amountOut).to.eq(8) + }) + + it('0 -> 2 cross 0 tick, starting tick initialized', async () => { + // Tick before 0, tick after -1. Tick 0 initialized. + await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) + + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 10 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3InitializedTicksCrossedList[0]).to.eq(1) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('79227817515327498931091950511') + expect(amountOut).to.eq(8) + }) + + it('2 -> 0 cross 2', async () => { + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 10000 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3InitializedTicksCrossedList[0]).to.eq(2) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('80001962924147897865541384515') + expect(v3InitializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(9871) + }) + + it('2 -> 0 cross 2 where tick after is initialized', async () => { + // The swap amount is set such that the active tick after the swap is 120. + // 120 is an initialized tick for this pool. We check we don't count it. + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 6250 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3InitializedTicksCrossedList[0]).to.eq(2) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('79705728824507063507279123685') + expect(v3InitializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(6190) + }) + + it('2 -> 0 cross 0 tick, starting tick initialized', async () => { + // Tick 0 initialized. Tick after = 1 + await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) + + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 200 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3InitializedTicksCrossedList[0]).to.eq(0) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('79235729830182478001034429156') + expect(v3InitializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(198) + }) + + it('2 -> 0 cross 0 tick, starting tick not initialized', async () => { + // Tick 0 initialized. Tick after = 1 + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 103 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3InitializedTicksCrossedList[0]).to.eq(0) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('79235858216754624215638319723') + expect(v3InitializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(101) + }) + + it('2 -> 1', async () => { + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM]), + 10000 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3SqrtPriceX96AfterList.length).to.eq(1) + expect(v3SqrtPriceX96AfterList[0]).to.eq('80018067294531553039351583520') + expect(v3InitializedTicksCrossedList[0]).to.eq(0) + expect(amountOut).to.eq(9871) + }) + + it('0 -> 2 -> 1', async () => { + const { + amountOut, + v3SqrtPriceX96AfterList, + v3InitializedTicksCrossedList, + v3SwapGasEstimate, + } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), + 10000 + ) + + await snapshotGasCost(v3SwapGasEstimate) + expect(v3SqrtPriceX96AfterList.length).to.eq(2) + expect(v3SqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') + expect(v3SqrtPriceX96AfterList[1]).to.eq('80007846861567212939802016351') + expect(v3InitializedTicksCrossedList[0]).to.eq(2) + expect(v3InitializedTicksCrossedList[1]).to.eq(0) + expect(amountOut).to.eq(9745) + }) + }) + + /// @dev Test running the old suite on the new function but with protocolFlags only being V2[] + describe('#quoteExactInput V2 only', () => { + it('0 -> 2', async () => { + const { amountOut, v3SwapGasEstimate } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[2].address], [V2_FEE_PLACEHOLDER]), + 10000 + ) + + expect(amountOut).to.eq(9969) + }) + + it('0 -> 1 -> 2', async () => { + const { amountOut, v3SwapGasEstimate } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath( + [tokens[0].address, tokens[1].address, tokens[2].address], + [V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER] + ), + 10000 + ) + + expect(amountOut).to.eq(9939) + }) + }) + + /// @dev Test copied over from QuoterV2.spec.ts + describe('#quoteExactInputSingle V3', () => { + it('0 -> 2', async () => { + const { + amountOut: quote, + sqrtPriceX96After, + initializedTicksCrossed, + gasEstimate, + } = await quoter.callStatic.quoteExactInputSingleV3({ + tokenIn: tokens[0].address, + tokenOut: tokens[2].address, + fee: FeeAmount.MEDIUM, + amountIn: 10000, + // -2% + sqrtPriceLimitX96: encodePriceSqrt(100, 102), + }) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossed).to.eq(2) + expect(quote).to.eq(9871) + expect(sqrtPriceX96After).to.eq('78461846509168490764501028180') + }) + + it('2 -> 0', async () => { + const { + amountOut: quote, + sqrtPriceX96After, + initializedTicksCrossed, + gasEstimate, + } = await quoter.callStatic.quoteExactInputSingleV3({ + tokenIn: tokens[2].address, + tokenOut: tokens[0].address, + fee: FeeAmount.MEDIUM, + amountIn: 10000, + // +2% + sqrtPriceLimitX96: encodePriceSqrt(102, 100), + }) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossed).to.eq(2) + expect(quote).to.eq(9871) + expect(sqrtPriceX96After).to.eq('80001962924147897865541384515') + }) + }) + + /// @dev Test the new function for fetching a single V2 pair quote on chain (exactIn) + describe('#quoteExactInputSingleV2', () => { + it('0 -> 2', async () => { + const amountIn = 10000 + const tokenIn = tokens[0].address + const tokenOut = tokens[2].address + const quote = await quoter.callStatic.quoteExactInputSingleV2({ tokenIn, tokenOut, amountIn }) + + expect(quote).to.eq(9969) + }) + + it('2 -> 0', async () => { + const amountIn = 10000 + const tokenIn = tokens[2].address + const tokenOut = tokens[0].address + const quote = await quoter.callStatic.quoteExactInputSingleV2({ tokenIn, tokenOut, amountIn }) + + expect(quote).to.eq(9969) + }) + + describe('+ with imbalanced pairs', () => { + before(async () => { + await addLiquidityV2(pair12Address, tokens[1], tokens[2], '1000000', '1000') + }) + + it('1 -> 2', async () => { + const amountIn = 2_000_000 + const tokenIn = tokens[1].address + const tokenOut = tokens[2].address + const quote = await quoter.callStatic.quoteExactInputSingleV2({ tokenIn, tokenOut, amountIn }) + + expect(quote).to.eq(1993999) + }) + }) + }) + + describe('testing bit masking for protocol selection', () => { + it('when given the max v3 fee, should still route v3 and revert because pool DNE', async () => { + /// @define 999999 is the max fee that can be set on a V3 pool per the factory + /// in this environment this pool does not exist, and thus the call should revert + /// - however, if the bitmask fails to catch this the call will succeed and route to V2 + /// - thus, we expect it to be reverted. + await expect( + quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[1].address], [V3_MAX_FEE]), + 10000 + ) + ).to.be.reverted + }) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/MulticallExtended.spec.ts b/lib/swap-router-contracts/test/MulticallExtended.spec.ts new file mode 100644 index 0000000..4e431f6 --- /dev/null +++ b/lib/swap-router-contracts/test/MulticallExtended.spec.ts @@ -0,0 +1,50 @@ +import { constants } from 'ethers' +import { ethers } from 'hardhat' +import { TestMulticallExtended } from '../typechain/TestMulticallExtended' +import { expect } from './shared/expect' + +describe('MulticallExtended', async () => { + let multicall: TestMulticallExtended + + beforeEach('create multicall', async () => { + const multicallTestFactory = await ethers.getContractFactory('TestMulticallExtended') + multicall = (await multicallTestFactory.deploy()) as TestMulticallExtended + }) + + it('fails deadline check', async () => { + await multicall.setTime(1) + await expect( + multicall['multicall(uint256,bytes[])'](0, [ + multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), + ]) + ).to.be.revertedWith('Transaction too old') + }) + + it('passes deadline check', async () => { + const [data] = await multicall.callStatic['multicall(uint256,bytes[])'](0, [ + multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), + ]) + const { + tuple: { a, b }, + } = multicall.interface.decodeFunctionResult('functionThatReturnsTuple', data) + expect(b).to.eq(1) + expect(a).to.eq(2) + }) + + it('fails previousBlockhash check', async () => { + await expect( + multicall['multicall(bytes32,bytes[])'](constants.HashZero, [ + multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), + ]) + ).to.be.revertedWith('Blockhash') + }) + + it('passes previousBlockhash check', async () => { + const block = await ethers.provider.getBlock('latest') + await expect( + multicall['multicall(bytes32,bytes[])'](block.hash, [ + multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), + ]) + ).to.not.be.reverted + }) +}) diff --git a/lib/swap-router-contracts/test/OracleSlippage.spec.ts b/lib/swap-router-contracts/test/OracleSlippage.spec.ts new file mode 100644 index 0000000..bd9d95b --- /dev/null +++ b/lib/swap-router-contracts/test/OracleSlippage.spec.ts @@ -0,0 +1,447 @@ +import { constants, ContractFactory } from 'ethers' +import { ethers, waffle } from 'hardhat' +import { MockObservations, OracleSlippageTest } from '../typechain' +import { FeeAmount } from './shared/constants' +import { expect } from './shared/expect' +import { encodePath } from './shared/path' + +const tokens = [ + '0x0000000000000000000000000000000000000001', + '0x0000000000000000000000000000000000000002', + '0x0000000000000000000000000000000000000003', +] + +describe('OracleSlippage', function () { + this.timeout(40000) + + let loadFixture: ReturnType + + let oracle: OracleSlippageTest + let mockObservationsFactory: ContractFactory + + const oracleTestFixture = async () => { + const oracleFactory = await ethers.getContractFactory('OracleSlippageTest') + const oracle = await oracleFactory.deploy(constants.AddressZero, constants.AddressZero) + + return oracle as OracleSlippageTest + } + + before('create fixture loader', async () => { + loadFixture = waffle.createFixtureLoader(await (ethers as any).getSigners()) + }) + + beforeEach('deploy fixture', async () => { + oracle = await loadFixture(oracleTestFixture) + }) + + before('create mockObservationsFactory', async () => { + mockObservationsFactory = await ethers.getContractFactory('MockObservations') + }) + + async function createMockPool( + tokenA: string, + tokenB: string, + fee: FeeAmount, + blockTimestamps: number[], + ticks: number[], + mockLowObservationCardinality = false + ): Promise { + const mockPool = await mockObservationsFactory.deploy(blockTimestamps, ticks, mockLowObservationCardinality) + await oracle.registerPool(mockPool.address, tokenA, tokenB, fee) + await oracle.setTime(blockTimestamps[blockTimestamps.length - 1]) + return mockPool as MockObservations + } + + describe('#getBlockStartingAndCurrentTick', () => { + it('fails when observationCardinality == 1', async () => { + const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 0, 0], true) + await expect(oracle.testGetBlockStartingAndCurrentTick(mockPool.address)).to.be.revertedWith('NEO') + }) + + it('works when ticks are the same in the same block', async () => { + const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) + const { blockStartingTick, currentTick } = await oracle.testGetBlockStartingAndCurrentTick(mockPool.address) + expect(blockStartingTick).to.eq(11) + expect(currentTick).to.eq(11) + }) + + it('works when ticks are different in the same block', async () => { + const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + const { blockStartingTick, currentTick } = await oracle.testGetBlockStartingAndCurrentTick(mockPool.address) + expect(blockStartingTick).to.eq(11) + expect(currentTick).to.eq(12) + }) + + it('works when time has passed since the last block', async () => { + const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + await oracle.setTime(3) + const { blockStartingTick, currentTick } = await oracle.testGetBlockStartingAndCurrentTick(mockPool.address) + expect(blockStartingTick).to.eq(12) + expect(currentTick).to.eq(12) + }) + }) + + describe('#getSyntheticTicks(bytes,uint32)', () => { + describe('single pool', () => { + describe('unchanged ticks; secondsAgo = 0', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(11) + expect(syntheticCurrentTick).to.eq(11) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(-11) + expect(syntheticCurrentTick).to.eq(-11) + }) + }) + + describe('changed ticks; secondsAgo = 0', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(11) + expect(syntheticCurrentTick).to.eq(12) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(-11) + expect(syntheticCurrentTick).to.eq(-12) + }) + }) + + describe('unchanged ticks; secondsAgo != 0', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(11) + expect(syntheticCurrentTick).to.eq(11) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(-11) + expect(syntheticCurrentTick).to.eq(-11) + }) + }) + + describe('changed ticks', () => { + describe('secondsAgo = 1', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(11) + expect(syntheticCurrentTick).to.eq(12) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(-11) + expect(syntheticCurrentTick).to.eq(-12) + }) + }) + + describe('secondsAgo = 2', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [10, 12, 13]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), + 2 + ) + expect(syntheticAverageTick).to.eq(11) + expect(syntheticCurrentTick).to.eq(13) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), + 2 + ) + expect(syntheticAverageTick).to.eq(-11) + expect(syntheticCurrentTick).to.eq(-13) + }) + }) + }) + }) + + describe('two pools', () => { + describe('unchanged ticks; secondsAgo = 0', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) + await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(22) + expect(syntheticCurrentTick).to.eq(22) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(-22) + expect(syntheticCurrentTick).to.eq(-22) + }) + }) + + describe('changed ticks; secondsAgo = 0', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(22) + expect(syntheticCurrentTick).to.eq(24) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + 0 + ) + expect(syntheticAverageTick).to.eq(-22) + expect(syntheticCurrentTick).to.eq(-24) + }) + }) + + describe('unchanged ticks; secondsAgo != 0', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) + await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(22) + expect(syntheticCurrentTick).to.eq(22) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(-22) + expect(syntheticCurrentTick).to.eq(-22) + }) + }) + + describe('changed ticks', () => { + describe('secondsAgo = 1', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(22) + expect(syntheticCurrentTick).to.eq(24) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + 1 + ) + expect(syntheticAverageTick).to.eq(-22) + expect(syntheticCurrentTick).to.eq(-24) + }) + }) + + describe('secondsAgo = 2', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [10, 12, 13]) + await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [10, 12, 13]) + }) + + it('normal order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), + 2 + ) + expect(syntheticAverageTick).to.eq(22) + expect(syntheticCurrentTick).to.eq(26) + }) + + it('reverse order', async () => { + const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + 2 + ) + expect(syntheticAverageTick).to.eq(-22) + expect(syntheticCurrentTick).to.eq(-26) + }) + }) + }) + }) + }) + + describe('#getSyntheticTicks(bytes[],uint128[],uint32)', () => { + describe('same price', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + await createMockPool(tokens[0], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 22, 24]) + }) + + it('normal order', async () => { + const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ + 'testGetSyntheticTicks(bytes[],uint128[],uint32)' + ]( + [encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), encodePath([tokens[0], tokens[2]], [FeeAmount.LOW])], + [1, 1], + 0 + ) + + expect(averageSyntheticAverageTick).to.eq(22) + expect(averageSyntheticCurrentTick).to.eq(24) + }) + + it('reverse order', async () => { + const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ + 'testGetSyntheticTicks(bytes[],uint128[],uint32)' + ]( + [ + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + encodePath([tokens[2], tokens[0]], [FeeAmount.LOW]), + ], + [1, 1], + 0 + ) + + expect(averageSyntheticAverageTick).to.eq(-22) + expect(averageSyntheticCurrentTick).to.eq(-24) + }) + }) + + describe('difference price', () => { + beforeEach(async () => { + await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) + await createMockPool(tokens[0], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 44, 48]) + }) + + describe('same weight', () => { + it('normal order', async () => { + const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ + 'testGetSyntheticTicks(bytes[],uint128[],uint32)' + ]( + [encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), encodePath([tokens[0], tokens[2]], [FeeAmount.LOW])], + [1, 1], + 0 + ) + + expect(averageSyntheticAverageTick).to.eq(33) + expect(averageSyntheticCurrentTick).to.eq(36) + }) + + it('reverse order', async () => { + const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ + 'testGetSyntheticTicks(bytes[],uint128[],uint32)' + ]( + [ + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + encodePath([tokens[2], tokens[0]], [FeeAmount.LOW]), + ], + [1, 1], + 0 + ) + + expect(averageSyntheticAverageTick).to.eq(-33) + expect(averageSyntheticCurrentTick).to.eq(-36) + }) + }) + + describe('different weights', () => { + it('normal order', async () => { + const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ + 'testGetSyntheticTicks(bytes[],uint128[],uint32)' + ]( + [encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), encodePath([tokens[0], tokens[2]], [FeeAmount.LOW])], + [1, 2], + 0 + ) + + expect(averageSyntheticAverageTick).to.eq(36) + expect(averageSyntheticCurrentTick).to.eq(40) + }) + + it('reverse order', async () => { + const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ + 'testGetSyntheticTicks(bytes[],uint128[],uint32)' + ]( + [ + encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), + encodePath([tokens[2], tokens[0]], [FeeAmount.LOW]), + ], + [1, 2], + 0 + ) + + expect(averageSyntheticAverageTick).to.eq(-37) + expect(averageSyntheticCurrentTick).to.eq(-40) + }) + }) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts b/lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts new file mode 100644 index 0000000..a10f04e --- /dev/null +++ b/lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts @@ -0,0 +1,50 @@ +import { Fixture } from 'ethereum-waffle' +import { constants, Contract, ContractTransaction, Wallet } from 'ethers' +import { waffle, ethers } from 'hardhat' +import { IWETH9, MockTimeSwapRouter02 } from '../typechain' +import completeFixture from './shared/completeFixture' +import { expect } from './shared/expect' + +describe('PeripheryPaymentsExtended', function () { + let wallet: Wallet + + const routerFixture: Fixture<{ + weth9: IWETH9 + router: MockTimeSwapRouter02 + }> = async (wallets, provider) => { + const { weth9, router } = await completeFixture(wallets, provider) + + return { + weth9, + router, + } + } + + let router: MockTimeSwapRouter02 + let weth9: IWETH9 + + let loadFixture: ReturnType + + before('create fixture loader', async () => { + ;[wallet] = await (ethers as any).getSigners() + loadFixture = waffle.createFixtureLoader([wallet]) + }) + + beforeEach('load fixture', async () => { + ;({ weth9, router } = await loadFixture(routerFixture)) + }) + + describe('wrapETH', () => { + it('increases router WETH9 balance by value amount', async () => { + const value = ethers.utils.parseEther('1') + + const weth9BalancePrev = await weth9.balanceOf(router.address) + await router.wrapETH(value, { value }) + const weth9BalanceCurrent = await weth9.balanceOf(router.address) + + expect(weth9BalanceCurrent.sub(weth9BalancePrev)).to.equal(value) + expect(await weth9.balanceOf(wallet.address)).to.equal('0') + expect(await router.provider.getBalance(router.address)).to.equal('0') + }) + }) +}) diff --git a/lib/swap-router-contracts/test/PoolTicksCounter.spec.ts b/lib/swap-router-contracts/test/PoolTicksCounter.spec.ts new file mode 100644 index 0000000..5be0ce0 --- /dev/null +++ b/lib/swap-router-contracts/test/PoolTicksCounter.spec.ts @@ -0,0 +1,280 @@ +import { waffle, ethers, artifacts } from 'hardhat' + +import { expect } from './shared/expect' + +import { PoolTicksCounterTest } from '../typechain' +import { deployMockContract, Fixture, MockContract } from 'ethereum-waffle' +import { Artifact } from 'hardhat/types' + +describe('PoolTicksCounter', () => { + const TICK_SPACINGS = [200, 60, 10] + + TICK_SPACINGS.forEach((TICK_SPACING) => { + let PoolTicksCounter: PoolTicksCounterTest + let pool: MockContract + let PoolAbi: Artifact + + // Bit index to tick + const bitIdxToTick = (idx: number, page = 0) => { + return idx * TICK_SPACING + page * 256 * TICK_SPACING + } + + before(async () => { + const wallets = await (ethers as any).getSigners() + PoolAbi = await artifacts.readArtifact('IUniswapV3Pool') + const poolTicksHelperFactory = await ethers.getContractFactory('PoolTicksCounterTest') + PoolTicksCounter = (await poolTicksHelperFactory.deploy()) as PoolTicksCounterTest + pool = await deployMockContract(wallets[0], PoolAbi.abi) + await pool.mock.tickSpacing.returns(TICK_SPACING) + }) + + describe(`[Tick Spacing: ${TICK_SPACING}]: tick after is bigger`, async () => { + it('same tick initialized', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(2), + bitIdxToTick(2) + ) + expect(result).to.be.eq(1) + }) + + it('same tick not-initialized', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(1), + bitIdxToTick(1) + ) + expect(result).to.be.eq(0) + }) + + it('same page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(0), + bitIdxToTick(255) + ) + expect(result).to.be.eq(2) + }) + + it('multiple pages', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 + await pool.mock.tickBitmap.withArgs(1).returns(0b1101) // 1101 + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(0), + bitIdxToTick(255, 1) + ) + expect(result).to.be.eq(5) + }) + + it('counts all ticks in a page except ending tick', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(ethers.constants.MaxUint256) + await pool.mock.tickBitmap.withArgs(1).returns(0x0) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(0), + bitIdxToTick(255, 1) + ) + expect(result).to.be.eq(255) + }) + + it('counts ticks to left of start and right of end on same page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(8), + bitIdxToTick(255) + ) + expect(result).to.be.eq(4) + }) + + it('counts ticks to left of start and right of end across on multiple pages', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) + await pool.mock.tickBitmap.withArgs(1).returns(0b1111000100001111) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(8), + bitIdxToTick(8, 1) + ) + expect(result).to.be.eq(9) + }) + + it('counts ticks when before and after are initialized on same page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) + const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(2), + bitIdxToTick(255) + ) + expect(startingTickInit).to.be.eq(5) + const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(0), + bitIdxToTick(3) + ) + expect(endingTickInit).to.be.eq(2) + const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(2), + bitIdxToTick(5) + ) + expect(bothInit).to.be.eq(3) + }) + + it('counts ticks when before and after are initialized on multiple page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) + await pool.mock.tickBitmap.withArgs(1).returns(0b11111100) + const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(2), + bitIdxToTick(255) + ) + expect(startingTickInit).to.be.eq(5) + const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(0), + bitIdxToTick(3, 1) + ) + expect(endingTickInit).to.be.eq(8) + const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(2), + bitIdxToTick(5, 1) + ) + expect(bothInit).to.be.eq(9) + }) + + it('counts ticks with lots of pages', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) + await pool.mock.tickBitmap.withArgs(1).returns(0b11111111) + await pool.mock.tickBitmap.withArgs(2).returns(0x0) + await pool.mock.tickBitmap.withArgs(3).returns(0x0) + await pool.mock.tickBitmap.withArgs(4).returns(0b11111100) + + const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(4), + bitIdxToTick(5, 4) + ) + expect(bothInit).to.be.eq(15) + }) + }) + + describe(`[Tick Spacing: ${TICK_SPACING}]: tick after is smaller`, async () => { + it('same page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1100) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(255), + bitIdxToTick(0) + ) + expect(result).to.be.eq(2) + }) + + it('multiple pages', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1100) + await pool.mock.tickBitmap.withArgs(-1).returns(0b1100) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(255), + bitIdxToTick(0, -1) + ) + expect(result).to.be.eq(4) + }) + + it('counts all ticks in a page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(ethers.constants.MaxUint256) + await pool.mock.tickBitmap.withArgs(-1).returns(0x0) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(255), + bitIdxToTick(0, -1) + ) + expect(result).to.be.eq(256) + }) + + it('counts ticks to right of start and left of end on same page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(15), + bitIdxToTick(2) + ) + expect(result).to.be.eq(6) + }) + + it('counts ticks to right of start and left of end on multiple pages', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) + await pool.mock.tickBitmap.withArgs(-1).returns(0b1111000100001111) + const result = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(8), + bitIdxToTick(8, -1) + ) + expect(result).to.be.eq(9) + }) + + it('counts ticks when before and after are initialized on same page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) + const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(3), + bitIdxToTick(0) + ) + expect(startingTickInit).to.be.eq(2) + const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(255), + bitIdxToTick(2) + ) + expect(endingTickInit).to.be.eq(5) + const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(5), + bitIdxToTick(2) + ) + expect(bothInit).to.be.eq(3) + }) + + it('counts ticks when before and after are initialized on multiple page', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) + await pool.mock.tickBitmap.withArgs(-1).returns(0b11111100) + const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(2), + bitIdxToTick(3, -1) + ) + expect(startingTickInit).to.be.eq(5) + const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(5), + bitIdxToTick(255, -1) + ) + expect(endingTickInit).to.be.eq(4) + const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(2), + bitIdxToTick(5, -1) + ) + expect(bothInit).to.be.eq(3) + }) + + it('counts ticks with lots of pages', async () => { + await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) + await pool.mock.tickBitmap.withArgs(-1).returns(0xff) + await pool.mock.tickBitmap.withArgs(-2).returns(0x0) + await pool.mock.tickBitmap.withArgs(-3).returns(0x0) + await pool.mock.tickBitmap.withArgs(-4).returns(0b11111100) + const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( + pool.address, + bitIdxToTick(3), + bitIdxToTick(6, -4) + ) + expect(bothInit).to.be.eq(11) + }) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/Quoter.spec.ts b/lib/swap-router-contracts/test/Quoter.spec.ts new file mode 100644 index 0000000..99c917b --- /dev/null +++ b/lib/swap-router-contracts/test/Quoter.spec.ts @@ -0,0 +1,201 @@ +import { Fixture } from 'ethereum-waffle' +import { constants, Wallet, Contract } from 'ethers' +import { ethers, waffle } from 'hardhat' +import { Quoter, TestERC20 } from '../typechain' +import completeFixture from './shared/completeFixture' +import { FeeAmount, MaxUint128, TICK_SPACINGS } from './shared/constants' +import { encodePriceSqrt } from './shared/encodePriceSqrt' +import { expandTo18Decimals } from './shared/expandTo18Decimals' +import { expect } from './shared/expect' +import { encodePath } from './shared/path' +import { createPool } from './shared/quoter' + +describe('Quoter', () => { + let wallet: Wallet + let trader: Wallet + + const swapRouterFixture: Fixture<{ + nft: Contract + tokens: [TestERC20, TestERC20, TestERC20] + quoter: Quoter + }> = async (wallets, provider) => { + const { weth9, factory, router, tokens, nft } = await completeFixture(wallets, provider) + + // approve & fund wallets + for (const token of tokens) { + await token.approve(router.address, constants.MaxUint256) + await token.approve(nft.address, constants.MaxUint256) + await token.connect(trader).approve(router.address, constants.MaxUint256) + await token.transfer(trader.address, expandTo18Decimals(1_000_000)) + } + + const quoterFactory = await ethers.getContractFactory('Quoter') + quoter = (await quoterFactory.deploy(factory.address, weth9.address)) as Quoter + + return { + tokens, + nft, + quoter, + } + } + + let nft: Contract + let tokens: [TestERC20, TestERC20, TestERC20] + let quoter: Quoter + + let loadFixture: ReturnType + + before('create fixture loader', async () => { + const wallets = await (ethers as any).getSigners() + ;[wallet, trader] = wallets + loadFixture = waffle.createFixtureLoader(wallets) + }) + + // helper for getting weth and token balances + beforeEach('load fixture', async () => { + ;({ tokens, nft, quoter } = await loadFixture(swapRouterFixture)) + }) + + describe('quotes', () => { + beforeEach(async () => { + await createPool(nft, wallet, tokens[0].address, tokens[1].address) + await createPool(nft, wallet, tokens[1].address, tokens[2].address) + }) + + describe('#quoteExactInput', () => { + it('0 -> 1', async () => { + const quote = await quoter.callStatic.quoteExactInput( + encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), + 3 + ) + + expect(quote).to.eq(1) + }) + + it('1 -> 0', async () => { + const quote = await quoter.callStatic.quoteExactInput( + encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), + 3 + ) + + expect(quote).to.eq(1) + }) + + it('0 -> 1 -> 2', async () => { + const quote = await quoter.callStatic.quoteExactInput( + encodePath( + tokens.map((token) => token.address), + [FeeAmount.MEDIUM, FeeAmount.MEDIUM] + ), + 5 + ) + + expect(quote).to.eq(1) + }) + + it('2 -> 1 -> 0', async () => { + const quote = await quoter.callStatic.quoteExactInput( + encodePath(tokens.map((token) => token.address).reverse(), [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), + 5 + ) + + expect(quote).to.eq(1) + }) + }) + + describe('#quoteExactInputSingle', () => { + it('0 -> 1', async () => { + const quote = await quoter.callStatic.quoteExactInputSingle( + tokens[0].address, + tokens[1].address, + FeeAmount.MEDIUM, + MaxUint128, + // -2% + encodePriceSqrt(100, 102) + ) + + expect(quote).to.eq(9852) + }) + + it('1 -> 0', async () => { + const quote = await quoter.callStatic.quoteExactInputSingle( + tokens[1].address, + tokens[0].address, + FeeAmount.MEDIUM, + MaxUint128, + // +2% + encodePriceSqrt(102, 100) + ) + + expect(quote).to.eq(9852) + }) + }) + + describe('#quoteExactOutput', () => { + it('0 -> 1', async () => { + const quote = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), + 1 + ) + + expect(quote).to.eq(3) + }) + + it('1 -> 0', async () => { + const quote = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), + 1 + ) + + expect(quote).to.eq(3) + }) + + it('0 -> 1 -> 2', async () => { + const quote = await quoter.callStatic.quoteExactOutput( + encodePath(tokens.map((token) => token.address).reverse(), [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), + 1 + ) + + expect(quote).to.eq(5) + }) + + it('2 -> 1 -> 0', async () => { + const quote = await quoter.callStatic.quoteExactOutput( + encodePath( + tokens.map((token) => token.address), + [FeeAmount.MEDIUM, FeeAmount.MEDIUM] + ), + 1 + ) + + expect(quote).to.eq(5) + }) + }) + + describe('#quoteExactOutputSingle', () => { + it('0 -> 1', async () => { + const quote = await quoter.callStatic.quoteExactOutputSingle( + tokens[0].address, + tokens[1].address, + FeeAmount.MEDIUM, + MaxUint128, + encodePriceSqrt(100, 102) + ) + + expect(quote).to.eq(9981) + }) + + it('1 -> 0', async () => { + const quote = await quoter.callStatic.quoteExactOutputSingle( + tokens[1].address, + tokens[0].address, + FeeAmount.MEDIUM, + MaxUint128, + encodePriceSqrt(102, 100) + ) + + expect(quote).to.eq(9981) + }) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/QuoterV2.spec.ts b/lib/swap-router-contracts/test/QuoterV2.spec.ts new file mode 100644 index 0000000..61cbb62 --- /dev/null +++ b/lib/swap-router-contracts/test/QuoterV2.spec.ts @@ -0,0 +1,578 @@ +import { Fixture } from 'ethereum-waffle' +import { constants, Wallet, Contract } from 'ethers' +import { ethers, waffle } from 'hardhat' +import { QuoterV2, TestERC20 } from '../typechain' +import completeFixture from './shared/completeFixture' +import { FeeAmount, MaxUint128 } from './shared/constants' +import { encodePriceSqrt } from './shared/encodePriceSqrt' +import { expandTo18Decimals } from './shared/expandTo18Decimals' +import { expect } from './shared/expect' +import { encodePath } from './shared/path' +import { createPool, createPoolWithMultiplePositions, createPoolWithZeroTickInitialized } from './shared/quoter' +import snapshotGasCost from './shared/snapshotGasCost' + +describe('QuoterV2', function () { + this.timeout(40000) + let wallet: Wallet + let trader: Wallet + + const swapRouterFixture: Fixture<{ + nft: Contract + tokens: [TestERC20, TestERC20, TestERC20] + quoter: QuoterV2 + }> = async (wallets, provider) => { + const { weth9, factory, router, tokens, nft } = await completeFixture(wallets, provider) + + // approve & fund wallets + for (const token of tokens) { + await token.approve(router.address, constants.MaxUint256) + await token.approve(nft.address, constants.MaxUint256) + await token.connect(trader).approve(router.address, constants.MaxUint256) + await token.transfer(trader.address, expandTo18Decimals(1_000_000)) + } + + const quoterFactory = await ethers.getContractFactory('QuoterV2') + quoter = (await quoterFactory.deploy(factory.address, weth9.address)) as QuoterV2 + + return { + tokens, + nft, + quoter, + } + } + + let nft: Contract + let tokens: [TestERC20, TestERC20, TestERC20] + let quoter: QuoterV2 + + let loadFixture: ReturnType + + before('create fixture loader', async () => { + const wallets = await (ethers as any).getSigners() + ;[wallet, trader] = wallets + loadFixture = waffle.createFixtureLoader(wallets) + }) + + // helper for getting weth and token balances + beforeEach('load fixture', async () => { + ;({ tokens, nft, quoter } = await loadFixture(swapRouterFixture)) + }) + + describe('quotes', () => { + beforeEach(async () => { + await createPool(nft, wallet, tokens[0].address, tokens[1].address) + await createPool(nft, wallet, tokens[1].address, tokens[2].address) + await createPoolWithMultiplePositions(nft, wallet, tokens[0].address, tokens[2].address) + }) + + describe('#quoteExactInput', () => { + it('0 -> 2 cross 2 tick', async () => { + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 10000 + ) + + await snapshotGasCost(gasEstimate) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') + expect(initializedTicksCrossedList[0]).to.eq(2) + expect(amountOut).to.eq(9871) + }) + + it('0 -> 2 cross 2 tick where after is initialized', async () => { + // The swap amount is set such that the active tick after the swap is -120. + // -120 is an initialized tick for this pool. We check that we don't count it. + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 6200 + ) + + await snapshotGasCost(gasEstimate) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('78757224507315167622282810783') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(initializedTicksCrossedList[0]).to.eq(1) + expect(amountOut).to.eq(6143) + }) + + it('0 -> 2 cross 1 tick', async () => { + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 4000 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(1) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('78926452400586371254602774705') + expect(amountOut).to.eq(3971) + }) + + it('0 -> 2 cross 0 tick, starting tick not initialized', async () => { + // Tick before 0, tick after -1. + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 10 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(0) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79227483487511329217250071027') + expect(amountOut).to.eq(8) + }) + + it('0 -> 2 cross 0 tick, starting tick initialized', async () => { + // Tick before 0, tick after -1. Tick 0 initialized. + await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) + + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 10 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(1) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79227817515327498931091950511') + expect(amountOut).to.eq(8) + }) + + it('2 -> 0 cross 2', async () => { + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 10000 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(2) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('80001962924147897865541384515') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(9871) + }) + + it('2 -> 0 cross 2 where tick after is initialized', async () => { + // The swap amount is set such that the active tick after the swap is 120. + // 120 is an initialized tick for this pool. We check we don't count it. + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 6250 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(2) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79705728824507063507279123685') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(6190) + }) + + it('2 -> 0 cross 0 tick, starting tick initialized', async () => { + // Tick 0 initialized. Tick after = 1 + await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) + + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 200 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(0) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79235729830182478001034429156') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(198) + }) + + it('2 -> 0 cross 0 tick, starting tick not initialized', async () => { + // Tick 0 initialized. Tick after = 1 + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 103 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(0) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79235858216754624215638319723') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(amountOut).to.eq(101) + }) + + it('2 -> 1', async () => { + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM]), + 10000 + ) + + await snapshotGasCost(gasEstimate) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('80018067294531553039351583520') + expect(initializedTicksCrossedList[0]).to.eq(0) + expect(amountOut).to.eq(9871) + }) + + it('0 -> 2 -> 1', async () => { + const { + amountOut, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactInput( + encodePath([tokens[0].address, tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), + 10000 + ) + + await snapshotGasCost(gasEstimate) + expect(sqrtPriceX96AfterList.length).to.eq(2) + expect(sqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') + expect(sqrtPriceX96AfterList[1]).to.eq('80007846861567212939802016351') + expect(initializedTicksCrossedList[0]).to.eq(2) + expect(initializedTicksCrossedList[1]).to.eq(0) + expect(amountOut).to.eq(9745) + }) + }) + + describe('#quoteExactInputSingle', () => { + it('0 -> 2', async () => { + const { + amountOut: quote, + sqrtPriceX96After, + initializedTicksCrossed, + gasEstimate, + } = await quoter.callStatic.quoteExactInputSingle({ + tokenIn: tokens[0].address, + tokenOut: tokens[2].address, + fee: FeeAmount.MEDIUM, + amountIn: 10000, + // -2% + sqrtPriceLimitX96: encodePriceSqrt(100, 102), + }) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossed).to.eq(2) + expect(quote).to.eq(9871) + expect(sqrtPriceX96After).to.eq('78461846509168490764501028180') + }) + + it('2 -> 0', async () => { + const { + amountOut: quote, + sqrtPriceX96After, + initializedTicksCrossed, + gasEstimate, + } = await quoter.callStatic.quoteExactInputSingle({ + tokenIn: tokens[2].address, + tokenOut: tokens[0].address, + fee: FeeAmount.MEDIUM, + amountIn: 10000, + // +2% + sqrtPriceLimitX96: encodePriceSqrt(102, 100), + }) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossed).to.eq(2) + expect(quote).to.eq(9871) + expect(sqrtPriceX96After).to.eq('80001962924147897865541384515') + }) + }) + + describe('#quoteExactOutput', () => { + it('0 -> 2 cross 2 tick', async () => { + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 15000 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList.length).to.eq(1) + expect(initializedTicksCrossedList[0]).to.eq(2) + expect(amountIn).to.eq(15273) + + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('78055527257643669242286029831') + }) + + it('0 -> 2 cross 2 where tick after is initialized', async () => { + // The swap amount is set such that the active tick after the swap is -120. + // -120 is an initialized tick for this pool. We check that we count it. + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 6143 + ) + + await snapshotGasCost(gasEstimate) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('78757225449310403327341205211') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(initializedTicksCrossedList[0]).to.eq(1) + expect(amountIn).to.eq(6200) + }) + + it('0 -> 2 cross 1 tick', async () => { + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 4000 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList.length).to.eq(1) + expect(initializedTicksCrossedList[0]).to.eq(1) + expect(amountIn).to.eq(4029) + + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('78924219757724709840818372098') + }) + + it('0 -> 2 cross 0 tick starting tick initialized', async () => { + // Tick before 0, tick after 1. Tick 0 initialized. + await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 100 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList.length).to.eq(1) + expect(initializedTicksCrossedList[0]).to.eq(1) + expect(amountIn).to.eq(102) + + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79224329176051641448521403903') + }) + + it('0 -> 2 cross 0 tick starting tick not initialized', async () => { + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), + 10 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList.length).to.eq(1) + expect(initializedTicksCrossedList[0]).to.eq(0) + expect(amountIn).to.eq(12) + + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79227408033628034983534698435') + }) + + it('2 -> 0 cross 2 ticks', async () => { + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 15000 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList.length).to.eq(1) + expect(initializedTicksCrossedList[0]).to.eq(2) + expect(amountIn).to.eq(15273) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('80418414376567919517220409857') + }) + + it('2 -> 0 cross 2 where tick after is initialized', async () => { + // The swap amount is set such that the active tick after the swap is 120. + // 120 is an initialized tick for this pool. We check that we don't count it. + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 6223 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(2) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79708304437530892332449657932') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(amountIn).to.eq(6283) + }) + + it('2 -> 0 cross 1 tick', async () => { + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), + 6000 + ) + + await snapshotGasCost(gasEstimate) + expect(initializedTicksCrossedList[0]).to.eq(1) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('79690640184021170956740081887') + expect(initializedTicksCrossedList.length).to.eq(1) + expect(amountIn).to.eq(6055) + }) + + it('2 -> 1', async () => { + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[1].address, tokens[2].address], [FeeAmount.MEDIUM]), + 9871 + ) + + await snapshotGasCost(gasEstimate) + expect(sqrtPriceX96AfterList.length).to.eq(1) + expect(sqrtPriceX96AfterList[0]).to.eq('80018020393569259756601362385') + expect(initializedTicksCrossedList[0]).to.eq(0) + expect(amountIn).to.eq(10000) + }) + + it('0 -> 2 -> 1', async () => { + const { + amountIn, + sqrtPriceX96AfterList, + initializedTicksCrossedList, + gasEstimate, + } = await quoter.callStatic.quoteExactOutput( + encodePath([tokens[0].address, tokens[2].address, tokens[1].address].reverse(), [ + FeeAmount.MEDIUM, + FeeAmount.MEDIUM, + ]), + 9745 + ) + + await snapshotGasCost(gasEstimate) + expect(sqrtPriceX96AfterList.length).to.eq(2) + expect(sqrtPriceX96AfterList[0]).to.eq('80007838904387594703933785072') + expect(sqrtPriceX96AfterList[1]).to.eq('78461888503179331029803316753') + expect(initializedTicksCrossedList[0]).to.eq(0) + expect(initializedTicksCrossedList[1]).to.eq(2) + expect(amountIn).to.eq(10000) + }) + }) + + describe('#quoteExactOutputSingle', () => { + it('0 -> 1', async () => { + const { + amountIn, + sqrtPriceX96After, + initializedTicksCrossed, + gasEstimate, + } = await quoter.callStatic.quoteExactOutputSingle({ + tokenIn: tokens[0].address, + tokenOut: tokens[1].address, + fee: FeeAmount.MEDIUM, + amount: MaxUint128, + sqrtPriceLimitX96: encodePriceSqrt(100, 102), + }) + + await snapshotGasCost(gasEstimate) + expect(amountIn).to.eq(9981) + expect(initializedTicksCrossed).to.eq(0) + expect(sqrtPriceX96After).to.eq('78447570448055484695608110440') + }) + + it('1 -> 0', async () => { + const { + amountIn, + sqrtPriceX96After, + initializedTicksCrossed, + gasEstimate, + } = await quoter.callStatic.quoteExactOutputSingle({ + tokenIn: tokens[1].address, + tokenOut: tokens[0].address, + fee: FeeAmount.MEDIUM, + amount: MaxUint128, + sqrtPriceLimitX96: encodePriceSqrt(102, 100), + }) + + await snapshotGasCost(gasEstimate) + expect(amountIn).to.eq(9981) + expect(initializedTicksCrossed).to.eq(0) + expect(sqrtPriceX96After).to.eq('80016521857016594389520272648') + }) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/SwapRouter.gas.spec.ts b/lib/swap-router-contracts/test/SwapRouter.gas.spec.ts new file mode 100644 index 0000000..7112a22 --- /dev/null +++ b/lib/swap-router-contracts/test/SwapRouter.gas.spec.ts @@ -0,0 +1,470 @@ +import { defaultAbiCoder } from '@ethersproject/abi' +import { abi as IUniswapV3PoolABI } from '@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json' +import { Fixture } from 'ethereum-waffle' +import { BigNumber, constants, ContractTransaction, Wallet } from 'ethers' +import { solidityPack } from 'ethers/lib/utils' +import { ethers, waffle } from 'hardhat' +import { IUniswapV3Pool, IWETH9, MockTimeSwapRouter02, TestERC20 } from '../typechain' +import completeFixture from './shared/completeFixture' +import { ADDRESS_THIS, FeeAmount, MSG_SENDER, TICK_SPACINGS } from './shared/constants' +import { encodePriceSqrt } from './shared/encodePriceSqrt' +import { expandTo18Decimals } from './shared/expandTo18Decimals' +import { expect } from './shared/expect' +import { encodePath } from './shared/path' +import snapshotGasCost from './shared/snapshotGasCost' +import { getMaxTick, getMinTick } from './shared/ticks' + +describe('SwapRouter gas tests', function () { + this.timeout(40000) + let wallet: Wallet + let trader: Wallet + + const swapRouterFixture: Fixture<{ + weth9: IWETH9 + router: MockTimeSwapRouter02 + tokens: [TestERC20, TestERC20, TestERC20] + pools: [IUniswapV3Pool, IUniswapV3Pool, IUniswapV3Pool] + }> = async (wallets, provider) => { + const { weth9, factory, router, tokens, nft } = await completeFixture(wallets, provider) + + // approve & fund wallets + for (const token of tokens) { + await token.approve(router.address, constants.MaxUint256) + await token.approve(nft.address, constants.MaxUint256) + await token.connect(trader).approve(router.address, constants.MaxUint256) + await token.transfer(trader.address, expandTo18Decimals(1_000_000)) + } + + const liquidity = 1000000 + async function createPool(tokenAddressA: string, tokenAddressB: string) { + if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) + [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] + + await nft.createAndInitializePoolIfNecessary( + tokenAddressA, + tokenAddressB, + FeeAmount.MEDIUM, + encodePriceSqrt(100005, 100000) // we don't want to cross any ticks + ) + + const liquidityParams = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: wallet.address, + amount0Desired: 1000000, + amount1Desired: 1000000, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + return nft.mint(liquidityParams) + } + + async function createPoolWETH9(tokenAddress: string) { + await weth9.deposit({ value: liquidity * 2 }) + await weth9.approve(nft.address, constants.MaxUint256) + return createPool(weth9.address, tokenAddress) + } + + // create pools + await createPool(tokens[0].address, tokens[1].address) + await createPool(tokens[1].address, tokens[2].address) + await createPoolWETH9(tokens[0].address) + + const poolAddresses = await Promise.all([ + factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM), + factory.getPool(tokens[1].address, tokens[2].address, FeeAmount.MEDIUM), + factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM), + ]) + + const pools = poolAddresses.map((poolAddress) => new ethers.Contract(poolAddress, IUniswapV3PoolABI, wallet)) as [ + IUniswapV3Pool, + IUniswapV3Pool, + IUniswapV3Pool + ] + + return { + weth9, + router, + tokens, + pools, + } + } + + let weth9: IWETH9 + let router: MockTimeSwapRouter02 + let tokens: [TestERC20, TestERC20, TestERC20] + let pools: [IUniswapV3Pool, IUniswapV3Pool, IUniswapV3Pool] + + let loadFixture: ReturnType + + function encodeUnwrapWETH9(amount: number) { + return solidityPack( + ['bytes4', 'bytes'], + [router.interface.getSighash('unwrapWETH9(uint256)'), defaultAbiCoder.encode(['uint256'], [amount])] + ) + } + + function encodeSweep(token: string, amount: number) { + const functionSignature = 'sweepToken(address,uint256)' + return solidityPack( + ['bytes4', 'bytes'], + [ + router.interface.getSighash(functionSignature), + defaultAbiCoder.encode((router.interface.functions as any)[functionSignature].inputs, [token, amount]), + ] + ) + } + + before('create fixture loader', async () => { + const wallets = await (ethers as any).getSigners() + ;[wallet, trader] = wallets + + loadFixture = waffle.createFixtureLoader(wallets) + }) + + beforeEach('load fixture', async () => { + ;({ router, weth9, tokens, pools } = await loadFixture(swapRouterFixture)) + }) + + async function exactInput( + tokens: string[], + amountIn: number = 2, + amountOutMinimum: number = 1 + ): Promise { + const inputIsWETH = weth9.address === tokens[0] + const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address + + const value = inputIsWETH ? amountIn : 0 + + const params = { + path: encodePath(tokens, new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountIn, + amountOutMinimum: outputIsWETH9 ? 0 : amountOutMinimum, // save on calldata + } + + const data = [router.interface.encodeFunctionData('exactInput', [params])] + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOutMinimum)) + } + + return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) + } + + async function exactInputSingle( + tokenIn: string, + tokenOut: string, + amountIn: number = 3, + amountOutMinimum: number = 1, + sqrtPriceLimitX96?: BigNumber + ): Promise { + const inputIsWETH = weth9.address === tokenIn + const outputIsWETH9 = tokenOut === weth9.address + + const value = inputIsWETH ? amountIn : 0 + + const params = { + tokenIn, + tokenOut, + fee: FeeAmount.MEDIUM, + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountIn, + amountOutMinimum: outputIsWETH9 ? 0 : amountOutMinimum, // save on calldata + sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, + } + + const data = [router.interface.encodeFunctionData('exactInputSingle', [params])] + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOutMinimum)) + } + + return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) + } + + async function exactOutput(tokens: string[]): Promise { + const amountInMaximum = 10 // we don't care + const amountOut = 1 + + const inputIsWETH9 = tokens[0] === weth9.address + const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address + + const value = inputIsWETH9 ? amountInMaximum : 0 + + const params = { + path: encodePath(tokens.slice().reverse(), new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountOut, + amountInMaximum, + } + + const data = [router.interface.encodeFunctionData('exactOutput', [params])] + if (inputIsWETH9) { + data.push(router.interface.encodeFunctionData('refundETH')) + } + + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOut)) + } + + return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) + } + + async function exactOutputSingle( + tokenIn: string, + tokenOut: string, + amountOut: number = 1, + amountInMaximum: number = 3, + sqrtPriceLimitX96?: BigNumber + ): Promise { + const inputIsWETH9 = tokenIn === weth9.address + const outputIsWETH9 = tokenOut === weth9.address + + const value = inputIsWETH9 ? amountInMaximum : 0 + + const params = { + tokenIn, + tokenOut, + fee: FeeAmount.MEDIUM, + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountOut, + amountInMaximum, + sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, + } + + const data = [router.interface.encodeFunctionData('exactOutputSingle', [params])] + if (inputIsWETH9) { + data.push(router.interface.encodeFunctionData('refundETH')) + } + + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOut)) + } + + return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) + } + + // TODO should really throw this in the fixture + beforeEach('intialize feeGrowthGlobals', async () => { + await exactInput([tokens[0].address, tokens[1].address], 1, 0) + await exactInput([tokens[1].address, tokens[0].address], 1, 0) + await exactInput([tokens[1].address, tokens[2].address], 1, 0) + await exactInput([tokens[2].address, tokens[1].address], 1, 0) + await exactInput([tokens[0].address, weth9.address], 1, 0) + await exactInput([weth9.address, tokens[0].address], 1, 0) + }) + + beforeEach('ensure feeGrowthGlobals are >0', async () => { + const slots = await Promise.all( + pools.map((pool) => + Promise.all([ + pool.feeGrowthGlobal0X128().then((f) => f.toString()), + pool.feeGrowthGlobal1X128().then((f) => f.toString()), + ]) + ) + ) + + expect(slots).to.deep.eq([ + ['340290874192793283295456993856614', '340290874192793283295456993856614'], + ['340290874192793283295456993856614', '340290874192793283295456993856614'], + ['340290874192793283295456993856614', '340290874192793283295456993856614'], + ]) + }) + + beforeEach('ensure ticks are 0 before', async () => { + const slots = await Promise.all(pools.map((pool) => pool.slot0().then(({ tick }) => tick))) + expect(slots).to.deep.eq([0, 0, 0]) + }) + + afterEach('ensure ticks are 0 after', async () => { + const slots = await Promise.all(pools.map((pool) => pool.slot0().then(({ tick }) => tick))) + expect(slots).to.deep.eq([0, 0, 0]) + }) + + describe('#exactInput', () => { + it('0 -> 1', async () => { + await snapshotGasCost(exactInput(tokens.slice(0, 2).map((token) => token.address))) + }) + + it('0 -> 1 minimal', async () => { + const calleeFactory = await ethers.getContractFactory('TestUniswapV3Callee') + const callee = await calleeFactory.deploy() + + await tokens[0].connect(trader).approve(callee.address, constants.MaxUint256) + await snapshotGasCost(callee.connect(trader).swapExact0For1(pools[0].address, 2, trader.address, '4295128740')) + }) + + it('0 -> 1 -> 2', async () => { + await snapshotGasCost( + exactInput( + tokens.map((token) => token.address), + 3 + ) + ) + }) + + it('WETH9 -> 0', async () => { + await snapshotGasCost( + exactInput( + [weth9.address, tokens[0].address], + weth9.address.toLowerCase() < tokens[0].address.toLowerCase() ? 2 : 3 + ) + ) + }) + + it('0 -> WETH9', async () => { + await snapshotGasCost( + exactInput( + [tokens[0].address, weth9.address], + tokens[0].address.toLowerCase() < weth9.address.toLowerCase() ? 2 : 3 + ) + ) + }) + + it('2 trades (via router)', async () => { + await weth9.connect(trader).deposit({ value: 3 }) + await weth9.connect(trader).approve(router.address, constants.MaxUint256) + const swap0 = { + path: encodePath([weth9.address, tokens[0].address], [FeeAmount.MEDIUM]), + recipient: ADDRESS_THIS, + amountIn: 3, + amountOutMinimum: 0, // save on calldata + } + + const swap1 = { + path: encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), + recipient: ADDRESS_THIS, + amountIn: 3, + amountOutMinimum: 0, // save on calldata + } + + const data = [ + router.interface.encodeFunctionData('exactInput', [swap0]), + router.interface.encodeFunctionData('exactInput', [swap1]), + encodeSweep(tokens[0].address, 2), + ] + + await snapshotGasCost(router.connect(trader)['multicall(uint256,bytes[])'](1, data)) + }) + + it('2 trades (directly to sender)', async () => { + await weth9.connect(trader).deposit({ value: 3 }) + await weth9.connect(trader).approve(router.address, constants.MaxUint256) + const swap0 = { + path: encodePath([weth9.address, tokens[0].address], [FeeAmount.MEDIUM]), + recipient: MSG_SENDER, + amountIn: 3, + amountOutMinimum: 1, + } + + const swap1 = { + path: encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), + recipient: MSG_SENDER, + amountIn: 3, + amountOutMinimum: 1, + } + + const data = [ + router.interface.encodeFunctionData('exactInput', [swap0]), + router.interface.encodeFunctionData('exactInput', [swap1]), + ] + + await snapshotGasCost(router.connect(trader)['multicall(uint256,bytes[])'](1, data)) + }) + + it('3 trades (directly to sender)', async () => { + await weth9.connect(trader).deposit({ value: 3 }) + await weth9.connect(trader).approve(router.address, constants.MaxUint256) + const swap0 = { + path: encodePath([weth9.address, tokens[0].address], [FeeAmount.MEDIUM]), + recipient: MSG_SENDER, + amountIn: 3, + amountOutMinimum: 1, + } + + const swap1 = { + path: encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), + recipient: MSG_SENDER, + amountIn: 3, + amountOutMinimum: 1, + } + + const swap2 = { + path: encodePath([tokens[1].address, tokens[2].address], [FeeAmount.MEDIUM]), + recipient: MSG_SENDER, + amountIn: 3, + amountOutMinimum: 1, + } + + const data = [ + router.interface.encodeFunctionData('exactInput', [swap0]), + router.interface.encodeFunctionData('exactInput', [swap1]), + router.interface.encodeFunctionData('exactInput', [swap2]), + ] + + await snapshotGasCost(router.connect(trader)['multicall(uint256,bytes[])'](1, data)) + }) + }) + + describe('#exactInputSingle', () => { + it('0 -> 1', async () => { + await snapshotGasCost(exactInputSingle(tokens[0].address, tokens[1].address)) + }) + + it('WETH9 -> 0', async () => { + await snapshotGasCost( + exactInputSingle( + weth9.address, + tokens[0].address, + weth9.address.toLowerCase() < tokens[0].address.toLowerCase() ? 2 : 3 + ) + ) + }) + + it('0 -> WETH9', async () => { + await snapshotGasCost( + exactInputSingle( + tokens[0].address, + weth9.address, + tokens[0].address.toLowerCase() < weth9.address.toLowerCase() ? 2 : 3 + ) + ) + }) + }) + + describe('#exactOutput', () => { + it('0 -> 1', async () => { + await snapshotGasCost(exactOutput(tokens.slice(0, 2).map((token) => token.address))) + }) + + it('0 -> 1 -> 2', async () => { + await snapshotGasCost(exactOutput(tokens.map((token) => token.address))) + }) + + it('WETH9 -> 0', async () => { + await snapshotGasCost(exactOutput([weth9.address, tokens[0].address])) + }) + + it('0 -> WETH9', async () => { + await snapshotGasCost(exactOutput([tokens[0].address, weth9.address])) + }) + }) + + describe('#exactOutputSingle', () => { + it('0 -> 1', async () => { + await snapshotGasCost(exactOutputSingle(tokens[0].address, tokens[1].address)) + }) + + it('WETH9 -> 0', async () => { + await snapshotGasCost(exactOutputSingle(weth9.address, tokens[0].address)) + }) + + it('0 -> WETH9', async () => { + await snapshotGasCost(exactOutputSingle(tokens[0].address, weth9.address)) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/SwapRouter.spec.ts b/lib/swap-router-contracts/test/SwapRouter.spec.ts new file mode 100644 index 0000000..1cdbddf --- /dev/null +++ b/lib/swap-router-contracts/test/SwapRouter.spec.ts @@ -0,0 +1,1623 @@ +import { defaultAbiCoder } from '@ethersproject/abi' +import { abi as PAIR_V2_ABI } from '@uniswap/v2-core/build/UniswapV2Pair.json' +import { Fixture } from 'ethereum-waffle' +import { BigNumber, constants, Contract, ContractTransaction, Wallet } from 'ethers' +import { solidityPack } from 'ethers/lib/utils' +import { ethers, waffle } from 'hardhat' +import { IUniswapV2Pair, IWETH9, MockTimeSwapRouter02, MixedRouteQuoterV1, TestERC20 } from '../typechain' +import completeFixture from './shared/completeFixture' +import { computePoolAddress } from './shared/computePoolAddress' +import { + ADDRESS_THIS, + CONTRACT_BALANCE, + FeeAmount, + MSG_SENDER, + TICK_SPACINGS, + V2_FEE_PLACEHOLDER, +} from './shared/constants' +import { encodePriceSqrt } from './shared/encodePriceSqrt' +import { expandTo18Decimals } from './shared/expandTo18Decimals' +import { expect } from './shared/expect' +import { encodePath } from './shared/path' +import { getMaxTick, getMinTick } from './shared/ticks' + +describe('SwapRouter', function () { + this.timeout(40000) + let wallet: Wallet + let trader: Wallet + + const swapRouterFixture: Fixture<{ + weth9: IWETH9 + factory: Contract + factoryV2: Contract + router: MockTimeSwapRouter02 + quoter: MixedRouteQuoterV1 + nft: Contract + tokens: [TestERC20, TestERC20, TestERC20] + }> = async (wallets, provider) => { + const { weth9, factory, factoryV2, router, tokens, nft } = await completeFixture(wallets, provider) + + // approve & fund wallets + for (const token of tokens) { + await token.approve(router.address, constants.MaxUint256) + await token.approve(nft.address, constants.MaxUint256) + await token.connect(trader).approve(router.address, constants.MaxUint256) + await token.transfer(trader.address, expandTo18Decimals(1_000_000)) + } + + const quoterFactory = await ethers.getContractFactory('MixedRouteQuoterV1') + quoter = (await quoterFactory.deploy(factory.address, factoryV2.address, weth9.address)) as MixedRouteQuoterV1 + + return { + weth9, + factory, + factoryV2, + router, + quoter, + tokens, + nft, + } + } + + let factory: Contract + let factoryV2: Contract + let weth9: IWETH9 + let router: MockTimeSwapRouter02 + let quoter: MixedRouteQuoterV1 + let nft: Contract + let tokens: [TestERC20, TestERC20, TestERC20] + let getBalances: ( + who: string + ) => Promise<{ + weth9: BigNumber + token0: BigNumber + token1: BigNumber + token2: BigNumber + }> + + let loadFixture: ReturnType + + function encodeUnwrapWETH9(amount: number) { + const functionSignature = 'unwrapWETH9(uint256,address)' + return solidityPack( + ['bytes4', 'bytes'], + [ + router.interface.getSighash(functionSignature), + defaultAbiCoder.encode(router.interface.functions[functionSignature].inputs, [amount, trader.address]), + ] + ) + } + + function encodeSweep(token: string, amount: number, recipient: string) { + const functionSignature = 'sweepToken(address,uint256,address)' + return solidityPack( + ['bytes4', 'bytes'], + [ + router.interface.getSighash(functionSignature), + defaultAbiCoder.encode(router.interface.functions[functionSignature].inputs, [token, amount, recipient]), + ] + ) + } + + before('create fixture loader', async () => { + ;[wallet, trader] = await (ethers as any).getSigners() + loadFixture = waffle.createFixtureLoader([wallet, trader]) + }) + + // helper for getting weth and token balances + beforeEach('load fixture', async () => { + ;({ router, quoter, weth9, factory, factoryV2, tokens, nft } = await loadFixture(swapRouterFixture)) + + getBalances = async (who: string) => { + const balances = await Promise.all([ + weth9.balanceOf(who), + tokens[0].balanceOf(who), + tokens[1].balanceOf(who), + tokens[2].balanceOf(who), + ]) + return { + weth9: balances[0], + token0: balances[1], + token1: balances[2], + token2: balances[3], + } + } + }) + + // ensure the swap router never ends up with a balance + afterEach('load fixture', async () => { + const balances = await getBalances(router.address) + expect(Object.values(balances).every((b) => b.eq(0))).to.be.eq(true) + const balance = await waffle.provider.getBalance(router.address) + expect(balance.eq(0)).to.be.eq(true) + }) + + it('bytecode size', async () => { + expect(((await router.provider.getCode(router.address)).length - 2) / 2).to.matchSnapshot() + }) + + const liquidity = 1000000 + async function createV3Pool(tokenAddressA: string, tokenAddressB: string) { + if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) + [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] + + await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) + + const liquidityParams = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: wallet.address, + amount0Desired: 1000000, + amount1Desired: 1000000, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + return nft.mint(liquidityParams) + } + describe('swaps - v3', () => { + async function createPoolWETH9(tokenAddress: string) { + await weth9.deposit({ value: liquidity }) + await weth9.approve(nft.address, constants.MaxUint256) + return createV3Pool(weth9.address, tokenAddress) + } + + beforeEach('create 0-1 and 1-2 pools', async () => { + await createV3Pool(tokens[0].address, tokens[1].address) + await createV3Pool(tokens[1].address, tokens[2].address) + }) + + describe('#exactInput', () => { + async function exactInput( + tokens: string[], + amountIn: number = 3, + amountOutMinimum: number = 1 + ): Promise { + const inputIsWETH = weth9.address === tokens[0] + const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address + + const value = inputIsWETH ? amountIn : 0 + + const params = { + path: encodePath(tokens, new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountIn, + amountOutMinimum, + } + + const data = [router.interface.encodeFunctionData('exactInput', [params])] + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOutMinimum)) + } + + // ensure that the swap fails if the limit is any tighter + const amountOut = await router.connect(trader).callStatic.exactInput(params, { value }) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + + return router.connect(trader)['multicall(bytes[])'](data, { value }) + } + + describe('single-pool', () => { + it('0 -> 1', async () => { + const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactInput(tokens.slice(0, 2).map((token) => token.address)) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) + }) + + it('1 -> 0', async () => { + const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactInput( + tokens + .slice(0, 2) + .reverse() + .map((token) => token.address) + ) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) + }) + }) + + describe('multi-pool', () => { + it('0 -> 1 -> 2', async () => { + const traderBefore = await getBalances(trader.address) + + await exactInput( + tokens.map((token) => token.address), + 5, + 1 + ) + + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) + }) + + it('2 -> 1 -> 0', async () => { + const traderBefore = await getBalances(trader.address) + + await exactInput(tokens.map((token) => token.address).reverse(), 5, 1) + + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(5)) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + }) + + it('events', async () => { + await expect( + exactInput( + tokens.map((token) => token.address), + 5, + 1 + ) + ) + .to.emit(tokens[0], 'Transfer') + .withArgs( + trader.address, + computePoolAddress(factory.address, [tokens[0].address, tokens[1].address], FeeAmount.MEDIUM), + 5 + ) + .to.emit(tokens[1], 'Transfer') + .withArgs( + computePoolAddress(factory.address, [tokens[0].address, tokens[1].address], FeeAmount.MEDIUM), + router.address, + 3 + ) + .to.emit(tokens[1], 'Transfer') + .withArgs( + router.address, + computePoolAddress(factory.address, [tokens[1].address, tokens[2].address], FeeAmount.MEDIUM), + 3 + ) + .to.emit(tokens[2], 'Transfer') + .withArgs( + computePoolAddress(factory.address, [tokens[1].address, tokens[2].address], FeeAmount.MEDIUM), + trader.address, + 1 + ) + }) + }) + + describe('ETH input', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + }) + + it('WETH9 -> 0', async () => { + const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactInput([weth9.address, tokens[0].address])) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 3) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + }) + + it('WETH9 -> 0 -> 1', async () => { + const traderBefore = await getBalances(trader.address) + + await expect(exactInput([weth9.address, tokens[0].address, tokens[1].address], 5)) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 5) + + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + }) + }) + }) + + describe('ETH output', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + await createPoolWETH9(tokens[1].address) + }) + + it('0 -> WETH9', async () => { + const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactInput([tokens[0].address, weth9.address])) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + }) + + it('0 -> 1 -> WETH9', async () => { + // get balances before + const traderBefore = await getBalances(trader.address) + + await expect(exactInput([tokens[0].address, tokens[1].address, weth9.address], 5)) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) + }) + }) + }) + }) + + describe('#exactInputSingle', () => { + async function exactInputSingle( + tokenIn: string, + tokenOut: string, + amountIn: number = 3, + amountOutMinimum: number = 1, + sqrtPriceLimitX96?: BigNumber + ): Promise { + const inputIsWETH = weth9.address === tokenIn + const outputIsWETH9 = tokenOut === weth9.address + + const value = inputIsWETH ? amountIn : 0 + + const params = { + tokenIn, + tokenOut, + fee: FeeAmount.MEDIUM, + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountIn, + amountOutMinimum, + sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, + } + + const data = [router.interface.encodeFunctionData('exactInputSingle', [params])] + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOutMinimum)) + } + + // ensure that the swap fails if the limit is any tighter + const amountOut = await router.connect(trader).callStatic.exactInputSingle(params, { value }) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + + // optimized for the gas test + return data.length === 1 + ? router.connect(trader).exactInputSingle(params, { value }) + : router.connect(trader)['multicall(bytes[])'](data, { value }) + } + + it('0 -> 1', async () => { + const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactInputSingle(tokens[0].address, tokens[1].address) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) + }) + + it('1 -> 0', async () => { + const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactInputSingle(tokens[1].address, tokens[0].address) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) + }) + + describe('ETH input', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + }) + + it('WETH9 -> 0', async () => { + const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactInputSingle(weth9.address, tokens[0].address)) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 3) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + }) + }) + }) + + describe('ETH output', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + await createPoolWETH9(tokens[1].address) + }) + + it('0 -> WETH9', async () => { + const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactInputSingle(tokens[0].address, weth9.address)) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + }) + }) + }) + }) + + describe('#exactOutput', () => { + async function exactOutput( + tokens: string[], + amountOut: number = 1, + amountInMaximum: number = 3 + ): Promise { + const inputIsWETH9 = tokens[0] === weth9.address + const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address + + const value = inputIsWETH9 ? amountInMaximum : 0 + + const params = { + path: encodePath(tokens.slice().reverse(), new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountOut, + amountInMaximum, + } + + const data = [router.interface.encodeFunctionData('exactOutput', [params])] + if (inputIsWETH9) { + data.push(router.interface.encodeFunctionData('refundETH')) + } + + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOut)) + } + + // ensure that the swap fails if the limit is any tighter + const amountIn = await router.connect(trader).callStatic.exactOutput(params, { value }) + expect(amountIn.toNumber()).to.be.eq(amountInMaximum) + + return router.connect(trader)['multicall(bytes[])'](data, { value }) + } + + describe('single-pool', () => { + it('0 -> 1', async () => { + const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactOutput(tokens.slice(0, 2).map((token) => token.address)) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) + }) + + it('1 -> 0', async () => { + const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactOutput( + tokens + .slice(0, 2) + .reverse() + .map((token) => token.address) + ) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) + }) + }) + + describe('multi-pool', () => { + it('0 -> 1 -> 2', async () => { + const traderBefore = await getBalances(trader.address) + + await exactOutput( + tokens.map((token) => token.address), + 1, + 5 + ) + + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) + }) + + it('2 -> 1 -> 0', async () => { + const traderBefore = await getBalances(trader.address) + + await exactOutput(tokens.map((token) => token.address).reverse(), 1, 5) + + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(5)) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + }) + + it('events', async () => { + await expect( + exactOutput( + tokens.map((token) => token.address), + 1, + 5 + ) + ) + .to.emit(tokens[2], 'Transfer') + .withArgs( + computePoolAddress(factory.address, [tokens[2].address, tokens[1].address], FeeAmount.MEDIUM), + trader.address, + 1 + ) + .to.emit(tokens[1], 'Transfer') + .withArgs( + computePoolAddress(factory.address, [tokens[1].address, tokens[0].address], FeeAmount.MEDIUM), + computePoolAddress(factory.address, [tokens[2].address, tokens[1].address], FeeAmount.MEDIUM), + 3 + ) + .to.emit(tokens[0], 'Transfer') + .withArgs( + trader.address, + computePoolAddress(factory.address, [tokens[1].address, tokens[0].address], FeeAmount.MEDIUM), + 5 + ) + }) + }) + + describe('ETH input', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + }) + + it('WETH9 -> 0', async () => { + const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactOutput([weth9.address, tokens[0].address])) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 3) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + }) + + it('WETH9 -> 0 -> 1', async () => { + const traderBefore = await getBalances(trader.address) + + await expect(exactOutput([weth9.address, tokens[0].address, tokens[1].address], 1, 5)) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 5) + + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + }) + }) + }) + + describe('ETH output', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + await createPoolWETH9(tokens[1].address) + }) + + it('0 -> WETH9', async () => { + const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactOutput([tokens[0].address, weth9.address])) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + }) + + it('0 -> 1 -> WETH9', async () => { + // get balances before + const traderBefore = await getBalances(trader.address) + + await expect(exactOutput([tokens[0].address, tokens[1].address, weth9.address], 1, 5)) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) + }) + }) + }) + }) + + describe('#exactOutputSingle', () => { + async function exactOutputSingle( + tokenIn: string, + tokenOut: string, + amountOut: number = 1, + amountInMaximum: number = 3, + sqrtPriceLimitX96?: BigNumber + ): Promise { + const inputIsWETH9 = tokenIn === weth9.address + const outputIsWETH9 = tokenOut === weth9.address + + const value = inputIsWETH9 ? amountInMaximum : 0 + + const params = { + tokenIn, + tokenOut, + fee: FeeAmount.MEDIUM, + recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + amountOut, + amountInMaximum, + sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, + } + + const data = [router.interface.encodeFunctionData('exactOutputSingle', [params])] + if (inputIsWETH9) { + data.push(router.interface.encodeFunctionData('refundETH')) + } + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOut)) + } + + // ensure that the swap fails if the limit is any tighter + const amountIn = await router.connect(trader).callStatic.exactOutputSingle(params, { value }) + expect(amountIn.toNumber()).to.be.eq(amountInMaximum) + + return router.connect(trader)['multicall(bytes[])'](data, { value }) + } + + it('0 -> 1', async () => { + const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactOutputSingle(tokens[0].address, tokens[1].address) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) + }) + + it('1 -> 0', async () => { + const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await exactOutputSingle(tokens[1].address, tokens[0].address) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) + }) + + describe('ETH input', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + }) + + it('WETH9 -> 0', async () => { + const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactOutputSingle(weth9.address, tokens[0].address)) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 3) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + }) + }) + }) + + describe('ETH output', () => { + describe('WETH9', () => { + beforeEach(async () => { + await createPoolWETH9(tokens[0].address) + await createPoolWETH9(tokens[1].address) + }) + + it('0 -> WETH9', async () => { + const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) + + // get balances before + const poolBefore = await getBalances(pool) + const traderBefore = await getBalances(trader.address) + + await expect(exactOutputSingle(tokens[0].address, weth9.address)) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const poolAfter = await getBalances(pool) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) + }) + }) + }) + }) + + describe('*WithFee', () => { + const feeRecipient = '0xfEE0000000000000000000000000000000000000' + + it('#sweepTokenWithFee', async () => { + const amountOutMinimum = 100 + const params = { + path: encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), + recipient: ADDRESS_THIS, + amountIn: 102, + amountOutMinimum: 0, + } + + const functionSignature = 'sweepTokenWithFee(address,uint256,address,uint256,address)' + + const data = [ + router.interface.encodeFunctionData('exactInput', [params]), + solidityPack( + ['bytes4', 'bytes'], + [ + router.interface.getSighash(functionSignature), + defaultAbiCoder.encode( + ['address', 'uint256', 'address', 'uint256', 'address'], + [tokens[1].address, amountOutMinimum, trader.address, 100, feeRecipient] + ), + ] + ), + ] + await router.connect(trader)['multicall(bytes[])'](data) + const balance = await tokens[1].balanceOf(feeRecipient) + expect(balance.eq(1)).to.be.eq(true) + }) + + it('#unwrapWETH9WithFee', async () => { + const startBalance = await waffle.provider.getBalance(feeRecipient) + await createPoolWETH9(tokens[0].address) + const amountOutMinimum = 100 + const params = { + path: encodePath([tokens[0].address, weth9.address], [FeeAmount.MEDIUM]), + recipient: ADDRESS_THIS, + amountIn: 102, + amountOutMinimum: 0, + } + + const functionSignature = 'unwrapWETH9WithFee(uint256,address,uint256,address)' + + const data = [ + router.interface.encodeFunctionData('exactInput', [params]), + solidityPack( + ['bytes4', 'bytes'], + [ + router.interface.getSighash(functionSignature), + defaultAbiCoder.encode( + ['uint256', 'address', 'uint256', 'address'], + [amountOutMinimum, trader.address, 100, feeRecipient] + ), + ] + ), + ] + await router.connect(trader)['multicall(bytes[])'](data) + const endBalance = await waffle.provider.getBalance(feeRecipient) + expect(endBalance.sub(startBalance).eq(1)).to.be.eq(true) + }) + }) + }) + + async function createV2Pool(tokenA: TestERC20, tokenB: TestERC20): Promise { + await factoryV2.createPair(tokenA.address, tokenB.address) + + const pairAddress = await factoryV2.getPair(tokenA.address, tokenB.address) + const pair = new ethers.Contract(pairAddress, PAIR_V2_ABI, wallet) as IUniswapV2Pair + + await tokenA.transfer(pair.address, liquidity) + await tokenB.transfer(pair.address, liquidity) + + await pair.mint(wallet.address) + + return pair + } + + describe('swaps - v2', () => { + let pairs: IUniswapV2Pair[] + let wethPairs: IUniswapV2Pair[] + + async function createPoolWETH9(token: TestERC20) { + await weth9.deposit({ value: liquidity }) + return createV2Pool((weth9 as unknown) as TestERC20, token) + } + + beforeEach('create 0-1 and 1-2 pools', async () => { + const pair01 = await createV2Pool(tokens[0], tokens[1]) + const pair12 = await createV2Pool(tokens[1], tokens[2]) + pairs = [pair01, pair12] + }) + + describe('#swapExactTokensForTokens', () => { + async function exactInput( + tokens: string[], + amountIn: number = 2, + amountOutMinimum: number = 1 + ): Promise { + const inputIsWETH = weth9.address === tokens[0] + const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address + + const value = inputIsWETH ? amountIn : 0 + + const params: [number, number, string[], string] = [ + amountIn, + amountOutMinimum, + tokens, + outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + ] + + const data = [router.interface.encodeFunctionData('swapExactTokensForTokens', params)] + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOutMinimum)) + } + + // ensure that the swap fails if the limit is any tighter + const paramsWithValue: [number, number, string[], string, { value: number }] = [...params, { value }] + const amountOut = await router.connect(trader).callStatic.swapExactTokensForTokens(...paramsWithValue) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + + return router.connect(trader)['multicall(bytes[])'](data, { value }) + } + + describe('single-pool', () => { + it('0 -> 1', async () => { + // get balances before + const poolBefore = await getBalances(pairs[0].address) + const traderBefore = await getBalances(trader.address) + + await exactInput(tokens.slice(0, 2).map((token) => token.address)) + + // get balances after + const poolAfter = await getBalances(pairs[0].address) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) + }) + + it('1 -> 0', async () => { + // get balances before + const poolBefore = await getBalances(pairs[0].address) + const traderBefore = await getBalances(trader.address) + + await exactInput( + tokens + .slice(0, 2) + .reverse() + .map((token) => token.address) + ) + + // get balances after + const poolAfter = await getBalances(pairs[0].address) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(2)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(2)) + }) + }) + + describe('multi-pool', () => { + it('0 -> 1 -> 2', async () => { + const traderBefore = await getBalances(trader.address) + await exactInput( + tokens.map((token) => token.address), + 3, + 1 + ) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) + }) + it('2 -> 1 -> 0', async () => { + const traderBefore = await getBalances(trader.address) + await exactInput(tokens.map((token) => token.address).reverse(), 3, 1) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(3)) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + }) + + it('events', async () => { + await expect( + exactInput( + tokens.map((token) => token.address), + 3, + 1 + ) + ) + .to.emit(tokens[0], 'Transfer') + .withArgs(trader.address, pairs[0].address, 3) + .to.emit(tokens[1], 'Transfer') + .withArgs(pairs[0].address, pairs[1].address, 2) + .to.emit(tokens[2], 'Transfer') + .withArgs(pairs[1].address, trader.address, 1) + }) + }) + + describe('ETH input', () => { + describe('WETH9', () => { + beforeEach(async () => { + const pair = await createPoolWETH9(tokens[0]) + wethPairs = [pair] + }) + + it('WETH9 -> 0', async () => { + // get balances before + const poolBefore = await getBalances(wethPairs[0].address) + const traderBefore = await getBalances(trader.address) + await expect(exactInput([weth9.address, tokens[0].address])) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 2) + // get balances after + const poolAfter = await getBalances(wethPairs[0].address) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(2)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + }) + + it('WETH9 -> 0 -> 1', async () => { + const traderBefore = await getBalances(trader.address) + await expect(exactInput([weth9.address, tokens[0].address, tokens[1].address], 3)) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 3) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + }) + }) + }) + + describe('ETH output', () => { + describe('WETH9', () => { + beforeEach(async () => { + const pair0 = await createPoolWETH9(tokens[0]) + const pair1 = await createPoolWETH9(tokens[1]) + wethPairs = [pair0, pair1] + }) + + it('0 -> WETH9', async () => { + // get balances before + const poolBefore = await getBalances(wethPairs[0].address) + const traderBefore = await getBalances(trader.address) + + await expect(exactInput([tokens[0].address, weth9.address])) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const poolAfter = await getBalances(wethPairs[0].address) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) + }) + + it('0 -> 1 -> WETH9', async () => { + // get balances before + const traderBefore = await getBalances(trader.address) + + await expect(exactInput([tokens[0].address, tokens[1].address, weth9.address], 3)) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + + // get balances after + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + }) + }) + }) + }) + + describe('#swapTokensForExactTokens', () => { + async function exactOutput( + tokens: string[], + amountOut: number = 1, + amountInMaximum: number = 2 + ): Promise { + const inputIsWETH9 = tokens[0] === weth9.address + const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address + + const value = inputIsWETH9 ? amountInMaximum : 0 + + const params: [number, number, string[], string] = [ + amountOut, + amountInMaximum, + tokens, + outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, + ] + + const data = [router.interface.encodeFunctionData('swapTokensForExactTokens', params)] + if (inputIsWETH9) { + data.push(router.interface.encodeFunctionData('refundETH')) + } + if (outputIsWETH9) { + data.push(encodeUnwrapWETH9(amountOut)) + } + + // ensure that the swap fails if the limit is any tighter + const paramsWithValue: [number, number, string[], string, { value: number }] = [...params, { value }] + const amountIn = await router.connect(trader).callStatic.swapTokensForExactTokens(...paramsWithValue) + expect(amountIn.toNumber()).to.be.eq(amountInMaximum) + + return router.connect(trader)['multicall(bytes[])'](data, { value }) + } + + describe('single-pool', () => { + it('0 -> 1', async () => { + // get balances before + const poolBefore = await getBalances(pairs[0].address) + const traderBefore = await getBalances(trader.address) + + await exactOutput(tokens.slice(0, 2).map((token) => token.address)) + + // get balances after + const poolAfter = await getBalances(pairs[0].address) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) + }) + + it('1 -> 0', async () => { + // get balances before + const poolBefore = await getBalances(pairs[0].address) + const traderBefore = await getBalances(trader.address) + await exactOutput( + tokens + .slice(0, 2) + .reverse() + .map((token) => token.address) + ) + // get balances after + const poolAfter = await getBalances(pairs[0].address) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(2)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(2)) + }) + }) + + describe('multi-pool', () => { + it('0 -> 1 -> 2', async () => { + const traderBefore = await getBalances(trader.address) + await exactOutput( + tokens.map((token) => token.address), + 1, + 3 + ) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) + }) + + it('2 -> 1 -> 0', async () => { + const traderBefore = await getBalances(trader.address) + await exactOutput(tokens.map((token) => token.address).reverse(), 1, 3) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(3)) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + }) + + it('events', async () => { + await expect( + exactOutput( + tokens.map((token) => token.address), + 1, + 3 + ) + ) + .to.emit(tokens[0], 'Transfer') + .withArgs(trader.address, pairs[0].address, 3) + .to.emit(tokens[1], 'Transfer') + .withArgs(pairs[0].address, pairs[1].address, 2) + .to.emit(tokens[2], 'Transfer') + .withArgs(pairs[1].address, trader.address, 1) + }) + }) + + describe('ETH input', () => { + describe('WETH9', () => { + beforeEach(async () => { + const pair = await createPoolWETH9(tokens[0]) + wethPairs = [pair] + }) + + it('WETH9 -> 0', async () => { + // get balances before + const poolBefore = await getBalances(wethPairs[0].address) + const traderBefore = await getBalances(trader.address) + await expect(exactOutput([weth9.address, tokens[0].address])) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 2) + // get balances after + const poolAfter = await getBalances(wethPairs[0].address) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(2)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) + }) + + it('WETH9 -> 0 -> 1', async () => { + const traderBefore = await getBalances(trader.address) + await expect(exactOutput([weth9.address, tokens[0].address, tokens[1].address], 1, 3)) + .to.emit(weth9, 'Deposit') + .withArgs(router.address, 3) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) + }) + }) + }) + + describe('ETH output', () => { + describe('WETH9', () => { + beforeEach(async () => { + const pair0 = await createPoolWETH9(tokens[0]) + const pair1 = await createPoolWETH9(tokens[1]) + wethPairs = [pair0, pair1] + }) + + it('0 -> WETH9', async () => { + // get balances before + const poolBefore = await getBalances(wethPairs[0].address) + const traderBefore = await getBalances(trader.address) + await expect(exactOutput([tokens[0].address, weth9.address])) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + // get balances after + const poolAfter = await getBalances(wethPairs[0].address) + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) + expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) + expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) + }) + + it('0 -> 1 -> WETH9', async () => { + // get balances before + const traderBefore = await getBalances(trader.address) + await expect(exactOutput([tokens[0].address, tokens[1].address, weth9.address], 1, 3)) + .to.emit(weth9, 'Withdrawal') + .withArgs(router.address, 1) + // get balances after + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) + }) + }) + }) + }) + }) + + describe('swaps - v2 + v3', () => { + beforeEach('create 0-1 and 1-2 pools', async () => { + await createV3Pool(tokens[0].address, tokens[1].address) + await createV3Pool(tokens[1].address, tokens[2].address) + }) + + beforeEach('create 0-1 and 1-2 pools', async () => { + await createV2Pool(tokens[0], tokens[1]) + await createV2Pool(tokens[1], tokens[2]) + }) + + async function exactInputV3( + tokens: string[], + amountIn: number = 3, + amountOutMinimum: number = 1, + recipient: string, + skipAmountOutMinimumCheck: boolean = false + ): Promise { + const params = { + path: encodePath(tokens, new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), + recipient, + amountIn, + amountOutMinimum, + } + + const data = [router.interface.encodeFunctionData('exactInput', [params])] + + if (!skipAmountOutMinimumCheck) { + // ensure that the swap fails if the limit is any tighter + const amountOut = await router.connect(trader).callStatic.exactInput(params) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + } + + return data + } + + async function exactOutputV3( + tokens: string[], + amountOut: number = 1, + amountInMaximum: number = 3, + recipient: string + ): Promise { + const params = { + path: encodePath(tokens.slice().reverse(), new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), + recipient, + amountOut, + amountInMaximum, + } + + const data = [router.interface.encodeFunctionData('exactOutput', [params])] + + // ensure that the swap fails if the limit is any tighter + const amountIn = await router.connect(trader).callStatic.exactOutput(params) + expect(amountIn.toNumber()).to.be.eq(amountInMaximum) + + return data + } + + async function exactInputV2( + tokens: string[], + amountIn: number = 2, + amountOutMinimum: number = 1, + recipient: string, + skipAmountOutMinimumCheck: boolean = false + ): Promise { + const params: [number, number, string[], string] = [amountIn, amountOutMinimum, tokens, recipient] + + const data = [router.interface.encodeFunctionData('swapExactTokensForTokens', params)] + + if (!skipAmountOutMinimumCheck) { + // ensure that the swap fails if the limit is any tighter + const amountOut = await router.connect(trader).callStatic.swapExactTokensForTokens(...params) + expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) + } + + return data + } + + async function exactOutputV2( + tokens: string[], + amountOut: number = 1, + amountInMaximum: number = 2, + recipient: string + ): Promise { + const params: [number, number, string[], string] = [amountOut, amountInMaximum, tokens, recipient] + + const data = [router.interface.encodeFunctionData('swapTokensForExactTokens', params)] + + // ensure that the swap fails if the limit is any tighter + const amountIn = await router.connect(trader).callStatic.swapTokensForExactTokens(...params) + expect(amountIn.toNumber()).to.be.eq(amountInMaximum) + + return data + } + + describe('simple split route', async () => { + it('sending directly', async () => { + const swapV3 = await exactInputV3( + tokens.slice(0, 2).map((token) => token.address), + 3, + 1, + MSG_SENDER + ) + const swapV2 = await exactInputV2( + tokens.slice(0, 2).map((token) => token.address), + 2, + 1, + MSG_SENDER + ) + + const traderBefore = await getBalances(trader.address) + + await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2]) + + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(2)) + }) + + it('sending to router and sweeping', async () => { + const swapV3 = await exactInputV3( + tokens.slice(0, 2).map((token) => token.address), + 3, + 1, + ADDRESS_THIS + ) + const swapV2 = await exactInputV2( + tokens.slice(0, 2).map((token) => token.address), + 2, + 1, + ADDRESS_THIS + ) + + const sweep = encodeSweep(tokens[1].address, 2, trader.address) + + const traderBefore = await getBalances(trader.address) + + await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2, sweep]) + + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) + expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(2)) + }) + }) + + describe('merging', () => { + // 0 ↘ + // 0 → 1 → 2 + + it('exactIn x 2 + exactIn', async () => { + const swapV3 = await exactInputV3( + tokens.slice(0, 2).map((token) => token.address), + 3, + 1, + ADDRESS_THIS + ) + const swapV2 = await exactInputV2( + tokens.slice(0, 2).map((token) => token.address), + 3, + 2, + ADDRESS_THIS + ) + + const mergeSwap = await exactInputV3( + tokens.slice(1, 3).map((token) => token.address), + CONTRACT_BALANCE, + 1, + MSG_SENDER, + true + ) + + const traderBefore = await getBalances(trader.address) + + await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2, ...mergeSwap]) + + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(6)) + expect(traderAfter.token2).to.be.eq(traderBefore.token1.add(1)) + }) + + it('exactOut x 2 + exactIn', async () => { + const swapV3 = await exactOutputV3( + tokens.slice(0, 2).map((token) => token.address), + 1, + 3, + ADDRESS_THIS + ) + const swapV2 = await exactOutputV2( + tokens.slice(0, 2).map((token) => token.address), + 2, + 3, + ADDRESS_THIS + ) + + const mergeSwap = await exactInputV3( + tokens.slice(1, 3).map((token) => token.address), + CONTRACT_BALANCE, + 1, + MSG_SENDER, + true + ) + + const traderBefore = await getBalances(trader.address) + + await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2, ...mergeSwap]) + + const traderAfter = await getBalances(trader.address) + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(6)) + expect(traderAfter.token2).to.be.eq(traderBefore.token1.add(1)) + }) + }) + + describe('interleaving', () => { + // 0 -V3-> 1 -V2-> 2 + it('exactIn 0 -V3-> 1 -V2-> 2', async () => { + const swapV3 = await exactInputV3( + tokens.slice(0, 2).map((token) => token.address), + 10, + 8, + ADDRESS_THIS + ) + + const swapV2 = await exactInputV2( + tokens.slice(1, 3).map((token) => token.address), + CONTRACT_BALANCE, + 7, + MSG_SENDER, + true + ) + + const traderBefore = await getBalances(trader.address) + await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2]) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(10)) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(7)) + + const routerAmountOut = traderAfter.token2.sub(traderBefore.token2) + + // expect to equal quoter output + const { amountOut: quoterAmountOut } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[1].address, tokens[2].address], [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER]), + 10 + ) + + expect(quoterAmountOut.eq(routerAmountOut)).to.be.true + }) + + it('exactIn 0 -V2-> 1 -V3-> 2', async () => { + const swapV2 = await exactInputV2( + tokens.slice(0, 2).map((token) => token.address), + 10, + 9, + ADDRESS_THIS + ) + + const swapV3 = await exactInputV3( + tokens.slice(1, 3).map((token) => token.address), + CONTRACT_BALANCE, + 7, + MSG_SENDER, + true + ) + + const traderBefore = await getBalances(trader.address) + await router.connect(trader)['multicall(bytes[])']([...swapV2, ...swapV3]) + const traderAfter = await getBalances(trader.address) + + expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(10)) + expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(7)) + + const routerAmountOut = traderAfter.token2.sub(traderBefore.token2) + + // expect to equal quoter output + const { amountOut: quoterAmountOut } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( + encodePath([tokens[0].address, tokens[1].address, tokens[2].address], [V2_FEE_PLACEHOLDER, FeeAmount.MEDIUM]), + 10 + ) + expect(quoterAmountOut.eq(routerAmountOut)).to.be.true + }) + }) + }) +}) diff --git a/lib/swap-router-contracts/test/TokenValidator.spec.ts b/lib/swap-router-contracts/test/TokenValidator.spec.ts new file mode 100644 index 0000000..d6c7353 --- /dev/null +++ b/lib/swap-router-contracts/test/TokenValidator.spec.ts @@ -0,0 +1,158 @@ +import { expect } from 'chai' +import { constants } from 'ethers' +import hre, { ethers } from 'hardhat' +import { TokenValidator, TestERC20, IUniswapV2Pair__factory } from '../typechain' + +describe('TokenValidator', function () { + let tokenValidator: TokenValidator + let testToken: TestERC20 + + this.timeout(100000) + + enum Status { + UNKN = 0, + FOT = 1, + STF = 2, + } + + // WETH9 and USDC + const BASE_TOKENS = ['0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'] + // Arbitrary amount to flash loan. + const AMOUNT_TO_BORROW = 1000 + + const FOT_TOKENS = [ + '0xa68dd8cb83097765263adad881af6eed479c4a33', // WTF + '0x8B3192f5eEBD8579568A2Ed41E6FEB402f93f73F', // SAITAMA + '0xA2b4C0Af19cC16a6CfAcCe81F192B024d625817D', // KISHU + ] + + const BROKEN_TOKENS = [ + '0xd233d1f6fd11640081abb8db125f722b5dc729dc', // USD + ] + + const NON_FOT_TOKENS = [ + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC + '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', // UNI + '0xc00e94Cb662C3520282E6f5717214004A7f26888', // COMP + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH9 + ] + + before(async function () { + // Easiest to test FOT using real world data, so these tests require a hardhat fork. + if (!process.env.ARCHIVE_RPC_URL) { + this.skip() + } + + await hre.network.provider.request({ + method: 'hardhat_reset', + params: [ + { + forking: { + jsonRpcUrl: process.env.ARCHIVE_RPC_URL, + blockNumber: 14024832, + }, + }, + ], + }) + + const factory = await ethers.getContractFactory('TokenValidator') + tokenValidator = (await factory.deploy( + '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', // V2 Factory + '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' // V3 NFT position manager + )) as TokenValidator + + // Deploy a new token for testing. + const tokenFactory = await ethers.getContractFactory('TestERC20') + testToken = (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20 + }) + + after(async () => { + // Disable mainnet forking to avoid effecting other tests. + await hre.network.provider.request({ + method: 'hardhat_reset', + params: [], + }) + }) + + it('succeeds for tokens that cant be transferred', async () => { + for (const token of BROKEN_TOKENS) { + const isFot = await tokenValidator.callStatic.validate(token, BASE_TOKENS, AMOUNT_TO_BORROW) + expect(isFot).to.equal(Status.STF) + } + }) + + it('succeeds to detect fot tokens', async () => { + for (const token of FOT_TOKENS) { + const isFot = await tokenValidator.callStatic.validate(token, [BASE_TOKENS[0]!], AMOUNT_TO_BORROW) + expect(isFot).to.equal(Status.FOT) + } + }) + + it('succeeds to detect fot token when token doesnt have pair with first base token', async () => { + const isFot = await tokenValidator.callStatic.validate( + FOT_TOKENS[0], + [testToken.address, ...BASE_TOKENS], + AMOUNT_TO_BORROW + ) + expect(isFot).to.equal(Status.FOT) + }) + + it('succeeds to return unknown when flash loaning full reserves', async () => { + const pairAddress = '0xab293dce330b92aa52bc2a7cd3816edaa75f890b' // WTF/ETH pair + const pair = IUniswapV2Pair__factory.connect(pairAddress, ethers.provider) + const { reserve0: wtfReserve } = await pair.callStatic.getReserves() + + const isFot1 = await tokenValidator.callStatic.validate( + '0xa68dd8cb83097765263adad881af6eed479c4a33', // WTF + ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'], // WETH + wtfReserve.sub(1).toString() + ) + expect(isFot1).to.equal(Status.FOT) + + const isFot2 = await tokenValidator.callStatic.validate( + '0xa68dd8cb83097765263adad881af6eed479c4a33', // WTF + ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'], // WETH + wtfReserve.toString() + ) + expect(isFot2).to.equal(Status.UNKN) + }) + + it('succeeds to batch detect fot tokens', async () => { + const isFots = await tokenValidator.callStatic.batchValidate(FOT_TOKENS, BASE_TOKENS, AMOUNT_TO_BORROW) + expect(isFots.every((isFot: Status) => isFot == Status.FOT)).to.be.true + }) + + it('succeeds to batch detect fot tokens when dont have pair with first base token', async () => { + const isFots = await tokenValidator.callStatic.batchValidate( + FOT_TOKENS, + [testToken.address, ...BASE_TOKENS], + AMOUNT_TO_BORROW + ) + expect(isFots.every((isFot: Status) => isFot == Status.FOT)).to.be.true + }) + + it('succeeds to detect non fot tokens', async () => { + for (const token of NON_FOT_TOKENS) { + const isFot = await tokenValidator.callStatic.validate(token, BASE_TOKENS, AMOUNT_TO_BORROW) + expect(isFot).to.equal(Status.UNKN) + } + }) + + it('succeeds to batch detect non fot tokens', async () => { + const isFots = await tokenValidator.callStatic.batchValidate(NON_FOT_TOKENS, BASE_TOKENS, AMOUNT_TO_BORROW) + expect(isFots.every((isFot: Status) => isFot == Status.UNKN)).to.be.true + }) + + it('succeeds to batch detect mix of fot tokens and non fot tokens', async () => { + const isFots = await tokenValidator.callStatic.batchValidate( + [NON_FOT_TOKENS[0], FOT_TOKENS[0], BROKEN_TOKENS[0]], + BASE_TOKENS, + 1000 + ) + expect(isFots).to.deep.equal([Status.UNKN, Status.FOT, Status.STF]) + }) + + it('succeeds to return false if token doesnt have a pool with any of the base tokens', async () => { + await tokenValidator.callStatic.validate(testToken.address, BASE_TOKENS, AMOUNT_TO_BORROW) + }) +}) diff --git a/lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap new file mode 100644 index 0000000..3a9002f --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ImmutableState bytecode size 1`] = `193`; diff --git a/lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap new file mode 100644 index 0000000..df91db3 --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 -> 1 1`] = `281505`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 0 tick, starting tick initialized 1`] = `123786`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 0 tick, starting tick not initialized 1`] = `104827`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 1 tick 1`] = `149094`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 2 tick 1`] = `186691`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 2 tick where after is initialized 1`] = `149132`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 0 tick, starting tick initialized 1`] = `97643`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 0 tick, starting tick not initialized 1`] = `97643`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 2 1`] = `179503`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 2 where tick after is initialized 1`] = `179511`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 1 1`] = `97318`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInputSingle V3 0 -> 2 1`] = `186673`; + +exports[`MixedRouteQuoterV1 quotes #quoteExactInputSingle V3 2 -> 0 1`] = `179475`; diff --git a/lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap new file mode 100644 index 0000000..8570516 --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Multicall gas cost of pay w/ multicall 1`] = `45928`; + +exports[`Multicall gas cost of pay w/o multicall 1`] = `43364`; diff --git a/lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap new file mode 100644 index 0000000..e450df9 --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Path gas cost 1`] = `451`; diff --git a/lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap new file mode 100644 index 0000000..7471415 --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PoolAddress #computeAddress gas cost 1`] = `642`; + +exports[`PoolAddress #computeAddress matches example from core repo 1`] = `"0x03D8bab195A5BC23d249693F53dfA0e358F2650D"`; diff --git a/lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap new file mode 100644 index 0000000..ccb9341 --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 -> 1 1`] = `277146`; + +exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 0 tick, starting tick initialized 1`] = `123797`; + +exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 0 tick, starting tick not initialized 1`] = `100962`; + +exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 1 tick 1`] = `144724`; + +exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 2 tick 1`] = `182321`; + +exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 2 tick where after is initialized 1`] = `144762`; + +exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 0 tick, starting tick initialized 1`] = `97654`; + +exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 0 tick, starting tick not initialized 1`] = `93779`; + +exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 2 1`] = `175133`; + +exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 2 where tick after is initialized 1`] = `175141`; + +exports[`QuoterV2 quotes #quoteExactInput 2 -> 1 1`] = `97329`; + +exports[`QuoterV2 quotes #quoteExactInputSingle 0 -> 2 1`] = `182303`; + +exports[`QuoterV2 quotes #quoteExactInputSingle 2 -> 0 1`] = `175105`; + +exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 -> 1 1`] = `276746`; + +exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 0 tick starting tick initialized 1`] = `123352`; + +exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 0 tick starting tick not initialized 1`] = `100537`; + +exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 1 tick 1`] = `144010`; + +exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 2 tick 1`] = `181363`; + +exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 2 where tick after is initialized 1`] = `144048`; + +exports[`QuoterV2 quotes #quoteExactOutput 2 -> 0 cross 1 tick 1`] = `137858`; + +exports[`QuoterV2 quotes #quoteExactOutput 2 -> 0 cross 2 ticks 1`] = `175203`; + +exports[`QuoterV2 quotes #quoteExactOutput 2 -> 0 cross 2 where tick after is initialized 1`] = `175197`; + +exports[`QuoterV2 quotes #quoteExactOutput 2 -> 1 1`] = `97870`; + +exports[`QuoterV2 quotes #quoteExactOutputSingle 0 -> 1 1`] = `105200`; + +exports[`QuoterV2 quotes #quoteExactOutputSingle 1 -> 0 1`] = `98511`; diff --git a/lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap new file mode 100644 index 0000000..8600170 --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SwapRouter gas tests #exactInput 0 -> 1 -> 2 1`] = `175302`; + +exports[`SwapRouter gas tests #exactInput 0 -> 1 1`] = `110495`; + +exports[`SwapRouter gas tests #exactInput 0 -> 1 minimal 1`] = `98059`; + +exports[`SwapRouter gas tests #exactInput 0 -> WETH9 1`] = `127401`; + +exports[`SwapRouter gas tests #exactInput 2 trades (directly to sender) 1`] = `178981`; + +exports[`SwapRouter gas tests #exactInput 2 trades (via router) 1`] = `188487`; + +exports[`SwapRouter gas tests #exactInput 3 trades (directly to sender) 1`] = `257705`; + +exports[`SwapRouter gas tests #exactInput WETH9 -> 0 1`] = `108832`; + +exports[`SwapRouter gas tests #exactInputSingle 0 -> 1 1`] = `109826`; + +exports[`SwapRouter gas tests #exactInputSingle 0 -> WETH9 1`] = `126732`; + +exports[`SwapRouter gas tests #exactInputSingle WETH9 -> 0 1`] = `108163`; + +exports[`SwapRouter gas tests #exactOutput 0 -> 1 -> 2 1`] = `169268`; + +exports[`SwapRouter gas tests #exactOutput 0 -> 1 1`] = `111692`; + +exports[`SwapRouter gas tests #exactOutput 0 -> WETH9 1`] = `128610`; + +exports[`SwapRouter gas tests #exactOutput WETH9 -> 0 1`] = `119706`; + +exports[`SwapRouter gas tests #exactOutputSingle 0 -> 1 1`] = `111826`; + +exports[`SwapRouter gas tests #exactOutputSingle 0 -> WETH9 1`] = `128744`; + +exports[`SwapRouter gas tests #exactOutputSingle WETH9 -> 0 1`] = `112627`; diff --git a/lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap new file mode 100644 index 0000000..e7f484a --- /dev/null +++ b/lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SwapRouter bytecode size 1`] = `24563`; diff --git a/lib/swap-router-contracts/test/contracts/WETH9.json b/lib/swap-router-contracts/test/contracts/WETH9.json new file mode 100644 index 0000000..68ec24f --- /dev/null +++ b/lib/swap-router-contracts/test/contracts/WETH9.json @@ -0,0 +1,156 @@ +{ + "bytecode": "60606040526040805190810160405280600d81526020017f57726170706564204574686572000000000000000000000000000000000000008152506000908051906020019061004f9291906100c8565b506040805190810160405280600481526020017f57455448000000000000000000000000000000000000000000000000000000008152506001908051906020019061009b9291906100c8565b506012600260006101000a81548160ff021916908360ff16021790555034156100c357600080fd5b61016d565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061010957805160ff1916838001178555610137565b82800160010185558215610137579182015b8281111561013657825182559160200191906001019061011b565b5b5090506101449190610148565b5090565b61016a91905b8082111561016657600081600090555060010161014e565b5090565b90565b610c348061017c6000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b9578063095ea7b31461014757806318160ddd146101a157806323b872dd146101ca5780632e1a7d4d14610243578063313ce5671461026657806370a082311461029557806395d89b41146102e2578063a9059cbb14610370578063d0e30db0146103ca578063dd62ed3e146103d4575b6100b7610440565b005b34156100c457600080fd5b6100cc6104dd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010c5780820151818401526020810190506100f1565b50505050905090810190601f1680156101395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015257600080fd5b610187600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061057b565b604051808215151515815260200191505060405180910390f35b34156101ac57600080fd5b6101b461066d565b6040518082815260200191505060405180910390f35b34156101d557600080fd5b610229600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061068c565b604051808215151515815260200191505060405180910390f35b341561024e57600080fd5b61026460048080359060200190919050506109d9565b005b341561027157600080fd5b610279610b05565b604051808260ff1660ff16815260200191505060405180910390f35b34156102a057600080fd5b6102cc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b18565b6040518082815260200191505060405180910390f35b34156102ed57600080fd5b6102f5610b30565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561033557808201518184015260208101905061031a565b50505050905090810190601f1680156103625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561037b57600080fd5b6103b0600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610bce565b604051808215151515815260200191505060405180910390f35b6103d2610440565b005b34156103df57600080fd5b61042a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610be3565b6040518082815260200191505060405180910390f35b34600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a2565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105735780601f1061054857610100808354040283529160200191610573565b820191906000526020600020905b81548152906001019060200180831161055657829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b600081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156106dc57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156107b457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156108cf5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084457600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a2757600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501515610ab457600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040518082815260200191505060405180910390a250565b600260009054906101000a900460ff1681565b60036020528060005260406000206000915090505481565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bc65780601f10610b9b57610100808354040283529160200191610bc6565b820191906000526020600020905b815481529060010190602001808311610ba957829003601f168201915b505050505081565b6000610bdb33848461068c565b905092915050565b60046020528160005260406000206020528060005260406000206000915091505054815600a165627a7a72305820deb4c2ccab3c2fdca32ab3f46728389c2fe2c165d5fafa07661e4e004f6c344a0029", + "abi": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "guy", "type": "address" }, + { "name": "wad", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "src", "type": "address" }, + { "name": "dst", "type": "address" }, + { "name": "wad", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "name": "wad", "type": "uint256" }], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [{ "name": "", "type": "uint8" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "dst", "type": "address" }, + { "name": "wad", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "deposit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "", "type": "address" }, + { "name": "", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { "payable": true, "stateMutability": "payable", "type": "fallback" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "src", "type": "address" }, + { "indexed": true, "name": "guy", "type": "address" }, + { "indexed": false, "name": "wad", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "src", "type": "address" }, + { "indexed": true, "name": "dst", "type": "address" }, + { "indexed": false, "name": "wad", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "dst", "type": "address" }, + { "indexed": false, "name": "wad", "type": "uint256" } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "src", "type": "address" }, + { "indexed": false, "name": "wad", "type": "uint256" } + ], + "name": "Withdrawal", + "type": "event" + } + ] +} diff --git a/lib/swap-router-contracts/test/shared/completeFixture.ts b/lib/swap-router-contracts/test/shared/completeFixture.ts new file mode 100644 index 0000000..5c44fd2 --- /dev/null +++ b/lib/swap-router-contracts/test/shared/completeFixture.ts @@ -0,0 +1,36 @@ +import { Fixture } from 'ethereum-waffle' +import { ethers, waffle } from 'hardhat' +import { v3RouterFixture } from './externalFixtures' +import { constants, Contract } from 'ethers' +import { IWETH9, MockTimeSwapRouter02, TestERC20 } from '../../typechain' + +const completeFixture: Fixture<{ + weth9: IWETH9 + factoryV2: Contract + factory: Contract + router: MockTimeSwapRouter02 + nft: Contract + tokens: [TestERC20, TestERC20, TestERC20] +}> = async ([wallet], provider) => { + const { weth9, factoryV2, factory, nft, router } = await v3RouterFixture([wallet], provider) + + const tokenFactory = await ethers.getContractFactory('TestERC20') + const tokens: [TestERC20, TestERC20, TestERC20] = [ + (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20, // do not use maxu256 to avoid overflowing + (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20, + (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20, + ] + + tokens.sort((a, b) => (a.address.toLowerCase() < b.address.toLowerCase() ? -1 : 1)) + + return { + weth9, + factoryV2, + factory, + router, + tokens, + nft, + } +} + +export default completeFixture diff --git a/lib/swap-router-contracts/test/shared/computePoolAddress.ts b/lib/swap-router-contracts/test/shared/computePoolAddress.ts new file mode 100644 index 0000000..fde8c8a --- /dev/null +++ b/lib/swap-router-contracts/test/shared/computePoolAddress.ts @@ -0,0 +1,22 @@ +import { bytecode } from '@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json' +import { utils } from 'ethers' + +export const POOL_BYTECODE_HASH = utils.keccak256(bytecode) + +export function computePoolAddress(factoryAddress: string, [tokenA, tokenB]: [string, string], fee: number): string { + const [token0, token1] = tokenA.toLowerCase() < tokenB.toLowerCase() ? [tokenA, tokenB] : [tokenB, tokenA] + const constructorArgumentsEncoded = utils.defaultAbiCoder.encode( + ['address', 'address', 'uint24'], + [token0, token1, fee] + ) + const create2Inputs = [ + '0xff', + factoryAddress, + // salt + utils.keccak256(constructorArgumentsEncoded), + // init code hash + POOL_BYTECODE_HASH, + ] + const sanitizedInputs = `0x${create2Inputs.map((i) => i.slice(2)).join('')}` + return utils.getAddress(`0x${utils.keccak256(sanitizedInputs).slice(-40)}`) +} diff --git a/lib/swap-router-contracts/test/shared/constants.ts b/lib/swap-router-contracts/test/shared/constants.ts new file mode 100644 index 0000000..15a188a --- /dev/null +++ b/lib/swap-router-contracts/test/shared/constants.ts @@ -0,0 +1,21 @@ +import { BigNumber } from 'ethers' + +export const MaxUint128 = BigNumber.from(2).pow(128).sub(1) + +export enum FeeAmount { + LOW = 500, + MEDIUM = 3000, + HIGH = 10000, +} + +export const V2_FEE_PLACEHOLDER = 8388608 // 1 << 23 + +export const TICK_SPACINGS: { [amount in FeeAmount]: number } = { + [FeeAmount.LOW]: 10, + [FeeAmount.MEDIUM]: 60, + [FeeAmount.HIGH]: 200, +} + +export const CONTRACT_BALANCE = 0 +export const MSG_SENDER = '0x0000000000000000000000000000000000000001' +export const ADDRESS_THIS = '0x0000000000000000000000000000000000000002' diff --git a/lib/swap-router-contracts/test/shared/encodePriceSqrt.ts b/lib/swap-router-contracts/test/shared/encodePriceSqrt.ts new file mode 100644 index 0000000..f95cd23 --- /dev/null +++ b/lib/swap-router-contracts/test/shared/encodePriceSqrt.ts @@ -0,0 +1,16 @@ +import bn from 'bignumber.js' +import { BigNumber, BigNumberish } from 'ethers' + +bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }) + +// returns the sqrt price as a 64x96 +export function encodePriceSqrt(reserve1: BigNumberish, reserve0: BigNumberish): BigNumber { + return BigNumber.from( + new bn(reserve1.toString()) + .div(reserve0.toString()) + .sqrt() + .multipliedBy(new bn(2).pow(96)) + .integerValue(3) + .toString() + ) +} diff --git a/lib/swap-router-contracts/test/shared/expandTo18Decimals.ts b/lib/swap-router-contracts/test/shared/expandTo18Decimals.ts new file mode 100644 index 0000000..cddc9ba --- /dev/null +++ b/lib/swap-router-contracts/test/shared/expandTo18Decimals.ts @@ -0,0 +1,9 @@ +import { BigNumber } from 'ethers' + +export function expandTo18Decimals(n: number): BigNumber { + return BigNumber.from(n).mul(BigNumber.from(10).pow(18)) +} + +export function expandToNDecimals(n: number, d: number): BigNumber { + return BigNumber.from(n).mul(BigNumber.from(10).pow(d)) +} diff --git a/lib/swap-router-contracts/test/shared/expect.ts b/lib/swap-router-contracts/test/shared/expect.ts new file mode 100644 index 0000000..ac8f19b --- /dev/null +++ b/lib/swap-router-contracts/test/shared/expect.ts @@ -0,0 +1,8 @@ +import { expect, use } from 'chai' +import { solidity } from 'ethereum-waffle' +import { jestSnapshotPlugin } from 'mocha-chai-jest-snapshot' + +use(solidity) +use(jestSnapshotPlugin()) + +export { expect } diff --git a/lib/swap-router-contracts/test/shared/externalFixtures.ts b/lib/swap-router-contracts/test/shared/externalFixtures.ts new file mode 100644 index 0000000..cb02d86 --- /dev/null +++ b/lib/swap-router-contracts/test/shared/externalFixtures.ts @@ -0,0 +1,76 @@ +import { + abi as FACTORY_ABI, + bytecode as FACTORY_BYTECODE, +} from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json' +import { abi as FACTORY_V2_ABI, bytecode as FACTORY_V2_BYTECODE } from '@uniswap/v2-core/build/UniswapV2Factory.json' +import { Fixture } from 'ethereum-waffle' +import { ethers, waffle } from 'hardhat' +import { IWETH9, MockTimeSwapRouter02 } from '../../typechain' + +import WETH9 from '../contracts/WETH9.json' +import { Contract } from '@ethersproject/contracts' +import { constants } from 'ethers' + +import { + abi as NFT_POSITION_MANAGER_ABI, + bytecode as NFT_POSITION_MANAGER_BYTECODE, +} from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json' + +const wethFixture: Fixture<{ weth9: IWETH9 }> = async ([wallet]) => { + const weth9 = (await waffle.deployContract(wallet, { + bytecode: WETH9.bytecode, + abi: WETH9.abi, + })) as IWETH9 + + return { weth9 } +} + +export const v2FactoryFixture: Fixture<{ factory: Contract }> = async ([wallet]) => { + const factory = await waffle.deployContract( + wallet, + { + bytecode: FACTORY_V2_BYTECODE, + abi: FACTORY_V2_ABI, + }, + [constants.AddressZero] + ) + + return { factory } +} + +const v3CoreFactoryFixture: Fixture = async ([wallet]) => { + return await waffle.deployContract(wallet, { + bytecode: FACTORY_BYTECODE, + abi: FACTORY_ABI, + }) +} + +export const v3RouterFixture: Fixture<{ + weth9: IWETH9 + factoryV2: Contract + factory: Contract + nft: Contract + router: MockTimeSwapRouter02 +}> = async ([wallet], provider) => { + const { weth9 } = await wethFixture([wallet], provider) + const { factory: factoryV2 } = await v2FactoryFixture([wallet], provider) + const factory = await v3CoreFactoryFixture([wallet], provider) + + const nft = await waffle.deployContract( + wallet, + { + bytecode: NFT_POSITION_MANAGER_BYTECODE, + abi: NFT_POSITION_MANAGER_ABI, + }, + [factory.address, weth9.address, constants.AddressZero] + ) + + const router = (await (await ethers.getContractFactory('MockTimeSwapRouter02')).deploy( + factoryV2.address, + factory.address, + nft.address, + weth9.address + )) as MockTimeSwapRouter02 + + return { weth9, factoryV2, factory, nft, router } +} diff --git a/lib/swap-router-contracts/test/shared/path.ts b/lib/swap-router-contracts/test/shared/path.ts new file mode 100644 index 0000000..99418b1 --- /dev/null +++ b/lib/swap-router-contracts/test/shared/path.ts @@ -0,0 +1,61 @@ +import { utils } from 'ethers' +import { FeeAmount } from './constants' + +const ADDR_SIZE = 20 +const FEE_SIZE = 3 +const OFFSET = ADDR_SIZE + FEE_SIZE +const DATA_SIZE = OFFSET + ADDR_SIZE + +export function encodePath(path: string[], fees: FeeAmount[]): string { + if (path.length != fees.length + 1) { + throw new Error('path/fee lengths do not match') + } + + let encoded = '0x' + for (let i = 0; i < fees.length; i++) { + // 20 byte encoding of the address + encoded += path[i].slice(2) + // 3 byte encoding of the fee + encoded += fees[i].toString(16).padStart(2 * FEE_SIZE, '0') + } + // encode the final token + encoded += path[path.length - 1].slice(2) + + return encoded.toLowerCase() +} + +function decodeOne(tokenFeeToken: Buffer): [[string, string], number] { + // reads the first 20 bytes for the token address + const tokenABuf = tokenFeeToken.slice(0, ADDR_SIZE) + const tokenA = utils.getAddress('0x' + tokenABuf.toString('hex')) + + // reads the next 2 bytes for the fee + const feeBuf = tokenFeeToken.slice(ADDR_SIZE, OFFSET) + const fee = feeBuf.readUIntBE(0, FEE_SIZE) + + // reads the next 20 bytes for the token address + const tokenBBuf = tokenFeeToken.slice(OFFSET, DATA_SIZE) + const tokenB = utils.getAddress('0x' + tokenBBuf.toString('hex')) + + return [[tokenA, tokenB], fee] +} + +export function decodePath(path: string): [string[], number[]] { + let data = Buffer.from(path.slice(2), 'hex') + + let tokens: string[] = [] + let fees: number[] = [] + let i = 0 + let finalToken: string = '' + while (data.length >= DATA_SIZE) { + const [[tokenA, tokenB], fee] = decodeOne(data) + finalToken = tokenB + tokens = [...tokens, tokenA] + fees = [...fees, fee] + data = data.slice((i + 1) * OFFSET) + i += 1 + } + tokens = [...tokens, finalToken] + + return [tokens, fees] +} diff --git a/lib/swap-router-contracts/test/shared/quoter.ts b/lib/swap-router-contracts/test/shared/quoter.ts new file mode 100644 index 0000000..2d4afcc --- /dev/null +++ b/lib/swap-router-contracts/test/shared/quoter.ts @@ -0,0 +1,160 @@ +import { Wallet, Contract } from 'ethers' +import { FeeAmount, TICK_SPACINGS } from './constants' +import { encodePriceSqrt } from './encodePriceSqrt' +import { getMaxTick, getMinTick } from './ticks' + +export async function createPool(nft: Contract, wallet: Wallet, tokenAddressA: string, tokenAddressB: string) { + if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) + [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] + + await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) + + const liquidityParams = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: wallet.address, + amount0Desired: 1000000, + amount1Desired: 1000000, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + return nft.mint(liquidityParams) +} + +export async function createPoolWithMultiplePositions( + nft: Contract, + wallet: Wallet, + tokenAddressA: string, + tokenAddressB: string +) { + if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) + [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] + + await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) + + const liquidityParams = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: wallet.address, + amount0Desired: 1000000, + amount1Desired: 1000000, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + await nft.mint(liquidityParams) + + const liquidityParams2 = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: -60, + tickUpper: 60, + recipient: wallet.address, + amount0Desired: 100, + amount1Desired: 100, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + await nft.mint(liquidityParams2) + + const liquidityParams3 = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: -120, + tickUpper: 120, + recipient: wallet.address, + amount0Desired: 100, + amount1Desired: 100, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + return nft.mint(liquidityParams3) +} + +export async function createPoolWithZeroTickInitialized( + nft: Contract, + wallet: Wallet, + tokenAddressA: string, + tokenAddressB: string +) { + if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) + [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] + + await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) + + const liquidityParams = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + recipient: wallet.address, + amount0Desired: 1000000, + amount1Desired: 1000000, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + await nft.mint(liquidityParams) + + const liquidityParams2 = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: 0, + tickUpper: 60, + recipient: wallet.address, + amount0Desired: 100, + amount1Desired: 100, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + await nft.mint(liquidityParams2) + + const liquidityParams3 = { + token0: tokenAddressA, + token1: tokenAddressB, + fee: FeeAmount.MEDIUM, + tickLower: -120, + tickUpper: 0, + recipient: wallet.address, + amount0Desired: 100, + amount1Desired: 100, + amount0Min: 0, + amount1Min: 0, + deadline: 2 ** 32, + } + + return nft.mint(liquidityParams3) +} + +/** + * Create V2 pairs for testing with IL routes + */ +export async function createPair(v2Factory: Contract, tokenAddressA: string, tokenAddressB: string): Promise { + // .createPair() sorts the tokens already + const receipt = await (await v2Factory.createPair(tokenAddressA, tokenAddressB)).wait() + // we can extract the pair address from the emitted event + // always the 3rd element: emit PairCreated(token0, token1, pair, allPairs.length); + const pairAddress = receipt.events[0].args[2] + if (!pairAddress) throw new Error('pairAddress not found in txn receipt') + return pairAddress +} diff --git a/lib/swap-router-contracts/test/shared/snapshotGasCost.ts b/lib/swap-router-contracts/test/shared/snapshotGasCost.ts new file mode 100644 index 0000000..5a606d2 --- /dev/null +++ b/lib/swap-router-contracts/test/shared/snapshotGasCost.ts @@ -0,0 +1,27 @@ +import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider' +import { expect } from './expect' +import { Contract, BigNumber, ContractTransaction } from 'ethers' + +export default async function snapshotGasCost( + x: + | TransactionResponse + | Promise + | ContractTransaction + | Promise + | TransactionReceipt + | Promise + | BigNumber + | Contract + | Promise +): Promise { + const resolved = await x + if ('deployTransaction' in resolved) { + const receipt = await resolved.deployTransaction.wait() + expect(receipt.gasUsed.toNumber()).toMatchSnapshot() + } else if ('wait' in resolved) { + const waited = await resolved.wait() + expect(waited.gasUsed.toNumber()).toMatchSnapshot() + } else if (BigNumber.isBigNumber(resolved)) { + expect(resolved.toNumber()).toMatchSnapshot() + } +} diff --git a/lib/swap-router-contracts/test/shared/ticks.ts b/lib/swap-router-contracts/test/shared/ticks.ts new file mode 100644 index 0000000..b162dfd --- /dev/null +++ b/lib/swap-router-contracts/test/shared/ticks.ts @@ -0,0 +1,2 @@ +export const getMinTick = (tickSpacing: number) => Math.ceil(-887272 / tickSpacing) * tickSpacing +export const getMaxTick = (tickSpacing: number) => Math.floor(887272 / tickSpacing) * tickSpacing diff --git a/lib/swap-router-contracts/tsconfig.json b/lib/swap-router-contracts/tsconfig.json new file mode 100644 index 0000000..69ab585 --- /dev/null +++ b/lib/swap-router-contracts/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2018", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "outDir": "dist", + "typeRoots": ["./typechain", "./node_modules/@types"], + "types": ["@nomiclabs/hardhat-ethers", "@nomiclabs/hardhat-waffle"] + }, + "include": ["./test"], + "files": ["./hardhat.config.ts"] +} diff --git a/lib/swap-router-contracts/yarn.lock b/lib/swap-router-contracts/yarn.lock new file mode 100644 index 0000000..ac17e7a --- /dev/null +++ b/lib/swap-router-contracts/yarn.lock @@ -0,0 +1,8128 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/types@^7.0.0", "@babel/types@^7.3.0": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@ensdomains/ens@^0.4.4": + version "0.4.5" + resolved "https://registry.yarnpkg.com/@ensdomains/ens/-/ens-0.4.5.tgz#e0aebc005afdc066447c6e22feb4eda89a5edbfc" + dependencies: + bluebird "^3.5.2" + eth-ens-namehash "^2.0.8" + solc "^0.4.20" + testrpc "0.0.1" + web3-utils "^1.0.0-beta.31" + +"@ensdomains/resolver@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89" + +"@ethereum-waffle/chai@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.2.1.tgz#5cb542b2a323adf0bc2dda00f48b0eb85944d8ab" + dependencies: + "@ethereum-waffle/provider" "^3.2.1" + ethers "^5.0.0" + +"@ethereum-waffle/compiler@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/compiler/-/compiler-3.2.1.tgz#612a9056285a94ce28eb57b895770ad10e438bf9" + dependencies: + "@resolver-engine/imports" "^0.3.3" + "@resolver-engine/imports-fs" "^0.3.3" + "@types/mkdirp" "^0.5.2" + "@types/node-fetch" "^2.5.5" + ethers "^5.0.1" + mkdirp "^0.5.1" + node-fetch "^2.6.0" + solc "^0.6.3" + +"@ethereum-waffle/ens@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/ens/-/ens-3.2.1.tgz#9f369112d62f7aa88d010be4d133b6d0f5e8c492" + dependencies: + "@ensdomains/ens" "^0.4.4" + "@ensdomains/resolver" "^0.2.4" + ethers "^5.0.1" + +"@ethereum-waffle/mock-contract@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/mock-contract/-/mock-contract-3.2.1.tgz#bf5f63f61c9749eb3270108893a88ff161e68f58" + dependencies: + "@ethersproject/abi" "^5.0.1" + ethers "^5.0.1" + +"@ethereum-waffle/provider@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/provider/-/provider-3.2.1.tgz#d84c0603936f09afa69ecb671d56f527e9818e71" + dependencies: + "@ethereum-waffle/ens" "^3.2.1" + ethers "^5.0.1" + ganache-core "^2.10.2" + patch-package "^6.2.2" + postinstall-postinstall "^2.1.0" + +"@ethereumjs/block@^3.4.0", "@ethereumjs/block@^3.5.0", "@ethereumjs/block@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/block/-/block-3.6.0.tgz#5cf89ea748607597a3f8b038abc986e4ac0b05db" + integrity sha512-dqLo1LtsLG+Oelu5S5tWUDG0pah3QUwV5TJZy2cm19BXDr4ka/S9XBSgao0i09gTcuPlovlHgcs6d7EZ37urjQ== + dependencies: + "@ethereumjs/common" "^2.6.0" + "@ethereumjs/tx" "^3.4.0" + ethereumjs-util "^7.1.3" + merkle-patricia-tree "^4.2.2" + +"@ethereumjs/blockchain@^5.4.0", "@ethereumjs/blockchain@^5.5.0": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/blockchain/-/blockchain-5.5.1.tgz#60f1f50592c06cc47e1704800b88b7d32f609742" + integrity sha512-JS2jeKxl3tlaa5oXrZ8mGoVBCz6YqsGG350XVNtHAtNZXKk7pU3rH4xzF2ru42fksMMqzFLzKh9l4EQzmNWDqA== + dependencies: + "@ethereumjs/block" "^3.6.0" + "@ethereumjs/common" "^2.6.0" + "@ethereumjs/ethash" "^1.1.0" + debug "^2.2.0" + ethereumjs-util "^7.1.3" + level-mem "^5.0.1" + lru-cache "^5.1.1" + semaphore-async-await "^1.5.1" + +"@ethereumjs/common@^2.4.0", "@ethereumjs/common@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.0.tgz#feb96fb154da41ee2cc2c5df667621a440f36348" + integrity sha512-Cq2qS0FTu6O2VU1sgg+WyU9Ps0M6j/BEMHN+hRaECXCV/r0aI78u4N6p52QW/BDVhwWZpCdrvG8X7NJdzlpNUA== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.3" + +"@ethereumjs/ethash@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/ethash/-/ethash-1.1.0.tgz#7c5918ffcaa9cb9c1dc7d12f77ef038c11fb83fb" + integrity sha512-/U7UOKW6BzpA+Vt+kISAoeDie1vAvY4Zy2KF5JJb+So7+1yKmJeJEHOGSnQIj330e9Zyl3L5Nae6VZyh2TJnAA== + dependencies: + "@ethereumjs/block" "^3.5.0" + "@types/levelup" "^4.3.0" + buffer-xor "^2.0.1" + ethereumjs-util "^7.1.1" + miller-rabin "^4.0.0" + +"@ethereumjs/tx@^3.3.0", "@ethereumjs/tx@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.4.0.tgz#7eb1947eefa55eb9cf05b3ca116fb7a3dbd0bce7" + integrity sha512-WWUwg1PdjHKZZxPPo274ZuPsJCWV3SqATrEKQP1n2DrVYVP1aZIYpo/mFaA0BDoE0tIQmBeimRCEA0Lgil+yYw== + dependencies: + "@ethereumjs/common" "^2.6.0" + ethereumjs-util "^7.1.3" + +"@ethereumjs/vm@^5.5.2": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/vm/-/vm-5.6.0.tgz#e0ca62af07de820143674c30b776b86c1983a464" + integrity sha512-J2m/OgjjiGdWF2P9bj/4LnZQ1zRoZhY8mRNVw/N3tXliGI8ai1sI1mlDPkLpeUUM4vq54gH6n0ZlSpz8U/qlYQ== + dependencies: + "@ethereumjs/block" "^3.6.0" + "@ethereumjs/blockchain" "^5.5.0" + "@ethereumjs/common" "^2.6.0" + "@ethereumjs/tx" "^3.4.0" + async-eventemitter "^0.2.4" + core-js-pure "^3.0.1" + debug "^2.2.0" + ethereumjs-util "^7.1.3" + functional-red-black-tree "^1.0.1" + mcl-wasm "^0.7.1" + merkle-patricia-tree "^4.2.2" + rustbn.js "~0.2.0" + +"@ethersproject/abi@5.0.0-beta.153": + version "5.0.0-beta.153" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" + dependencies: + "@ethersproject/address" ">=5.0.0-beta.128" + "@ethersproject/bignumber" ">=5.0.0-beta.130" + "@ethersproject/bytes" ">=5.0.0-beta.129" + "@ethersproject/constants" ">=5.0.0-beta.128" + "@ethersproject/hash" ">=5.0.0-beta.128" + "@ethersproject/keccak256" ">=5.0.0-beta.127" + "@ethersproject/logger" ">=5.0.0-beta.129" + "@ethersproject/properties" ">=5.0.0-beta.131" + "@ethersproject/strings" ">=5.0.0-beta.130" + +"@ethersproject/abi@5.0.9", "@ethersproject/abi@^5.0.1", "@ethersproject/abi@^5.0.5": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.9.tgz#738c1c557e56d8f395a5a27caef9b0449bc85a10" + dependencies: + "@ethersproject/address" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + +"@ethersproject/abi@^5.1.2": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" + integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== + dependencies: + "@ethersproject/address" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/constants" "^5.5.0" + "@ethersproject/hash" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + +"@ethersproject/abstract-provider@5.0.7", "@ethersproject/abstract-provider@^5.0.4": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.0.7.tgz#04ee3bfe43323384e7fecf6c774975b8dec4bdc9" + dependencies: + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/networks" "^5.0.3" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/transactions" "^5.0.5" + "@ethersproject/web" "^5.0.6" + +"@ethersproject/abstract-provider@^5.5.0": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" + integrity sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/networks" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/transactions" "^5.5.0" + "@ethersproject/web" "^5.5.0" + +"@ethersproject/abstract-signer@5.0.9", "@ethersproject/abstract-signer@^5.0.4", "@ethersproject/abstract-signer@^5.0.6": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.0.9.tgz#238ddc06031aeb9dfceee2add965292d7dd1acbf" + dependencies: + "@ethersproject/abstract-provider" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + +"@ethersproject/abstract-signer@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" + integrity sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA== + dependencies: + "@ethersproject/abstract-provider" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + +"@ethersproject/address@5.0.8", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.0.5": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.8.tgz#0c551659144a5a7643c6bea337149d410825298f" + dependencies: + "@ethersproject/bignumber" "^5.0.10" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/rlp" "^5.0.3" + +"@ethersproject/address@^5.0.2": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.1.0.tgz#3854fd7ebcb6af7597de66f847c3345dae735b58" + integrity sha512-rfWQR12eHn2cpstCFS4RF7oGjfbkZb0oqep+BfrT+gWEGWG2IowJvIsacPOvzyS1jhNF4MQ4BS59B04Mbovteg== + dependencies: + "@ethersproject/bignumber" "^5.1.0" + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/keccak256" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + "@ethersproject/rlp" "^5.1.0" + +"@ethersproject/address@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" + integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/rlp" "^5.5.0" + +"@ethersproject/base64@5.0.6", "@ethersproject/base64@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.0.6.tgz#26311ebf29ea3d0b9c300ccf3e1fdc44b7481516" + dependencies: + "@ethersproject/bytes" "^5.0.4" + +"@ethersproject/base64@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090" + integrity sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA== + dependencies: + "@ethersproject/bytes" "^5.5.0" + +"@ethersproject/basex@5.0.6", "@ethersproject/basex@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.0.6.tgz#ab95c32e48288a3d868726463506641cb1e9fb6b" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/properties" "^5.0.3" + +"@ethersproject/bignumber@5.0.12", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.0.10", "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.0.8": + version "5.0.12" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.12.tgz#fe4a78667d7cb01790f75131147e82d6ea7e7cba" + dependencies: + "@ethersproject/bytes" "^5.0.8" + "@ethersproject/logger" "^5.0.5" + bn.js "^4.4.0" + +"@ethersproject/bignumber@^5.1.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.1.1.tgz#84812695253ccbc639117f7ac49ee1529b68e637" + integrity sha512-AVz5iqz7+70RIqoQTznsdJ6DOVBYciNlvO+AlQmPTB6ofCvoihI9bQdr6wljsX+d5W7Yc4nyvQvP4JMzg0Agig== + dependencies: + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + bn.js "^4.4.0" + +"@ethersproject/bignumber@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527" + integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + bn.js "^4.11.9" + +"@ethersproject/bytes@5.0.8", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.0.8": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.8.tgz#cf1246a6a386086e590063a4602b1ffb6cc43db1" + dependencies: + "@ethersproject/logger" "^5.0.5" + +"@ethersproject/bytes@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.1.0.tgz#55dfa9c4c21df1b1b538be3accb50fb76d5facfd" + integrity sha512-sGTxb+LVjFxJcJeUswAIK6ncgOrh3D8c192iEJd7mLr95V6du119rRfYT/b87WPkZ5I3gRBUYIYXtdgCWACe8g== + dependencies: + "@ethersproject/logger" "^5.1.0" + +"@ethersproject/bytes@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" + integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== + dependencies: + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/constants@5.0.7", "@ethersproject/constants@>=5.0.0-beta.128", "@ethersproject/constants@^5.0.4": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.7.tgz#44ff979e5781b17c8c6901266896c3ee745f4e7e" + dependencies: + "@ethersproject/bignumber" "^5.0.7" + +"@ethersproject/constants@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.5.0.tgz#d2a2cd7d94bd1d58377d1d66c4f53c9be4d0a45e" + integrity sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + +"@ethersproject/contracts@5.0.8": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.0.8.tgz#71d3ba16853a1555be2e161a6741df186f81c73b" + dependencies: + "@ethersproject/abi" "^5.0.5" + "@ethersproject/abstract-provider" "^5.0.4" + "@ethersproject/abstract-signer" "^5.0.4" + "@ethersproject/address" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + +"@ethersproject/hash@5.0.9", "@ethersproject/hash@>=5.0.0-beta.128", "@ethersproject/hash@^5.0.4": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.0.9.tgz#81252a848185b584aa600db4a1a68cad9229a4d4" + dependencies: + "@ethersproject/abstract-signer" "^5.0.6" + "@ethersproject/address" "^5.0.5" + "@ethersproject/bignumber" "^5.0.8" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.4" + "@ethersproject/strings" "^5.0.4" + +"@ethersproject/hash@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" + integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg== + dependencies: + "@ethersproject/abstract-signer" "^5.5.0" + "@ethersproject/address" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + +"@ethersproject/hdnode@5.0.7", "@ethersproject/hdnode@^5.0.4": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.0.7.tgz#c7bce94a337ea65e37c46bab09a83e1c1a555d99" + dependencies: + "@ethersproject/abstract-signer" "^5.0.4" + "@ethersproject/basex" "^5.0.3" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/pbkdf2" "^5.0.3" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/sha2" "^5.0.3" + "@ethersproject/signing-key" "^5.0.4" + "@ethersproject/strings" "^5.0.4" + "@ethersproject/transactions" "^5.0.5" + "@ethersproject/wordlists" "^5.0.4" + +"@ethersproject/json-wallets@5.0.9", "@ethersproject/json-wallets@^5.0.6": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.0.9.tgz#2e1708c2854c4ab764e35920bd1f44c948b95434" + dependencies: + "@ethersproject/abstract-signer" "^5.0.4" + "@ethersproject/address" "^5.0.4" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/hdnode" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/pbkdf2" "^5.0.3" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/random" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + "@ethersproject/transactions" "^5.0.5" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.0.6", "@ethersproject/keccak256@>=5.0.0-beta.127", "@ethersproject/keccak256@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.0.6.tgz#5b5ba715ef1be86efde5c271f896fa0daf0e1efe" + dependencies: + "@ethersproject/bytes" "^5.0.4" + js-sha3 "0.5.7" + +"@ethersproject/keccak256@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.1.0.tgz#fdcd88fb13bfef4271b225cdd8dec4d315c8e60e" + integrity sha512-vrTB1W6AEYoadww5c9UyVJ2YcSiyIUTNDRccZIgwTmFFoSHwBtcvG1hqy9RzJ1T0bMdATbM9Hfx2mJ6H0i7Hig== + dependencies: + "@ethersproject/bytes" "^5.1.0" + js-sha3 "0.5.7" + +"@ethersproject/keccak256@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492" + integrity sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg== + dependencies: + "@ethersproject/bytes" "^5.5.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.0.8", "@ethersproject/logger@>=5.0.0-beta.129", "@ethersproject/logger@^5.0.5": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.8.tgz#135c1903d35c878265f3cbf2b287042c4c20d5d4" + +"@ethersproject/logger@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.1.0.tgz#4cdeeefac029373349d5818f39c31b82cc6d9bbf" + integrity sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw== + +"@ethersproject/logger@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" + integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== + +"@ethersproject/networks@5.0.6", "@ethersproject/networks@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.0.6.tgz#4d6586bbebfde1c027504ebf6dfb783b29c3803a" + dependencies: + "@ethersproject/logger" "^5.0.5" + +"@ethersproject/networks@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.0.tgz#babec47cab892c51f8dd652ce7f2e3e14283981a" + integrity sha512-KWfP3xOnJeF89Uf/FCJdV1a2aDJe5XTN2N52p4fcQ34QhDqQFkgQKZ39VGtiqUgHcLI8DfT0l9azC3KFTunqtA== + dependencies: + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/pbkdf2@5.0.6", "@ethersproject/pbkdf2@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.0.6.tgz#105dbfb08cd5fcf33869b42bfdc35a3ebd978cbd" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/sha2" "^5.0.3" + +"@ethersproject/properties@5.0.6", "@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.0.4": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.0.6.tgz#44d82aaa294816fd63333e7def42426cf0e87b3b" + dependencies: + "@ethersproject/logger" "^5.0.5" + +"@ethersproject/properties@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" + integrity sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA== + dependencies: + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/providers@5.0.17": + version "5.0.17" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.0.17.tgz#f380e7831149e24e7a1c6c9b5fb1d6dfc729d024" + dependencies: + "@ethersproject/abstract-provider" "^5.0.4" + "@ethersproject/abstract-signer" "^5.0.4" + "@ethersproject/address" "^5.0.4" + "@ethersproject/basex" "^5.0.3" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/networks" "^5.0.3" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/random" "^5.0.3" + "@ethersproject/rlp" "^5.0.3" + "@ethersproject/sha2" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + "@ethersproject/transactions" "^5.0.5" + "@ethersproject/web" "^5.0.6" + bech32 "1.1.4" + ws "7.2.3" + +"@ethersproject/random@5.0.6", "@ethersproject/random@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.0.6.tgz#9be80a1065f2b8e6f321dccb3ebeb4886cac9ea4" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + +"@ethersproject/rlp@5.0.6", "@ethersproject/rlp@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.0.6.tgz#29f9097348a3c330811997433b7df89ab51cd644" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + +"@ethersproject/rlp@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.1.0.tgz#700f4f071c27fa298d3c1d637485fefe919dd084" + integrity sha512-vDTyHIwNPrecy55gKGZ47eJZhBm8LLBxihzi5ou+zrSvYTpkSTWRcKUlXFDFQVwfWB+P5PGyERAdiDEI76clxw== + dependencies: + "@ethersproject/bytes" "^5.1.0" + "@ethersproject/logger" "^5.1.0" + +"@ethersproject/rlp@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" + integrity sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/sha2@5.0.6", "@ethersproject/sha2@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.0.6.tgz#175116dc10b866a0a381f6316d094bcc510bee3c" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + hash.js "1.1.3" + +"@ethersproject/signing-key@5.0.7", "@ethersproject/signing-key@^5.0.4": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.0.7.tgz#d03bfc5f565efb962bafebf8e6965e70d1c46d31" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + elliptic "6.5.3" + +"@ethersproject/signing-key@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" + integrity sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + bn.js "^4.11.9" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.0.7": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.0.7.tgz#72a3455f47a454db2dcf363992d42e9045dc7fce" + dependencies: + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/sha2" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + +"@ethersproject/strings@5.0.7", "@ethersproject/strings@>=5.0.0-beta.130", "@ethersproject/strings@^5.0.4": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.0.7.tgz#8dc68f794c9e2901f3b75e53b2afbcb6b6c15037" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + +"@ethersproject/strings@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549" + integrity sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/constants" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/transactions@5.0.8", "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.0.5": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.0.8.tgz#3b4d7041e13b957a9c4f131e0aea9dae7b6f5a23" + dependencies: + "@ethersproject/address" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/rlp" "^5.0.3" + "@ethersproject/signing-key" "^5.0.4" + +"@ethersproject/transactions@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" + integrity sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA== + dependencies: + "@ethersproject/address" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/constants" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/rlp" "^5.5.0" + "@ethersproject/signing-key" "^5.5.0" + +"@ethersproject/units@5.0.8": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.0.8.tgz#563325b20fe1eceff7b61857711d5e2b3f38fd09" + dependencies: + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + +"@ethersproject/wallet@5.0.9": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.0.9.tgz#976c7d950489c40308d676869d24e59ab7b82ad1" + dependencies: + "@ethersproject/abstract-provider" "^5.0.4" + "@ethersproject/abstract-signer" "^5.0.4" + "@ethersproject/address" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/hdnode" "^5.0.4" + "@ethersproject/json-wallets" "^5.0.6" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/random" "^5.0.3" + "@ethersproject/signing-key" "^5.0.4" + "@ethersproject/transactions" "^5.0.5" + "@ethersproject/wordlists" "^5.0.4" + +"@ethersproject/web@5.0.11", "@ethersproject/web@^5.0.6": + version "5.0.11" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.0.11.tgz#d47da612b958b4439e415782a53c8f8461522d68" + dependencies: + "@ethersproject/base64" "^5.0.3" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + +"@ethersproject/web@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.0.tgz#0e5bb21a2b58fb4960a705bfc6522a6acf461e28" + integrity sha512-BEgY0eL5oH4mAo37TNYVrFeHsIXLRxggCRG/ksRIxI2X5uj5IsjGmcNiRN/VirQOlBxcUhCgHhaDLG4m6XAVoA== + dependencies: + "@ethersproject/base64" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + +"@ethersproject/wordlists@5.0.7", "@ethersproject/wordlists@^5.0.4": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.0.7.tgz#4e5ad38cfbef746b196a3290c0d41696eb7ab468" + dependencies: + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + +"@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" + slash "^3.0.0" + +"@jest/test-result@^26.5.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + dependencies: + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@nomiclabs/hardhat-ethers@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.2.tgz#c472abcba0c5185aaa4ad4070146e95213c68511" + integrity sha512-6quxWe8wwS4X5v3Au8q1jOvXYEPkS1Fh+cME5u6AwNdnI4uERvPlVjlgRWzpnb+Rrt1l/cEqiNRH9GlsBMSDQg== + +"@nomiclabs/hardhat-etherscan@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-2.1.8.tgz#e206275e96962cd15e5ba9148b44388bc922d8c2" + integrity sha512-0+rj0SsZotVOcTLyDOxnOc3Gulo8upo0rsw/h+gBPcmtj91YqYJNhdARHoBxOhhE8z+5IUQPx+Dii04lXT14PA== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^5.0.2" + debug "^4.1.1" + fs-extra "^7.0.1" + node-fetch "^2.6.0" + semver "^6.3.0" + +"@nomiclabs/hardhat-waffle@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.1.tgz#5d43654fba780720c5033dea240fe14f70ef4bd2" + integrity sha512-2YR2V5zTiztSH9n8BYWgtv3Q+EL0N5Ltm1PAr5z20uAY4SkkfylJ98CIqt18XFvxTD5x4K2wKBzddjV9ViDAZQ== + dependencies: + "@types/sinon-chai" "^3.2.3" + "@types/web3" "1.0.19" + +"@openzeppelin/contracts@3.4.2-solc-0.7": + version "3.4.2-solc-0.7" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" + integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== + +"@resolver-engine/core@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.3.3.tgz#590f77d85d45bc7ecc4e06c654f41345db6ca967" + dependencies: + debug "^3.1.0" + is-url "^1.2.4" + request "^2.85.0" + +"@resolver-engine/fs@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@resolver-engine/fs/-/fs-0.3.3.tgz#fbf83fa0c4f60154a82c817d2fe3f3b0c049a973" + dependencies: + "@resolver-engine/core" "^0.3.3" + debug "^3.1.0" + +"@resolver-engine/imports-fs@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@resolver-engine/imports-fs/-/imports-fs-0.3.3.tgz#4085db4b8d3c03feb7a425fbfcf5325c0d1e6c1b" + dependencies: + "@resolver-engine/fs" "^0.3.3" + "@resolver-engine/imports" "^0.3.3" + debug "^3.1.0" + +"@resolver-engine/imports@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@resolver-engine/imports/-/imports-0.3.3.tgz#badfb513bb3ff3c1ee9fd56073e3144245588bcc" + dependencies: + "@resolver-engine/core" "^0.3.3" + debug "^3.1.0" + hosted-git-info "^2.6.0" + path-browserify "^1.0.0" + url "^0.11.0" + +"@sentry/core@5.29.2": + version "5.29.2" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.29.2.tgz#9e05fe197234161d57aabaf52fab336a7c520d81" + dependencies: + "@sentry/hub" "5.29.2" + "@sentry/minimal" "5.29.2" + "@sentry/types" "5.29.2" + "@sentry/utils" "5.29.2" + tslib "^1.9.3" + +"@sentry/hub@5.29.2": + version "5.29.2" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.29.2.tgz#208f10fe6674695575ad74182a1151f71d6df00a" + dependencies: + "@sentry/types" "5.29.2" + "@sentry/utils" "5.29.2" + tslib "^1.9.3" + +"@sentry/minimal@5.29.2": + version "5.29.2" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.29.2.tgz#420bebac8d03d30980fdb05c72d7b253d8aa541b" + dependencies: + "@sentry/hub" "5.29.2" + "@sentry/types" "5.29.2" + tslib "^1.9.3" + +"@sentry/node@^5.18.1": + version "5.29.2" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.29.2.tgz#f0f0b4b2be63c9ddd702729fab998cead271dff1" + dependencies: + "@sentry/core" "5.29.2" + "@sentry/hub" "5.29.2" + "@sentry/tracing" "5.29.2" + "@sentry/types" "5.29.2" + "@sentry/utils" "5.29.2" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@5.29.2": + version "5.29.2" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.29.2.tgz#6012788547d2ab7893799d82c4941bda145dcd47" + dependencies: + "@sentry/hub" "5.29.2" + "@sentry/minimal" "5.29.2" + "@sentry/types" "5.29.2" + "@sentry/utils" "5.29.2" + tslib "^1.9.3" + +"@sentry/types@5.29.2": + version "5.29.2" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.29.2.tgz#ac87383df1222c2d9b9f8f9ed7a6b86ea41a098a" + +"@sentry/utils@5.29.2": + version "5.29.2" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.29.2.tgz#99a5cdda2ea19d34a41932f138d470adcb3ee673" + dependencies: + "@sentry/types" "5.29.2" + tslib "^1.9.3" + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + +"@solidity-parser/parser@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.12.1.tgz#10ce249890d32ba500e9ce449e60a2b26b11be7a" + integrity sha512-ikxVpwskNxEp2fvYS1BdRImnevHmM97zdPFBa1cVtjtNpoqCm/EmljATTZk0s9G/zsN5ZbPf9OAIAW4gbBJiRA== + +"@solidity-parser/parser@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.0.tgz#d51f074efb0acce0e953ec48133561ed710cebc0" + integrity sha512-cX0JJRcmPtNUJpzD2K7FdA7qQsTOk1UZnFx2k7qAg9ZRvuaH5NBe5IEdBMXGlmf2+FmjhqbygJ26H8l2SV7aKQ== + dependencies: + antlr4ts "^0.5.0-alpha.4" + +"@solidity-parser/parser@^0.8.2": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.8.2.tgz#a6a5e93ac8dca6884a99a532f133beba59b87b69" + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + dependencies: + defer-to-connect "^1.0.1" + +"@typechain/ethers-v5@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-4.0.0.tgz#2a8be5e108d23f3b8e6354d1618fdc2abcb00b07" + +"@types/abstract-leveldown@*": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz#3c7750d0186b954c7f2d2f6acc8c3c7ba0c3412e" + integrity sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ== + +"@types/babel__traverse@^7.0.4": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.11.0.tgz#b9a1efa635201ba9bc850323a8793ee2d36c04a0" + dependencies: + "@babel/types" "^7.3.0" + +"@types/bn.js@*", "@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": + version "4.11.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + dependencies: + "@types/node" "*" + +"@types/bn.js@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" + integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA== + dependencies: + "@types/node" "*" + +"@types/chai@*", "@types/chai@^4.2.6": + version "4.2.14" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.14.tgz#44d2dd0b5de6185089375d976b4ec5caf6861193" + +"@types/graceful-fs@^4.1.2": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/levelup@^4.3.0": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@types/levelup/-/levelup-4.3.1.tgz#7a53b9fd510716e11b2065332790fdf5f9b950b9" + integrity sha512-n//PeTpbHLjMLTIgW5B/g06W/6iuTBHuvUka2nFL9APMSVMNe2r4enADfu3CIE9IyV9E+uquf9OEQQqrDeg24A== + dependencies: + "@types/abstract-leveldown" "*" + "@types/node" "*" + +"@types/lru-cache@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03" + +"@types/mkdirp@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" + dependencies: + "@types/node" "*" + +"@types/mocha@^5.2.7": + version "5.2.7" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" + +"@types/node-fetch@^2.5.5": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" + dependencies: + "@types/node" "*" + form-data "^3.0.0" + +"@types/node@*": + version "14.14.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.14.tgz#f7fd5f3cc8521301119f63910f0fb965c7d761ae" + +"@types/node@^12.12.6": + version "12.19.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" + +"@types/normalize-package-data@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + +"@types/pbkdf2@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" + dependencies: + "@types/node" "*" + +"@types/prettier@^2.0.0", "@types/prettier@^2.1.1": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00" + +"@types/resolve@^0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" + dependencies: + "@types/node" "*" + +"@types/secp256k1@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.1.tgz#fb3aa61a1848ad97d7425ff9dcba784549fca5a4" + dependencies: + "@types/node" "*" + +"@types/sinon-chai@^3.2.3": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.5.tgz#df21ae57b10757da0b26f512145c065f2ad45c48" + dependencies: + "@types/chai" "*" + "@types/sinon" "*" + +"@types/sinon@*": + version "9.0.10" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.10.tgz#7fb9bcb6794262482859cab66d59132fca18fcf7" + dependencies: + "@types/sinonjs__fake-timers" "*" + +"@types/sinonjs__fake-timers@*": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae" + +"@types/stack-utils@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" + +"@types/underscore@*": + version "1.10.24" + resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.10.24.tgz#dede004deed3b3f99c4db0bdb9ee21cae25befdd" + +"@types/web3@1.0.19": + version "1.0.19" + resolved "https://registry.yarnpkg.com/@types/web3/-/web3-1.0.19.tgz#46b85d91d398ded9ab7c85a5dd57cb33ac558924" + dependencies: + "@types/bn.js" "*" + "@types/underscore" "*" + +"@types/yargs-parser@*": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" + +"@types/yargs@^15.0.0": + version "15.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.12.tgz#6234ce3e3e3fa32c5db301a170f96a599c960d74" + dependencies: + "@types/yargs-parser" "*" + +"@uniswap/lib@^4.0.1-alpha": + version "4.0.1-alpha" + resolved "https://registry.yarnpkg.com/@uniswap/lib/-/lib-4.0.1-alpha.tgz#2881008e55f075344675b3bca93f020b028fbd02" + integrity sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA== + +"@uniswap/v2-core@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425" + integrity sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q== + +"@uniswap/v3-core@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.1.tgz#b6d2bdc6ba3c3fbd610bdc502395d86cd35264a0" + integrity sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ== + +"@uniswap/v3-periphery@^1.4.4": + version "1.4.4" + resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.4.tgz#d2756c23b69718173c5874f37fd4ad57d2f021b7" + integrity sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw== + dependencies: + "@openzeppelin/contracts" "3.4.2-solc-0.7" + "@uniswap/lib" "^4.0.1-alpha" + "@uniswap/v2-core" "^1.0.1" + "@uniswap/v3-core" "^1.0.0" + base64-sol "1.0.1" + +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + dependencies: + event-target-shim "^5.0.0" + +abstract-leveldown@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz#5cb89f958a44f526779d740d1440e743e0c30a57" + dependencies: + xtend "~4.0.0" + +abstract-leveldown@^2.4.1, abstract-leveldown@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" + dependencies: + xtend "~4.0.0" + +abstract-leveldown@^5.0.0, abstract-leveldown@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz#f7128e1f86ccabf7d2893077ce5d06d798e386c6" + dependencies: + xtend "~4.0.0" + +abstract-leveldown@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" + integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +abstract-leveldown@~2.6.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" + dependencies: + xtend "~4.0.0" + +abstract-leveldown@~6.2.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" + integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-jsx@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + +acorn@^6.0.7: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + +adm-zip@^0.4.16: + version "0.4.16" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + +aes-js@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + dependencies: + debug "4" + +ajv@^6.10.2, ajv@^6.12.3, ajv@^6.6.1, ajv@^6.9.1: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + +ansi-escapes@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + dependencies: + type-fest "^0.11.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + dependencies: + color-convert "^2.0.1" + +antlr4@4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" + +antlr4ts@^0.5.0-alpha.4: + version "0.5.0-alpha.4" + resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" + integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@^3.0.3, anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-back@^1.0.3, array-back@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-1.0.4.tgz#644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b" + dependencies: + typical "^2.6.0" + +array-back@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022" + dependencies: + typical "^2.6.1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +ast-parents@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + +async-eventemitter@^0.2.2, async-eventemitter@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" + dependencies: + async "^2.4.0" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + +async@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + dependencies: + lodash "^4.17.11" + +async@^1.4.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0, async@^2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.0.14, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babelify@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" + dependencies: + babel-core "^6.0.14" + object-assign "^4.0.0" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +backoff@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" + dependencies: + precond "0.2" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base-x@^3.0.2, base-x@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + +base64-sol@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/base64-sol/-/base64-sol-1.0.1.tgz#91317aa341f0bc763811783c5729f1c2574600f6" + integrity sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + +bignumber.js@^9.0.0, bignumber.js@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" + +binary-extensions@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" + +bip39@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.5.0.tgz#51cbd5179460504a63ea3c000db3f787ca051235" + dependencies: + create-hash "^1.1.0" + pbkdf2 "^3.0.9" + randombytes "^2.0.1" + safe-buffer "^5.0.1" + unorm "^1.3.3" + +blakejs@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" + +bluebird@^3.5.0, bluebird@^3.5.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.4.0, bn.js@^4.8.0: + version "4.11.9" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" + +bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2: + version "5.1.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" + +body-parser@1.19.0, body-parser@^1.16.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer-xor@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-2.0.2.tgz#34f7c64f04c777a1f8aac5e661273bb9dd320289" + dependencies: + safe-buffer "^5.1.1" + +buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +bufferutil@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.2.tgz#79f68631910f6b993d870fc77dc0a2894eb96cd5" + dependencies: + node-gyp-build "^4.2.0" + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + +bytewise-core@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bytewise-core/-/bytewise-core-1.2.3.tgz#3fb410c7e91558eb1ab22a82834577aa6bd61d42" + dependencies: + typewise-core "^1.2" + +bytewise@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/bytewise/-/bytewise-1.1.0.tgz#1d13cbff717ae7158094aa881b35d081b387253e" + dependencies: + bytewise-core "^1.2.2" + typewise "^1.0.3" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +cachedown@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cachedown/-/cachedown-1.0.0.tgz#d43f036e4510696b31246d7db31ebf0f7ac32d15" + dependencies: + abstract-leveldown "^2.4.1" + lru-cache "^3.2.0" + +call-bind@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.0" + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + +caniuse-lite@^1.0.30000844: + version "1.0.30001170" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz#0088bfecc6a14694969e391cc29d7eb6362ca6a7" + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + dependencies: + rsvp "^4.8.4" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +cbor@^5.0.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c" + integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A== + dependencies: + bignumber.js "^9.0.1" + nofilter "^1.0.4" + +chai@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + +checkpoint-store@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" + dependencies: + functional-red-black-tree "^1.0.1" + +chokidar@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.2.0" + optionalDependencies: + fsevents "~2.1.1" + +chokidar@^3.4.0: + version "3.4.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.1.2" + +chokidar@^3.4.3: + version "3.5.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.3.1" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + +cids@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.6.0" + multicodec "^1.0.0" + multihashes "~0.4.15" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-is@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + dependencies: + mimic-response "^1.0.0" + +clone@2.1.2, clone@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + dependencies: + delayed-stream "~1.0.0" + +command-exists@^1.2.8: + version "1.2.9" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + +command-line-args@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-4.0.7.tgz#f8d1916ecb90e9e121eda6428e41300bfb64cc46" + dependencies: + array-back "^2.0.0" + find-replace "^1.0.3" + typical "^2.6.1" + +commander@2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" + +commander@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + dependencies: + safe-buffer "5.1.2" + +content-hash@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" + dependencies: + cids "^0.7.1" + multicodec "^0.5.5" + multihashes "^0.4.15" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +convert-source-map@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + +cookie@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + +cookiejar@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js-pure@^3.0.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.8.1.tgz#23f84048f366fdfcf52d3fd1c68fec349177d119" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@^2.8.1: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + dependencies: + object-assign "^4" + vary "^1" + +cosmiconfig@^5.0.7: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +crc-32@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-fetch@^2.1.0, cross-fetch@^2.1.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.3.tgz#e8a0b3c54598136e037f8650f8e823ccdfac198e" + dependencies: + node-fetch "2.1.2" + whatwg-fetch "2.0.4" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + dependencies: + ms "^2.1.1" + +debug@4, debug@^4.0.1, debug@^4.1.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + dependencies: + ms "2.1.2" + +debug@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decimal.js@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + dependencies: + mimic-response "^1.0.0" + +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + dependencies: + type-detect "^4.0.0" + +deep-equal@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + +deferred-leveldown@~1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" + dependencies: + abstract-leveldown "~2.6.0" + +deferred-leveldown@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz#0b0570087827bf480a23494b398f04c128c19a20" + dependencies: + abstract-leveldown "~5.0.0" + inherits "^2.0.3" + +deferred-leveldown@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" + integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== + dependencies: + abstract-leveldown "~6.2.1" + inherits "^2.0.3" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + +diff@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-to-object@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dir-to-object/-/dir-to-object-2.0.0.tgz#29723e9bd1c3e58e4f307bd04ff634c0370c8f8a" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + dependencies: + esutils "^2.0.2" + +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + +dotenv@^14.2.0: + version "14.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.2.0.tgz#7e77fd5dd6cff5942c4496e1acf2d0f37a9e67aa" + integrity sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw== + +dotignore@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" + dependencies: + minimatch "^3.0.4" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +electron-to-chromium@^1.3.47: + version "1.3.633" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz#16dd5aec9de03894e8d14a1db4cda8a369b9b7fe" + +elliptic@6.5.3, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3: + version "6.5.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +encoding-down@5.0.4, encoding-down@~5.0.0: + version "5.0.4" + resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-5.0.4.tgz#1e477da8e9e9d0f7c8293d320044f8b2cd8e9614" + dependencies: + abstract-leveldown "^5.0.0" + inherits "^2.0.3" + level-codec "^9.0.0" + level-errors "^2.0.0" + xtend "^4.0.1" + +encoding-down@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" + integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== + dependencies: + abstract-leveldown "^6.2.1" + inherits "^2.0.3" + level-codec "^9.0.0" + level-errors "^2.0.0" + +encoding@^0.1.11: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + dependencies: + once "^1.4.0" + +enquirer@^2.3.0: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + dependencies: + ansi-colors "^4.1.1" + +env-paths@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" + +errno@~0.1.1: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: + version "1.17.7" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-abstract@^1.18.0-next.1: + version "1.18.0-next.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-negative-zero "^2.0.0" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + dependencies: + d "^1.0.1" + ext "^1.1.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + +eslint@^5.6.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +esquery@^1.0.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +eth-block-tracker@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz#95cd5e763c7293e0b1b2790a2a39ac2ac188a5e1" + dependencies: + eth-query "^2.1.0" + ethereumjs-tx "^1.3.3" + ethereumjs-util "^5.1.3" + ethjs-util "^0.1.3" + json-rpc-engine "^3.6.0" + pify "^2.3.0" + tape "^4.6.3" + +eth-ens-namehash@2.0.8, eth-ens-namehash@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + +eth-json-rpc-infura@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.1.tgz#26702a821067862b72d979c016fd611502c6057f" + dependencies: + cross-fetch "^2.1.1" + eth-json-rpc-middleware "^1.5.0" + json-rpc-engine "^3.4.0" + json-rpc-error "^2.0.0" + +eth-json-rpc-middleware@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz#5c9d4c28f745ccb01630f0300ba945f4bef9593f" + dependencies: + async "^2.5.0" + eth-query "^2.1.2" + eth-tx-summary "^3.1.2" + ethereumjs-block "^1.6.0" + ethereumjs-tx "^1.3.3" + ethereumjs-util "^5.1.2" + ethereumjs-vm "^2.1.0" + fetch-ponyfill "^4.0.0" + json-rpc-engine "^3.6.0" + json-rpc-error "^2.0.0" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + tape "^4.6.3" + +eth-lib@0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +eth-lib@^0.1.26: + version "0.1.29" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + +eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" + dependencies: + json-rpc-random-id "^1.0.0" + xtend "^4.0.1" + +eth-sig-util@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" + dependencies: + ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" + ethereumjs-util "^5.1.1" + +eth-sig-util@^2.0.0, eth-sig-util@^2.5.2: + version "2.5.3" + resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-2.5.3.tgz#6938308b38226e0b3085435474900b03036abcbe" + dependencies: + buffer "^5.2.1" + elliptic "^6.4.0" + ethereumjs-abi "0.6.5" + ethereumjs-util "^5.1.1" + tweetnacl "^1.0.0" + tweetnacl-util "^0.15.0" + +eth-tx-summary@^3.1.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c" + dependencies: + async "^2.1.2" + clone "^2.0.0" + concat-stream "^1.5.1" + end-of-stream "^1.1.0" + eth-query "^2.0.2" + ethereumjs-block "^1.4.1" + ethereumjs-tx "^1.1.1" + ethereumjs-util "^5.0.1" + ethereumjs-vm "^2.6.0" + through2 "^2.0.3" + +ethashjs@~0.0.7: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ethashjs/-/ethashjs-0.0.8.tgz#227442f1bdee409a548fb04136e24c874f3aa6f9" + dependencies: + async "^2.1.2" + buffer-xor "^2.0.1" + ethereumjs-util "^7.0.2" + miller-rabin "^4.0.0" + +ethereum-bloom-filters@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz#b7b80735e385dbb7f944ce6b4533e24511306060" + dependencies: + js-sha3 "^0.8.0" + +ethereum-common@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" + +ethereum-common@^0.0.18: + version "0.0.18" + resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" + +ethereum-cryptography@^0.1.2, ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + +ethereum-waffle@^3.0.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ethereum-waffle/-/ethereum-waffle-3.2.1.tgz#9d6d6b93484c5e1b77dfdeb646c050ed877e836e" + dependencies: + "@ethereum-waffle/chai" "^3.2.1" + "@ethereum-waffle/compiler" "^3.2.1" + "@ethereum-waffle/mock-contract" "^3.2.1" + "@ethereum-waffle/provider" "^3.2.1" + ethers "^5.0.1" + +ethereumjs-abi@0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz#5a637ef16ab43473fa72a29ad90871405b3f5241" + dependencies: + bn.js "^4.10.0" + ethereumjs-util "^4.3.0" + +ethereumjs-abi@0.6.8, ethereumjs-abi@^0.6.8: + version "0.6.8" + resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": + version "0.6.8" + resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#1ce6a1d64235fabe2aaf827fd606def55693508f" + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +ethereumjs-account@3.0.0, ethereumjs-account@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-3.0.0.tgz#728f060c8e0c6e87f1e987f751d3da25422570a9" + dependencies: + ethereumjs-util "^6.0.0" + rlp "^2.2.1" + safe-buffer "^5.1.1" + +ethereumjs-account@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" + dependencies: + ethereumjs-util "^5.0.0" + rlp "^2.0.0" + safe-buffer "^5.1.1" + +ethereumjs-block@2.2.2, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.0, ethereumjs-block@~2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" + dependencies: + async "^2.0.1" + ethereumjs-common "^1.5.0" + ethereumjs-tx "^2.1.1" + ethereumjs-util "^5.0.0" + merkle-patricia-tree "^2.1.2" + +ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" + dependencies: + async "^2.0.1" + ethereum-common "0.2.0" + ethereumjs-tx "^1.2.2" + ethereumjs-util "^5.0.0" + merkle-patricia-tree "^2.1.2" + +ethereumjs-blockchain@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.4.tgz#30f2228dc35f6dcf94423692a6902604ae34960f" + dependencies: + async "^2.6.1" + ethashjs "~0.0.7" + ethereumjs-block "~2.2.2" + ethereumjs-common "^1.5.0" + ethereumjs-util "^6.1.0" + flow-stoplight "^1.0.0" + level-mem "^3.0.1" + lru-cache "^5.1.1" + rlp "^2.2.2" + semaphore "^1.1.0" + +ethereumjs-common@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz#d3e82fc7c47c0cef95047f431a99485abc9bb1cd" + +ethereumjs-common@^1.1.0, ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" + +ethereumjs-tx@2.1.2, ethereumjs-tx@^2.1.1, ethereumjs-tx@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" + dependencies: + ethereumjs-common "^1.5.0" + ethereumjs-util "^6.0.0" + +ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" + dependencies: + ethereum-common "^0.0.18" + ethereumjs-util "^5.0.0" + +ethereumjs-util@6.2.1, ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0, ethereumjs-util@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.3" + +ethereumjs-util@^4.3.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.1.tgz#f4bf9b3b515a484e3cc8781d61d9d980f7c83bd0" + dependencies: + bn.js "^4.8.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + rlp "^2.0.0" + +ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.3, ethereumjs-util@^5.1.5, ethereumjs-util@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" + dependencies: + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "^0.1.3" + rlp "^2.0.0" + safe-buffer "^5.1.1" + +ethereumjs-util@^7.0.2: + version "7.0.7" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.7.tgz#484fb9c03b766b2ee64821281070616562fb5a59" + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.4" + +ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz#b55d7b64dde3e3e45749e4c41288238edec32d23" + integrity sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethereumjs-vm@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-4.2.0.tgz#e885e861424e373dbc556278f7259ff3fca5edab" + dependencies: + async "^2.1.2" + async-eventemitter "^0.2.2" + core-js-pure "^3.0.1" + ethereumjs-account "^3.0.0" + ethereumjs-block "^2.2.2" + ethereumjs-blockchain "^4.0.3" + ethereumjs-common "^1.5.0" + ethereumjs-tx "^2.1.2" + ethereumjs-util "^6.2.0" + fake-merkle-patricia-tree "^1.0.1" + functional-red-black-tree "^1.0.1" + merkle-patricia-tree "^2.3.2" + rustbn.js "~0.2.0" + safe-buffer "^5.1.1" + util.promisify "^1.0.0" + +ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" + dependencies: + async "^2.1.2" + async-eventemitter "^0.2.2" + ethereumjs-account "^2.0.3" + ethereumjs-block "~2.2.0" + ethereumjs-common "^1.1.0" + ethereumjs-util "^6.0.0" + fake-merkle-patricia-tree "^1.0.1" + functional-red-black-tree "^1.0.1" + merkle-patricia-tree "^2.3.2" + rustbn.js "~0.2.0" + safe-buffer "^5.1.1" + +ethereumjs-wallet@0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.5.tgz#685e9091645cee230ad125c007658833991ed474" + dependencies: + aes-js "^3.1.1" + bs58check "^2.1.2" + ethereum-cryptography "^0.1.3" + ethereumjs-util "^6.0.0" + randombytes "^2.0.6" + safe-buffer "^5.1.2" + scryptsy "^1.2.1" + utf8 "^3.0.0" + uuid "^3.3.2" + +ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.8: + version "5.0.24" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.24.tgz#fbb8e4d35070d134f2eb846c07500b8c0eaef6d3" + dependencies: + "@ethersproject/abi" "5.0.9" + "@ethersproject/abstract-provider" "5.0.7" + "@ethersproject/abstract-signer" "5.0.9" + "@ethersproject/address" "5.0.8" + "@ethersproject/base64" "5.0.6" + "@ethersproject/basex" "5.0.6" + "@ethersproject/bignumber" "5.0.12" + "@ethersproject/bytes" "5.0.8" + "@ethersproject/constants" "5.0.7" + "@ethersproject/contracts" "5.0.8" + "@ethersproject/hash" "5.0.9" + "@ethersproject/hdnode" "5.0.7" + "@ethersproject/json-wallets" "5.0.9" + "@ethersproject/keccak256" "5.0.6" + "@ethersproject/logger" "5.0.8" + "@ethersproject/networks" "5.0.6" + "@ethersproject/pbkdf2" "5.0.6" + "@ethersproject/properties" "5.0.6" + "@ethersproject/providers" "5.0.17" + "@ethersproject/random" "5.0.6" + "@ethersproject/rlp" "5.0.6" + "@ethersproject/sha2" "5.0.6" + "@ethersproject/signing-key" "5.0.7" + "@ethersproject/solidity" "5.0.7" + "@ethersproject/strings" "5.0.7" + "@ethersproject/transactions" "5.0.8" + "@ethersproject/units" "5.0.8" + "@ethersproject/wallet" "5.0.9" + "@ethersproject/web" "5.0.11" + "@ethersproject/wordlists" "5.0.7" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +ethjs-util@0.1.6, ethjs-util@^0.1.3: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" + dependencies: + is-hex-prefixed "1.0.0" + strip-hex-prefix "1.0.0" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + +eventemitter3@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" + +events@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + dependencies: + "@jest/types" "^26.6.2" + ansi-styles "^4.0.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + +express@^4.14.0: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +ext@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" + dependencies: + type "^2.0.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fake-merkle-patricia-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" + dependencies: + checkpoint-store "^1.1.0" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fast-xml-parser@^3.19.0: + version "3.19.0" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01" + integrity sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg== + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + dependencies: + bser "2.1.1" + +fetch-ponyfill@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" + dependencies: + node-fetch "~1.7.1" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + dependencies: + flat-cache "^2.0.1" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-package-json@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/find-package-json/-/find-package-json-1.2.0.tgz#4057d1b943f82d8445fe52dc9cf456f6b8b58083" + +find-replace@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-1.0.3.tgz#b88e7364d2d9c959559f388c66670d6130441fa0" + dependencies: + array-back "^1.0.4" + test-value "^2.1.0" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + dependencies: + locate-path "^3.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-yarn-workspace-root@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db" + dependencies: + fs-extra "^4.0.3" + micromatch "^3.1.4" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flat@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" + dependencies: + is-buffer "~2.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + +flow-stoplight@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" + +follow-redirects@^1.12.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7" + +for-each@~0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + dependencies: + is-callable "^1.1.3" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fp-ts@1.19.3: + version "1.19.3" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" + +fp-ts@^1.0.0: + version "1.19.5" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^4.0.2, fs-extra@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^7.0.0, fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + dependencies: + minipass "^2.6.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.2.1.tgz#1fb02ded2036a8ac288d507a65962bd87b97628d" + +fsevents@~2.1.1, fsevents@~2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" + +fsevents@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1, function-bind@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +ganache-core@^2.10.2: + version "2.13.1" + resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.13.1.tgz#bf60399a2dd084e1090db91cbbc7ed3885dc01e4" + dependencies: + abstract-leveldown "3.0.0" + async "2.6.2" + bip39 "2.5.0" + cachedown "1.0.0" + clone "2.1.2" + debug "3.2.6" + encoding-down "5.0.4" + eth-sig-util "^2.0.0" + ethereumjs-abi "0.6.8" + ethereumjs-account "3.0.0" + ethereumjs-block "2.2.2" + ethereumjs-common "1.5.0" + ethereumjs-tx "2.1.2" + ethereumjs-util "6.2.1" + ethereumjs-vm "4.2.0" + heap "0.2.6" + keccak "3.0.1" + level-sublevel "6.6.4" + levelup "3.1.1" + lodash "4.17.20" + lru-cache "5.1.1" + merkle-patricia-tree "3.0.0" + patch-package "6.2.2" + seedrandom "3.0.1" + source-map-support "0.5.12" + tmp "0.1.0" + web3-provider-engine "14.2.1" + websocket "1.0.32" + optionalDependencies: + ethereumjs-wallet "0.6.5" + web3 "1.2.11" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + +get-intrinsic@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49" + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-parent@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + dependencies: + is-glob "^4.0.1" + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2, glob@^7.1.3, glob@~7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +got@9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +got@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +hardhat-typechain@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/hardhat-typechain/-/hardhat-typechain-0.3.5.tgz#8e50616a9da348b33bd001168c8fda9c66b7b4af" + integrity sha512-w9lm8sxqTJACY+V7vijiH+NkPExnmtiQEjsV9JKD1KgMdVk2q8y+RhvU/c4B7+7b1+HylRUCxpOIvFuB3rE4+w== + +hardhat-watcher@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/hardhat-watcher/-/hardhat-watcher-2.1.1.tgz#8b05fec429ed45da11808bbf6054a90f3e34c51a" + integrity sha512-zilmvxAYD34IofBrwOliQn4z92UiDmt2c949DW4Gokf0vS0qk4YTfVCi/LmUBICThGygNANE3WfnRTpjCJGtDA== + dependencies: + chokidar "^3.4.3" + +hardhat@^2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.6.8.tgz#9ef6f8c16f9044acb95609d15a760b89177b8181" + integrity sha512-iRVd5DgcIVV3rNXMlogOfwlXAhHp7Wy/OjjFiUhTey8Unvo6oq5+Is5ANiKVN+Iw07Pcb/HpkGt7jCB6a4ITgg== + dependencies: + "@ethereumjs/block" "^3.4.0" + "@ethereumjs/blockchain" "^5.4.0" + "@ethereumjs/common" "^2.4.0" + "@ethereumjs/tx" "^3.3.0" + "@ethereumjs/vm" "^5.5.2" + "@ethersproject/abi" "^5.1.2" + "@sentry/node" "^5.18.1" + "@solidity-parser/parser" "^0.14.0" + "@types/bn.js" "^5.1.0" + "@types/lru-cache" "^5.1.0" + abort-controller "^3.0.0" + adm-zip "^0.4.16" + ansi-escapes "^4.3.0" + chalk "^2.4.2" + chokidar "^3.4.0" + ci-info "^2.0.0" + debug "^4.1.1" + enquirer "^2.3.0" + env-paths "^2.2.0" + eth-sig-util "^2.5.2" + ethereum-cryptography "^0.1.2" + ethereumjs-abi "^0.6.8" + ethereumjs-util "^7.1.0" + find-up "^2.1.0" + fp-ts "1.19.3" + fs-extra "^7.0.1" + glob "^7.1.3" + https-proxy-agent "^5.0.0" + immutable "^4.0.0-rc.12" + io-ts "1.10.4" + lodash "^4.17.11" + merkle-patricia-tree "^4.2.0" + mnemonist "^0.38.0" + mocha "^7.1.2" + node-fetch "^2.6.0" + qs "^6.7.0" + raw-body "^2.4.1" + resolve "1.17.0" + semver "^6.3.0" + slash "^3.0.0" + solc "0.7.3" + source-map-support "^0.5.13" + stacktrace-parser "^0.1.10" + "true-case-path" "^2.2.1" + tsort "0.0.1" + uuid "^3.3.2" + ws "^7.4.6" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + dependencies: + has-symbol-support-x "^1.4.1" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.3, has@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + +heap@0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" + +hmac-drbg@^1.0.0, hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@1.7.3, http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + dependencies: + agent-base "6" + debug "4" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + dependencies: + punycode "2.1.0" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + +immediate@^3.2.3: + version "3.3.0" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" + +immediate@~3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" + +immutable@^4.0.0-rc.12: + version "4.0.0-rc.12" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-fresh@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inquirer@^6.2.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +io-ts@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" + dependencies: + fp-ts "^1.0.0" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" + dependencies: + call-bind "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + dependencies: + binary-extensions "^2.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-buffer@~2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + +is-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + +is-function@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + +is-negative-zero@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + +is-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4, is-regex@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + dependencies: + has-symbols "^1.0.1" + +is-regex@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + dependencies: + has "^1.0.3" + +is-retry-allowed@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.3.1.tgz#8c63ec8c67c8c7f0a8de0a71c8c7d58eccf4406b" + integrity sha512-h2CGs+yPUyvkgTJQS9cJzo9lYK06WgRiXUqBBHtglSzVKAuH4/oWsqk7LGfbSa1hGk9QcZ0SyQtVggvBA8LZXA== + dependencies: + fast-xml-parser "^3.19.0" + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + dependencies: + has-symbols "^1.0.1" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-url@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + dependencies: + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" + +jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + dependencies: + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.2" + pretty-format "^26.6.2" + slash "^3.0.0" + stack-utils "^2.0.2" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + +jest-regex-util@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + +jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" + read-pkg-up "^7.0.1" + resolve "^1.18.1" + slash "^3.0.0" + +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^26.5.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.6.2" + graceful-fs "^4.2.4" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + natural-compare "^1.4.0" + pretty-format "^26.6.2" + semver "^7.3.2" + +jest-util@^26.5.2, jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +js-sha3@0.5.7, js-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + +js-sha3@0.8.0, js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + +json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" + dependencies: + async "^2.0.1" + babel-preset-env "^1.7.0" + babelify "^7.3.0" + json-rpc-error "^2.0.0" + promise-to-callback "^1.0.0" + safe-event-emitter "^1.0.1" + +json-rpc-error@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" + dependencies: + inherits "^2.0.1" + +json-rpc-random-id@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keccak@3.0.1, keccak@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.1.tgz#ae30a0e94dbe43414f741375cff6d64c8bea0bff" + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + dependencies: + graceful-fs "^4.1.11" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +level-codec@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" + dependencies: + buffer "^5.6.0" + +level-codec@~7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" + +level-concat-iterator@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" + integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== + +level-errors@^1.0.3: + version "1.1.2" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" + dependencies: + errno "~0.1.1" + +level-errors@^2.0.0, level-errors@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" + dependencies: + errno "~0.1.1" + +level-errors@~1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" + dependencies: + errno "~0.1.1" + +level-iterator-stream@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-2.0.3.tgz#ccfff7c046dcf47955ae9a86f46dfa06a31688b4" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.5" + xtend "^4.0.0" + +level-iterator-stream@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" + dependencies: + inherits "^2.0.1" + level-errors "^1.0.3" + readable-stream "^1.0.33" + xtend "^4.0.0" + +level-iterator-stream@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-3.0.1.tgz#2c98a4f8820d87cdacab3132506815419077c730" + dependencies: + inherits "^2.0.1" + readable-stream "^2.3.6" + xtend "^4.0.0" + +level-iterator-stream@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" + integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== + dependencies: + inherits "^2.0.4" + readable-stream "^3.4.0" + xtend "^4.0.2" + +level-mem@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-3.0.1.tgz#7ce8cf256eac40f716eb6489654726247f5a89e5" + dependencies: + level-packager "~4.0.0" + memdown "~3.0.0" + +level-mem@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-5.0.1.tgz#c345126b74f5b8aa376dc77d36813a177ef8251d" + integrity sha512-qd+qUJHXsGSFoHTziptAKXoLX87QjR7v2KMbqncDXPxQuCdsQlzmyX+gwrEHhlzn08vkf8TyipYyMmiC6Gobzg== + dependencies: + level-packager "^5.0.3" + memdown "^5.0.0" + +level-packager@^5.0.3: + version "5.1.1" + resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" + integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== + dependencies: + encoding-down "^6.3.0" + levelup "^4.3.2" + +level-packager@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-4.0.1.tgz#7e7d3016af005be0869bc5fa8de93d2a7f56ffe6" + dependencies: + encoding-down "~5.0.0" + levelup "^3.0.0" + +level-post@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/level-post/-/level-post-1.0.7.tgz#19ccca9441a7cc527879a0635000f06d5e8f27d0" + dependencies: + ltgt "^2.1.2" + +level-sublevel@6.6.4: + version "6.6.4" + resolved "https://registry.yarnpkg.com/level-sublevel/-/level-sublevel-6.6.4.tgz#f7844ae893919cd9d69ae19d7159499afd5352ba" + dependencies: + bytewise "~1.1.0" + level-codec "^9.0.0" + level-errors "^2.0.0" + level-iterator-stream "^2.0.3" + ltgt "~2.1.1" + pull-defer "^0.2.2" + pull-level "^2.0.3" + pull-stream "^3.6.8" + typewiselite "~1.0.0" + xtend "~4.0.0" + +level-supports@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" + integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== + dependencies: + xtend "^4.0.2" + +level-ws@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" + dependencies: + readable-stream "~1.0.15" + xtend "~2.1.1" + +level-ws@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-1.0.0.tgz#19a22d2d4ac57b18cc7c6ecc4bd23d899d8f603b" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.8" + xtend "^4.0.1" + +level-ws@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" + integrity sha512-1iv7VXx0G9ec1isqQZ7y5LmoZo/ewAsyDHNA8EFDW5hqH2Kqovm33nSFkSdnLLAK+I5FlT+lo5Cw9itGe+CpQA== + dependencies: + inherits "^2.0.3" + readable-stream "^3.1.0" + xtend "^4.0.1" + +levelup@3.1.1, levelup@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-3.1.1.tgz#c2c0b3be2b4dc316647c53b42e2f559e232d2189" + dependencies: + deferred-leveldown "~4.0.0" + level-errors "~2.0.0" + level-iterator-stream "~3.0.0" + xtend "~4.0.0" + +levelup@^1.2.1: + version "1.3.9" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" + dependencies: + deferred-leveldown "~1.2.1" + level-codec "~7.0.0" + level-errors "~1.0.3" + level-iterator-stream "~1.3.0" + prr "~1.0.1" + semver "~5.4.1" + xtend "~4.0.0" + +levelup@^4.3.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" + integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== + dependencies: + deferred-leveldown "~5.3.0" + level-errors "~2.0.0" + level-iterator-stream "~4.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + dependencies: + p-locate "^4.1.0" + +lodash.assign@^4.0.3, lodash.assign@^4.0.6: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash@4.17.20, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + +log-symbols@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +log-symbols@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + dependencies: + chalk "^2.4.2" + +looper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" + +looper@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/looper/-/looper-3.0.0.tgz#2efa54c3b1cbaba9b94aee2e5914b0be57fbb749" + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + +lru-cache@5.1.1, lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + dependencies: + yallist "^3.0.2" + +lru-cache@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" + dependencies: + pseudomap "^1.0.1" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + dependencies: + yallist "^4.0.0" + +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + +ltgt@^2.1.2, ltgt@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + +ltgt@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +mcl-wasm@^0.7.1: + version "0.7.6" + resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.6.tgz#c1789ebda5565d49b77d2ee195ff3e4d282f1554" + integrity sha512-cbRl3sUOkBeRY2hsM4t1EIln2TIdQBkSiTOqNTv/4Hu5KOECnMWCgjIf+a9Ebunyn22VKqkMF3zj6ejRzz7YBw== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +memdown@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" + dependencies: + abstract-leveldown "~2.7.1" + functional-red-black-tree "^1.0.1" + immediate "^3.2.3" + inherits "~2.0.1" + ltgt "~2.2.0" + safe-buffer "~5.1.1" + +memdown@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb" + integrity sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw== + dependencies: + abstract-leveldown "~6.2.1" + functional-red-black-tree "~1.0.1" + immediate "~3.2.3" + inherits "~2.0.1" + ltgt "~2.2.0" + safe-buffer "~5.2.0" + +memdown@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/memdown/-/memdown-3.0.0.tgz#93aca055d743b20efc37492e9e399784f2958309" + dependencies: + abstract-leveldown "~5.0.0" + functional-red-black-tree "~1.0.1" + immediate "~3.2.3" + inherits "~2.0.1" + ltgt "~2.2.0" + safe-buffer "~5.1.1" + +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + +merkle-patricia-tree@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-3.0.0.tgz#448d85415565df72febc33ca362b8b614f5a58f8" + dependencies: + async "^2.6.1" + ethereumjs-util "^5.2.0" + level-mem "^3.0.1" + level-ws "^1.0.0" + readable-stream "^3.0.6" + rlp "^2.0.0" + semaphore ">=1.0.1" + +merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" + dependencies: + async "^1.4.2" + ethereumjs-util "^5.0.0" + level-ws "0.0.0" + levelup "^1.2.1" + memdown "^1.0.0" + readable-stream "^2.0.0" + rlp "^2.0.0" + semaphore ">=1.0.1" + +merkle-patricia-tree@^4.2.0, merkle-patricia-tree@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-4.2.2.tgz#6dec17855370172458244c2f42c989dd60b773a3" + integrity sha512-eqZYNTshcYx9aESkSPr71EqwsR/QmpnObDEV4iLxkt/x/IoLYZYjJvKY72voP/27Vy61iMOrfOG6jrn7ttXD+Q== + dependencies: + "@types/levelup" "^4.3.0" + ethereumjs-util "^7.1.2" + level-mem "^5.0.1" + level-ws "^2.0.0" + readable-stream "^3.6.0" + rlp "^2.2.4" + semaphore-async-await "^1.5.1" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + dependencies: + mime-db "1.44.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + dependencies: + minipass "^2.9.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + dependencies: + mkdirp "*" + +mkdirp@*: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + +mkdirp@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" + dependencies: + minimist "^1.2.5" + +mkdirp@0.5.5, mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + dependencies: + minimist "^1.2.5" + +mnemonist@^0.38.0: + version "0.38.3" + resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.3.tgz#35ec79c1c1f4357cfda2fe264659c2775ccd7d9d" + integrity sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw== + dependencies: + obliterator "^1.6.1" + +mocha-chai-jest-snapshot@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/mocha-chai-jest-snapshot/-/mocha-chai-jest-snapshot-1.1.1.tgz#7e49f20d0c12e6792d7f7da2e4ee0c38950571cc" + dependencies: + "@jest/test-result" "^26.5.2" + chalk "^4.1.0" + find-package-json "^1.2.0" + jest-snapshot "^26.5.2" + jest-util "^26.5.2" + slash "^3.0.0" + yargs "^16.0.3" + +mocha@^6.2.2: + version "6.2.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.3.tgz#e648432181d8b99393410212664450a4c1e31912" + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "2.2.0" + minimatch "3.0.4" + mkdirp "0.5.4" + ms "2.1.1" + node-environment-flags "1.0.5" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "1.6.0" + +mocha@^7.1.2: + version "7.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + chokidar "3.3.0" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "3.0.0" + minimatch "3.0.4" + mkdirp "0.5.5" + ms "2.1.1" + node-environment-flags "1.0.6" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "1.6.0" + +mock-fs@^4.1.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.13.0.tgz#31c02263673ec3789f90eb7b6963676aa407a598" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + +multibase@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multibase@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multicodec@^0.5.5: + version "0.5.7" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" + dependencies: + varint "^5.0.0" + +multicodec@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" + dependencies: + buffer "^5.6.0" + varint "^5.0.0" + +multihashes@^0.4.15, multihashes@~0.4.15: + version "0.4.21" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + +node-environment-flags@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +node-environment-flags@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +node-fetch@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" + +node-fetch@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + +node-fetch@~1.7.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-gyp-build@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + +nofilter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e" + integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA== + +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + +normalize-url@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + +object-assign@^4, object-assign@^4.0.0, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.8.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" + +object-inspect@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + +object-is@^1.0.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.4.tgz#63d6c83c00a43f4cbc9434eb9757c8a5b8565068" + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.assign@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz#0dfda8d108074d9c563e80490c883b6661091544" + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +obliterator@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3" + integrity sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig== + +oboe@2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" + dependencies: + http-https "^1.0.0" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + dependencies: + p-limit "^2.2.0" + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-headers@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-json@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646" + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +patch-package@6.2.2, patch-package@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.2.2.tgz#71d170d650c65c26556f0d0fbbb48d92b6cc5f39" + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^2.4.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^1.2.1" + fs-extra "^7.0.1" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.0" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" + +path-browserify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pathval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + +pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +postinstall-postinstall@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" + +precond@0.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + dependencies: + fast-diff "^1.1.2" + +prettier-plugin-solidity@^1.0.0-beta.10: + version "1.0.0-beta.10" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.10.tgz#f2a249002733826b08d981b599335ddb7e93af8d" + integrity sha512-55UsEbeJfqYKB3RFR7Nvpi+ApEoUfgdKHVg2ZybrbOkRW4RTblyONLL3mEr8Vrxpo7wBbObVLbWodGg4YXIQ7g== + dependencies: + "@solidity-parser/parser" "^0.12.1" + dir-to-object "^2.0.0" + emoji-regex "^9.2.2" + escape-string-regexp "^4.0.0" + prettier "^2.2.1" + semver "^7.3.5" + solidity-comments-extractor "^0.0.7" + string-width "^4.2.2" + +prettier@^1.14.3: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + +prettier@^2.0.5, prettier@^2.1.2, prettier@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" + +pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +printj@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + +promise-to-callback@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" + dependencies: + is-fn "^1.0.0" + set-immediate-shim "^1.0.1" + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pull-cat@^1.1.9: + version "1.1.11" + resolved "https://registry.yarnpkg.com/pull-cat/-/pull-cat-1.1.11.tgz#b642dd1255da376a706b6db4fa962f5fdb74c31b" + +pull-defer@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/pull-defer/-/pull-defer-0.2.3.tgz#4ee09c6d9e227bede9938db80391c3dac489d113" + +pull-level@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pull-level/-/pull-level-2.0.4.tgz#4822e61757c10bdcc7cf4a03af04c92734c9afac" + dependencies: + level-post "^1.0.7" + pull-cat "^1.1.9" + pull-live "^1.0.1" + pull-pushable "^2.0.0" + pull-stream "^3.4.0" + pull-window "^2.1.4" + stream-to-pull-stream "^1.7.1" + +pull-live@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pull-live/-/pull-live-1.0.1.tgz#a4ecee01e330155e9124bbbcf4761f21b38f51f5" + dependencies: + pull-cat "^1.1.9" + pull-stream "^3.4.0" + +pull-pushable@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pull-pushable/-/pull-pushable-2.2.0.tgz#5f2f3aed47ad86919f01b12a2e99d6f1bd776581" + +pull-stream@^3.2.3, pull-stream@^3.4.0, pull-stream@^3.6.8: + version "3.6.14" + resolved "https://registry.yarnpkg.com/pull-stream/-/pull-stream-3.6.14.tgz#529dbd5b86131f4a5ed636fdf7f6af00781357ee" + +pull-window@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/pull-window/-/pull-window-2.1.4.tgz#fc3b86feebd1920c7ae297691e23f705f88552f0" + dependencies: + looper "^2.0.0" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + +qs@^6.7.0: + version "6.9.4" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +raw-body@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" + dependencies: + bytes "3.1.0" + http-errors "1.7.3" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-is@^17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +readable-stream@^1.0.33: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.1.0, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~1.0.15: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" + dependencies: + picomatch "^2.0.4" + +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + dependencies: + picomatch "^2.2.1" + +regenerate@^1.2.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@^2.79.0, request@^2.85.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" + +require-from-string@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.17.0, resolve@~1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + dependencies: + path-parse "^1.0.6" + +resolve@^1.10.0, resolve@^1.18.1, resolve@^1.8.1: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + dependencies: + glob "^7.1.3" + +rimraf@^2.2.8, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3, rlp@^2.2.4: + version "2.2.6" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.6.tgz#c80ba6266ac7a483ef1e69e8e2f056656de2fb2c" + dependencies: + bn.js "^4.11.1" + +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + +run-async@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + +rustbn.js@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" + +rxjs@^6.4.0: + version "6.6.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + +safe-event-emitter@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" + dependencies: + events "^3.0.0" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + +scryptsy@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" + dependencies: + pbkdf2 "^3.0.3" + +secp256k1@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.2.tgz#15dd57d0f0b9fdb54ac1fa1694f40e5e9a54f4a1" + dependencies: + elliptic "^6.5.2" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +seedrandom@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.1.tgz#eb3dde015bcf55df05a233514e5df44ef9dce083" + +semaphore-async-await@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz#857bef5e3644601ca4b9570b87e9df5ca12974fa" + integrity sha1-hXvvXjZEYBykuVcLh+nfXKEpdPo= + +semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + +semver@^7.3.2: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + dependencies: + lru-cache "^6.0.0" + +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +semver@~5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +solc@0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + follow-redirects "^1.12.1" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + +solc@^0.4.20: + version "0.4.26" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.26.tgz#5390a62a99f40806b86258c737c1cf653cc35cb5" + dependencies: + fs-extra "^0.30.0" + memorystream "^0.3.1" + require-from-string "^1.1.0" + semver "^5.3.0" + yargs "^4.7.1" + +solc@^0.6.3: + version "0.6.12" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.6.12.tgz#48ac854e0c729361b22a7483645077f58cba080e" + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + +solhint-plugin-prettier@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz#e3b22800ba435cd640a9eca805a7f8bc3e3e6a6b" + dependencies: + prettier-linter-helpers "^1.0.0" + +solhint@^3.2.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.3.2.tgz#ebd7270bb50fd378b427d7a6fc9f2a7fd00216c0" + dependencies: + "@solidity-parser/parser" "^0.8.2" + ajv "^6.6.1" + antlr4 "4.7.1" + ast-parents "0.0.1" + chalk "^2.4.2" + commander "2.18.0" + cosmiconfig "^5.0.7" + eslint "^5.6.0" + fast-diff "^1.1.2" + glob "^7.1.3" + ignore "^4.0.6" + js-yaml "^3.12.0" + lodash "^4.17.11" + semver "^6.3.0" + optionalDependencies: + prettier "^1.14.3" + +solidity-comments-extractor@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" + integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@0.5.12: + version "0.5.12" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-support@^0.5.13, source-map-support@^0.5.17: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.7" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stack-utils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277" + dependencies: + escape-string-regexp "^2.0.0" + +stacktrace-parser@^0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + dependencies: + type-fest "^0.7.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +stream-to-pull-stream@^1.7.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz#4161aa2d2eb9964de60bfa1af7feaf917e874ece" + dependencies: + looper "^3.0.0" + pull-stream "^3.2.3" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string-width@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trim@~1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.3.tgz#d23a22fde01c1e6571a7fadcb9be11decd8061a7" + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + +string.prototype.trimend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + dependencies: + ansi-regex "^5.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@2.0.1, strip-json-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + dependencies: + has-flag "^4.0.0" + +swarm-js@^0.1.40: + version "0.1.40" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request "^1.0.1" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tape@^4.6.3: + version "4.13.3" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.13.3.tgz#51b3d91c83668c7a45b1a594b607dee0a0b46278" + dependencies: + deep-equal "~1.1.1" + defined "~1.0.0" + dotignore "~0.1.2" + for-each "~0.3.3" + function-bind "~1.1.1" + glob "~7.1.6" + has "~1.0.3" + inherits "~2.0.4" + is-regex "~1.0.5" + minimist "~1.2.5" + object-inspect "~1.7.0" + resolve "~1.17.0" + resumer "~0.0.0" + string.prototype.trim "~1.2.1" + through "~2.3.8" + +tar@^4.0.2: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +test-value@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/test-value/-/test-value-2.1.0.tgz#11da6ff670f3471a73b625ca4f3fdcf7bb748291" + dependencies: + array-back "^1.0.3" + typical "^2.6.0" + +testrpc@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/testrpc/-/testrpc-0.0.1.tgz#83e2195b1f5873aec7be1af8cbe6dcf39edb7aed" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.6, through@~2.3.4, through@~2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +tmp@0.0.33, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +tmp@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" + dependencies: + rimraf "^2.6.3" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +"true-case-path@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-2.2.1.tgz#c5bf04a5bbec3fd118be4084461b3a27c4d796bf" + +ts-essentials@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a" + +ts-essentials@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.1.tgz#d205508cae0cdadfb73c89503140cf2228389e2d" + +ts-generator@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ts-generator/-/ts-generator-0.1.1.tgz#af46f2fb88a6db1f9785977e9590e7bcd79220ab" + dependencies: + "@types/mkdirp" "^0.5.2" + "@types/prettier" "^2.1.1" + "@types/resolve" "^0.0.8" + chalk "^2.4.1" + glob "^7.1.2" + mkdirp "^0.5.1" + prettier "^2.1.2" + resolve "^1.8.1" + ts-essentials "^1.0.0" + +ts-node@^8.5.4: + version "8.10.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + +tslib@^1.9.0, tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + +tsort@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl-util@^0.15.0: + version "0.15.1" + resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +tweetnacl@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + +type@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f" + +typechain@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-4.0.1.tgz#b40eaf5ede15588d97a4b9a5f85120f7ea1cf262" + dependencies: + command-line-args "^4.0.7" + debug "^4.1.1" + fs-extra "^7.0.0" + js-sha3 "^0.8.0" + lodash "^4.17.15" + ts-essentials "^7.0.1" + ts-generator "^0.1.1" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +typescript@^3.7.3: + version "3.9.7" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" + +typewise-core@^1.2, typewise-core@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/typewise-core/-/typewise-core-1.2.0.tgz#97eb91805c7f55d2f941748fa50d315d991ef195" + +typewise@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typewise/-/typewise-1.0.3.tgz#1067936540af97937cc5dcf9922486e9fa284651" + dependencies: + typewise-core "^1.2.0" + +typewiselite@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typewiselite/-/typewiselite-1.0.0.tgz#c8882fa1bb1092c06005a97f34ef5c8508e3664e" + +typical@^2.6.0, typical@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + +underscore@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + +unorm@^1.3.3: + version "1.6.0" + resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +uri-js@^4.2.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + dependencies: + prepend-http "^2.0.0" + +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +utf-8-validate@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.3.tgz#3b64e418ad2ff829809025fdfef595eab2f03a27" + dependencies: + node-gyp-build "^4.2.0" + +utf8@3.0.0, utf8@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util.promisify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +varint@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +walker@^1.0.7, walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +web3-bzz@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.11.tgz#41bc19a77444bd5365744596d778b811880f707f" + dependencies: + "@types/node" "^12.12.6" + got "9.6.0" + swarm-js "^0.1.40" + underscore "1.9.1" + +web3-core-helpers@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.11.tgz#84c681ed0b942c0203f3b324a245a127e8c67a99" + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.11" + web3-utils "1.2.11" + +web3-core-method@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.11.tgz#f880137d1507a0124912bf052534f168b8d8fbb6" + dependencies: + "@ethersproject/transactions" "^5.0.0-beta.135" + underscore "1.9.1" + web3-core-helpers "1.2.11" + web3-core-promievent "1.2.11" + web3-core-subscriptions "1.2.11" + web3-utils "1.2.11" + +web3-core-promievent@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.11.tgz#51fe97ca0ddec2f99bf8c3306a7a8e4b094ea3cf" + dependencies: + eventemitter3 "4.0.4" + +web3-core-requestmanager@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.11.tgz#fe6eb603fbaee18530293a91f8cf26d8ae28c45a" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.11" + web3-providers-http "1.2.11" + web3-providers-ipc "1.2.11" + web3-providers-ws "1.2.11" + +web3-core-subscriptions@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.11.tgz#beca908fbfcb050c16f45f3f0f4c205e8505accd" + dependencies: + eventemitter3 "4.0.4" + underscore "1.9.1" + web3-core-helpers "1.2.11" + +web3-core@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.11.tgz#1043cacc1becb80638453cc5b2a14be9050288a7" + dependencies: + "@types/bn.js" "^4.11.5" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-core-requestmanager "1.2.11" + web3-utils "1.2.11" + +web3-eth-abi@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.11.tgz#a887494e5d447c2926d557a3834edd66e17af9b0" + dependencies: + "@ethersproject/abi" "5.0.0-beta.153" + underscore "1.9.1" + web3-utils "1.2.11" + +web3-eth-accounts@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.11.tgz#a9e3044da442d31903a7ce035a86d8fa33f90520" + dependencies: + crypto-browserify "3.12.0" + eth-lib "0.2.8" + ethereumjs-common "^1.3.2" + ethereumjs-tx "^2.1.1" + scrypt-js "^3.0.1" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-utils "1.2.11" + +web3-eth-contract@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.11.tgz#917065902bc27ce89da9a1da26e62ef663663b90" + dependencies: + "@types/bn.js" "^4.11.5" + underscore "1.9.1" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-core-promievent "1.2.11" + web3-core-subscriptions "1.2.11" + web3-eth-abi "1.2.11" + web3-utils "1.2.11" + +web3-eth-ens@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.11.tgz#26d4d7f16d6cbcfff918e39832b939edc3162532" + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-promievent "1.2.11" + web3-eth-abi "1.2.11" + web3-eth-contract "1.2.11" + web3-utils "1.2.11" + +web3-eth-iban@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.11.tgz#f5f73298305bc7392e2f188bf38a7362b42144ef" + dependencies: + bn.js "^4.11.9" + web3-utils "1.2.11" + +web3-eth-personal@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.11.tgz#a38b3942a1d87a62070ce0622a941553c3d5aa70" + dependencies: + "@types/node" "^12.12.6" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-net "1.2.11" + web3-utils "1.2.11" + +web3-eth@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.11.tgz#4c81fcb6285b8caf544058fba3ae802968fdc793" + dependencies: + underscore "1.9.1" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-core-subscriptions "1.2.11" + web3-eth-abi "1.2.11" + web3-eth-accounts "1.2.11" + web3-eth-contract "1.2.11" + web3-eth-ens "1.2.11" + web3-eth-iban "1.2.11" + web3-eth-personal "1.2.11" + web3-net "1.2.11" + web3-utils "1.2.11" + +web3-net@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.11.tgz#eda68ef25e5cdb64c96c39085cdb74669aabbe1b" + dependencies: + web3-core "1.2.11" + web3-core-method "1.2.11" + web3-utils "1.2.11" + +web3-provider-engine@14.2.1: + version "14.2.1" + resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.2.1.tgz#ef351578797bf170e08d529cb5b02f8751329b95" + dependencies: + async "^2.5.0" + backoff "^2.5.0" + clone "^2.0.0" + cross-fetch "^2.1.0" + eth-block-tracker "^3.0.0" + eth-json-rpc-infura "^3.1.0" + eth-sig-util "^1.4.2" + ethereumjs-block "^1.2.2" + ethereumjs-tx "^1.2.0" + ethereumjs-util "^5.1.5" + ethereumjs-vm "^2.3.4" + json-rpc-error "^2.0.0" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + readable-stream "^2.2.9" + request "^2.85.0" + semaphore "^1.0.3" + ws "^5.1.1" + xhr "^2.2.0" + xtend "^4.0.1" + +web3-providers-http@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.11.tgz#1cd03442c61670572d40e4dcdf1faff8bd91e7c6" + dependencies: + web3-core-helpers "1.2.11" + xhr2-cookies "1.1.0" + +web3-providers-ipc@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.11.tgz#d16d6c9be1be6e0b4f4536c4acc16b0f4f27ef21" + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.11" + +web3-providers-ws@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.11.tgz#a1dfd6d9778d840561d9ec13dd453046451a96bb" + dependencies: + eventemitter3 "4.0.4" + underscore "1.9.1" + web3-core-helpers "1.2.11" + websocket "^1.0.31" + +web3-shh@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.11.tgz#f5d086f9621c9a47e98d438010385b5f059fd88f" + dependencies: + web3-core "1.2.11" + web3-core-method "1.2.11" + web3-core-subscriptions "1.2.11" + web3-net "1.2.11" + +web3-utils@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.11.tgz#af1942aead3fb166ae851a985bed8ef2c2d95a82" + dependencies: + bn.js "^4.11.9" + eth-lib "0.2.8" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + underscore "1.9.1" + utf8 "3.0.0" + +web3-utils@^1.0.0-beta.31: + version "1.3.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.3.1.tgz#9aa880dd8c9463fe5c099107889f86a085370c2e" + dependencies: + bn.js "^4.11.9" + eth-lib "0.2.8" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + underscore "1.9.1" + utf8 "3.0.0" + +web3@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.11.tgz#50f458b2e8b11aa37302071c170ed61cff332975" + dependencies: + web3-bzz "1.2.11" + web3-core "1.2.11" + web3-eth "1.2.11" + web3-eth-personal "1.2.11" + web3-net "1.2.11" + web3-shh "1.2.11" + web3-utils "1.2.11" + +websocket@1.0.32: + version "1.0.32" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.32.tgz#1f16ddab3a21a2d929dec1687ab21cfdc6d3dbb1" + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +websocket@^1.0.31: + version "1.0.33" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.33.tgz#407f763fc58e74a3fa41ca3ae5d78d3f5e3b82a5" + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +whatwg-fetch@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@1.3.1, which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + dependencies: + mkdirp "^0.5.1" + +ws@7.2.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" + +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +ws@^5.1.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + dependencies: + async-limiter "~1.0.0" + +ws@^7.4.6: + version "7.5.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + +xhr-request-promise@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" + dependencies: + xhr-request "^1.1.0" + +xhr-request@^1.0.1, xhr-request@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + dependencies: + cookiejar "^2.1.1" + +xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: + version "2.6.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" + dependencies: + global "~4.4.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + +xtend@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + dependencies: + object-keys "~0.4.0" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +y18n@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" + +y18n@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + +yargs-parser@13.1.2, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.0.6" + +yargs-parser@^20.2.2: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + +yargs-unparser@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.3.2, yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yargs@^16.0.3: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^4.7.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.0.3" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.1" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^2.4.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From c04744d0c8646dc09c23ae6b660ddcb15060a2c6 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Mon, 28 Oct 2024 10:06:53 +0100 Subject: [PATCH 11/19] Adds Swap on registration so ETH goes and swaps for RGCVII tokens --- lib/swap-router-contracts/.gitattributes | 1 - .../.github/workflows/lint.yml | 33 - .../.github/workflows/release.yml | 45 - .../.github/workflows/tests.yml | 41 - lib/swap-router-contracts/.gitignore | 7 - lib/swap-router-contracts/.prettierignore | 1 - lib/swap-router-contracts/.prettierrc | 5 - lib/swap-router-contracts/.solhint.json | 6 - lib/swap-router-contracts/.yarnrc | 1 - lib/swap-router-contracts/LICENSE | 339 - lib/swap-router-contracts/README.md | 65 - lib/swap-router-contracts/bug-bounty.md | 80 - .../contracts/SwapRouter02.sol | 22 - .../contracts/V2SwapRouter.sol | 94 - .../contracts/V3SwapRouter.sol | 238 - .../contracts/base/ApproveAndCall.sol | 126 - .../contracts/base/ImmutableState.sol | 18 - .../contracts/base/MulticallExtended.sol | 34 - .../contracts/base/OracleSlippage.sol | 171 - .../base/PeripheryPaymentsExtended.sol | 29 - .../base/PeripheryPaymentsWithFeeExtended.sol | 32 - .../base/PeripheryValidationExtended.sol | 11 - .../contracts/interfaces/IApproveAndCall.sol | 63 - .../contracts/interfaces/IImmutableState.sol | 12 - .../interfaces/IMixedRouteQuoterV1.sol | 72 - .../interfaces/IMulticallExtended.sol | 26 - .../contracts/interfaces/IOracleSlippage.sol | 31 - .../interfaces/IPeripheryPaymentsExtended.sol | 29 - .../IPeripheryPaymentsWithFeeExtended.sol | 29 - .../contracts/interfaces/IQuoter.sol | 51 - .../contracts/interfaces/IQuoterV2.sol | 98 - .../contracts/interfaces/ISwapRouter02.sol | 15 - .../contracts/interfaces/ITokenValidator.sol | 50 - .../contracts/interfaces/IV2SwapRouter.sol | 35 - .../contracts/interfaces/IV3SwapRouter.sol | 69 - .../contracts/interfaces/IWETH.sol | 10 - .../contracts/lens/MixedRouteQuoterV1.sol | 237 - .../contracts/lens/Quoter.sol | 170 - .../contracts/lens/QuoterV2.sol | 273 - .../contracts/lens/README.md | 4 - .../contracts/lens/TokenValidator.sol | 159 - .../contracts/libraries/Constants.sol | 15 - .../contracts/libraries/PoolTicksCounter.sol | 96 - .../contracts/libraries/UniswapV2Library.sol | 90 - .../contracts/test/ImmutableStateTest.sol | 8 - .../contracts/test/MockObservations.sol | 77 - .../contracts/test/MockTimeSwapRouter.sol | 24 - .../contracts/test/OracleSlippageTest.sol | 62 - .../contracts/test/PoolTicksCounterTest.sol | 18 - .../contracts/test/TestERC20.sol | 10 - .../contracts/test/TestMulticallExtended.sol | 26 - .../contracts/test/TestUniswapV3Callee.sol | 62 - lib/swap-router-contracts/hardhat.config.ts | 70 - lib/swap-router-contracts/package.json | 68 - .../test/ApproveAndCall.spec.ts | 388 - .../test/ImmutableState.spec.ts | 58 - .../test/MixedRouteQuoterV1.integ.ts | 184 - .../test/MixedRouteQuoterV1.spec.ts | 460 - .../test/MulticallExtended.spec.ts | 50 - .../test/OracleSlippage.spec.ts | 447 - .../test/PeripheryPaymentsExtended.spec.ts | 50 - .../test/PoolTicksCounter.spec.ts | 280 - lib/swap-router-contracts/test/Quoter.spec.ts | 201 - .../test/QuoterV2.spec.ts | 578 -- .../test/SwapRouter.gas.spec.ts | 470 - .../test/SwapRouter.spec.ts | 1623 ---- .../test/TokenValidator.spec.ts | 158 - .../__snapshots__/ImmutableState.spec.ts.snap | 3 - .../MixedRouteQuoterV1.spec.ts.snap | 27 - .../test/__snapshots__/Multicall.spec.ts.snap | 5 - .../test/__snapshots__/Path.spec.ts.snap | 3 - .../__snapshots__/PoolAddress.spec.ts.snap | 5 - .../test/__snapshots__/QuoterV2.spec.ts.snap | 51 - .../__snapshots__/SwapRouter.gas.spec.ts.snap | 37 - .../__snapshots__/SwapRouter.spec.ts.snap | 3 - .../test/contracts/WETH9.json | 156 - .../test/shared/completeFixture.ts | 36 - .../test/shared/computePoolAddress.ts | 22 - .../test/shared/constants.ts | 21 - .../test/shared/encodePriceSqrt.ts | 16 - .../test/shared/expandTo18Decimals.ts | 9 - .../test/shared/expect.ts | 8 - .../test/shared/externalFixtures.ts | 76 - lib/swap-router-contracts/test/shared/path.ts | 61 - .../test/shared/quoter.ts | 160 - .../test/shared/snapshotGasCost.ts | 27 - .../test/shared/ticks.ts | 2 - lib/swap-router-contracts/tsconfig.json | 14 - lib/swap-router-contracts/yarn.lock | 8128 ----------------- remappings.txt | 2 - src/Constants.sol | 2 +- src/RaidGeld.sol | 64 +- test/RaidGeld.t.sol | 50 +- 93 files changed, 62 insertions(+), 17331 deletions(-) delete mode 100644 lib/swap-router-contracts/.gitattributes delete mode 100644 lib/swap-router-contracts/.github/workflows/lint.yml delete mode 100644 lib/swap-router-contracts/.github/workflows/release.yml delete mode 100644 lib/swap-router-contracts/.github/workflows/tests.yml delete mode 100644 lib/swap-router-contracts/.gitignore delete mode 100644 lib/swap-router-contracts/.prettierignore delete mode 100644 lib/swap-router-contracts/.prettierrc delete mode 100644 lib/swap-router-contracts/.solhint.json delete mode 100644 lib/swap-router-contracts/.yarnrc delete mode 100644 lib/swap-router-contracts/LICENSE delete mode 100644 lib/swap-router-contracts/README.md delete mode 100644 lib/swap-router-contracts/bug-bounty.md delete mode 100644 lib/swap-router-contracts/contracts/SwapRouter02.sol delete mode 100644 lib/swap-router-contracts/contracts/V2SwapRouter.sol delete mode 100644 lib/swap-router-contracts/contracts/V3SwapRouter.sol delete mode 100644 lib/swap-router-contracts/contracts/base/ApproveAndCall.sol delete mode 100644 lib/swap-router-contracts/contracts/base/ImmutableState.sol delete mode 100644 lib/swap-router-contracts/contracts/base/MulticallExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/base/OracleSlippage.sol delete mode 100644 lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IQuoter.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol delete mode 100644 lib/swap-router-contracts/contracts/interfaces/IWETH.sol delete mode 100644 lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol delete mode 100644 lib/swap-router-contracts/contracts/lens/Quoter.sol delete mode 100644 lib/swap-router-contracts/contracts/lens/QuoterV2.sol delete mode 100644 lib/swap-router-contracts/contracts/lens/README.md delete mode 100644 lib/swap-router-contracts/contracts/lens/TokenValidator.sol delete mode 100644 lib/swap-router-contracts/contracts/libraries/Constants.sol delete mode 100644 lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol delete mode 100644 lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol delete mode 100644 lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol delete mode 100644 lib/swap-router-contracts/contracts/test/MockObservations.sol delete mode 100644 lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol delete mode 100644 lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol delete mode 100644 lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol delete mode 100644 lib/swap-router-contracts/contracts/test/TestERC20.sol delete mode 100644 lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol delete mode 100644 lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol delete mode 100644 lib/swap-router-contracts/hardhat.config.ts delete mode 100644 lib/swap-router-contracts/package.json delete mode 100644 lib/swap-router-contracts/test/ApproveAndCall.spec.ts delete mode 100644 lib/swap-router-contracts/test/ImmutableState.spec.ts delete mode 100644 lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts delete mode 100644 lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts delete mode 100644 lib/swap-router-contracts/test/MulticallExtended.spec.ts delete mode 100644 lib/swap-router-contracts/test/OracleSlippage.spec.ts delete mode 100644 lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts delete mode 100644 lib/swap-router-contracts/test/PoolTicksCounter.spec.ts delete mode 100644 lib/swap-router-contracts/test/Quoter.spec.ts delete mode 100644 lib/swap-router-contracts/test/QuoterV2.spec.ts delete mode 100644 lib/swap-router-contracts/test/SwapRouter.gas.spec.ts delete mode 100644 lib/swap-router-contracts/test/SwapRouter.spec.ts delete mode 100644 lib/swap-router-contracts/test/TokenValidator.spec.ts delete mode 100644 lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap delete mode 100644 lib/swap-router-contracts/test/contracts/WETH9.json delete mode 100644 lib/swap-router-contracts/test/shared/completeFixture.ts delete mode 100644 lib/swap-router-contracts/test/shared/computePoolAddress.ts delete mode 100644 lib/swap-router-contracts/test/shared/constants.ts delete mode 100644 lib/swap-router-contracts/test/shared/encodePriceSqrt.ts delete mode 100644 lib/swap-router-contracts/test/shared/expandTo18Decimals.ts delete mode 100644 lib/swap-router-contracts/test/shared/expect.ts delete mode 100644 lib/swap-router-contracts/test/shared/externalFixtures.ts delete mode 100644 lib/swap-router-contracts/test/shared/path.ts delete mode 100644 lib/swap-router-contracts/test/shared/quoter.ts delete mode 100644 lib/swap-router-contracts/test/shared/snapshotGasCost.ts delete mode 100644 lib/swap-router-contracts/test/shared/ticks.ts delete mode 100644 lib/swap-router-contracts/tsconfig.json delete mode 100644 lib/swap-router-contracts/yarn.lock diff --git a/lib/swap-router-contracts/.gitattributes b/lib/swap-router-contracts/.gitattributes deleted file mode 100644 index 7cc88f0..0000000 --- a/lib/swap-router-contracts/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.sol linguist-language=Solidity \ No newline at end of file diff --git a/lib/swap-router-contracts/.github/workflows/lint.yml b/lib/swap-router-contracts/.github/workflows/lint.yml deleted file mode 100644 index 2f78834..0000000 --- a/lib/swap-router-contracts/.github/workflows/lint.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Lint - -on: - push: - branches: - - main - pull_request: - -jobs: - run-linters: - name: Run linters - runs-on: ubuntu-latest - - steps: - - name: Check out Git repository - uses: actions/checkout@v2 - - - name: Set up node - uses: actions/setup-node@v1 - with: - node-version: 12.x - registry-url: https://registry.npmjs.org - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Run linters - uses: wearerequired/lint-action@a8497ddb33fb1205941fd40452ca9fff07e0770d - with: - github_token: ${{ secrets.github_token }} - prettier: true - auto_fix: true - prettier_extensions: 'css,html,js,json,jsx,md,sass,scss,ts,tsx,vue,yaml,yml,sol' diff --git a/lib/swap-router-contracts/.github/workflows/release.yml b/lib/swap-router-contracts/.github/workflows/release.yml deleted file mode 100644 index 238720e..0000000 --- a/lib/swap-router-contracts/.github/workflows/release.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Release - -on: workflow_dispatch # TODO set this on a deploy schedule - -jobs: - release: - name: Release - environment: - name: release - runs-on: - group: npm-deploy - steps: - - name: Load Secrets - uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0 - with: - # Export loaded secrets as environment variables - export-env: true - env: - OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} - NPM_TOKEN: op://npm-deploy/npm-runner-token/secret - - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: "true" - fetch-depth: 2 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 18 - registry-url: 'https://registry.npmjs.org' - # Defaults to the user or organization that owns the workflow file - scope: '@uniswap' - - - name: Setup CI - run: npm ci - - - name: Build - run: npm run build - - - name: Publish - run: npm publish - env: - NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }} diff --git a/lib/swap-router-contracts/.github/workflows/tests.yml b/lib/swap-router-contracts/.github/workflows/tests.yml deleted file mode 100644 index 3b969f7..0000000 --- a/lib/swap-router-contracts/.github/workflows/tests.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Tests - -on: - push: - branches: - - main - pull_request: - -jobs: - unit-tests: - name: Unit Tests - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 - with: - node-version: 12.x - registry-url: https://registry.npmjs.org - - - id: yarn-cache - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v1 - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - yarn- - - - name: Install dependencies - run: yarn install --frozen-lockfile - - # This is required separately from yarn test because it generates the typechain definitions - - name: Compile - run: yarn compile - - - name: Run unit tests - run: yarn test - env: # Or as an environment variable - ARCHIVE_RPC_URL: ${{ secrets.ARCHIVE_RPC_URL }} diff --git a/lib/swap-router-contracts/.gitignore b/lib/swap-router-contracts/.gitignore deleted file mode 100644 index bde9d13..0000000 --- a/lib/swap-router-contracts/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -artifacts/ -cache/ -crytic-export/ -node_modules/ -typechain/ -.env -.vscode \ No newline at end of file diff --git a/lib/swap-router-contracts/.prettierignore b/lib/swap-router-contracts/.prettierignore deleted file mode 100644 index 821c19d..0000000 --- a/lib/swap-router-contracts/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -.github \ No newline at end of file diff --git a/lib/swap-router-contracts/.prettierrc b/lib/swap-router-contracts/.prettierrc deleted file mode 100644 index 31ba22d..0000000 --- a/lib/swap-router-contracts/.prettierrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "semi": false, - "singleQuote": true, - "printWidth": 120 -} diff --git a/lib/swap-router-contracts/.solhint.json b/lib/swap-router-contracts/.solhint.json deleted file mode 100644 index 11b3647..0000000 --- a/lib/swap-router-contracts/.solhint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "plugins": ["prettier"], - "rules": { - "prettier/prettier": "error" - } -} diff --git a/lib/swap-router-contracts/.yarnrc b/lib/swap-router-contracts/.yarnrc deleted file mode 100644 index 5455c6c..0000000 --- a/lib/swap-router-contracts/.yarnrc +++ /dev/null @@ -1 +0,0 @@ -ignore-scripts true diff --git a/lib/swap-router-contracts/LICENSE b/lib/swap-router-contracts/LICENSE deleted file mode 100644 index ecbc059..0000000 --- a/lib/swap-router-contracts/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. \ No newline at end of file diff --git a/lib/swap-router-contracts/README.md b/lib/swap-router-contracts/README.md deleted file mode 100644 index 9260c3f..0000000 --- a/lib/swap-router-contracts/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Uniswap Swap Router - -[![Tests](https://github.com/Uniswap/swap-router-contracts/workflows/Tests/badge.svg)](https://github.com/Uniswap/swap-router-contracts/actions?query=workflow%3ATests) -[![Lint](https://github.com/Uniswap/swap-router-contracts/workflows/Lint/badge.svg)](https://github.com/Uniswap/swap-router-contracts/actions?query=workflow%3ALint) - -This repository contains smart contracts for swapping on the Uniswap V2 and V3 protocols. - -## Bug bounty - -This repository is subject to the Uniswap V3 bug bounty program, -per the terms defined [here](./bug-bounty.md). - -## Local deployment - -In order to deploy this code to a local testnet, you should install the npm package -`@uniswap/swap-router-contracts` -and import bytecode imported from artifacts located at -`@uniswap/swap-router-contracts/artifacts/contracts/*/*.json`. -For example: - -```typescript -import { - abi as SWAP_ROUTER_ABI, - bytecode as SWAP_ROUTER_BYTECODE, -} from '@uniswap/swap-router-contracts/artifacts/contracts/SwapRouter02.sol/SwapRouter02.json' - -// deploy the bytecode -``` - -This will ensure that you are testing against the same bytecode that is deployed to -mainnet and public testnets, and all Uniswap code will correctly interoperate with -your local deployment. - -## Using solidity interfaces - -The swap router contract interfaces are available for import into solidity smart contracts -via the npm artifact `@uniswap/swap-router-contracts`, e.g.: - -```solidity -import '@uniswap/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol'; - -contract MyContract { - ISwapRouter02 router; - - function doSomethingWithSwapRouter() { - // router.exactInput(...); - } -} - -``` - -## Tests - -Some tests use Hardhat mainnet forking and therefore require an archive node. -Either create a `.env` file in the workspace root containing: - -``` -ARCHIVE_RPC_URL='...' -``` - -Or set the variable when running tests: - -``` -export ARCHIVE_RPC_URL='...' && npm run test -``` diff --git a/lib/swap-router-contracts/bug-bounty.md b/lib/swap-router-contracts/bug-bounty.md deleted file mode 100644 index 7ac66d4..0000000 --- a/lib/swap-router-contracts/bug-bounty.md +++ /dev/null @@ -1,80 +0,0 @@ -# Uniswap V3 Bug Bounty - -## Overview - -Starting on September 16th, 2021, the [swap-router-contracts](https://github.com/Uniswap/swap-router-contracts) repository is -subject to the Uniswap V3 Bug Bounty (the “Program”) to incentivize responsible bug disclosure. - -We are limiting the scope of the Program to critical and high severity bugs, and are offering a reward of up to $500,000. Happy hunting! - -## Scope - -The scope of the Program is limited to bugs that result in the loss of user funds. - -The following are not within the scope of the Program: - -- Any contract located under [contracts/test](./contracts/test) or [contracts/lens](./contracts/lens). -- Bugs in any third party contract or platform. -- Vulnerabilities already reported and/or discovered in contracts built by third parties. -- Any already-reported bugs. - -Vulnerabilities contingent upon the occurrence of any of the following also are outside the scope of this Program: - -- Frontend bugs -- DDOS attacks -- Spamming -- Phishing -- Automated tools (Github Actions, AWS, etc.) -- Compromise or misuse of third party systems or services - -## Assumptions - -Uniswap V3 was developed with the following assumptions, and thus any bug must also adhere to the following assumptions -to be eligible for the bug bounty: - -- The total supply of any token does not exceed 2128 - 1, i.e. `type(uint128).max`. -- The `transfer` and `transferFrom` methods of any token strictly decrease the balance of the token sender by the transfer amount and increases the balance of token recipient by the transfer amount, i.e. fee on transfer tokens are excluded. -- The token balance of an address can only change due to a call to `transfer` by the sender or `transferFrom` by an approved address, i.e. rebase tokens and interest bearing tokens are excluded. - -## Rewards - -Rewards will be allocated based on the severity of the bug disclosed and will be evaluated and rewarded at the discretion of the Uniswap Labs team. -For critical bugs that lead to loss of user funds (more than 1% or user specified slippage tolerance), -rewards of up to $500,000 will be granted. Lower severity bugs will be rewarded at the discretion of the team. -In addition, all vulnerabilities disclosed prior to the mainnet launch date will be subject to receive higher rewards. - -## Disclosure - -Any vulnerability or bug discovered must be reported only to the following email: [security@uniswap.org](mailto:security@uniswap.org). - -The vulnerability must not be disclosed publicly or to any other person, entity or email address before Uniswap Labs has been notified, has fixed the issue, and has granted permission for public disclosure. In addition, disclosure must be made within 24 hours following discovery of the vulnerability. - -A detailed report of a vulnerability increases the likelihood of a reward and may increase the reward amount. Please provide as much information about the vulnerability as possible, including: - -- The conditions on which reproducing the bug is contingent. -- The steps needed to reproduce the bug or, preferably, a proof of concept. -- The potential implications of the vulnerability being abused. - -Anyone who reports a unique, previously-unreported vulnerability that results in a change to the code or a configuration change and who keeps such vulnerability confidential until it has been resolved by our engineers will be recognized publicly for their contribution if they so choose. - -## Eligibility - -To be eligible for a reward under this Program, you must: - -- Discover a previously unreported, non-public vulnerability that would result in a loss of and/or lock on any ERC-20 token on Uniswap V2 or V3 (but not on any third party platform) and that is within the scope of this Program. Vulnerabilities must be distinct from the issues covered in the Trail of Bits or ABDK audits. -- Be the first to disclose the unique vulnerability to [security@uniswap.org](mailto:security@uniswap.org), in compliance with the disclosure requirements above. If similar vulnerabilities are reported within the same 24 hour period, rewards will be split at the discretion of Uniswap Labs. -- Provide sufficient information to enable our engineers to reproduce and fix the vulnerability. -- Not engage in any unlawful conduct when disclosing the bug, including through threats, demands, or any other coercive tactics. -- Not exploit the vulnerability in any way, including through making it public or by obtaining a profit (other than a reward under this Program). -- Make a good faith effort to avoid privacy violations, destruction of data, interruption or degradation of Uniswap V2 or V3. -- Submit only one vulnerability per submission, unless you need to chain vulnerabilities to provide impact regarding any of the vulnerabilities. -- Not submit a vulnerability caused by an underlying issue that is the same as an issue on which a reward has been paid under this Program. -- Not be one of our current or former employees, vendors, or contractors or an employee of any of those vendors or contractors. -- Not be subject to US sanctions or reside in a US-embargoed country. -- Be at least 18 years of age or, if younger, submit your vulnerability with the consent of your parent or guardian. - -## Other Terms - -By submitting your report, you grant Uniswap Labs any and all rights, including intellectual property rights, needed to validate, mitigate, and disclose the vulnerability. All reward decisions, including eligibility for and amounts of the rewards and the manner in which such rewards will be paid, are made at our sole discretion. - -The terms and conditions of this Program may be altered at any time. diff --git a/lib/swap-router-contracts/contracts/SwapRouter02.sol b/lib/swap-router-contracts/contracts/SwapRouter02.sol deleted file mode 100644 index afef66f..0000000 --- a/lib/swap-router-contracts/contracts/SwapRouter02.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@uniswap/v3-periphery/contracts/base/SelfPermit.sol'; -import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; - -import './interfaces/ISwapRouter02.sol'; -import './V2SwapRouter.sol'; -import './V3SwapRouter.sol'; -import './base/ApproveAndCall.sol'; -import './base/MulticallExtended.sol'; - -/// @title Uniswap V2 and V3 Swap Router -contract SwapRouter02 is ISwapRouter02, V2SwapRouter, V3SwapRouter, ApproveAndCall, MulticallExtended, SelfPermit { - constructor( - address _factoryV2, - address factoryV3, - address _positionManager, - address _WETH9 - ) ImmutableState(_factoryV2, _positionManager) PeripheryImmutableState(factoryV3, _WETH9) {} -} diff --git a/lib/swap-router-contracts/contracts/V2SwapRouter.sol b/lib/swap-router-contracts/contracts/V2SwapRouter.sol deleted file mode 100644 index 5738bd5..0000000 --- a/lib/swap-router-contracts/contracts/V2SwapRouter.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol'; -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -import './interfaces/IV2SwapRouter.sol'; -import './base/ImmutableState.sol'; -import './base/PeripheryPaymentsWithFeeExtended.sol'; -import './libraries/Constants.sol'; -import './libraries/UniswapV2Library.sol'; - -/// @title Uniswap V2 Swap Router -/// @notice Router for stateless execution of swaps against Uniswap V2 -abstract contract V2SwapRouter is IV2SwapRouter, ImmutableState, PeripheryPaymentsWithFeeExtended { - using LowGasSafeMath for uint256; - - // supports fee-on-transfer tokens - // requires the initial amount to have already been sent to the first pair - function _swap(address[] memory path, address _to) private { - for (uint256 i; i < path.length - 1; i++) { - (address input, address output) = (path[i], path[i + 1]); - (address token0, ) = UniswapV2Library.sortTokens(input, output); - IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factoryV2, input, output)); - uint256 amountInput; - uint256 amountOutput; - // scope to avoid stack too deep errors - { - (uint256 reserve0, uint256 reserve1, ) = pair.getReserves(); - (uint256 reserveInput, uint256 reserveOutput) = - input == token0 ? (reserve0, reserve1) : (reserve1, reserve0); - amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput); - amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput); - } - (uint256 amount0Out, uint256 amount1Out) = - input == token0 ? (uint256(0), amountOutput) : (amountOutput, uint256(0)); - address to = i < path.length - 2 ? UniswapV2Library.pairFor(factoryV2, output, path[i + 2]) : _to; - pair.swap(amount0Out, amount1Out, to, new bytes(0)); - } - } - - /// @inheritdoc IV2SwapRouter - function swapExactTokensForTokens( - uint256 amountIn, - uint256 amountOutMin, - address[] calldata path, - address to - ) external payable override returns (uint256 amountOut) { - // use amountIn == Constants.CONTRACT_BALANCE as a flag to swap the entire balance of the contract - bool hasAlreadyPaid; - if (amountIn == Constants.CONTRACT_BALANCE) { - hasAlreadyPaid = true; - amountIn = IERC20(path[0]).balanceOf(address(this)); - } - - pay( - path[0], - hasAlreadyPaid ? address(this) : msg.sender, - UniswapV2Library.pairFor(factoryV2, path[0], path[1]), - amountIn - ); - - // find and replace to addresses - if (to == Constants.MSG_SENDER) to = msg.sender; - else if (to == Constants.ADDRESS_THIS) to = address(this); - - uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); - - _swap(path, to); - - amountOut = IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore); - require(amountOut >= amountOutMin, 'Too little received'); - } - - /// @inheritdoc IV2SwapRouter - function swapTokensForExactTokens( - uint256 amountOut, - uint256 amountInMax, - address[] calldata path, - address to - ) external payable override returns (uint256 amountIn) { - amountIn = UniswapV2Library.getAmountsIn(factoryV2, amountOut, path)[0]; - require(amountIn <= amountInMax, 'Too much requested'); - - pay(path[0], msg.sender, UniswapV2Library.pairFor(factoryV2, path[0], path[1]), amountIn); - - // find and replace to addresses - if (to == Constants.MSG_SENDER) to = msg.sender; - else if (to == Constants.ADDRESS_THIS) to = address(this); - - _swap(path, to); - } -} diff --git a/lib/swap-router-contracts/contracts/V3SwapRouter.sol b/lib/swap-router-contracts/contracts/V3SwapRouter.sol deleted file mode 100644 index 5ffc42a..0000000 --- a/lib/swap-router-contracts/contracts/V3SwapRouter.sol +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; -import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; -import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; -import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; -import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -import './interfaces/IV3SwapRouter.sol'; -import './base/PeripheryPaymentsWithFeeExtended.sol'; -import './base/OracleSlippage.sol'; -import './libraries/Constants.sol'; - -/// @title Uniswap V3 Swap Router -/// @notice Router for stateless execution of swaps against Uniswap V3 -abstract contract V3SwapRouter is IV3SwapRouter, PeripheryPaymentsWithFeeExtended, OracleSlippage { - using Path for bytes; - using SafeCast for uint256; - - /// @dev Used as the placeholder value for amountInCached, because the computed amount in for an exact output swap - /// can never actually be this value - uint256 private constant DEFAULT_AMOUNT_IN_CACHED = type(uint256).max; - - /// @dev Transient storage variable used for returning the computed amount in for an exact output swap. - uint256 private amountInCached = DEFAULT_AMOUNT_IN_CACHED; - - /// @dev Returns the pool for the given token pair and fee. The pool contract may or may not exist. - function getPool( - address tokenA, - address tokenB, - uint24 fee - ) private view returns (IUniswapV3Pool) { - return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); - } - - struct SwapCallbackData { - bytes path; - address payer; - } - - /// @inheritdoc IUniswapV3SwapCallback - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes calldata _data - ) external override { - require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported - SwapCallbackData memory data = abi.decode(_data, (SwapCallbackData)); - (address tokenIn, address tokenOut, uint24 fee) = data.path.decodeFirstPool(); - CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); - - (bool isExactInput, uint256 amountToPay) = - amount0Delta > 0 - ? (tokenIn < tokenOut, uint256(amount0Delta)) - : (tokenOut < tokenIn, uint256(amount1Delta)); - - if (isExactInput) { - pay(tokenIn, data.payer, msg.sender, amountToPay); - } else { - // either initiate the next swap or pay - if (data.path.hasMultiplePools()) { - data.path = data.path.skipToken(); - exactOutputInternal(amountToPay, msg.sender, 0, data); - } else { - amountInCached = amountToPay; - // note that because exact output swaps are executed in reverse order, tokenOut is actually tokenIn - pay(tokenOut, data.payer, msg.sender, amountToPay); - } - } - } - - /// @dev Performs a single exact input swap - function exactInputInternal( - uint256 amountIn, - address recipient, - uint160 sqrtPriceLimitX96, - SwapCallbackData memory data - ) private returns (uint256 amountOut) { - // find and replace recipient addresses - if (recipient == Constants.MSG_SENDER) recipient = msg.sender; - else if (recipient == Constants.ADDRESS_THIS) recipient = address(this); - - (address tokenIn, address tokenOut, uint24 fee) = data.path.decodeFirstPool(); - - bool zeroForOne = tokenIn < tokenOut; - - (int256 amount0, int256 amount1) = - getPool(tokenIn, tokenOut, fee).swap( - recipient, - zeroForOne, - amountIn.toInt256(), - sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) - : sqrtPriceLimitX96, - abi.encode(data) - ); - - return uint256(-(zeroForOne ? amount1 : amount0)); - } - - /// @inheritdoc IV3SwapRouter - function exactInputSingle(ExactInputSingleParams memory params) - external - payable - override - returns (uint256 amountOut) - { - // use amountIn == Constants.CONTRACT_BALANCE as a flag to swap the entire balance of the contract - bool hasAlreadyPaid; - if (params.amountIn == Constants.CONTRACT_BALANCE) { - hasAlreadyPaid = true; - params.amountIn = IERC20(params.tokenIn).balanceOf(address(this)); - } - - amountOut = exactInputInternal( - params.amountIn, - params.recipient, - params.sqrtPriceLimitX96, - SwapCallbackData({ - path: abi.encodePacked(params.tokenIn, params.fee, params.tokenOut), - payer: hasAlreadyPaid ? address(this) : msg.sender - }) - ); - require(amountOut >= params.amountOutMinimum, 'Too little received'); - } - - /// @inheritdoc IV3SwapRouter - function exactInput(ExactInputParams memory params) external payable override returns (uint256 amountOut) { - // use amountIn == Constants.CONTRACT_BALANCE as a flag to swap the entire balance of the contract - bool hasAlreadyPaid; - if (params.amountIn == Constants.CONTRACT_BALANCE) { - hasAlreadyPaid = true; - (address tokenIn, , ) = params.path.decodeFirstPool(); - params.amountIn = IERC20(tokenIn).balanceOf(address(this)); - } - - address payer = hasAlreadyPaid ? address(this) : msg.sender; - - while (true) { - bool hasMultiplePools = params.path.hasMultiplePools(); - - // the outputs of prior swaps become the inputs to subsequent ones - params.amountIn = exactInputInternal( - params.amountIn, - hasMultiplePools ? address(this) : params.recipient, // for intermediate swaps, this contract custodies - 0, - SwapCallbackData({ - path: params.path.getFirstPool(), // only the first pool in the path is necessary - payer: payer - }) - ); - - // decide whether to continue or terminate - if (hasMultiplePools) { - payer = address(this); - params.path = params.path.skipToken(); - } else { - amountOut = params.amountIn; - break; - } - } - - require(amountOut >= params.amountOutMinimum, 'Too little received'); - } - - /// @dev Performs a single exact output swap - function exactOutputInternal( - uint256 amountOut, - address recipient, - uint160 sqrtPriceLimitX96, - SwapCallbackData memory data - ) private returns (uint256 amountIn) { - // find and replace recipient addresses - if (recipient == Constants.MSG_SENDER) recipient = msg.sender; - else if (recipient == Constants.ADDRESS_THIS) recipient = address(this); - - (address tokenOut, address tokenIn, uint24 fee) = data.path.decodeFirstPool(); - - bool zeroForOne = tokenIn < tokenOut; - - (int256 amount0Delta, int256 amount1Delta) = - getPool(tokenIn, tokenOut, fee).swap( - recipient, - zeroForOne, - -amountOut.toInt256(), - sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) - : sqrtPriceLimitX96, - abi.encode(data) - ); - - uint256 amountOutReceived; - (amountIn, amountOutReceived) = zeroForOne - ? (uint256(amount0Delta), uint256(-amount1Delta)) - : (uint256(amount1Delta), uint256(-amount0Delta)); - // it's technically possible to not receive the full output amount, - // so if no price limit has been specified, require this possibility away - if (sqrtPriceLimitX96 == 0) require(amountOutReceived == amountOut); - } - - /// @inheritdoc IV3SwapRouter - function exactOutputSingle(ExactOutputSingleParams calldata params) - external - payable - override - returns (uint256 amountIn) - { - // avoid an SLOAD by using the swap return data - amountIn = exactOutputInternal( - params.amountOut, - params.recipient, - params.sqrtPriceLimitX96, - SwapCallbackData({path: abi.encodePacked(params.tokenOut, params.fee, params.tokenIn), payer: msg.sender}) - ); - - require(amountIn <= params.amountInMaximum, 'Too much requested'); - // has to be reset even though we don't use it in the single hop case - amountInCached = DEFAULT_AMOUNT_IN_CACHED; - } - - /// @inheritdoc IV3SwapRouter - function exactOutput(ExactOutputParams calldata params) external payable override returns (uint256 amountIn) { - exactOutputInternal( - params.amountOut, - params.recipient, - 0, - SwapCallbackData({path: params.path, payer: msg.sender}) - ); - - amountIn = amountInCached; - require(amountIn <= params.amountInMaximum, 'Too much requested'); - amountInCached = DEFAULT_AMOUNT_IN_CACHED; - } -} diff --git a/lib/swap-router-contracts/contracts/base/ApproveAndCall.sol b/lib/swap-router-contracts/contracts/base/ApproveAndCall.sol deleted file mode 100644 index fdb8859..0000000 --- a/lib/swap-router-contracts/contracts/base/ApproveAndCall.sol +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import '@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol'; - -import '../interfaces/IApproveAndCall.sol'; -import './ImmutableState.sol'; - -/// @title Approve and Call -/// @notice Allows callers to approve the Uniswap V3 position manager from this contract, -/// for any token, and then make calls into the position manager -abstract contract ApproveAndCall is IApproveAndCall, ImmutableState { - function tryApprove(address token, uint256 amount) private returns (bool) { - (bool success, bytes memory data) = - token.call(abi.encodeWithSelector(IERC20.approve.selector, positionManager, amount)); - return success && (data.length == 0 || abi.decode(data, (bool))); - } - - /// @inheritdoc IApproveAndCall - function getApprovalType(address token, uint256 amount) external override returns (ApprovalType) { - // check existing approval - if (IERC20(token).allowance(address(this), positionManager) >= amount) return ApprovalType.NOT_REQUIRED; - - // try type(uint256).max / type(uint256).max - 1 - if (tryApprove(token, type(uint256).max)) return ApprovalType.MAX; - if (tryApprove(token, type(uint256).max - 1)) return ApprovalType.MAX_MINUS_ONE; - - // set approval to 0 (must succeed) - require(tryApprove(token, 0)); - - // try type(uint256).max / type(uint256).max - 1 - if (tryApprove(token, type(uint256).max)) return ApprovalType.ZERO_THEN_MAX; - if (tryApprove(token, type(uint256).max - 1)) return ApprovalType.ZERO_THEN_MAX_MINUS_ONE; - - revert(); - } - - /// @inheritdoc IApproveAndCall - function approveMax(address token) external payable override { - require(tryApprove(token, type(uint256).max)); - } - - /// @inheritdoc IApproveAndCall - function approveMaxMinusOne(address token) external payable override { - require(tryApprove(token, type(uint256).max - 1)); - } - - /// @inheritdoc IApproveAndCall - function approveZeroThenMax(address token) external payable override { - require(tryApprove(token, 0)); - require(tryApprove(token, type(uint256).max)); - } - - /// @inheritdoc IApproveAndCall - function approveZeroThenMaxMinusOne(address token) external payable override { - require(tryApprove(token, 0)); - require(tryApprove(token, type(uint256).max - 1)); - } - - /// @inheritdoc IApproveAndCall - function callPositionManager(bytes memory data) public payable override returns (bytes memory result) { - bool success; - (success, result) = positionManager.call(data); - - if (!success) { - // Next 5 lines from https://ethereum.stackexchange.com/a/83577 - if (result.length < 68) revert(); - assembly { - result := add(result, 0x04) - } - revert(abi.decode(result, (string))); - } - } - - function balanceOf(address token) private view returns (uint256) { - return IERC20(token).balanceOf(address(this)); - } - - /// @inheritdoc IApproveAndCall - function mint(MintParams calldata params) external payable override returns (bytes memory result) { - return - callPositionManager( - abi.encodeWithSelector( - INonfungiblePositionManager.mint.selector, - INonfungiblePositionManager.MintParams({ - token0: params.token0, - token1: params.token1, - fee: params.fee, - tickLower: params.tickLower, - tickUpper: params.tickUpper, - amount0Desired: balanceOf(params.token0), - amount1Desired: balanceOf(params.token1), - amount0Min: params.amount0Min, - amount1Min: params.amount1Min, - recipient: params.recipient, - deadline: type(uint256).max // deadline should be checked via multicall - }) - ) - ); - } - - /// @inheritdoc IApproveAndCall - function increaseLiquidity(IncreaseLiquidityParams calldata params) - external - payable - override - returns (bytes memory result) - { - return - callPositionManager( - abi.encodeWithSelector( - INonfungiblePositionManager.increaseLiquidity.selector, - INonfungiblePositionManager.IncreaseLiquidityParams({ - tokenId: params.tokenId, - amount0Desired: balanceOf(params.token0), - amount1Desired: balanceOf(params.token1), - amount0Min: params.amount0Min, - amount1Min: params.amount1Min, - deadline: type(uint256).max // deadline should be checked via multicall - }) - ) - ); - } -} diff --git a/lib/swap-router-contracts/contracts/base/ImmutableState.sol b/lib/swap-router-contracts/contracts/base/ImmutableState.sol deleted file mode 100644 index 8ba7929..0000000 --- a/lib/swap-router-contracts/contracts/base/ImmutableState.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; - -import '../interfaces/IImmutableState.sol'; - -/// @title Immutable state -/// @notice Immutable state used by the swap router -abstract contract ImmutableState is IImmutableState { - /// @inheritdoc IImmutableState - address public immutable override factoryV2; - /// @inheritdoc IImmutableState - address public immutable override positionManager; - - constructor(address _factoryV2, address _positionManager) { - factoryV2 = _factoryV2; - positionManager = _positionManager; - } -} diff --git a/lib/swap-router-contracts/contracts/base/MulticallExtended.sol b/lib/swap-router-contracts/contracts/base/MulticallExtended.sol deleted file mode 100644 index fe32ef6..0000000 --- a/lib/swap-router-contracts/contracts/base/MulticallExtended.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@uniswap/v3-periphery/contracts/base/Multicall.sol'; - -import '../interfaces/IMulticallExtended.sol'; -import '../base/PeripheryValidationExtended.sol'; - -/// @title Multicall -/// @notice Enables calling multiple methods in a single call to the contract -abstract contract MulticallExtended is IMulticallExtended, Multicall, PeripheryValidationExtended { - /// @inheritdoc IMulticallExtended - function multicall(uint256 deadline, bytes[] calldata data) - external - payable - override - checkDeadline(deadline) - returns (bytes[] memory) - { - return multicall(data); - } - - /// @inheritdoc IMulticallExtended - function multicall(bytes32 previousBlockhash, bytes[] calldata data) - external - payable - override - checkPreviousBlockhash(previousBlockhash) - returns (bytes[] memory) - { - return multicall(data); - } -} diff --git a/lib/swap-router-contracts/contracts/base/OracleSlippage.sol b/lib/swap-router-contracts/contracts/base/OracleSlippage.sol deleted file mode 100644 index 4a1424b..0000000 --- a/lib/swap-router-contracts/contracts/base/OracleSlippage.sol +++ /dev/null @@ -1,171 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '../interfaces/IOracleSlippage.sol'; - -import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; -import '@uniswap/v3-periphery/contracts/base/BlockTimestamp.sol'; -import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; -import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; -import '@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol'; - -abstract contract OracleSlippage is IOracleSlippage, PeripheryImmutableState, BlockTimestamp { - using Path for bytes; - - /// @dev Returns the tick as of the beginning of the current block, and as of right now, for the given pool. - function getBlockStartingAndCurrentTick(IUniswapV3Pool pool) - internal - view - returns (int24 blockStartingTick, int24 currentTick) - { - uint16 observationIndex; - uint16 observationCardinality; - (, currentTick, observationIndex, observationCardinality, , , ) = pool.slot0(); - - // 2 observations are needed to reliably calculate the block starting tick - require(observationCardinality > 1, 'NEO'); - - // If the latest observation occurred in the past, then no tick-changing trades have happened in this block - // therefore the tick in `slot0` is the same as at the beginning of the current block. - // We don't need to check if this observation is initialized - it is guaranteed to be. - (uint32 observationTimestamp, int56 tickCumulative, , ) = pool.observations(observationIndex); - if (observationTimestamp != uint32(_blockTimestamp())) { - blockStartingTick = currentTick; - } else { - uint256 prevIndex = (uint256(observationIndex) + observationCardinality - 1) % observationCardinality; - (uint32 prevObservationTimestamp, int56 prevTickCumulative, , bool prevInitialized) = - pool.observations(prevIndex); - - require(prevInitialized, 'ONI'); - - uint32 delta = observationTimestamp - prevObservationTimestamp; - blockStartingTick = int24((tickCumulative - prevTickCumulative) / delta); - } - } - - /// @dev Virtual function to get pool addresses that can be overridden in tests. - function getPoolAddress( - address tokenA, - address tokenB, - uint24 fee - ) internal view virtual returns (IUniswapV3Pool pool) { - pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); - } - - /// @dev Returns the synthetic time-weighted average tick as of secondsAgo, as well as the current tick, - /// for the given path. Returned synthetic ticks always represent tokenOut/tokenIn prices, - /// meaning lower ticks are worse. - function getSyntheticTicks(bytes memory path, uint32 secondsAgo) - internal - view - returns (int256 syntheticAverageTick, int256 syntheticCurrentTick) - { - bool lowerTicksAreWorse; - - uint256 numPools = path.numPools(); - address previousTokenIn; - for (uint256 i = 0; i < numPools; i++) { - // this assumes the path is sorted in swap order - (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); - IUniswapV3Pool pool = getPoolAddress(tokenIn, tokenOut, fee); - - // get the average and current ticks for the current pool - int256 averageTick; - int256 currentTick; - if (secondsAgo == 0) { - // we optimize for the secondsAgo == 0 case, i.e. since the beginning of the block - (averageTick, currentTick) = getBlockStartingAndCurrentTick(pool); - } else { - (averageTick, ) = OracleLibrary.consult(address(pool), secondsAgo); - (, currentTick, , , , , ) = IUniswapV3Pool(pool).slot0(); - } - - if (i == numPools - 1) { - // if we're here, this is the last pool in the path, meaning tokenOut represents the - // destination token. so, if tokenIn < tokenOut, then tokenIn is token0 of the last pool, - // meaning the current running ticks are going to represent tokenOut/tokenIn prices. - // so, the lower these prices get, the worse of a price the swap will get - lowerTicksAreWorse = tokenIn < tokenOut; - } else { - // if we're here, we need to iterate over the next pool in the path - path = path.skipToken(); - previousTokenIn = tokenIn; - } - - // accumulate the ticks derived from the current pool into the running synthetic ticks, - // ensuring that intermediate tokens "cancel out" - bool add = (i == 0) || (previousTokenIn < tokenIn ? tokenIn < tokenOut : tokenOut < tokenIn); - if (add) { - syntheticAverageTick += averageTick; - syntheticCurrentTick += currentTick; - } else { - syntheticAverageTick -= averageTick; - syntheticCurrentTick -= currentTick; - } - } - - // flip the sign of the ticks if necessary, to ensure that the lower ticks are always worse - if (!lowerTicksAreWorse) { - syntheticAverageTick *= -1; - syntheticCurrentTick *= -1; - } - } - - /// @dev Cast a int256 to a int24, revert on overflow or underflow - function toInt24(int256 y) private pure returns (int24 z) { - require((z = int24(y)) == y); - } - - /// @dev For each passed path, fetches the synthetic time-weighted average tick as of secondsAgo, - /// as well as the current tick. Then, synthetic ticks from all paths are subjected to a weighted - /// average, where the weights are the fraction of the total input amount allocated to each path. - /// Returned synthetic ticks always represent tokenOut/tokenIn prices, meaning lower ticks are worse. - /// Paths must all start and end in the same token. - function getSyntheticTicks( - bytes[] memory paths, - uint128[] memory amounts, - uint32 secondsAgo - ) internal view returns (int256 averageSyntheticAverageTick, int256 averageSyntheticCurrentTick) { - require(paths.length == amounts.length); - - OracleLibrary.WeightedTickData[] memory weightedSyntheticAverageTicks = - new OracleLibrary.WeightedTickData[](paths.length); - OracleLibrary.WeightedTickData[] memory weightedSyntheticCurrentTicks = - new OracleLibrary.WeightedTickData[](paths.length); - - for (uint256 i = 0; i < paths.length; i++) { - (int256 syntheticAverageTick, int256 syntheticCurrentTick) = getSyntheticTicks(paths[i], secondsAgo); - weightedSyntheticAverageTicks[i].tick = toInt24(syntheticAverageTick); - weightedSyntheticCurrentTicks[i].tick = toInt24(syntheticCurrentTick); - weightedSyntheticAverageTicks[i].weight = amounts[i]; - weightedSyntheticCurrentTicks[i].weight = amounts[i]; - } - - averageSyntheticAverageTick = OracleLibrary.getWeightedArithmeticMeanTick(weightedSyntheticAverageTicks); - averageSyntheticCurrentTick = OracleLibrary.getWeightedArithmeticMeanTick(weightedSyntheticCurrentTicks); - } - - /// @inheritdoc IOracleSlippage - function checkOracleSlippage( - bytes memory path, - uint24 maximumTickDivergence, - uint32 secondsAgo - ) external view override { - (int256 syntheticAverageTick, int256 syntheticCurrentTick) = getSyntheticTicks(path, secondsAgo); - require(syntheticAverageTick - syntheticCurrentTick < maximumTickDivergence, 'TD'); - } - - /// @inheritdoc IOracleSlippage - function checkOracleSlippage( - bytes[] memory paths, - uint128[] memory amounts, - uint24 maximumTickDivergence, - uint32 secondsAgo - ) external view override { - (int256 averageSyntheticAverageTick, int256 averageSyntheticCurrentTick) = - getSyntheticTicks(paths, amounts, secondsAgo); - require(averageSyntheticAverageTick - averageSyntheticCurrentTick < maximumTickDivergence, 'TD'); - } -} diff --git a/lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol b/lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol deleted file mode 100644 index 08877ac..0000000 --- a/lib/swap-router-contracts/contracts/base/PeripheryPaymentsExtended.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; - -import '@uniswap/v3-periphery/contracts/base/PeripheryPayments.sol'; -import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol'; - -import '../interfaces/IPeripheryPaymentsExtended.sol'; - -abstract contract PeripheryPaymentsExtended is IPeripheryPaymentsExtended, PeripheryPayments { - /// @inheritdoc IPeripheryPaymentsExtended - function unwrapWETH9(uint256 amountMinimum) external payable override { - unwrapWETH9(amountMinimum, msg.sender); - } - - /// @inheritdoc IPeripheryPaymentsExtended - function wrapETH(uint256 value) external payable override { - IWETH9(WETH9).deposit{value: value}(); - } - - /// @inheritdoc IPeripheryPaymentsExtended - function sweepToken(address token, uint256 amountMinimum) external payable override { - sweepToken(token, amountMinimum, msg.sender); - } - - /// @inheritdoc IPeripheryPaymentsExtended - function pull(address token, uint256 value) external payable override { - TransferHelper.safeTransferFrom(token, msg.sender, address(this), value); - } -} diff --git a/lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol b/lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol deleted file mode 100644 index f4a9e42..0000000 --- a/lib/swap-router-contracts/contracts/base/PeripheryPaymentsWithFeeExtended.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; - -import '@uniswap/v3-periphery/contracts/base/PeripheryPaymentsWithFee.sol'; - -import '../interfaces/IPeripheryPaymentsWithFeeExtended.sol'; -import './PeripheryPaymentsExtended.sol'; - -abstract contract PeripheryPaymentsWithFeeExtended is - IPeripheryPaymentsWithFeeExtended, - PeripheryPaymentsExtended, - PeripheryPaymentsWithFee -{ - /// @inheritdoc IPeripheryPaymentsWithFeeExtended - function unwrapWETH9WithFee( - uint256 amountMinimum, - uint256 feeBips, - address feeRecipient - ) external payable override { - unwrapWETH9WithFee(amountMinimum, msg.sender, feeBips, feeRecipient); - } - - /// @inheritdoc IPeripheryPaymentsWithFeeExtended - function sweepTokenWithFee( - address token, - uint256 amountMinimum, - uint256 feeBips, - address feeRecipient - ) external payable override { - sweepTokenWithFee(token, amountMinimum, msg.sender, feeBips, feeRecipient); - } -} diff --git a/lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol b/lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol deleted file mode 100644 index 17afbf2..0000000 --- a/lib/swap-router-contracts/contracts/base/PeripheryValidationExtended.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; - -import '@uniswap/v3-periphery/contracts/base/PeripheryValidation.sol'; - -abstract contract PeripheryValidationExtended is PeripheryValidation { - modifier checkPreviousBlockhash(bytes32 previousBlockhash) { - require(blockhash(block.number - 1) == previousBlockhash, 'Blockhash'); - _; - } -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol b/lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol deleted file mode 100644 index 6e50dd0..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IApproveAndCall.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -interface IApproveAndCall { - enum ApprovalType {NOT_REQUIRED, MAX, MAX_MINUS_ONE, ZERO_THEN_MAX, ZERO_THEN_MAX_MINUS_ONE} - - /// @dev Lens to be called off-chain to determine which (if any) of the relevant approval functions should be called - /// @param token The token to approve - /// @param amount The amount to approve - /// @return The required approval type - function getApprovalType(address token, uint256 amount) external returns (ApprovalType); - - /// @notice Approves a token for the maximum possible amount - /// @param token The token to approve - function approveMax(address token) external payable; - - /// @notice Approves a token for the maximum possible amount minus one - /// @param token The token to approve - function approveMaxMinusOne(address token) external payable; - - /// @notice Approves a token for zero, then the maximum possible amount - /// @param token The token to approve - function approveZeroThenMax(address token) external payable; - - /// @notice Approves a token for zero, then the maximum possible amount minus one - /// @param token The token to approve - function approveZeroThenMaxMinusOne(address token) external payable; - - /// @notice Calls the position manager with arbitrary calldata - /// @param data Calldata to pass along to the position manager - /// @return result The result from the call - function callPositionManager(bytes memory data) external payable returns (bytes memory result); - - struct MintParams { - address token0; - address token1; - uint24 fee; - int24 tickLower; - int24 tickUpper; - uint256 amount0Min; - uint256 amount1Min; - address recipient; - } - - /// @notice Calls the position manager's mint function - /// @param params Calldata to pass along to the position manager - /// @return result The result from the call - function mint(MintParams calldata params) external payable returns (bytes memory result); - - struct IncreaseLiquidityParams { - address token0; - address token1; - uint256 tokenId; - uint256 amount0Min; - uint256 amount1Min; - } - - /// @notice Calls the position manager's increaseLiquidity function - /// @param params Calldata to pass along to the position manager - /// @return result The result from the call - function increaseLiquidity(IncreaseLiquidityParams calldata params) external payable returns (bytes memory result); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol b/lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol deleted file mode 100644 index 58120dd..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IImmutableState.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title Immutable state -/// @notice Functions that return immutable state of the router -interface IImmutableState { - /// @return Returns the address of the Uniswap V2 factory - function factoryV2() external view returns (address); - - /// @return Returns the address of Uniswap V3 NFT position manager - function positionManager() external view returns (address); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol b/lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol deleted file mode 100644 index 084f970..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IMixedRouteQuoterV1.sol +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -/// @title MixedRouteQuoterV1 Interface -/// @notice Supports quoting the calculated amounts for exact input swaps. Is specialized for routes containing a mix of V2 and V3 liquidity. -/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. -/// @dev These functions are not marked view because they rely on calling non-view functions and reverting -/// to compute the result. They are also not gas efficient and should not be called on-chain. -interface IMixedRouteQuoterV1 { - /// @notice Returns the amount out received for a given exact input swap without executing the swap - /// @param path The path of the swap, i.e. each token pair and the pool fee - /// @param amountIn The amount of the first token to swap - /// @return amountOut The amount of the last token that would be received - /// @return v3SqrtPriceX96AfterList List of the sqrt price after the swap for each v3 pool in the path, 0 for v2 pools - /// @return v3InitializedTicksCrossedList List of the initialized ticks that the swap crossed for each v3 pool in the path, 0 for v2 pools - /// @return v3SwapGasEstimate The estimate of the gas that the v3 swaps in the path consume - function quoteExactInput(bytes memory path, uint256 amountIn) - external - returns ( - uint256 amountOut, - uint160[] memory v3SqrtPriceX96AfterList, - uint32[] memory v3InitializedTicksCrossedList, - uint256 v3SwapGasEstimate - ); - - struct QuoteExactInputSingleV3Params { - address tokenIn; - address tokenOut; - uint256 amountIn; - uint24 fee; - uint160 sqrtPriceLimitX96; - } - - struct QuoteExactInputSingleV2Params { - address tokenIn; - address tokenOut; - uint256 amountIn; - } - - /// @notice Returns the amount out received for a given exact input but for a swap of a single pool - /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` - /// tokenIn The token being swapped in - /// tokenOut The token being swapped out - /// fee The fee of the token pool to consider for the pair - /// amountIn The desired input amount - /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountOut The amount of `tokenOut` that would be received - /// @return sqrtPriceX96After The sqrt price of the pool after the swap - /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed - /// @return gasEstimate The estimate of the gas that the swap consumes - function quoteExactInputSingleV3(QuoteExactInputSingleV3Params memory params) - external - returns ( - uint256 amountOut, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 gasEstimate - ); - - /// @notice Returns the amount out received for a given exact input but for a swap of a single V2 pool - /// @param params The params for the quote, encoded as `QuoteExactInputSingleV2Params` - /// tokenIn The token being swapped in - /// tokenOut The token being swapped out - /// amountIn The desired input amount - /// @return amountOut The amount of `tokenOut` that would be received - function quoteExactInputSingleV2(QuoteExactInputSingleV2Params memory params) external returns (uint256 amountOut); - - /// @dev ExactOutput swaps are not supported by this new Quoter which is specialized for supporting routes - /// crossing both V2 liquidity pairs and V3 pools. - /// @deprecated quoteExactOutputSingle and exactOutput. Use QuoterV2 instead. -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol b/lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol deleted file mode 100644 index 1e1a2c4..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IMulticallExtended.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -import '@uniswap/v3-periphery/contracts/interfaces/IMulticall.sol'; - -/// @title MulticallExtended interface -/// @notice Enables calling multiple methods in a single call to the contract with optional validation -interface IMulticallExtended is IMulticall { - /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed - /// @dev The `msg.value` should not be trusted for any method callable from multicall. - /// @param deadline The time by which this function must be called before failing - /// @param data The encoded function data for each of the calls to make to this contract - /// @return results The results from each of the calls passed in via data - function multicall(uint256 deadline, bytes[] calldata data) external payable returns (bytes[] memory results); - - /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed - /// @dev The `msg.value` should not be trusted for any method callable from multicall. - /// @param previousBlockhash The expected parent blockHash - /// @param data The encoded function data for each of the calls to make to this contract - /// @return results The results from each of the calls passed in via data - function multicall(bytes32 previousBlockhash, bytes[] calldata data) - external - payable - returns (bytes[] memory results); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol b/lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol deleted file mode 100644 index 734fb33..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IOracleSlippage.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -/// @title OracleSlippage interface -/// @notice Enables slippage checks against oracle prices -interface IOracleSlippage { - /// @notice Ensures that the current (synthetic) tick over the path is no worse than - /// `maximumTickDivergence` ticks away from the average as of `secondsAgo` - /// @param path The path to fetch prices over - /// @param maximumTickDivergence The maximum number of ticks that the price can degrade by - /// @param secondsAgo The number of seconds ago to compute oracle prices against - function checkOracleSlippage( - bytes memory path, - uint24 maximumTickDivergence, - uint32 secondsAgo - ) external view; - - /// @notice Ensures that the weighted average current (synthetic) tick over the path is no - /// worse than `maximumTickDivergence` ticks away from the average as of `secondsAgo` - /// @param paths The paths to fetch prices over - /// @param amounts The weights for each entry in `paths` - /// @param maximumTickDivergence The maximum number of ticks that the price can degrade by - /// @param secondsAgo The number of seconds ago to compute oracle prices against - function checkOracleSlippage( - bytes[] memory paths, - uint128[] memory amounts, - uint24 maximumTickDivergence, - uint32 secondsAgo - ) external view; -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol b/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol deleted file mode 100644 index 53c026b..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsExtended.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; - -import '@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol'; - -/// @title Periphery Payments Extended -/// @notice Functions to ease deposits and withdrawals of ETH and tokens -interface IPeripheryPaymentsExtended is IPeripheryPayments { - /// @notice Unwraps the contract's WETH9 balance and sends it to msg.sender as ETH. - /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. - /// @param amountMinimum The minimum amount of WETH9 to unwrap - function unwrapWETH9(uint256 amountMinimum) external payable; - - /// @notice Wraps the contract's ETH balance into WETH9 - /// @dev The resulting WETH9 is custodied by the router, thus will require further distribution - /// @param value The amount of ETH to wrap - function wrapETH(uint256 value) external payable; - - /// @notice Transfers the full amount of a token held by this contract to msg.sender - /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users - /// @param token The contract address of the token which will be transferred to msg.sender - /// @param amountMinimum The minimum amount of token required for a transfer - function sweepToken(address token, uint256 amountMinimum) external payable; - - /// @notice Transfers the specified amount of a token from the msg.sender to address(this) - /// @param token The token to pull - /// @param value The amount to pay - function pull(address token, uint256 value) external payable; -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol b/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol deleted file mode 100644 index fdbc461..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; - -import '@uniswap/v3-periphery/contracts/interfaces/IPeripheryPaymentsWithFee.sol'; - -import './IPeripheryPaymentsExtended.sol'; - -/// @title Periphery Payments With Fee Extended -/// @notice Functions to ease deposits and withdrawals of ETH -interface IPeripheryPaymentsWithFeeExtended is IPeripheryPaymentsExtended, IPeripheryPaymentsWithFee { - /// @notice Unwraps the contract's WETH9 balance and sends it to msg.sender as ETH, with a percentage between - /// 0 (exclusive), and 1 (inclusive) going to feeRecipient - /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. - function unwrapWETH9WithFee( - uint256 amountMinimum, - uint256 feeBips, - address feeRecipient - ) external payable; - - /// @notice Transfers the full amount of a token held by this contract to msg.sender, with a percentage between - /// 0 (exclusive) and 1 (inclusive) going to feeRecipient - /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users - function sweepTokenWithFee( - address token, - uint256 amountMinimum, - uint256 feeBips, - address feeRecipient - ) external payable; -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IQuoter.sol b/lib/swap-router-contracts/contracts/interfaces/IQuoter.sol deleted file mode 100644 index 3410e0c..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IQuoter.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -/// @title Quoter Interface -/// @notice Supports quoting the calculated amounts from exact input or exact output swaps -/// @dev These functions are not marked view because they rely on calling non-view functions and reverting -/// to compute the result. They are also not gas efficient and should not be called on-chain. -interface IQuoter { - /// @notice Returns the amount out received for a given exact input swap without executing the swap - /// @param path The path of the swap, i.e. each token pair and the pool fee - /// @param amountIn The amount of the first token to swap - /// @return amountOut The amount of the last token that would be received - function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut); - - /// @notice Returns the amount out received for a given exact input but for a swap of a single pool - /// @param tokenIn The token being swapped in - /// @param tokenOut The token being swapped out - /// @param fee The fee of the token pool to consider for the pair - /// @param amountIn The desired input amount - /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountOut The amount of `tokenOut` that would be received - function quoteExactInputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountIn, - uint160 sqrtPriceLimitX96 - ) external returns (uint256 amountOut); - - /// @notice Returns the amount in required for a given exact output swap without executing the swap - /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order - /// @param amountOut The amount of the last token to receive - /// @return amountIn The amount of first token required to be paid - function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn); - - /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool - /// @param tokenIn The token being swapped in - /// @param tokenOut The token being swapped out - /// @param fee The fee of the token pool to consider for the pair - /// @param amountOut The desired output amount - /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` - function quoteExactOutputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountOut, - uint160 sqrtPriceLimitX96 - ) external returns (uint256 amountIn); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol b/lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol deleted file mode 100644 index 3c2961b..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IQuoterV2.sol +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -/// @title QuoterV2 Interface -/// @notice Supports quoting the calculated amounts from exact input or exact output swaps. -/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. -/// @dev These functions are not marked view because they rely on calling non-view functions and reverting -/// to compute the result. They are also not gas efficient and should not be called on-chain. -interface IQuoterV2 { - /// @notice Returns the amount out received for a given exact input swap without executing the swap - /// @param path The path of the swap, i.e. each token pair and the pool fee - /// @param amountIn The amount of the first token to swap - /// @return amountOut The amount of the last token that would be received - /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path - /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path - /// @return gasEstimate The estimate of the gas that the swap consumes - function quoteExactInput(bytes memory path, uint256 amountIn) - external - returns ( - uint256 amountOut, - uint160[] memory sqrtPriceX96AfterList, - uint32[] memory initializedTicksCrossedList, - uint256 gasEstimate - ); - - struct QuoteExactInputSingleParams { - address tokenIn; - address tokenOut; - uint256 amountIn; - uint24 fee; - uint160 sqrtPriceLimitX96; - } - - /// @notice Returns the amount out received for a given exact input but for a swap of a single pool - /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` - /// tokenIn The token being swapped in - /// tokenOut The token being swapped out - /// fee The fee of the token pool to consider for the pair - /// amountIn The desired input amount - /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountOut The amount of `tokenOut` that would be received - /// @return sqrtPriceX96After The sqrt price of the pool after the swap - /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed - /// @return gasEstimate The estimate of the gas that the swap consumes - function quoteExactInputSingle(QuoteExactInputSingleParams memory params) - external - returns ( - uint256 amountOut, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 gasEstimate - ); - - /// @notice Returns the amount in required for a given exact output swap without executing the swap - /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order - /// @param amountOut The amount of the last token to receive - /// @return amountIn The amount of first token required to be paid - /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path - /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path - /// @return gasEstimate The estimate of the gas that the swap consumes - function quoteExactOutput(bytes memory path, uint256 amountOut) - external - returns ( - uint256 amountIn, - uint160[] memory sqrtPriceX96AfterList, - uint32[] memory initializedTicksCrossedList, - uint256 gasEstimate - ); - - struct QuoteExactOutputSingleParams { - address tokenIn; - address tokenOut; - uint256 amount; - uint24 fee; - uint160 sqrtPriceLimitX96; - } - - /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool - /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams` - /// tokenIn The token being swapped in - /// tokenOut The token being swapped out - /// fee The fee of the token pool to consider for the pair - /// amountOut The desired output amount - /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` - /// @return sqrtPriceX96After The sqrt price of the pool after the swap - /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed - /// @return gasEstimate The estimate of the gas that the swap consumes - function quoteExactOutputSingle(QuoteExactOutputSingleParams memory params) - external - returns ( - uint256 amountIn, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 gasEstimate - ); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol b/lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol deleted file mode 100644 index 688fc3d..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/ISwapRouter02.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -import '@uniswap/v3-periphery/contracts/interfaces/ISelfPermit.sol'; - -import './IV2SwapRouter.sol'; -import './IV3SwapRouter.sol'; -import './IApproveAndCall.sol'; -import './IMulticallExtended.sol'; - -/// @title Router token swapping functionality -interface ISwapRouter02 is IV2SwapRouter, IV3SwapRouter, IApproveAndCall, IMulticallExtended, ISelfPermit { - -} diff --git a/lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol b/lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol deleted file mode 100644 index a002188..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/ITokenValidator.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -/// @notice Validates tokens by flash borrowing from the token/ pool on V2. -/// @notice Returns -/// Status.FOT if we detected a fee is taken on transfer. -/// Status.STF if transfer failed for the token. -/// Status.UNKN if we did not detect any issues with the token. -/// @notice A return value of Status.UNKN does not mean the token is definitely not a fee on transfer token -/// or definitely has no problems with its transfer. It just means we cant say for sure that it has any -/// issues. -/// @dev We can not guarantee the result of this lens is correct for a few reasons: -/// @dev 1/ Some tokens take fees or allow transfers under specific conditions, for example some have an allowlist -/// @dev of addresses that do/dont require fees. Therefore the result is not guaranteed to be correct -/// @dev in all circumstances. -/// @dev 2/ It is possible that the token does not have any pools on V2 therefore we are not able to perform -/// @dev a flashloan to test the token. -/// @dev These functions are not marked view because they rely on calling non-view functions and reverting -/// to compute the result. -interface ITokenValidator { - // Status.FOT: detected a fee is taken on transfer. - // Status.STF: transfer failed for the token. - // Status.UNKN: no issues found with the token. - enum Status {UNKN, FOT, STF} - - /// @notice Validates a token by detecting if its transferable or takes a fee on transfer - /// @param token The address of the token to check for fee on transfer - /// @param baseTokens The addresses of the tokens to try pairing with - /// token when looking for a pool to flash loan from. - /// @param amountToBorrow The amount to try flash borrowing from the pools - /// @return The status of the token - function validate( - address token, - address[] calldata baseTokens, - uint256 amountToBorrow - ) external returns (Status); - - /// @notice Validates each token by detecting if its transferable or takes a fee on transfer - /// @param tokens The addresses of the tokens to check for fee on transfer - /// @param baseTokens The addresses of the tokens to try pairing with - /// token when looking for a pool to flash loan from. - /// @param amountToBorrow The amount to try flash borrowing from the pools - /// @return The status of the token - function batchValidate( - address[] calldata tokens, - address[] calldata baseTokens, - uint256 amountToBorrow - ) external returns (Status[] memory); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol b/lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol deleted file mode 100644 index 0d1ded3..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IV2SwapRouter.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -/// @title Router token swapping functionality -/// @notice Functions for swapping tokens via Uniswap V2 -interface IV2SwapRouter { - /// @notice Swaps `amountIn` of one token for as much as possible of another token - /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, - /// and swap the entire amount, enabling contracts to send tokens before calling this function. - /// @param amountIn The amount of token to swap - /// @param amountOutMin The minimum amount of output that must be received - /// @param path The ordered list of tokens to swap through - /// @param to The recipient address - /// @return amountOut The amount of the received token - function swapExactTokensForTokens( - uint256 amountIn, - uint256 amountOutMin, - address[] calldata path, - address to - ) external payable returns (uint256 amountOut); - - /// @notice Swaps as little as possible of one token for an exact amount of another token - /// @param amountOut The amount of token to swap for - /// @param amountInMax The maximum amount of input that the caller will pay - /// @param path The ordered list of tokens to swap through - /// @param to The recipient address - /// @return amountIn The amount of token to pay - function swapTokensForExactTokens( - uint256 amountOut, - uint256 amountInMax, - address[] calldata path, - address to - ) external payable returns (uint256 amountIn); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol b/lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol deleted file mode 100644 index f5d6459..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; -pragma abicoder v2; - -import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; - -/// @title Router token swapping functionality -/// @notice Functions for swapping tokens via Uniswap V3 -interface IV3SwapRouter is IUniswapV3SwapCallback { - struct ExactInputSingleParams { - address tokenIn; - address tokenOut; - uint24 fee; - address recipient; - uint256 amountIn; - uint256 amountOutMinimum; - uint160 sqrtPriceLimitX96; - } - - /// @notice Swaps `amountIn` of one token for as much as possible of another token - /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, - /// and swap the entire amount, enabling contracts to send tokens before calling this function. - /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata - /// @return amountOut The amount of the received token - function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); - - struct ExactInputParams { - bytes path; - address recipient; - uint256 amountIn; - uint256 amountOutMinimum; - } - - /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path - /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, - /// and swap the entire amount, enabling contracts to send tokens before calling this function. - /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata - /// @return amountOut The amount of the received token - function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); - - struct ExactOutputSingleParams { - address tokenIn; - address tokenOut; - uint24 fee; - address recipient; - uint256 amountOut; - uint256 amountInMaximum; - uint160 sqrtPriceLimitX96; - } - - /// @notice Swaps as little as possible of one token for `amountOut` of another token - /// that may remain in the router after the swap. - /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata - /// @return amountIn The amount of the input token - function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); - - struct ExactOutputParams { - bytes path; - address recipient; - uint256 amountOut; - uint256 amountInMaximum; - } - - /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) - /// that may remain in the router after the swap. - /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata - /// @return amountIn The amount of the input token - function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); -} diff --git a/lib/swap-router-contracts/contracts/interfaces/IWETH.sol b/lib/swap-router-contracts/contracts/interfaces/IWETH.sol deleted file mode 100644 index 24cbe47..0000000 --- a/lib/swap-router-contracts/contracts/interfaces/IWETH.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -interface IWETH { - function deposit() external payable; - - function transfer(address to, uint256 value) external returns (bool); - - function withdraw(uint256) external; -} diff --git a/lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol b/lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol deleted file mode 100644 index b2beb08..0000000 --- a/lib/swap-router-contracts/contracts/lens/MixedRouteQuoterV1.sol +++ /dev/null @@ -1,237 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; -import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; -import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; -import '@uniswap/v3-core/contracts/libraries/TickBitmap.sol'; -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; -import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; -import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; -import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; -import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; -import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; - -import '../base/ImmutableState.sol'; -import '../interfaces/IMixedRouteQuoterV1.sol'; -import '../libraries/PoolTicksCounter.sol'; -import '../libraries/UniswapV2Library.sol'; - -/// @title Provides on chain quotes for V3, V2, and MixedRoute exact input swaps -/// @notice Allows getting the expected amount out for a given swap without executing the swap -/// @notice Does not support exact output swaps since using the contract balance between exactOut swaps is not supported -/// @dev These functions are not gas efficient and should _not_ be called on chain. Instead, optimistically execute -/// the swap and check the amounts in the callback. -contract MixedRouteQuoterV1 is IMixedRouteQuoterV1, IUniswapV3SwapCallback, PeripheryImmutableState { - using Path for bytes; - using SafeCast for uint256; - using PoolTicksCounter for IUniswapV3Pool; - address public immutable factoryV2; - /// @dev Value to bit mask with path fee to determine if V2 or V3 route - // max V3 fee: 000011110100001001000000 (24 bits) - // mask: 1 << 23 = 100000000000000000000000 = decimal value 8388608 - uint24 private constant flagBitmask = 8388608; - - /// @dev Transient storage variable used to check a safety condition in exact output swaps. - uint256 private amountOutCached; - - constructor( - address _factory, - address _factoryV2, - address _WETH9 - ) PeripheryImmutableState(_factory, _WETH9) { - factoryV2 = _factoryV2; - } - - function getPool( - address tokenA, - address tokenB, - uint24 fee - ) private view returns (IUniswapV3Pool) { - return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); - } - - /// @dev Given an amountIn, fetch the reserves of the V2 pair and get the amountOut - function getPairAmountOut( - uint256 amountIn, - address tokenIn, - address tokenOut - ) private view returns (uint256) { - (uint256 reserveIn, uint256 reserveOut) = UniswapV2Library.getReserves(factoryV2, tokenIn, tokenOut); - return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut); - } - - /// @inheritdoc IUniswapV3SwapCallback - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes memory path - ) external view override { - require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported - (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); - CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); - - (bool isExactInput, uint256 amountReceived) = - amount0Delta > 0 - ? (tokenIn < tokenOut, uint256(-amount1Delta)) - : (tokenOut < tokenIn, uint256(-amount0Delta)); - - IUniswapV3Pool pool = getPool(tokenIn, tokenOut, fee); - (uint160 v3SqrtPriceX96After, int24 tickAfter, , , , , ) = pool.slot0(); - - if (isExactInput) { - assembly { - let ptr := mload(0x40) - mstore(ptr, amountReceived) - mstore(add(ptr, 0x20), v3SqrtPriceX96After) - mstore(add(ptr, 0x40), tickAfter) - revert(ptr, 0x60) - } - } else { - /// since we don't support exactOutput, revert here - revert('Exact output quote not supported'); - } - } - - /// @dev Parses a revert reason that should contain the numeric quote - function parseRevertReason(bytes memory reason) - private - pure - returns ( - uint256 amount, - uint160 sqrtPriceX96After, - int24 tickAfter - ) - { - if (reason.length != 0x60) { - if (reason.length < 0x44) revert('Unexpected error'); - assembly { - reason := add(reason, 0x04) - } - revert(abi.decode(reason, (string))); - } - return abi.decode(reason, (uint256, uint160, int24)); - } - - function handleV3Revert( - bytes memory reason, - IUniswapV3Pool pool, - uint256 gasEstimate - ) - private - view - returns ( - uint256 amount, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 - ) - { - int24 tickBefore; - int24 tickAfter; - (, tickBefore, , , , , ) = pool.slot0(); - (amount, sqrtPriceX96After, tickAfter) = parseRevertReason(reason); - - initializedTicksCrossed = pool.countInitializedTicksCrossed(tickBefore, tickAfter); - - return (amount, sqrtPriceX96After, initializedTicksCrossed, gasEstimate); - } - - /// @dev Fetch an exactIn quote for a V3 Pool on chain - function quoteExactInputSingleV3(QuoteExactInputSingleV3Params memory params) - public - override - returns ( - uint256 amountOut, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 gasEstimate - ) - { - bool zeroForOne = params.tokenIn < params.tokenOut; - IUniswapV3Pool pool = getPool(params.tokenIn, params.tokenOut, params.fee); - - uint256 gasBefore = gasleft(); - try - pool.swap( - address(this), // address(0) might cause issues with some tokens - zeroForOne, - params.amountIn.toInt256(), - params.sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) - : params.sqrtPriceLimitX96, - abi.encodePacked(params.tokenIn, params.fee, params.tokenOut) - ) - {} catch (bytes memory reason) { - gasEstimate = gasBefore - gasleft(); - return handleV3Revert(reason, pool, gasEstimate); - } - } - - /// @dev Fetch an exactIn quote for a V2 pair on chain - function quoteExactInputSingleV2(QuoteExactInputSingleV2Params memory params) - public - view - override - returns (uint256 amountOut) - { - amountOut = getPairAmountOut(params.amountIn, params.tokenIn, params.tokenOut); - } - - /// @dev Get the quote for an exactIn swap between an array of V2 and/or V3 pools - /// @notice To encode a V2 pair within the path, use 0x800000 (hex value of 8388608) for the fee between the two token addresses - function quoteExactInput(bytes memory path, uint256 amountIn) - public - override - returns ( - uint256 amountOut, - uint160[] memory v3SqrtPriceX96AfterList, - uint32[] memory v3InitializedTicksCrossedList, - uint256 v3SwapGasEstimate - ) - { - v3SqrtPriceX96AfterList = new uint160[](path.numPools()); - v3InitializedTicksCrossedList = new uint32[](path.numPools()); - - uint256 i = 0; - while (true) { - (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); - - if (fee & flagBitmask != 0) { - amountIn = quoteExactInputSingleV2( - QuoteExactInputSingleV2Params({tokenIn: tokenIn, tokenOut: tokenOut, amountIn: amountIn}) - ); - } else { - /// the outputs of prior swaps become the inputs to subsequent ones - ( - uint256 _amountOut, - uint160 _sqrtPriceX96After, - uint32 _initializedTicksCrossed, - uint256 _gasEstimate - ) = - quoteExactInputSingleV3( - QuoteExactInputSingleV3Params({ - tokenIn: tokenIn, - tokenOut: tokenOut, - fee: fee, - amountIn: amountIn, - sqrtPriceLimitX96: 0 - }) - ); - v3SqrtPriceX96AfterList[i] = _sqrtPriceX96After; - v3InitializedTicksCrossedList[i] = _initializedTicksCrossed; - v3SwapGasEstimate += _gasEstimate; - amountIn = _amountOut; - } - i++; - - /// decide whether to continue or terminate - if (path.hasMultiplePools()) { - path = path.skipToken(); - } else { - return (amountIn, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList, v3SwapGasEstimate); - } - } - } -} diff --git a/lib/swap-router-contracts/contracts/lens/Quoter.sol b/lib/swap-router-contracts/contracts/lens/Quoter.sol deleted file mode 100644 index e34d43d..0000000 --- a/lib/swap-router-contracts/contracts/lens/Quoter.sol +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; -import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; -import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; -import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; -import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; -import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; -import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; - -import '../interfaces/IQuoter.sol'; - -/// @title Provides quotes for swaps -/// @notice Allows getting the expected amount out or amount in for a given swap without executing the swap -/// @dev These functions are not gas efficient and should _not_ be called on chain. Instead, optimistically execute -/// the swap and check the amounts in the callback. -contract Quoter is IQuoter, IUniswapV3SwapCallback, PeripheryImmutableState { - using Path for bytes; - using SafeCast for uint256; - - /// @dev Transient storage variable used to check a safety condition in exact output swaps. - uint256 private amountOutCached; - - constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} - - function getPool( - address tokenA, - address tokenB, - uint24 fee - ) private view returns (IUniswapV3Pool) { - return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); - } - - /// @inheritdoc IUniswapV3SwapCallback - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes memory path - ) external view override { - require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported - (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); - CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); - - (bool isExactInput, uint256 amountToPay, uint256 amountReceived) = - amount0Delta > 0 - ? (tokenIn < tokenOut, uint256(amount0Delta), uint256(-amount1Delta)) - : (tokenOut < tokenIn, uint256(amount1Delta), uint256(-amount0Delta)); - if (isExactInput) { - assembly { - let ptr := mload(0x40) - mstore(ptr, amountReceived) - revert(ptr, 32) - } - } else { - // if the cache has been populated, ensure that the full output amount has been received - if (amountOutCached != 0) require(amountReceived == amountOutCached); - assembly { - let ptr := mload(0x40) - mstore(ptr, amountToPay) - revert(ptr, 32) - } - } - } - - /// @dev Parses a revert reason that should contain the numeric quote - function parseRevertReason(bytes memory reason) private pure returns (uint256) { - if (reason.length != 32) { - if (reason.length < 68) revert('Unexpected error'); - assembly { - reason := add(reason, 0x04) - } - revert(abi.decode(reason, (string))); - } - return abi.decode(reason, (uint256)); - } - - /// @inheritdoc IQuoter - function quoteExactInputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountIn, - uint160 sqrtPriceLimitX96 - ) public override returns (uint256 amountOut) { - bool zeroForOne = tokenIn < tokenOut; - - try - getPool(tokenIn, tokenOut, fee).swap( - address(this), // address(0) might cause issues with some tokens - zeroForOne, - amountIn.toInt256(), - sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) - : sqrtPriceLimitX96, - abi.encodePacked(tokenIn, fee, tokenOut) - ) - {} catch (bytes memory reason) { - return parseRevertReason(reason); - } - } - - /// @inheritdoc IQuoter - function quoteExactInput(bytes memory path, uint256 amountIn) external override returns (uint256 amountOut) { - while (true) { - bool hasMultiplePools = path.hasMultiplePools(); - - (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); - - // the outputs of prior swaps become the inputs to subsequent ones - amountIn = quoteExactInputSingle(tokenIn, tokenOut, fee, amountIn, 0); - - // decide whether to continue or terminate - if (hasMultiplePools) { - path = path.skipToken(); - } else { - return amountIn; - } - } - } - - /// @inheritdoc IQuoter - function quoteExactOutputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountOut, - uint160 sqrtPriceLimitX96 - ) public override returns (uint256 amountIn) { - bool zeroForOne = tokenIn < tokenOut; - - // if no price limit has been specified, cache the output amount for comparison in the swap callback - if (sqrtPriceLimitX96 == 0) amountOutCached = amountOut; - try - getPool(tokenIn, tokenOut, fee).swap( - address(this), // address(0) might cause issues with some tokens - zeroForOne, - -amountOut.toInt256(), - sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) - : sqrtPriceLimitX96, - abi.encodePacked(tokenOut, fee, tokenIn) - ) - {} catch (bytes memory reason) { - if (sqrtPriceLimitX96 == 0) delete amountOutCached; // clear cache - return parseRevertReason(reason); - } - } - - /// @inheritdoc IQuoter - function quoteExactOutput(bytes memory path, uint256 amountOut) external override returns (uint256 amountIn) { - while (true) { - bool hasMultiplePools = path.hasMultiplePools(); - - (address tokenOut, address tokenIn, uint24 fee) = path.decodeFirstPool(); - - // the inputs of prior swaps become the outputs of subsequent ones - amountOut = quoteExactOutputSingle(tokenIn, tokenOut, fee, amountOut, 0); - - // decide whether to continue or terminate - if (hasMultiplePools) { - path = path.skipToken(); - } else { - return amountOut; - } - } - } -} diff --git a/lib/swap-router-contracts/contracts/lens/QuoterV2.sol b/lib/swap-router-contracts/contracts/lens/QuoterV2.sol deleted file mode 100644 index 9c17c17..0000000 --- a/lib/swap-router-contracts/contracts/lens/QuoterV2.sol +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; -import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; -import '@uniswap/v3-core/contracts/libraries/TickMath.sol'; -import '@uniswap/v3-core/contracts/libraries/TickBitmap.sol'; -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; -import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; -import '@uniswap/v3-periphery/contracts/libraries/Path.sol'; -import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol'; -import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol'; - -import '../interfaces/IQuoterV2.sol'; -import '../libraries/PoolTicksCounter.sol'; - -/// @title Provides quotes for swaps -/// @notice Allows getting the expected amount out or amount in for a given swap without executing the swap -/// @dev These functions are not gas efficient and should _not_ be called on chain. Instead, optimistically execute -/// the swap and check the amounts in the callback. -contract QuoterV2 is IQuoterV2, IUniswapV3SwapCallback, PeripheryImmutableState { - using Path for bytes; - using SafeCast for uint256; - using PoolTicksCounter for IUniswapV3Pool; - - /// @dev Transient storage variable used to check a safety condition in exact output swaps. - uint256 private amountOutCached; - - constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} - - function getPool( - address tokenA, - address tokenB, - uint24 fee - ) private view returns (IUniswapV3Pool) { - return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); - } - - /// @inheritdoc IUniswapV3SwapCallback - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes memory path - ) external view override { - require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported - (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); - CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); - - (bool isExactInput, uint256 amountToPay, uint256 amountReceived) = - amount0Delta > 0 - ? (tokenIn < tokenOut, uint256(amount0Delta), uint256(-amount1Delta)) - : (tokenOut < tokenIn, uint256(amount1Delta), uint256(-amount0Delta)); - - IUniswapV3Pool pool = getPool(tokenIn, tokenOut, fee); - (uint160 sqrtPriceX96After, int24 tickAfter, , , , , ) = pool.slot0(); - - if (isExactInput) { - assembly { - let ptr := mload(0x40) - mstore(ptr, amountReceived) - mstore(add(ptr, 0x20), sqrtPriceX96After) - mstore(add(ptr, 0x40), tickAfter) - revert(ptr, 96) - } - } else { - // if the cache has been populated, ensure that the full output amount has been received - if (amountOutCached != 0) require(amountReceived == amountOutCached); - assembly { - let ptr := mload(0x40) - mstore(ptr, amountToPay) - mstore(add(ptr, 0x20), sqrtPriceX96After) - mstore(add(ptr, 0x40), tickAfter) - revert(ptr, 96) - } - } - } - - /// @dev Parses a revert reason that should contain the numeric quote - function parseRevertReason(bytes memory reason) - private - pure - returns ( - uint256 amount, - uint160 sqrtPriceX96After, - int24 tickAfter - ) - { - if (reason.length != 96) { - if (reason.length < 68) revert('Unexpected error'); - assembly { - reason := add(reason, 0x04) - } - revert(abi.decode(reason, (string))); - } - return abi.decode(reason, (uint256, uint160, int24)); - } - - function handleRevert( - bytes memory reason, - IUniswapV3Pool pool, - uint256 gasEstimate - ) - private - view - returns ( - uint256 amount, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 - ) - { - int24 tickBefore; - int24 tickAfter; - (, tickBefore, , , , , ) = pool.slot0(); - (amount, sqrtPriceX96After, tickAfter) = parseRevertReason(reason); - - initializedTicksCrossed = pool.countInitializedTicksCrossed(tickBefore, tickAfter); - - return (amount, sqrtPriceX96After, initializedTicksCrossed, gasEstimate); - } - - function quoteExactInputSingle(QuoteExactInputSingleParams memory params) - public - override - returns ( - uint256 amountOut, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 gasEstimate - ) - { - bool zeroForOne = params.tokenIn < params.tokenOut; - IUniswapV3Pool pool = getPool(params.tokenIn, params.tokenOut, params.fee); - - uint256 gasBefore = gasleft(); - try - pool.swap( - address(this), // address(0) might cause issues with some tokens - zeroForOne, - params.amountIn.toInt256(), - params.sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) - : params.sqrtPriceLimitX96, - abi.encodePacked(params.tokenIn, params.fee, params.tokenOut) - ) - {} catch (bytes memory reason) { - gasEstimate = gasBefore - gasleft(); - return handleRevert(reason, pool, gasEstimate); - } - } - - function quoteExactInput(bytes memory path, uint256 amountIn) - public - override - returns ( - uint256 amountOut, - uint160[] memory sqrtPriceX96AfterList, - uint32[] memory initializedTicksCrossedList, - uint256 gasEstimate - ) - { - sqrtPriceX96AfterList = new uint160[](path.numPools()); - initializedTicksCrossedList = new uint32[](path.numPools()); - - uint256 i = 0; - while (true) { - (address tokenIn, address tokenOut, uint24 fee) = path.decodeFirstPool(); - - // the outputs of prior swaps become the inputs to subsequent ones - (uint256 _amountOut, uint160 _sqrtPriceX96After, uint32 _initializedTicksCrossed, uint256 _gasEstimate) = - quoteExactInputSingle( - QuoteExactInputSingleParams({ - tokenIn: tokenIn, - tokenOut: tokenOut, - fee: fee, - amountIn: amountIn, - sqrtPriceLimitX96: 0 - }) - ); - - sqrtPriceX96AfterList[i] = _sqrtPriceX96After; - initializedTicksCrossedList[i] = _initializedTicksCrossed; - amountIn = _amountOut; - gasEstimate += _gasEstimate; - i++; - - // decide whether to continue or terminate - if (path.hasMultiplePools()) { - path = path.skipToken(); - } else { - return (amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate); - } - } - } - - function quoteExactOutputSingle(QuoteExactOutputSingleParams memory params) - public - override - returns ( - uint256 amountIn, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 gasEstimate - ) - { - bool zeroForOne = params.tokenIn < params.tokenOut; - IUniswapV3Pool pool = getPool(params.tokenIn, params.tokenOut, params.fee); - - // if no price limit has been specified, cache the output amount for comparison in the swap callback - if (params.sqrtPriceLimitX96 == 0) amountOutCached = params.amount; - uint256 gasBefore = gasleft(); - try - pool.swap( - address(this), // address(0) might cause issues with some tokens - zeroForOne, - -params.amount.toInt256(), - params.sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) - : params.sqrtPriceLimitX96, - abi.encodePacked(params.tokenOut, params.fee, params.tokenIn) - ) - {} catch (bytes memory reason) { - gasEstimate = gasBefore - gasleft(); - if (params.sqrtPriceLimitX96 == 0) delete amountOutCached; // clear cache - return handleRevert(reason, pool, gasEstimate); - } - } - - function quoteExactOutput(bytes memory path, uint256 amountOut) - public - override - returns ( - uint256 amountIn, - uint160[] memory sqrtPriceX96AfterList, - uint32[] memory initializedTicksCrossedList, - uint256 gasEstimate - ) - { - sqrtPriceX96AfterList = new uint160[](path.numPools()); - initializedTicksCrossedList = new uint32[](path.numPools()); - - uint256 i = 0; - while (true) { - (address tokenOut, address tokenIn, uint24 fee) = path.decodeFirstPool(); - - // the inputs of prior swaps become the outputs of subsequent ones - (uint256 _amountIn, uint160 _sqrtPriceX96After, uint32 _initializedTicksCrossed, uint256 _gasEstimate) = - quoteExactOutputSingle( - QuoteExactOutputSingleParams({ - tokenIn: tokenIn, - tokenOut: tokenOut, - amount: amountOut, - fee: fee, - sqrtPriceLimitX96: 0 - }) - ); - - sqrtPriceX96AfterList[i] = _sqrtPriceX96After; - initializedTicksCrossedList[i] = _initializedTicksCrossed; - amountOut = _amountIn; - gasEstimate += _gasEstimate; - i++; - - // decide whether to continue or terminate - if (path.hasMultiplePools()) { - path = path.skipToken(); - } else { - return (amountOut, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate); - } - } - } -} diff --git a/lib/swap-router-contracts/contracts/lens/README.md b/lib/swap-router-contracts/contracts/lens/README.md deleted file mode 100644 index 8359711..0000000 --- a/lib/swap-router-contracts/contracts/lens/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# lens - -These contracts are not designed to be called on-chain. They simplify -fetching on-chain data from off-chain. diff --git a/lib/swap-router-contracts/contracts/lens/TokenValidator.sol b/lib/swap-router-contracts/contracts/lens/TokenValidator.sol deleted file mode 100644 index ba3afde..0000000 --- a/lib/swap-router-contracts/contracts/lens/TokenValidator.sol +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol'; -import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Callee.sol'; -import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; -import '../libraries/UniswapV2Library.sol'; -import '../interfaces/ISwapRouter02.sol'; -import '../interfaces/ITokenValidator.sol'; -import '../base/ImmutableState.sol'; - -/// @notice Validates tokens by flash borrowing from the token/ pool on V2. -/// @notice Returns -/// Status.FOT if we detected a fee is taken on transfer. -/// Status.STF if transfer failed for the token. -/// Status.UNKN if we did not detect any issues with the token. -/// @notice A return value of Status.UNKN does not mean the token is definitely not a fee on transfer token -/// or definitely has no problems with its transfer. It just means we cant say for sure that it has any -/// issues. -/// @dev We can not guarantee the result of this lens is correct for a few reasons: -/// @dev 1/ Some tokens take fees or allow transfers under specific conditions, for example some have an allowlist -/// @dev of addresses that do/dont require fees. Therefore the result is not guaranteed to be correct -/// @dev in all circumstances. -/// @dev 2/ It is possible that the token does not have any pools on V2 therefore we are not able to perform -/// @dev a flashloan to test the token. -contract TokenValidator is ITokenValidator, IUniswapV2Callee, ImmutableState { - string internal constant FOT_REVERT_STRING = 'FOT'; - // https://github.com/Uniswap/v2-core/blob/1136544ac842ff48ae0b1b939701436598d74075/contracts/UniswapV2Pair.sol#L46 - string internal constant STF_REVERT_STRING_SUFFIX = 'TRANSFER_FAILED'; - - constructor(address _factoryV2, address _positionManager) ImmutableState(_factoryV2, _positionManager) {} - - function batchValidate( - address[] calldata tokens, - address[] calldata baseTokens, - uint256 amountToBorrow - ) public override returns (Status[] memory isFotResults) { - isFotResults = new Status[](tokens.length); - for (uint256 i = 0; i < tokens.length; i++) { - isFotResults[i] = validate(tokens[i], baseTokens, amountToBorrow); - } - } - - function validate( - address token, - address[] calldata baseTokens, - uint256 amountToBorrow - ) public override returns (Status) { - for (uint256 i = 0; i < baseTokens.length; i++) { - Status result = _validate(token, baseTokens[i], amountToBorrow); - if (result == Status.FOT || result == Status.STF) { - return result; - } - } - return Status.UNKN; - } - - function _validate( - address token, - address baseToken, - uint256 amountToBorrow - ) internal returns (Status) { - if (token == baseToken) { - return Status.UNKN; - } - - address pairAddress = UniswapV2Library.pairFor(this.factoryV2(), token, baseToken); - - // If the token/baseToken pair exists, get token0. - // Must do low level call as try/catch does not support case where contract does not exist. - (, bytes memory returnData) = address(pairAddress).call(abi.encodeWithSelector(IUniswapV2Pair.token0.selector)); - - if (returnData.length == 0) { - return Status.UNKN; - } - - address token0Address = abi.decode(returnData, (address)); - - // Flash loan {amountToBorrow} - (uint256 amount0Out, uint256 amount1Out) = - token == token0Address ? (amountToBorrow, uint256(0)) : (uint256(0), amountToBorrow); - - uint256 balanceBeforeLoan = IERC20(token).balanceOf(address(this)); - - IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); - - try - pair.swap(amount0Out, amount1Out, address(this), abi.encode(balanceBeforeLoan, amountToBorrow)) - {} catch Error(string memory reason) { - if (isFotFailed(reason)) { - return Status.FOT; - } - - if (isTransferFailed(reason)) { - return Status.STF; - } - - return Status.UNKN; - } - - // Swap always reverts so should never reach. - revert('Unexpected error'); - } - - function isFotFailed(string memory reason) internal pure returns (bool) { - return keccak256(bytes(reason)) == keccak256(bytes(FOT_REVERT_STRING)); - } - - function isTransferFailed(string memory reason) internal pure returns (bool) { - // We check the suffix of the revert string so we can support forks that - // may have modified the prefix. - string memory stf = STF_REVERT_STRING_SUFFIX; - - uint256 reasonLength = bytes(reason).length; - uint256 suffixLength = bytes(stf).length; - if (reasonLength < suffixLength) { - return false; - } - - uint256 ptr; - uint256 offset = 32 + reasonLength - suffixLength; - bool transferFailed; - assembly { - ptr := add(reason, offset) - let suffixPtr := add(stf, 32) - transferFailed := eq(keccak256(ptr, suffixLength), keccak256(suffixPtr, suffixLength)) - } - - return transferFailed; - } - - function uniswapV2Call( - address, - uint256 amount0, - uint256, - bytes calldata data - ) external view override { - IUniswapV2Pair pair = IUniswapV2Pair(msg.sender); - (address token0, address token1) = (pair.token0(), pair.token1()); - - IERC20 tokenBorrowed = IERC20(amount0 > 0 ? token0 : token1); - - (uint256 balanceBeforeLoan, uint256 amountRequestedToBorrow) = abi.decode(data, (uint256, uint256)); - uint256 amountBorrowed = tokenBorrowed.balanceOf(address(this)) - balanceBeforeLoan; - - // If we received less token than we requested when we called swap, then a fee must have been taken - // by the token during transfer. - if (amountBorrowed != amountRequestedToBorrow) { - revert(FOT_REVERT_STRING); - } - - // Note: If we do not revert here, we would end up reverting in the pair's swap method anyway - // since for a flash borrow we need to transfer back the amount we borrowed + 0.3% fee, and we don't - // have funds to cover the fee. Revert early here to save gas/time. - revert('Unknown'); - } -} diff --git a/lib/swap-router-contracts/contracts/libraries/Constants.sol b/lib/swap-router-contracts/contracts/libraries/Constants.sol deleted file mode 100644 index 7428170..0000000 --- a/lib/swap-router-contracts/contracts/libraries/Constants.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; - -/// @title Constant state -/// @notice Constant state used by the swap router -library Constants { - /// @dev Used for identifying cases when this contract's balance of a token is to be used - uint256 internal constant CONTRACT_BALANCE = 0; - - /// @dev Used as a flag for identifying msg.sender, saves gas by sending more 0 bytes - address internal constant MSG_SENDER = address(1); - - /// @dev Used as a flag for identifying address(this), saves gas by sending more 0 bytes - address internal constant ADDRESS_THIS = address(2); -} diff --git a/lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol b/lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol deleted file mode 100644 index fb0682f..0000000 --- a/lib/swap-router-contracts/contracts/libraries/PoolTicksCounter.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.6.0; - -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; - -library PoolTicksCounter { - /// @dev This function counts the number of initialized ticks that would incur a gas cost between tickBefore and tickAfter. - /// When tickBefore and/or tickAfter themselves are initialized, the logic over whether we should count them depends on the - /// direction of the swap. If we are swapping upwards (tickAfter > tickBefore) we don't want to count tickBefore but we do - /// want to count tickAfter. The opposite is true if we are swapping downwards. - function countInitializedTicksCrossed( - IUniswapV3Pool self, - int24 tickBefore, - int24 tickAfter - ) internal view returns (uint32 initializedTicksCrossed) { - int16 wordPosLower; - int16 wordPosHigher; - uint8 bitPosLower; - uint8 bitPosHigher; - bool tickBeforeInitialized; - bool tickAfterInitialized; - - { - // Get the key and offset in the tick bitmap of the active tick before and after the swap. - int16 wordPos = int16((tickBefore / self.tickSpacing()) >> 8); - uint8 bitPos = uint8((tickBefore / self.tickSpacing()) % 256); - - int16 wordPosAfter = int16((tickAfter / self.tickSpacing()) >> 8); - uint8 bitPosAfter = uint8((tickAfter / self.tickSpacing()) % 256); - - // In the case where tickAfter is initialized, we only want to count it if we are swapping downwards. - // If the initializable tick after the swap is initialized, our original tickAfter is a - // multiple of tick spacing, and we are swapping downwards we know that tickAfter is initialized - // and we shouldn't count it. - tickAfterInitialized = - ((self.tickBitmap(wordPosAfter) & (1 << bitPosAfter)) > 0) && - ((tickAfter % self.tickSpacing()) == 0) && - (tickBefore > tickAfter); - - // In the case where tickBefore is initialized, we only want to count it if we are swapping upwards. - // Use the same logic as above to decide whether we should count tickBefore or not. - tickBeforeInitialized = - ((self.tickBitmap(wordPos) & (1 << bitPos)) > 0) && - ((tickBefore % self.tickSpacing()) == 0) && - (tickBefore < tickAfter); - - if (wordPos < wordPosAfter || (wordPos == wordPosAfter && bitPos <= bitPosAfter)) { - wordPosLower = wordPos; - bitPosLower = bitPos; - wordPosHigher = wordPosAfter; - bitPosHigher = bitPosAfter; - } else { - wordPosLower = wordPosAfter; - bitPosLower = bitPosAfter; - wordPosHigher = wordPos; - bitPosHigher = bitPos; - } - } - - // Count the number of initialized ticks crossed by iterating through the tick bitmap. - // Our first mask should include the lower tick and everything to its left. - uint256 mask = type(uint256).max << bitPosLower; - while (wordPosLower <= wordPosHigher) { - // If we're on the final tick bitmap page, ensure we only count up to our - // ending tick. - if (wordPosLower == wordPosHigher) { - mask = mask & (type(uint256).max >> (255 - bitPosHigher)); - } - - uint256 masked = self.tickBitmap(wordPosLower) & mask; - initializedTicksCrossed += countOneBits(masked); - wordPosLower++; - // Reset our mask so we consider all bits on the next iteration. - mask = type(uint256).max; - } - - if (tickAfterInitialized) { - initializedTicksCrossed -= 1; - } - - if (tickBeforeInitialized) { - initializedTicksCrossed -= 1; - } - - return initializedTicksCrossed; - } - - function countOneBits(uint256 x) private pure returns (uint16) { - uint16 bits = 0; - while (x != 0) { - bits++; - x &= (x - 1); - } - return bits; - } -} diff --git a/lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol b/lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol deleted file mode 100644 index a90b07e..0000000 --- a/lib/swap-router-contracts/contracts/libraries/UniswapV2Library.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; -import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol'; - -library UniswapV2Library { - using LowGasSafeMath for uint256; - - // returns sorted token addresses, used to handle return values from pairs sorted in this order - function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { - require(tokenA != tokenB); - (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); - require(token0 != address(0)); - } - - // calculates the CREATE2 address for a pair without making any external calls - function pairFor( - address factory, - address tokenA, - address tokenB - ) internal pure returns (address pair) { - (address token0, address token1) = sortTokens(tokenA, tokenB); - pair = address( - uint256( - keccak256( - abi.encodePacked( - hex'ff', - factory, - keccak256(abi.encodePacked(token0, token1)), - hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash - ) - ) - ) - ); - } - - // fetches and sorts the reserves for a pair - function getReserves( - address factory, - address tokenA, - address tokenB - ) internal view returns (uint256 reserveA, uint256 reserveB) { - (address token0, ) = sortTokens(tokenA, tokenB); - (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); - (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); - } - - // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset - function getAmountOut( - uint256 amountIn, - uint256 reserveIn, - uint256 reserveOut - ) internal pure returns (uint256 amountOut) { - require(amountIn > 0, 'INSUFFICIENT_INPUT_AMOUNT'); - require(reserveIn > 0 && reserveOut > 0); - uint256 amountInWithFee = amountIn.mul(997); - uint256 numerator = amountInWithFee.mul(reserveOut); - uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); - amountOut = numerator / denominator; - } - - // given an output amount of an asset and pair reserves, returns a required input amount of the other asset - function getAmountIn( - uint256 amountOut, - uint256 reserveIn, - uint256 reserveOut - ) internal pure returns (uint256 amountIn) { - require(amountOut > 0, 'INSUFFICIENT_OUTPUT_AMOUNT'); - require(reserveIn > 0 && reserveOut > 0); - uint256 numerator = reserveIn.mul(amountOut).mul(1000); - uint256 denominator = reserveOut.sub(amountOut).mul(997); - amountIn = (numerator / denominator).add(1); - } - - // performs chained getAmountIn calculations on any number of pairs - function getAmountsIn( - address factory, - uint256 amountOut, - address[] memory path - ) internal view returns (uint256[] memory amounts) { - require(path.length >= 2); - amounts = new uint256[](path.length); - amounts[amounts.length - 1] = amountOut; - for (uint256 i = path.length - 1; i > 0; i--) { - (uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i - 1], path[i]); - amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); - } - } -} diff --git a/lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol b/lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol deleted file mode 100644 index 0c55ca7..0000000 --- a/lib/swap-router-contracts/contracts/test/ImmutableStateTest.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; - -import '../base/ImmutableState.sol'; - -contract ImmutableStateTest is ImmutableState { - constructor(address _factoryV2, address _positionManager) ImmutableState(_factoryV2, _positionManager) {} -} diff --git a/lib/swap-router-contracts/contracts/test/MockObservations.sol b/lib/swap-router-contracts/contracts/test/MockObservations.sol deleted file mode 100644 index 2d4edbe..0000000 --- a/lib/swap-router-contracts/contracts/test/MockObservations.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.7.6; - -import '@uniswap/v3-core/contracts/libraries/Oracle.sol'; - -contract MockObservations { - using Oracle for Oracle.Observation[65535]; - - // slot0 - int24 private slot0Tick; - uint16 private slot0ObservationCardinality; - uint16 private slot0ObservationIndex; - - // observations - Oracle.Observation[65535] public observations; - - // block timestamps always monotonic increasing from 0, cumulative ticks are calculated automatically - constructor( - uint32[3] memory blockTimestamps, - int24[3] memory ticks, - bool mockLowObservationCardinality - ) { - require(blockTimestamps[0] == 0, '0'); - require(blockTimestamps[1] > 0, '1'); - require(blockTimestamps[2] > blockTimestamps[1], '2'); - - int56 tickCumulative = 0; - for (uint256 i = 0; i < blockTimestamps.length; i++) { - if (i != 0) { - int24 tick = ticks[i - 1]; - uint32 delta = blockTimestamps[i] - blockTimestamps[i - 1]; - tickCumulative += int56(tick) * delta; - } - observations[i] = Oracle.Observation({ - blockTimestamp: blockTimestamps[i], - tickCumulative: tickCumulative, - secondsPerLiquidityCumulativeX128: uint160(i), - initialized: true - }); - } - slot0Tick = ticks[2]; - slot0ObservationCardinality = mockLowObservationCardinality ? 1 : 3; - slot0ObservationIndex = 2; - } - - function slot0() - external - view - returns ( - uint160, - int24, - uint16, - uint16, - uint16, - uint8, - bool - ) - { - return (0, slot0Tick, slot0ObservationIndex, slot0ObservationCardinality, 0, 0, false); - } - - function observe(uint32[] calldata secondsAgos) - external - view - returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) - { - return - observations.observe( - observations[2].blockTimestamp, - secondsAgos, - slot0Tick, - slot0ObservationIndex, - 0, - slot0ObservationCardinality - ); - } -} diff --git a/lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol b/lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol deleted file mode 100644 index 7e76c09..0000000 --- a/lib/swap-router-contracts/contracts/test/MockTimeSwapRouter.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.7.6; -pragma abicoder v2; - -import '../SwapRouter02.sol'; - -contract MockTimeSwapRouter02 is SwapRouter02 { - uint256 time; - - constructor( - address _factoryV2, - address factoryV3, - address _positionManager, - address _WETH9 - ) SwapRouter02(_factoryV2, factoryV3, _positionManager, _WETH9) {} - - function _blockTimestamp() internal view override returns (uint256) { - return time; - } - - function setTime(uint256 _time) external { - time = _time; - } -} diff --git a/lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol b/lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol deleted file mode 100644 index 4d97120..0000000 --- a/lib/swap-router-contracts/contracts/test/OracleSlippageTest.sol +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity =0.7.6; -pragma abicoder v2; - -import '../base/OracleSlippage.sol'; - -contract OracleSlippageTest is OracleSlippage { - mapping(address => mapping(address => mapping(uint24 => IUniswapV3Pool))) private pools; - uint256 internal time; - - constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} - - function setTime(uint256 _time) external { - time = _time; - } - - function _blockTimestamp() internal view override returns (uint256) { - return time; - } - - function registerPool( - IUniswapV3Pool pool, - address tokenIn, - address tokenOut, - uint24 fee - ) external { - pools[tokenIn][tokenOut][fee] = pool; - pools[tokenOut][tokenIn][fee] = pool; - } - - function getPoolAddress( - address tokenA, - address tokenB, - uint24 fee - ) internal view override returns (IUniswapV3Pool pool) { - pool = pools[tokenA][tokenB][fee]; - } - - function testGetBlockStartingAndCurrentTick(IUniswapV3Pool pool) - external - view - returns (int24 blockStartingTick, int24 currentTick) - { - return getBlockStartingAndCurrentTick(pool); - } - - function testGetSyntheticTicks(bytes memory path, uint32 secondsAgo) - external - view - returns (int256 syntheticAverageTick, int256 syntheticCurrentTick) - { - return getSyntheticTicks(path, secondsAgo); - } - - function testGetSyntheticTicks( - bytes[] memory paths, - uint128[] memory amounts, - uint32 secondsAgo - ) external view returns (int256 averageSyntheticAverageTick, int256 averageSyntheticCurrentTick) { - return getSyntheticTicks(paths, amounts, secondsAgo); - } -} diff --git a/lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol b/lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol deleted file mode 100644 index 3d47bf7..0000000 --- a/lib/swap-router-contracts/contracts/test/PoolTicksCounterTest.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; - -pragma solidity >=0.6.0; - -import '../libraries/PoolTicksCounter.sol'; - -contract PoolTicksCounterTest { - using PoolTicksCounter for IUniswapV3Pool; - - function countInitializedTicksCrossed( - IUniswapV3Pool pool, - int24 tickBefore, - int24 tickAfter - ) external view returns (uint32 initializedTicksCrossed) { - return pool.countInitializedTicksCrossed(tickBefore, tickAfter); - } -} diff --git a/lib/swap-router-contracts/contracts/test/TestERC20.sol b/lib/swap-router-contracts/contracts/test/TestERC20.sol deleted file mode 100644 index 66ed4ac..0000000 --- a/lib/swap-router-contracts/contracts/test/TestERC20.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.7.6; - -import '@openzeppelin/contracts/drafts/ERC20Permit.sol'; - -contract TestERC20 is ERC20Permit { - constructor(uint256 amountToMint) ERC20('Test ERC20', 'TEST') ERC20Permit('Test ERC20') { - _mint(msg.sender, amountToMint); - } -} diff --git a/lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol b/lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol deleted file mode 100644 index b32b54e..0000000 --- a/lib/swap-router-contracts/contracts/test/TestMulticallExtended.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.7.6; -pragma abicoder v2; - -import '../base/MulticallExtended.sol'; - -contract TestMulticallExtended is MulticallExtended { - uint256 time; - - function _blockTimestamp() internal view override returns (uint256) { - return time; - } - - function setTime(uint256 _time) external { - time = _time; - } - - struct Tuple { - uint256 a; - uint256 b; - } - - function functionThatReturnsTuple(uint256 a, uint256 b) external pure returns (Tuple memory tuple) { - tuple = Tuple({b: a, a: b}); - } -} diff --git a/lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol b/lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol deleted file mode 100644 index 1400bd6..0000000 --- a/lib/swap-router-contracts/contracts/test/TestUniswapV3Callee.sol +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.7.6; - -import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; -import '@uniswap/v3-core/contracts/libraries/SafeCast.sol'; -import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -contract TestUniswapV3Callee is IUniswapV3SwapCallback { - using SafeCast for uint256; - - function swapExact0For1( - address pool, - uint256 amount0In, - address recipient, - uint160 sqrtPriceLimitX96 - ) external { - IUniswapV3Pool(pool).swap(recipient, true, amount0In.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); - } - - function swap0ForExact1( - address pool, - uint256 amount1Out, - address recipient, - uint160 sqrtPriceLimitX96 - ) external { - IUniswapV3Pool(pool).swap(recipient, true, -amount1Out.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); - } - - function swapExact1For0( - address pool, - uint256 amount1In, - address recipient, - uint160 sqrtPriceLimitX96 - ) external { - IUniswapV3Pool(pool).swap(recipient, false, amount1In.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); - } - - function swap1ForExact0( - address pool, - uint256 amount0Out, - address recipient, - uint160 sqrtPriceLimitX96 - ) external { - IUniswapV3Pool(pool).swap(recipient, false, -amount0Out.toInt256(), sqrtPriceLimitX96, abi.encode(msg.sender)); - } - - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes calldata data - ) external override { - address sender = abi.decode(data, (address)); - - if (amount0Delta > 0) { - IERC20(IUniswapV3Pool(msg.sender).token0()).transferFrom(sender, msg.sender, uint256(amount0Delta)); - } else { - assert(amount1Delta > 0); - IERC20(IUniswapV3Pool(msg.sender).token1()).transferFrom(sender, msg.sender, uint256(amount1Delta)); - } - } -} diff --git a/lib/swap-router-contracts/hardhat.config.ts b/lib/swap-router-contracts/hardhat.config.ts deleted file mode 100644 index 2afe809..0000000 --- a/lib/swap-router-contracts/hardhat.config.ts +++ /dev/null @@ -1,70 +0,0 @@ -import '@nomiclabs/hardhat-ethers' -import '@nomiclabs/hardhat-etherscan' -import '@nomiclabs/hardhat-waffle' -import 'hardhat-typechain' -import 'hardhat-watcher' -import 'dotenv/config' - -const DEFAULT_COMPILER_SETTINGS = { - version: '0.7.6', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1_000_000, - }, - metadata: { - bytecodeHash: 'none', - }, - }, -} - -export default { - networks: { - hardhat: { - allowUnlimitedContractSize: false, - }, - mainnet: { - url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, - }, - ropsten: { - url: `https://ropsten.infura.io/v3/${process.env.INFURA_API_KEY}`, - }, - rinkeby: { - url: `https://rinkeby.infura.io/v3/${process.env.INFURA_API_KEY}`, - }, - goerli: { - url: `https://goerli.infura.io/v3/${process.env.INFURA_API_KEY}`, - }, - kovan: { - url: `https://kovan.infura.io/v3/${process.env.INFURA_API_KEY}`, - }, - arbitrumRinkeby: { - url: `https://rinkeby.arbitrum.io/rpc`, - }, - arbitrum: { - url: `https://arb1.arbitrum.io/rpc`, - }, - optimismKovan: { - url: `https://kovan.optimism.io`, - }, - optimism: { - url: `https://mainnet.optimism.io`, - }, - }, - etherscan: { - // Your API key for Etherscan - // Obtain one at https://etherscan.io/ - apiKey: process.env.ETHERSCAN_API_KEY, - }, - solidity: { - compilers: [DEFAULT_COMPILER_SETTINGS], - }, - watcher: { - test: { - tasks: [{ command: 'test', params: { testFiles: ['{path}'] } }], - files: ['./test/**/*'], - verbose: true, - }, - }, -} diff --git a/lib/swap-router-contracts/package.json b/lib/swap-router-contracts/package.json deleted file mode 100644 index 908cb25..0000000 --- a/lib/swap-router-contracts/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@uniswap/swap-router-contracts", - "description": "Smart contracts for swapping on Uniswap V2 and V3", - "license": "GPL-2.0-or-later", - "publishConfig": { - "access": "public" - }, - "version": "1.3.1", - "homepage": "https://uniswap.org", - "keywords": [ - "uniswap", - "v2", - "v3" - ], - "repository": { - "type": "git", - "url": "https://github.com/Uniswap/swap-router-contracts" - }, - "files": [ - "contracts/base", - "contracts/interfaces", - "contracts/libraries", - "artifacts/contracts/**/*.json", - "!artifacts/contracts/**/*.dbg.json", - "!artifacts/contracts/test/**/*", - "!artifacts/contracts/base/**/*" - ], - "engines": { - "node": ">=10" - }, - "dependencies": { - "@openzeppelin/contracts": "3.4.2-solc-0.7", - "@uniswap/v2-core": "^1.0.1", - "@uniswap/v3-core": "^1.0.0", - "@uniswap/v3-periphery": "^1.4.4", - "dotenv": "^14.2.0", - "hardhat-watcher": "^2.1.1" - }, - "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.2", - "@nomiclabs/hardhat-etherscan": "^2.1.8", - "@nomiclabs/hardhat-waffle": "^2.0.1", - "@typechain/ethers-v5": "^4.0.0", - "@types/chai": "^4.2.6", - "@types/mocha": "^5.2.7", - "chai": "^4.2.0", - "decimal.js": "^10.2.1", - "ethereum-waffle": "^3.0.2", - "ethers": "^5.0.8", - "hardhat": "^2.6.8", - "hardhat-typechain": "^0.3.5", - "is-svg": "^4.3.1", - "mocha": "^6.2.2", - "mocha-chai-jest-snapshot": "^1.1.0", - "prettier": "^2.0.5", - "prettier-plugin-solidity": "^1.0.0-beta.10", - "solhint": "^3.2.1", - "solhint-plugin-prettier": "^0.0.5", - "ts-generator": "^0.1.1", - "ts-node": "^8.5.4", - "typechain": "^4.0.0", - "typescript": "^3.7.3" - }, - "scripts": { - "compile": "hardhat compile", - "test": "hardhat test" - } -} diff --git a/lib/swap-router-contracts/test/ApproveAndCall.spec.ts b/lib/swap-router-contracts/test/ApproveAndCall.spec.ts deleted file mode 100644 index 1476b53..0000000 --- a/lib/swap-router-contracts/test/ApproveAndCall.spec.ts +++ /dev/null @@ -1,388 +0,0 @@ -import { defaultAbiCoder } from '@ethersproject/abi' -import { Fixture } from 'ethereum-waffle' -import { constants, Contract, ContractTransaction, Wallet } from 'ethers' -import { solidityPack } from 'ethers/lib/utils' -import { ethers, waffle } from 'hardhat' -import { MockTimeSwapRouter02, TestERC20 } from '../typechain' -import completeFixture from './shared/completeFixture' -import { ADDRESS_THIS, FeeAmount, TICK_SPACINGS } from './shared/constants' -import { encodePriceSqrt } from './shared/encodePriceSqrt' -import { expect } from './shared/expect' -import { encodePath } from './shared/path' -import { getMaxTick, getMinTick } from './shared/ticks' - -enum ApprovalType { - NOT_REQUIRED, - MAX, - MAX_MINUS_ONE, - ZERO_THEN_MAX, - ZERO_THEN_MAX_MINUS_ONE, -} - -describe('ApproveAndCall', function () { - this.timeout(40000) - let wallet: Wallet - let trader: Wallet - - const swapRouterFixture: Fixture<{ - factory: Contract - router: MockTimeSwapRouter02 - nft: Contract - tokens: [TestERC20, TestERC20, TestERC20] - }> = async (wallets, provider) => { - const { factory, router, tokens, nft } = await completeFixture(wallets, provider) - - // approve & fund wallets - for (const token of tokens) { - await token.approve(nft.address, constants.MaxUint256) - } - - return { - factory, - router, - tokens, - nft, - } - } - - let factory: Contract - let router: MockTimeSwapRouter02 - let nft: Contract - let tokens: [TestERC20, TestERC20, TestERC20] - - let loadFixture: ReturnType - - function encodeSweepToken(token: string, amount: number) { - const functionSignature = 'sweepToken(address,uint256)' - return solidityPack( - ['bytes4', 'bytes'], - [router.interface.getSighash(functionSignature), defaultAbiCoder.encode(['address', 'uint256'], [token, amount])] - ) - } - - before('create fixture loader', async () => { - ;[wallet, trader] = await (ethers as any).getSigners() - loadFixture = waffle.createFixtureLoader([wallet, trader]) - }) - - beforeEach('load fixture', async () => { - ;({ factory, router, tokens, nft } = await loadFixture(swapRouterFixture)) - }) - - describe('swap and add', () => { - async function createPool(tokenAddressA: string, tokenAddressB: string) { - if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) - [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] - - await nft.createAndInitializePoolIfNecessary( - tokenAddressA, - tokenAddressB, - FeeAmount.MEDIUM, - encodePriceSqrt(1, 1) - ) - - const liquidityParams = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: wallet.address, - amount0Desired: 1000000, - amount1Desired: 1000000, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - return nft.mint(liquidityParams) - } - - describe('approvals', () => { - it('#approveMax', async () => { - let approvalType = await router.callStatic.getApprovalType(tokens[0].address, 123) - expect(approvalType).to.be.eq(ApprovalType.MAX) - - await router.approveMax(tokens[0].address) - - approvalType = await router.callStatic.getApprovalType(tokens[0].address, 123) - expect(approvalType).to.be.eq(ApprovalType.NOT_REQUIRED) - }) - - it('#approveMax', async () => { - await router.approveMax(tokens[0].address) - }) - - it('#approveMaxMinusOne', async () => { - await router.approveMaxMinusOne(tokens[0].address) - }) - - describe('#approveZeroThenMax', async () => { - it('from 0', async () => { - await router.approveZeroThenMax(tokens[0].address) - }) - it('from max', async () => { - await router.approveMax(tokens[0].address) - await router.approveZeroThenMax(tokens[0].address) - }) - }) - - describe('#approveZeroThenMax', async () => { - it('from 0', async () => { - await router.approveZeroThenMaxMinusOne(tokens[0].address) - }) - it('from max', async () => { - await router.approveMax(tokens[0].address) - await router.approveZeroThenMaxMinusOne(tokens[0].address) - }) - }) - }) - - it('#mint and #increaseLiquidity', async () => { - await createPool(tokens[0].address, tokens[1].address) - const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) - - // approve in advance - await router.approveMax(tokens[0].address) - await router.approveMax(tokens[1].address) - - // send dummy amount of tokens to the pair in advance - const amount = 1000 - await tokens[0].transfer(router.address, amount) - await tokens[1].transfer(router.address, amount) - expect((await tokens[0].balanceOf(router.address)).toNumber()).to.be.eq(amount) - expect((await tokens[1].balanceOf(router.address)).toNumber()).to.be.eq(amount) - - let poolBalance0Before = await tokens[0].balanceOf(pool) - let poolBalance1Before = await tokens[1].balanceOf(pool) - - // perform the mint - await router.mint({ - token0: tokens[0].address, - token1: tokens[1].address, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: trader.address, - amount0Min: 0, - amount1Min: 0, - }) - - expect((await tokens[0].balanceOf(router.address)).toNumber()).to.be.eq(0) - expect((await tokens[1].balanceOf(router.address)).toNumber()).to.be.eq(0) - expect((await tokens[0].balanceOf(pool)).toNumber()).to.be.eq(poolBalance0Before.toNumber() + amount) - expect((await tokens[1].balanceOf(pool)).toNumber()).to.be.eq(poolBalance1Before.toNumber() + amount) - - expect((await nft.balanceOf(trader.address)).toNumber()).to.be.eq(1) - - // send more tokens - await tokens[0].transfer(router.address, amount) - await tokens[1].transfer(router.address, amount) - - // perform the increaseLiquidity - await router.increaseLiquidity({ - token0: tokens[0].address, - token1: tokens[1].address, - tokenId: 2, - amount0Min: 0, - amount1Min: 0, - }) - - expect((await tokens[0].balanceOf(router.address)).toNumber()).to.be.eq(0) - expect((await tokens[1].balanceOf(router.address)).toNumber()).to.be.eq(0) - expect((await tokens[0].balanceOf(pool)).toNumber()).to.be.eq(poolBalance0Before.toNumber() + amount * 2) - expect((await tokens[1].balanceOf(pool)).toNumber()).to.be.eq(poolBalance1Before.toNumber() + amount * 2) - - expect((await nft.balanceOf(trader.address)).toNumber()).to.be.eq(1) - }) - - describe('single-asset add', () => { - beforeEach('create 0-1 pool', async () => { - await createPool(tokens[0].address, tokens[1].address) - }) - - async function singleAssetAddExactInput( - tokenIn: string, - tokenOut: string, - amountIn: number, - amountOutMinimum: number - ): Promise { - // encode the exact input swap - const params = { - path: encodePath([tokenIn, tokenOut], [FeeAmount.MEDIUM]), - recipient: ADDRESS_THIS, // have to send to the router, as it will be adding liquidity for the caller - amountIn, - amountOutMinimum, - } - // ensure that the swap fails if the limit is any tighter - const amountOut = await router.connect(trader).callStatic.exactInput(params) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - const data = [router.interface.encodeFunctionData('exactInput', [params])] - - // encode the pull (we take the same as the amountOutMinimum, assuming a 50/50 range) - data.push(router.interface.encodeFunctionData('pull', [tokenIn, amountOutMinimum])) - - // encode the approves - data.push(router.interface.encodeFunctionData('approveMax', [tokenIn])) - data.push(router.interface.encodeFunctionData('approveMax', [tokenOut])) - - // encode the add liquidity - const [token0, token1] = - tokenIn.toLowerCase() < tokenOut.toLowerCase() ? [tokenIn, tokenOut] : [tokenOut, tokenIn] - const liquidityParams = { - token0, - token1, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: trader.address, - amount0Desired: amountOutMinimum, - amount1Desired: amountOutMinimum, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - data.push( - router.interface.encodeFunctionData('callPositionManager', [ - nft.interface.encodeFunctionData('mint', [liquidityParams]), - ]) - ) - - // encode the sweeps - data.push(encodeSweepToken(tokenIn, 0)) - data.push(encodeSweepToken(tokenOut, 0)) - - return router.connect(trader)['multicall(bytes[])'](data) - } - - it('0 -> 1', async () => { - const amountIn = 1000 - const amountOutMinimum = 996 - - // prep for the swap + add by sending tokens - await tokens[0].transfer(trader.address, amountIn + amountOutMinimum) - await tokens[0].connect(trader).approve(router.address, amountIn + amountOutMinimum) - - const traderToken0BalanceBefore = await tokens[0].balanceOf(trader.address) - const traderToken1BalanceBefore = await tokens[1].balanceOf(trader.address) - expect(traderToken0BalanceBefore.toNumber()).to.be.eq(amountIn + amountOutMinimum) - expect(traderToken1BalanceBefore.toNumber()).to.be.eq(0) - - const traderNFTBalanceBefore = await nft.balanceOf(trader.address) - expect(traderNFTBalanceBefore.toNumber()).to.be.eq(0) - - await singleAssetAddExactInput(tokens[0].address, tokens[1].address, amountIn, amountOutMinimum) - - const traderToken0BalanceAfter = await tokens[0].balanceOf(trader.address) - const traderToken1BalanceAfter = await tokens[1].balanceOf(trader.address) - expect(traderToken0BalanceAfter.toNumber()).to.be.eq(0) - expect(traderToken1BalanceAfter.toNumber()).to.be.eq(1) // dust - - const traderNFTBalanceAfter = await nft.balanceOf(trader.address) - expect(traderNFTBalanceAfter.toNumber()).to.be.eq(1) - }) - }) - - describe('any-asset add', () => { - beforeEach('create 0-1, 0-2, and 1-2 pools pools', async () => { - await createPool(tokens[0].address, tokens[1].address) - await createPool(tokens[0].address, tokens[2].address) - await createPool(tokens[1].address, tokens[2].address) - }) - - async function anyAssetAddExactInput( - tokenStart: string, - tokenA: string, - tokenB: string, - amountIn: number, - amountOutMinimum: number - ): Promise { - // encode the exact input swaps - let params = { - path: encodePath([tokenStart, tokenA], [FeeAmount.MEDIUM]), - recipient: ADDRESS_THIS, // have to send to the router, as it will be adding liquidity for the caller - amountIn, - amountOutMinimum, - } - // ensure that the swap fails if the limit is any tighter - let amountOut = await router.connect(trader).callStatic.exactInput(params) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - let data = [router.interface.encodeFunctionData('exactInput', [params])] - - // encode the exact input swaps - params = { - path: encodePath([tokenStart, tokenB], [FeeAmount.MEDIUM]), - recipient: ADDRESS_THIS, // have to send to the router, as it will be adding liquidity for the caller - amountIn, - amountOutMinimum, - } - // ensure that the swap fails if the limit is any tighter - amountOut = await router.connect(trader).callStatic.exactInput(params) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - data.push(router.interface.encodeFunctionData('exactInput', [params])) - - // encode the approves - data.push(router.interface.encodeFunctionData('approveMax', [tokenA])) - data.push(router.interface.encodeFunctionData('approveMax', [tokenB])) - - // encode the add liquidity - const [token0, token1] = tokenA.toLowerCase() < tokenB.toLowerCase() ? [tokenA, tokenB] : [tokenB, tokenA] - const liquidityParams = { - token0, - token1, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: trader.address, - amount0Desired: amountOutMinimum, - amount1Desired: amountOutMinimum, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - data.push( - router.interface.encodeFunctionData('callPositionManager', [ - nft.interface.encodeFunctionData('mint', [liquidityParams]), - ]) - ) - - // encode the sweeps - data.push(encodeSweepToken(tokenA, 0)) - data.push(encodeSweepToken(tokenB, 0)) - - return router.connect(trader)['multicall(bytes[])'](data) - } - - it('0 -> 1 and 0 -> 2', async () => { - const amountIn = 1000 - const amountOutMinimum = 996 - - // prep for the swap + add by sending tokens - await tokens[0].transfer(trader.address, amountIn * 2) - await tokens[0].connect(trader).approve(router.address, amountIn * 2) - - const traderToken0BalanceBefore = await tokens[0].balanceOf(trader.address) - const traderToken1BalanceBefore = await tokens[1].balanceOf(trader.address) - const traderToken2BalanceBefore = await tokens[2].balanceOf(trader.address) - expect(traderToken0BalanceBefore.toNumber()).to.be.eq(amountIn * 2) - expect(traderToken1BalanceBefore.toNumber()).to.be.eq(0) - expect(traderToken2BalanceBefore.toNumber()).to.be.eq(0) - - const traderNFTBalanceBefore = await nft.balanceOf(trader.address) - expect(traderNFTBalanceBefore.toNumber()).to.be.eq(0) - - await anyAssetAddExactInput(tokens[0].address, tokens[1].address, tokens[2].address, amountIn, amountOutMinimum) - - const traderToken0BalanceAfter = await tokens[0].balanceOf(trader.address) - const traderToken1BalanceAfter = await tokens[1].balanceOf(trader.address) - const traderToken2BalanceAfter = await tokens[2].balanceOf(trader.address) - expect(traderToken0BalanceAfter.toNumber()).to.be.eq(0) - expect(traderToken1BalanceAfter.toNumber()).to.be.eq(0) - expect(traderToken2BalanceAfter.toNumber()).to.be.eq(0) - - const traderNFTBalanceAfter = await nft.balanceOf(trader.address) - expect(traderNFTBalanceAfter.toNumber()).to.be.eq(1) - }) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/ImmutableState.spec.ts b/lib/swap-router-contracts/test/ImmutableState.spec.ts deleted file mode 100644 index 6bd642b..0000000 --- a/lib/swap-router-contracts/test/ImmutableState.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Contract } from 'ethers' -import { waffle, ethers } from 'hardhat' - -import { Fixture } from 'ethereum-waffle' -import { ImmutableStateTest } from '../typechain' -import { expect } from './shared/expect' -import completeFixture from './shared/completeFixture' -import { v2FactoryFixture } from './shared/externalFixtures' - -describe('ImmutableState', () => { - const fixture: Fixture<{ - factoryV2: Contract - nft: Contract - state: ImmutableStateTest - }> = async (wallets, provider) => { - const { factory: factoryV2 } = await v2FactoryFixture(wallets, provider) - const { nft } = await completeFixture(wallets, provider) - - const stateFactory = await ethers.getContractFactory('ImmutableStateTest') - const state = (await stateFactory.deploy(factoryV2.address, nft.address)) as ImmutableStateTest - - return { - nft, - factoryV2, - state, - } - } - - let factoryV2: Contract - let nft: Contract - let state: ImmutableStateTest - - let loadFixture: ReturnType - - before('create fixture loader', async () => { - loadFixture = waffle.createFixtureLoader(await (ethers as any).getSigners()) - }) - - beforeEach('load fixture', async () => { - ;({ factoryV2, nft, state } = await loadFixture(fixture)) - }) - - it('bytecode size', async () => { - expect(((await state.provider.getCode(state.address)).length - 2) / 2).to.matchSnapshot() - }) - - describe('#factoryV2', () => { - it('points to v2 core factory', async () => { - expect(await state.factoryV2()).to.eq(factoryV2.address) - }) - }) - - describe('#positionManager', () => { - it('points to NFT', async () => { - expect(await state.positionManager()).to.eq(nft.address) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts b/lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts deleted file mode 100644 index a84b46f..0000000 --- a/lib/swap-router-contracts/test/MixedRouteQuoterV1.integ.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { expect } from 'chai' -import { BigNumber } from 'ethers' -import { MixedRouteQuoterV1 } from '../typechain' - -import hre, { ethers } from 'hardhat' -import { encodePath } from './shared/path' -import { expandTo18Decimals, expandToNDecimals } from './shared/expandTo18Decimals' -import { FeeAmount, V2_FEE_PLACEHOLDER } from './shared/constants' - -const V3_FACTORY = '0x1F98431c8aD98523631AE4a59f267346ea31F984' -const V2_FACTORY = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' - -const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' -const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' -const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' -const UNI = '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984' -const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F' - -/// @dev basic V2 routes -const DAI_V2_UNI_V2_WETH = encodePath([DAI, UNI, WETH], [V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER]) -const USDC_V2_UNI_V2_WETH = encodePath([USDC, UNI, WETH], [V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER]) - -/// @dev basic V3 routes -const USDC_V3_USDT = encodePath([USDC, USDT], [FeeAmount.LOW]) -const UNI_V3_WETH = encodePath([UNI, WETH], [FeeAmount.MEDIUM]) - -/// @dev stablecoin IL routes -const USDT_V3_DAI_V2_USDC = encodePath([USDT, DAI, USDC], [FeeAmount.LOW, V2_FEE_PLACEHOLDER]) -const DAI_V3_USDC_V2_USDT = encodePath([DAI, USDC, USDT], [100, V2_FEE_PLACEHOLDER]) - -/// @dev erc20 IL routes -// V3 - V2 -const UNI_V3_WETH_V2_DAI = encodePath([UNI, WETH, DAI], [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER]) -const USDC_V3_UNI_V2_WETH = encodePath([USDC, UNI, WETH], [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER]) -// V2 - V3 -const UNI_V2_WETH_V3_DAI = encodePath([UNI, WETH, DAI], [V2_FEE_PLACEHOLDER, FeeAmount.MEDIUM]) - -/// @dev complex IL routes -// (use two V3 pools) -const DAI_V3_3000_UNI_V2_USDT_V3_3000_WETH = encodePath( - [DAI, UNI, USDT, WETH], - [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER, FeeAmount.MEDIUM] -) -// (use two V2 pools) -const DAI_V3_3000_UNI_V2_USDT_V2_WETH = encodePath( - [DAI, UNI, USDT, WETH], - [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER] -) - -describe('MixedRouteQuoterV1 integration tests', function () { - let mixedRouteQuoter: MixedRouteQuoterV1 - - this.timeout(100000) - - before(async function () { - if (!process.env.ARCHIVE_RPC_URL) { - this.skip() - } - - await hre.network.provider.request({ - method: 'hardhat_reset', - params: [ - { - forking: { - jsonRpcUrl: process.env.ARCHIVE_RPC_URL, - blockNumber: 14390000, - }, - }, - ], - }) - - const MixedRouteQuoterV1Factory = await ethers.getContractFactory('MixedRouteQuoterV1') - mixedRouteQuoter = (await MixedRouteQuoterV1Factory.deploy(V3_FACTORY, V2_FACTORY, WETH)) as MixedRouteQuoterV1 - }) - - after(async () => { - // Disable mainnet forking to avoid effecting other tests. - await hre.network.provider.request({ - method: 'hardhat_reset', - params: [], - }) - }) - - /** - * Test values only valid starting at block 14390000 - */ - it('sets block number correctly', async () => { - const blockNumber = BigNumber.from( - await hre.network.provider.request({ - method: 'eth_blockNumber', - params: [], - }) - ) - /// @dev +1 so 14390001 since we just requested - expect(blockNumber.eq(14390001)).to.be.true - }) - - describe('quotes stablecoin only paths correctly', () => { - /// @dev the amount must be expanded to the decimals of the first token in the path - it('V3-V2 stablecoin path with 6 decimal in start of path', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](USDT_V3_DAI_V2_USDC, expandToNDecimals(10000, 6)) - - expect(amountOut).eq(BigNumber.from('9966336832')) - expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x10c6727487c45717095f'))).to.be.true - }) - - it('V3-V2 stablecoin path with 6 decimal in middle of path', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](DAI_V3_USDC_V2_USDT, expandTo18Decimals(10000)) - - expect(amountOut).eq(BigNumber.from('9959354898')) - expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x10c715093f77e3073634'))).to.be.true - }) - }) - - describe('V2-V2 quotes', () => { - it('quotes V2-V2 correctly', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](DAI_V2_UNI_V2_WETH, expandTo18Decimals(10000)) - - expect(amountOut).eq(BigNumber.from('2035189623576328665')) - expect(v3SqrtPriceX96AfterList.every((el) => el.eq(0))).to.be.true - expect(v3InitializedTicksCrossedList.every((el) => el == 0)).to.be.true - }) - - it('quotes V2 (6 decimal stablecoin) -V2 correctly', async () => { - const { amountOut } = await mixedRouteQuoter.callStatic['quoteExactInput(bytes,uint256)']( - USDC_V2_UNI_V2_WETH, - expandToNDecimals(10000, 6) - ) - - expect(amountOut).eq(BigNumber.from('1989381322826753150')) - }) - }) - - it('quotes V3-V2 erc20s with mixed decimal scales correctly', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](USDC_V3_UNI_V2_WETH, expandToNDecimals(10000, 6)) - - expect(amountOut).eq(BigNumber.from('3801923847986895918')) // 3.801923847986895918 - expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x3110863ba621ac3915fd'))).to.be.true - }) - - it('quotes V3-V2 correctly', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](UNI_V3_WETH_V2_DAI, expandTo18Decimals(10000)) - - expect(amountOut).eq(BigNumber.from('80675538331724434694636')) - expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0x0e83f285cb58c4cca14fb78b'))).to.be.true - }) - - it('quotes V3-V2-V3 correctly', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](DAI_V3_3000_UNI_V2_USDT_V3_3000_WETH, expandTo18Decimals(10000)) - - expect(amountOut).eq(BigNumber.from('886596560223108447')) - expect(v3SqrtPriceX96AfterList[0].eq(BigNumber.from('0xfffd8963efd1fc6a506488495d951d5263988d25'))).to.be.true - expect(v3SqrtPriceX96AfterList[2].eq(BigNumber.from('0x034b624fce51aba62a4722'))).to.be.true - }) - - it('quotes V2-V3 correctly', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](UNI_V2_WETH_V3_DAI, expandTo18Decimals(10000)) - - expect(amountOut).eq(BigNumber.from('81108655328627859394525')) - expect(v3SqrtPriceX96AfterList[1].eq(BigNumber.from('0x0518b75d40eb50192903493d'))).to.be.true - }) - - it('quotes only V3 correctly', async () => { - const { amountOut, v3SqrtPriceX96AfterList, v3InitializedTicksCrossedList } = await mixedRouteQuoter.callStatic[ - 'quoteExactInput(bytes,uint256)' - ](UNI_V3_WETH, expandTo18Decimals(10000)) - - expect(amountOut.eq(BigNumber.from('32215526370828998898'))).to.be.true - }) -}) diff --git a/lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts b/lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts deleted file mode 100644 index f0b6ed4..0000000 --- a/lib/swap-router-contracts/test/MixedRouteQuoterV1.spec.ts +++ /dev/null @@ -1,460 +0,0 @@ -import { Fixture } from 'ethereum-waffle' -import { constants, Wallet, Contract, BigNumber } from 'ethers' -import { ethers, waffle } from 'hardhat' -import { MixedRouteQuoterV1, TestERC20 } from '../typechain' -import completeFixture from './shared/completeFixture' -import { FeeAmount, V2_FEE_PLACEHOLDER } from './shared/constants' -import { encodePriceSqrt } from './shared/encodePriceSqrt' -import { expandTo18Decimals } from './shared/expandTo18Decimals' -import { expect } from './shared/expect' -import { encodePath } from './shared/path' -import { - createPair, - createPool, - createPoolWithMultiplePositions, - createPoolWithZeroTickInitialized, -} from './shared/quoter' -import snapshotGasCost from './shared/snapshotGasCost' - -import { abi as PAIR_V2_ABI } from '@uniswap/v2-core/build/UniswapV2Pair.json' - -const V3_MAX_FEE = 999999 // = 1_000_000 - 1 since must be < 1_000_000 - -describe('MixedRouteQuoterV1', function () { - this.timeout(40000) - let wallet: Wallet - let trader: Wallet - - const swapRouterFixture: Fixture<{ - nft: Contract - factoryV2: Contract - tokens: [TestERC20, TestERC20, TestERC20] - quoter: MixedRouteQuoterV1 - }> = async (wallets, provider) => { - const { weth9, factory, factoryV2, router, tokens, nft } = await completeFixture(wallets, provider) - - // approve & fund wallets - for (const token of tokens) { - await token.approve(router.address, constants.MaxUint256) - await token.approve(nft.address, constants.MaxUint256) - await token.connect(trader).approve(router.address, constants.MaxUint256) - await token.transfer(trader.address, expandTo18Decimals(1_000_000)) - } - - const quoterFactory = await ethers.getContractFactory('MixedRouteQuoterV1') - quoter = (await quoterFactory.deploy(factory.address, factoryV2.address, weth9.address)) as MixedRouteQuoterV1 - - return { - tokens, - nft, - factoryV2, - quoter, - } - } - - let nft: Contract - let factoryV2: Contract - let tokens: [TestERC20, TestERC20, TestERC20] - let quoter: MixedRouteQuoterV1 - - let pair01Address, pair02Address, pair12Address: string - - let loadFixture: ReturnType - - before('create fixture loader', async () => { - const wallets = await (ethers as any).getSigners() - ;[wallet, trader] = wallets - loadFixture = waffle.createFixtureLoader(wallets) - }) - - // helper for getting weth and token balances - beforeEach('load fixture', async () => { - ;({ tokens, nft, factoryV2, quoter } = await loadFixture(swapRouterFixture)) - }) - - const addLiquidityV2 = async ( - pairAddress: string, - token0: TestERC20, - token1: TestERC20, - amount0: string, - amount1: string - ) => { - const pair = new Contract(pairAddress, PAIR_V2_ABI, wallet) - expect(await pair.callStatic.token0()).to.equal(token0.address) - expect(await pair.callStatic.token1()).to.equal(token1.address) - // seed the pairs with liquidity - - const [reserve0Before, reserve1Before]: [BigNumber, BigNumber] = await pair.callStatic.getReserves() - - const token0BalanceBefore = await token0.balanceOf(pairAddress) - const token1BalanceBefore = await token1.balanceOf(pairAddress) - - await token0.transfer(pairAddress, ethers.utils.parseEther(amount0)) - await token1.transfer(pairAddress, ethers.utils.parseEther(amount1)) - - expect(await token0.balanceOf(pairAddress)).to.equal(token0BalanceBefore.add(ethers.utils.parseEther(amount0))) - expect(await token1.balanceOf(pairAddress)).to.equal(token1BalanceBefore.add(ethers.utils.parseEther(amount1))) - - await pair.mint(wallet.address) // update the reserves - - const [reserve0, reserve1] = await pair.callStatic.getReserves() - expect(reserve0).to.equal(reserve0Before.add(ethers.utils.parseEther(amount0))) - expect(reserve1).to.equal(reserve1Before.add(ethers.utils.parseEther(amount1))) - } - - describe('quotes', () => { - beforeEach(async () => { - await createPool(nft, wallet, tokens[0].address, tokens[1].address) - await createPool(nft, wallet, tokens[1].address, tokens[2].address) - await createPoolWithMultiplePositions(nft, wallet, tokens[0].address, tokens[2].address) - /// @dev Create V2 Pairs - pair01Address = await createPair(factoryV2, tokens[0].address, tokens[1].address) - pair12Address = await createPair(factoryV2, tokens[1].address, tokens[2].address) - pair02Address = await createPair(factoryV2, tokens[0].address, tokens[2].address) - - await addLiquidityV2(pair01Address, tokens[0], tokens[1], '1000000', '1000000') - await addLiquidityV2(pair12Address, tokens[1], tokens[2], '1000000', '1000000') - await addLiquidityV2(pair02Address, tokens[0], tokens[2], '1000000', '1000000') - }) - - /// @dev Test running the old suite on the new function but with protocolFlags only being V3[] - describe('#quoteExactInput V3 only', () => { - it('0 -> 2 cross 2 tick', async () => { - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 10000 - ) - - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') - expect(v3InitializedTicksCrossedList[0]).to.eq(2) - expect(amountOut).to.eq(9871) - await snapshotGasCost(v3SwapGasEstimate) - }) - - it('0 -> 2 cross 2 tick where after is initialized', async () => { - // The swap amount is set such that the active tick after the swap is -120. - // -120 is an initialized tick for this pool. We check that we don't count it. - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 6200 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('78757224507315167622282810783') - expect(v3InitializedTicksCrossedList.length).to.eq(1) - expect(v3InitializedTicksCrossedList[0]).to.eq(1) - expect(amountOut).to.eq(6143) - }) - - it('0 -> 2 cross 1 tick', async () => { - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 4000 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3InitializedTicksCrossedList[0]).to.eq(1) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('78926452400586371254602774705') - expect(amountOut).to.eq(3971) - }) - - it('0 -> 2 cross 0 tick, starting tick not initialized', async () => { - // Tick before 0, tick after -1. - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 10 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3InitializedTicksCrossedList[0]).to.eq(0) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('79227483487511329217250071027') - expect(amountOut).to.eq(8) - }) - - it('0 -> 2 cross 0 tick, starting tick initialized', async () => { - // Tick before 0, tick after -1. Tick 0 initialized. - await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) - - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 10 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3InitializedTicksCrossedList[0]).to.eq(1) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('79227817515327498931091950511') - expect(amountOut).to.eq(8) - }) - - it('2 -> 0 cross 2', async () => { - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 10000 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3InitializedTicksCrossedList[0]).to.eq(2) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('80001962924147897865541384515') - expect(v3InitializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(9871) - }) - - it('2 -> 0 cross 2 where tick after is initialized', async () => { - // The swap amount is set such that the active tick after the swap is 120. - // 120 is an initialized tick for this pool. We check we don't count it. - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 6250 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3InitializedTicksCrossedList[0]).to.eq(2) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('79705728824507063507279123685') - expect(v3InitializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(6190) - }) - - it('2 -> 0 cross 0 tick, starting tick initialized', async () => { - // Tick 0 initialized. Tick after = 1 - await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) - - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 200 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3InitializedTicksCrossedList[0]).to.eq(0) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('79235729830182478001034429156') - expect(v3InitializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(198) - }) - - it('2 -> 0 cross 0 tick, starting tick not initialized', async () => { - // Tick 0 initialized. Tick after = 1 - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 103 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3InitializedTicksCrossedList[0]).to.eq(0) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('79235858216754624215638319723') - expect(v3InitializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(101) - }) - - it('2 -> 1', async () => { - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM]), - 10000 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3SqrtPriceX96AfterList.length).to.eq(1) - expect(v3SqrtPriceX96AfterList[0]).to.eq('80018067294531553039351583520') - expect(v3InitializedTicksCrossedList[0]).to.eq(0) - expect(amountOut).to.eq(9871) - }) - - it('0 -> 2 -> 1', async () => { - const { - amountOut, - v3SqrtPriceX96AfterList, - v3InitializedTicksCrossedList, - v3SwapGasEstimate, - } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), - 10000 - ) - - await snapshotGasCost(v3SwapGasEstimate) - expect(v3SqrtPriceX96AfterList.length).to.eq(2) - expect(v3SqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') - expect(v3SqrtPriceX96AfterList[1]).to.eq('80007846861567212939802016351') - expect(v3InitializedTicksCrossedList[0]).to.eq(2) - expect(v3InitializedTicksCrossedList[1]).to.eq(0) - expect(amountOut).to.eq(9745) - }) - }) - - /// @dev Test running the old suite on the new function but with protocolFlags only being V2[] - describe('#quoteExactInput V2 only', () => { - it('0 -> 2', async () => { - const { amountOut, v3SwapGasEstimate } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[2].address], [V2_FEE_PLACEHOLDER]), - 10000 - ) - - expect(amountOut).to.eq(9969) - }) - - it('0 -> 1 -> 2', async () => { - const { amountOut, v3SwapGasEstimate } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath( - [tokens[0].address, tokens[1].address, tokens[2].address], - [V2_FEE_PLACEHOLDER, V2_FEE_PLACEHOLDER] - ), - 10000 - ) - - expect(amountOut).to.eq(9939) - }) - }) - - /// @dev Test copied over from QuoterV2.spec.ts - describe('#quoteExactInputSingle V3', () => { - it('0 -> 2', async () => { - const { - amountOut: quote, - sqrtPriceX96After, - initializedTicksCrossed, - gasEstimate, - } = await quoter.callStatic.quoteExactInputSingleV3({ - tokenIn: tokens[0].address, - tokenOut: tokens[2].address, - fee: FeeAmount.MEDIUM, - amountIn: 10000, - // -2% - sqrtPriceLimitX96: encodePriceSqrt(100, 102), - }) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossed).to.eq(2) - expect(quote).to.eq(9871) - expect(sqrtPriceX96After).to.eq('78461846509168490764501028180') - }) - - it('2 -> 0', async () => { - const { - amountOut: quote, - sqrtPriceX96After, - initializedTicksCrossed, - gasEstimate, - } = await quoter.callStatic.quoteExactInputSingleV3({ - tokenIn: tokens[2].address, - tokenOut: tokens[0].address, - fee: FeeAmount.MEDIUM, - amountIn: 10000, - // +2% - sqrtPriceLimitX96: encodePriceSqrt(102, 100), - }) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossed).to.eq(2) - expect(quote).to.eq(9871) - expect(sqrtPriceX96After).to.eq('80001962924147897865541384515') - }) - }) - - /// @dev Test the new function for fetching a single V2 pair quote on chain (exactIn) - describe('#quoteExactInputSingleV2', () => { - it('0 -> 2', async () => { - const amountIn = 10000 - const tokenIn = tokens[0].address - const tokenOut = tokens[2].address - const quote = await quoter.callStatic.quoteExactInputSingleV2({ tokenIn, tokenOut, amountIn }) - - expect(quote).to.eq(9969) - }) - - it('2 -> 0', async () => { - const amountIn = 10000 - const tokenIn = tokens[2].address - const tokenOut = tokens[0].address - const quote = await quoter.callStatic.quoteExactInputSingleV2({ tokenIn, tokenOut, amountIn }) - - expect(quote).to.eq(9969) - }) - - describe('+ with imbalanced pairs', () => { - before(async () => { - await addLiquidityV2(pair12Address, tokens[1], tokens[2], '1000000', '1000') - }) - - it('1 -> 2', async () => { - const amountIn = 2_000_000 - const tokenIn = tokens[1].address - const tokenOut = tokens[2].address - const quote = await quoter.callStatic.quoteExactInputSingleV2({ tokenIn, tokenOut, amountIn }) - - expect(quote).to.eq(1993999) - }) - }) - }) - - describe('testing bit masking for protocol selection', () => { - it('when given the max v3 fee, should still route v3 and revert because pool DNE', async () => { - /// @define 999999 is the max fee that can be set on a V3 pool per the factory - /// in this environment this pool does not exist, and thus the call should revert - /// - however, if the bitmask fails to catch this the call will succeed and route to V2 - /// - thus, we expect it to be reverted. - await expect( - quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[1].address], [V3_MAX_FEE]), - 10000 - ) - ).to.be.reverted - }) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/MulticallExtended.spec.ts b/lib/swap-router-contracts/test/MulticallExtended.spec.ts deleted file mode 100644 index 4e431f6..0000000 --- a/lib/swap-router-contracts/test/MulticallExtended.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { constants } from 'ethers' -import { ethers } from 'hardhat' -import { TestMulticallExtended } from '../typechain/TestMulticallExtended' -import { expect } from './shared/expect' - -describe('MulticallExtended', async () => { - let multicall: TestMulticallExtended - - beforeEach('create multicall', async () => { - const multicallTestFactory = await ethers.getContractFactory('TestMulticallExtended') - multicall = (await multicallTestFactory.deploy()) as TestMulticallExtended - }) - - it('fails deadline check', async () => { - await multicall.setTime(1) - await expect( - multicall['multicall(uint256,bytes[])'](0, [ - multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), - ]) - ).to.be.revertedWith('Transaction too old') - }) - - it('passes deadline check', async () => { - const [data] = await multicall.callStatic['multicall(uint256,bytes[])'](0, [ - multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), - ]) - const { - tuple: { a, b }, - } = multicall.interface.decodeFunctionResult('functionThatReturnsTuple', data) - expect(b).to.eq(1) - expect(a).to.eq(2) - }) - - it('fails previousBlockhash check', async () => { - await expect( - multicall['multicall(bytes32,bytes[])'](constants.HashZero, [ - multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), - ]) - ).to.be.revertedWith('Blockhash') - }) - - it('passes previousBlockhash check', async () => { - const block = await ethers.provider.getBlock('latest') - await expect( - multicall['multicall(bytes32,bytes[])'](block.hash, [ - multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), - ]) - ).to.not.be.reverted - }) -}) diff --git a/lib/swap-router-contracts/test/OracleSlippage.spec.ts b/lib/swap-router-contracts/test/OracleSlippage.spec.ts deleted file mode 100644 index bd9d95b..0000000 --- a/lib/swap-router-contracts/test/OracleSlippage.spec.ts +++ /dev/null @@ -1,447 +0,0 @@ -import { constants, ContractFactory } from 'ethers' -import { ethers, waffle } from 'hardhat' -import { MockObservations, OracleSlippageTest } from '../typechain' -import { FeeAmount } from './shared/constants' -import { expect } from './shared/expect' -import { encodePath } from './shared/path' - -const tokens = [ - '0x0000000000000000000000000000000000000001', - '0x0000000000000000000000000000000000000002', - '0x0000000000000000000000000000000000000003', -] - -describe('OracleSlippage', function () { - this.timeout(40000) - - let loadFixture: ReturnType - - let oracle: OracleSlippageTest - let mockObservationsFactory: ContractFactory - - const oracleTestFixture = async () => { - const oracleFactory = await ethers.getContractFactory('OracleSlippageTest') - const oracle = await oracleFactory.deploy(constants.AddressZero, constants.AddressZero) - - return oracle as OracleSlippageTest - } - - before('create fixture loader', async () => { - loadFixture = waffle.createFixtureLoader(await (ethers as any).getSigners()) - }) - - beforeEach('deploy fixture', async () => { - oracle = await loadFixture(oracleTestFixture) - }) - - before('create mockObservationsFactory', async () => { - mockObservationsFactory = await ethers.getContractFactory('MockObservations') - }) - - async function createMockPool( - tokenA: string, - tokenB: string, - fee: FeeAmount, - blockTimestamps: number[], - ticks: number[], - mockLowObservationCardinality = false - ): Promise { - const mockPool = await mockObservationsFactory.deploy(blockTimestamps, ticks, mockLowObservationCardinality) - await oracle.registerPool(mockPool.address, tokenA, tokenB, fee) - await oracle.setTime(blockTimestamps[blockTimestamps.length - 1]) - return mockPool as MockObservations - } - - describe('#getBlockStartingAndCurrentTick', () => { - it('fails when observationCardinality == 1', async () => { - const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 0, 0], true) - await expect(oracle.testGetBlockStartingAndCurrentTick(mockPool.address)).to.be.revertedWith('NEO') - }) - - it('works when ticks are the same in the same block', async () => { - const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) - const { blockStartingTick, currentTick } = await oracle.testGetBlockStartingAndCurrentTick(mockPool.address) - expect(blockStartingTick).to.eq(11) - expect(currentTick).to.eq(11) - }) - - it('works when ticks are different in the same block', async () => { - const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - const { blockStartingTick, currentTick } = await oracle.testGetBlockStartingAndCurrentTick(mockPool.address) - expect(blockStartingTick).to.eq(11) - expect(currentTick).to.eq(12) - }) - - it('works when time has passed since the last block', async () => { - const mockPool = await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - await oracle.setTime(3) - const { blockStartingTick, currentTick } = await oracle.testGetBlockStartingAndCurrentTick(mockPool.address) - expect(blockStartingTick).to.eq(12) - expect(currentTick).to.eq(12) - }) - }) - - describe('#getSyntheticTicks(bytes,uint32)', () => { - describe('single pool', () => { - describe('unchanged ticks; secondsAgo = 0', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(11) - expect(syntheticCurrentTick).to.eq(11) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(-11) - expect(syntheticCurrentTick).to.eq(-11) - }) - }) - - describe('changed ticks; secondsAgo = 0', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(11) - expect(syntheticCurrentTick).to.eq(12) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(-11) - expect(syntheticCurrentTick).to.eq(-12) - }) - }) - - describe('unchanged ticks; secondsAgo != 0', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(11) - expect(syntheticCurrentTick).to.eq(11) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(-11) - expect(syntheticCurrentTick).to.eq(-11) - }) - }) - - describe('changed ticks', () => { - describe('secondsAgo = 1', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(11) - expect(syntheticCurrentTick).to.eq(12) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(-11) - expect(syntheticCurrentTick).to.eq(-12) - }) - }) - - describe('secondsAgo = 2', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [10, 12, 13]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2), [FeeAmount.LOW]), - 2 - ) - expect(syntheticAverageTick).to.eq(11) - expect(syntheticCurrentTick).to.eq(13) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice(0, 2).reverse(), [FeeAmount.LOW]), - 2 - ) - expect(syntheticAverageTick).to.eq(-11) - expect(syntheticCurrentTick).to.eq(-13) - }) - }) - }) - }) - - describe('two pools', () => { - describe('unchanged ticks; secondsAgo = 0', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) - await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(22) - expect(syntheticCurrentTick).to.eq(22) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(-22) - expect(syntheticCurrentTick).to.eq(-22) - }) - }) - - describe('changed ticks; secondsAgo = 0', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(22) - expect(syntheticCurrentTick).to.eq(24) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - 0 - ) - expect(syntheticAverageTick).to.eq(-22) - expect(syntheticCurrentTick).to.eq(-24) - }) - }) - - describe('unchanged ticks; secondsAgo != 0', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) - await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 11]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(22) - expect(syntheticCurrentTick).to.eq(22) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(-22) - expect(syntheticCurrentTick).to.eq(-22) - }) - }) - - describe('changed ticks', () => { - describe('secondsAgo = 1', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(22) - expect(syntheticCurrentTick).to.eq(24) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - 1 - ) - expect(syntheticAverageTick).to.eq(-22) - expect(syntheticCurrentTick).to.eq(-24) - }) - }) - - describe('secondsAgo = 2', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [10, 12, 13]) - await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [10, 12, 13]) - }) - - it('normal order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), - 2 - ) - expect(syntheticAverageTick).to.eq(22) - expect(syntheticCurrentTick).to.eq(26) - }) - - it('reverse order', async () => { - const { syntheticAverageTick, syntheticCurrentTick } = await oracle['testGetSyntheticTicks(bytes,uint32)']( - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - 2 - ) - expect(syntheticAverageTick).to.eq(-22) - expect(syntheticCurrentTick).to.eq(-26) - }) - }) - }) - }) - }) - - describe('#getSyntheticTicks(bytes[],uint128[],uint32)', () => { - describe('same price', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - await createMockPool(tokens[0], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 22, 24]) - }) - - it('normal order', async () => { - const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ - 'testGetSyntheticTicks(bytes[],uint128[],uint32)' - ]( - [encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), encodePath([tokens[0], tokens[2]], [FeeAmount.LOW])], - [1, 1], - 0 - ) - - expect(averageSyntheticAverageTick).to.eq(22) - expect(averageSyntheticCurrentTick).to.eq(24) - }) - - it('reverse order', async () => { - const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ - 'testGetSyntheticTicks(bytes[],uint128[],uint32)' - ]( - [ - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - encodePath([tokens[2], tokens[0]], [FeeAmount.LOW]), - ], - [1, 1], - 0 - ) - - expect(averageSyntheticAverageTick).to.eq(-22) - expect(averageSyntheticCurrentTick).to.eq(-24) - }) - }) - - describe('difference price', () => { - beforeEach(async () => { - await createMockPool(tokens[0], tokens[1], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - await createMockPool(tokens[1], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 11, 12]) - await createMockPool(tokens[0], tokens[2], FeeAmount.LOW, [0, 1, 2], [0, 44, 48]) - }) - - describe('same weight', () => { - it('normal order', async () => { - const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ - 'testGetSyntheticTicks(bytes[],uint128[],uint32)' - ]( - [encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), encodePath([tokens[0], tokens[2]], [FeeAmount.LOW])], - [1, 1], - 0 - ) - - expect(averageSyntheticAverageTick).to.eq(33) - expect(averageSyntheticCurrentTick).to.eq(36) - }) - - it('reverse order', async () => { - const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ - 'testGetSyntheticTicks(bytes[],uint128[],uint32)' - ]( - [ - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - encodePath([tokens[2], tokens[0]], [FeeAmount.LOW]), - ], - [1, 1], - 0 - ) - - expect(averageSyntheticAverageTick).to.eq(-33) - expect(averageSyntheticCurrentTick).to.eq(-36) - }) - }) - - describe('different weights', () => { - it('normal order', async () => { - const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ - 'testGetSyntheticTicks(bytes[],uint128[],uint32)' - ]( - [encodePath(tokens, [FeeAmount.LOW, FeeAmount.LOW]), encodePath([tokens[0], tokens[2]], [FeeAmount.LOW])], - [1, 2], - 0 - ) - - expect(averageSyntheticAverageTick).to.eq(36) - expect(averageSyntheticCurrentTick).to.eq(40) - }) - - it('reverse order', async () => { - const { averageSyntheticAverageTick, averageSyntheticCurrentTick } = await oracle[ - 'testGetSyntheticTicks(bytes[],uint128[],uint32)' - ]( - [ - encodePath(tokens.slice().reverse(), [FeeAmount.LOW, FeeAmount.LOW]), - encodePath([tokens[2], tokens[0]], [FeeAmount.LOW]), - ], - [1, 2], - 0 - ) - - expect(averageSyntheticAverageTick).to.eq(-37) - expect(averageSyntheticCurrentTick).to.eq(-40) - }) - }) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts b/lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts deleted file mode 100644 index a10f04e..0000000 --- a/lib/swap-router-contracts/test/PeripheryPaymentsExtended.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Fixture } from 'ethereum-waffle' -import { constants, Contract, ContractTransaction, Wallet } from 'ethers' -import { waffle, ethers } from 'hardhat' -import { IWETH9, MockTimeSwapRouter02 } from '../typechain' -import completeFixture from './shared/completeFixture' -import { expect } from './shared/expect' - -describe('PeripheryPaymentsExtended', function () { - let wallet: Wallet - - const routerFixture: Fixture<{ - weth9: IWETH9 - router: MockTimeSwapRouter02 - }> = async (wallets, provider) => { - const { weth9, router } = await completeFixture(wallets, provider) - - return { - weth9, - router, - } - } - - let router: MockTimeSwapRouter02 - let weth9: IWETH9 - - let loadFixture: ReturnType - - before('create fixture loader', async () => { - ;[wallet] = await (ethers as any).getSigners() - loadFixture = waffle.createFixtureLoader([wallet]) - }) - - beforeEach('load fixture', async () => { - ;({ weth9, router } = await loadFixture(routerFixture)) - }) - - describe('wrapETH', () => { - it('increases router WETH9 balance by value amount', async () => { - const value = ethers.utils.parseEther('1') - - const weth9BalancePrev = await weth9.balanceOf(router.address) - await router.wrapETH(value, { value }) - const weth9BalanceCurrent = await weth9.balanceOf(router.address) - - expect(weth9BalanceCurrent.sub(weth9BalancePrev)).to.equal(value) - expect(await weth9.balanceOf(wallet.address)).to.equal('0') - expect(await router.provider.getBalance(router.address)).to.equal('0') - }) - }) -}) diff --git a/lib/swap-router-contracts/test/PoolTicksCounter.spec.ts b/lib/swap-router-contracts/test/PoolTicksCounter.spec.ts deleted file mode 100644 index 5be0ce0..0000000 --- a/lib/swap-router-contracts/test/PoolTicksCounter.spec.ts +++ /dev/null @@ -1,280 +0,0 @@ -import { waffle, ethers, artifacts } from 'hardhat' - -import { expect } from './shared/expect' - -import { PoolTicksCounterTest } from '../typechain' -import { deployMockContract, Fixture, MockContract } from 'ethereum-waffle' -import { Artifact } from 'hardhat/types' - -describe('PoolTicksCounter', () => { - const TICK_SPACINGS = [200, 60, 10] - - TICK_SPACINGS.forEach((TICK_SPACING) => { - let PoolTicksCounter: PoolTicksCounterTest - let pool: MockContract - let PoolAbi: Artifact - - // Bit index to tick - const bitIdxToTick = (idx: number, page = 0) => { - return idx * TICK_SPACING + page * 256 * TICK_SPACING - } - - before(async () => { - const wallets = await (ethers as any).getSigners() - PoolAbi = await artifacts.readArtifact('IUniswapV3Pool') - const poolTicksHelperFactory = await ethers.getContractFactory('PoolTicksCounterTest') - PoolTicksCounter = (await poolTicksHelperFactory.deploy()) as PoolTicksCounterTest - pool = await deployMockContract(wallets[0], PoolAbi.abi) - await pool.mock.tickSpacing.returns(TICK_SPACING) - }) - - describe(`[Tick Spacing: ${TICK_SPACING}]: tick after is bigger`, async () => { - it('same tick initialized', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(2), - bitIdxToTick(2) - ) - expect(result).to.be.eq(1) - }) - - it('same tick not-initialized', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(1), - bitIdxToTick(1) - ) - expect(result).to.be.eq(0) - }) - - it('same page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(0), - bitIdxToTick(255) - ) - expect(result).to.be.eq(2) - }) - - it('multiple pages', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1100) // 1100 - await pool.mock.tickBitmap.withArgs(1).returns(0b1101) // 1101 - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(0), - bitIdxToTick(255, 1) - ) - expect(result).to.be.eq(5) - }) - - it('counts all ticks in a page except ending tick', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(ethers.constants.MaxUint256) - await pool.mock.tickBitmap.withArgs(1).returns(0x0) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(0), - bitIdxToTick(255, 1) - ) - expect(result).to.be.eq(255) - }) - - it('counts ticks to left of start and right of end on same page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(8), - bitIdxToTick(255) - ) - expect(result).to.be.eq(4) - }) - - it('counts ticks to left of start and right of end across on multiple pages', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) - await pool.mock.tickBitmap.withArgs(1).returns(0b1111000100001111) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(8), - bitIdxToTick(8, 1) - ) - expect(result).to.be.eq(9) - }) - - it('counts ticks when before and after are initialized on same page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) - const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(2), - bitIdxToTick(255) - ) - expect(startingTickInit).to.be.eq(5) - const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(0), - bitIdxToTick(3) - ) - expect(endingTickInit).to.be.eq(2) - const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(2), - bitIdxToTick(5) - ) - expect(bothInit).to.be.eq(3) - }) - - it('counts ticks when before and after are initialized on multiple page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) - await pool.mock.tickBitmap.withArgs(1).returns(0b11111100) - const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(2), - bitIdxToTick(255) - ) - expect(startingTickInit).to.be.eq(5) - const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(0), - bitIdxToTick(3, 1) - ) - expect(endingTickInit).to.be.eq(8) - const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(2), - bitIdxToTick(5, 1) - ) - expect(bothInit).to.be.eq(9) - }) - - it('counts ticks with lots of pages', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) - await pool.mock.tickBitmap.withArgs(1).returns(0b11111111) - await pool.mock.tickBitmap.withArgs(2).returns(0x0) - await pool.mock.tickBitmap.withArgs(3).returns(0x0) - await pool.mock.tickBitmap.withArgs(4).returns(0b11111100) - - const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(4), - bitIdxToTick(5, 4) - ) - expect(bothInit).to.be.eq(15) - }) - }) - - describe(`[Tick Spacing: ${TICK_SPACING}]: tick after is smaller`, async () => { - it('same page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1100) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(255), - bitIdxToTick(0) - ) - expect(result).to.be.eq(2) - }) - - it('multiple pages', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1100) - await pool.mock.tickBitmap.withArgs(-1).returns(0b1100) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(255), - bitIdxToTick(0, -1) - ) - expect(result).to.be.eq(4) - }) - - it('counts all ticks in a page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(ethers.constants.MaxUint256) - await pool.mock.tickBitmap.withArgs(-1).returns(0x0) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(255), - bitIdxToTick(0, -1) - ) - expect(result).to.be.eq(256) - }) - - it('counts ticks to right of start and left of end on same page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(15), - bitIdxToTick(2) - ) - expect(result).to.be.eq(6) - }) - - it('counts ticks to right of start and left of end on multiple pages', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b1111000100001111) - await pool.mock.tickBitmap.withArgs(-1).returns(0b1111000100001111) - const result = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(8), - bitIdxToTick(8, -1) - ) - expect(result).to.be.eq(9) - }) - - it('counts ticks when before and after are initialized on same page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) - const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(3), - bitIdxToTick(0) - ) - expect(startingTickInit).to.be.eq(2) - const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(255), - bitIdxToTick(2) - ) - expect(endingTickInit).to.be.eq(5) - const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(5), - bitIdxToTick(2) - ) - expect(bothInit).to.be.eq(3) - }) - - it('counts ticks when before and after are initialized on multiple page', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) - await pool.mock.tickBitmap.withArgs(-1).returns(0b11111100) - const startingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(2), - bitIdxToTick(3, -1) - ) - expect(startingTickInit).to.be.eq(5) - const endingTickInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(5), - bitIdxToTick(255, -1) - ) - expect(endingTickInit).to.be.eq(4) - const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(2), - bitIdxToTick(5, -1) - ) - expect(bothInit).to.be.eq(3) - }) - - it('counts ticks with lots of pages', async () => { - await pool.mock.tickBitmap.withArgs(0).returns(0b11111100) - await pool.mock.tickBitmap.withArgs(-1).returns(0xff) - await pool.mock.tickBitmap.withArgs(-2).returns(0x0) - await pool.mock.tickBitmap.withArgs(-3).returns(0x0) - await pool.mock.tickBitmap.withArgs(-4).returns(0b11111100) - const bothInit = await PoolTicksCounter.countInitializedTicksCrossed( - pool.address, - bitIdxToTick(3), - bitIdxToTick(6, -4) - ) - expect(bothInit).to.be.eq(11) - }) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/Quoter.spec.ts b/lib/swap-router-contracts/test/Quoter.spec.ts deleted file mode 100644 index 99c917b..0000000 --- a/lib/swap-router-contracts/test/Quoter.spec.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { Fixture } from 'ethereum-waffle' -import { constants, Wallet, Contract } from 'ethers' -import { ethers, waffle } from 'hardhat' -import { Quoter, TestERC20 } from '../typechain' -import completeFixture from './shared/completeFixture' -import { FeeAmount, MaxUint128, TICK_SPACINGS } from './shared/constants' -import { encodePriceSqrt } from './shared/encodePriceSqrt' -import { expandTo18Decimals } from './shared/expandTo18Decimals' -import { expect } from './shared/expect' -import { encodePath } from './shared/path' -import { createPool } from './shared/quoter' - -describe('Quoter', () => { - let wallet: Wallet - let trader: Wallet - - const swapRouterFixture: Fixture<{ - nft: Contract - tokens: [TestERC20, TestERC20, TestERC20] - quoter: Quoter - }> = async (wallets, provider) => { - const { weth9, factory, router, tokens, nft } = await completeFixture(wallets, provider) - - // approve & fund wallets - for (const token of tokens) { - await token.approve(router.address, constants.MaxUint256) - await token.approve(nft.address, constants.MaxUint256) - await token.connect(trader).approve(router.address, constants.MaxUint256) - await token.transfer(trader.address, expandTo18Decimals(1_000_000)) - } - - const quoterFactory = await ethers.getContractFactory('Quoter') - quoter = (await quoterFactory.deploy(factory.address, weth9.address)) as Quoter - - return { - tokens, - nft, - quoter, - } - } - - let nft: Contract - let tokens: [TestERC20, TestERC20, TestERC20] - let quoter: Quoter - - let loadFixture: ReturnType - - before('create fixture loader', async () => { - const wallets = await (ethers as any).getSigners() - ;[wallet, trader] = wallets - loadFixture = waffle.createFixtureLoader(wallets) - }) - - // helper for getting weth and token balances - beforeEach('load fixture', async () => { - ;({ tokens, nft, quoter } = await loadFixture(swapRouterFixture)) - }) - - describe('quotes', () => { - beforeEach(async () => { - await createPool(nft, wallet, tokens[0].address, tokens[1].address) - await createPool(nft, wallet, tokens[1].address, tokens[2].address) - }) - - describe('#quoteExactInput', () => { - it('0 -> 1', async () => { - const quote = await quoter.callStatic.quoteExactInput( - encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), - 3 - ) - - expect(quote).to.eq(1) - }) - - it('1 -> 0', async () => { - const quote = await quoter.callStatic.quoteExactInput( - encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), - 3 - ) - - expect(quote).to.eq(1) - }) - - it('0 -> 1 -> 2', async () => { - const quote = await quoter.callStatic.quoteExactInput( - encodePath( - tokens.map((token) => token.address), - [FeeAmount.MEDIUM, FeeAmount.MEDIUM] - ), - 5 - ) - - expect(quote).to.eq(1) - }) - - it('2 -> 1 -> 0', async () => { - const quote = await quoter.callStatic.quoteExactInput( - encodePath(tokens.map((token) => token.address).reverse(), [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), - 5 - ) - - expect(quote).to.eq(1) - }) - }) - - describe('#quoteExactInputSingle', () => { - it('0 -> 1', async () => { - const quote = await quoter.callStatic.quoteExactInputSingle( - tokens[0].address, - tokens[1].address, - FeeAmount.MEDIUM, - MaxUint128, - // -2% - encodePriceSqrt(100, 102) - ) - - expect(quote).to.eq(9852) - }) - - it('1 -> 0', async () => { - const quote = await quoter.callStatic.quoteExactInputSingle( - tokens[1].address, - tokens[0].address, - FeeAmount.MEDIUM, - MaxUint128, - // +2% - encodePriceSqrt(102, 100) - ) - - expect(quote).to.eq(9852) - }) - }) - - describe('#quoteExactOutput', () => { - it('0 -> 1', async () => { - const quote = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), - 1 - ) - - expect(quote).to.eq(3) - }) - - it('1 -> 0', async () => { - const quote = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), - 1 - ) - - expect(quote).to.eq(3) - }) - - it('0 -> 1 -> 2', async () => { - const quote = await quoter.callStatic.quoteExactOutput( - encodePath(tokens.map((token) => token.address).reverse(), [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), - 1 - ) - - expect(quote).to.eq(5) - }) - - it('2 -> 1 -> 0', async () => { - const quote = await quoter.callStatic.quoteExactOutput( - encodePath( - tokens.map((token) => token.address), - [FeeAmount.MEDIUM, FeeAmount.MEDIUM] - ), - 1 - ) - - expect(quote).to.eq(5) - }) - }) - - describe('#quoteExactOutputSingle', () => { - it('0 -> 1', async () => { - const quote = await quoter.callStatic.quoteExactOutputSingle( - tokens[0].address, - tokens[1].address, - FeeAmount.MEDIUM, - MaxUint128, - encodePriceSqrt(100, 102) - ) - - expect(quote).to.eq(9981) - }) - - it('1 -> 0', async () => { - const quote = await quoter.callStatic.quoteExactOutputSingle( - tokens[1].address, - tokens[0].address, - FeeAmount.MEDIUM, - MaxUint128, - encodePriceSqrt(102, 100) - ) - - expect(quote).to.eq(9981) - }) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/QuoterV2.spec.ts b/lib/swap-router-contracts/test/QuoterV2.spec.ts deleted file mode 100644 index 61cbb62..0000000 --- a/lib/swap-router-contracts/test/QuoterV2.spec.ts +++ /dev/null @@ -1,578 +0,0 @@ -import { Fixture } from 'ethereum-waffle' -import { constants, Wallet, Contract } from 'ethers' -import { ethers, waffle } from 'hardhat' -import { QuoterV2, TestERC20 } from '../typechain' -import completeFixture from './shared/completeFixture' -import { FeeAmount, MaxUint128 } from './shared/constants' -import { encodePriceSqrt } from './shared/encodePriceSqrt' -import { expandTo18Decimals } from './shared/expandTo18Decimals' -import { expect } from './shared/expect' -import { encodePath } from './shared/path' -import { createPool, createPoolWithMultiplePositions, createPoolWithZeroTickInitialized } from './shared/quoter' -import snapshotGasCost from './shared/snapshotGasCost' - -describe('QuoterV2', function () { - this.timeout(40000) - let wallet: Wallet - let trader: Wallet - - const swapRouterFixture: Fixture<{ - nft: Contract - tokens: [TestERC20, TestERC20, TestERC20] - quoter: QuoterV2 - }> = async (wallets, provider) => { - const { weth9, factory, router, tokens, nft } = await completeFixture(wallets, provider) - - // approve & fund wallets - for (const token of tokens) { - await token.approve(router.address, constants.MaxUint256) - await token.approve(nft.address, constants.MaxUint256) - await token.connect(trader).approve(router.address, constants.MaxUint256) - await token.transfer(trader.address, expandTo18Decimals(1_000_000)) - } - - const quoterFactory = await ethers.getContractFactory('QuoterV2') - quoter = (await quoterFactory.deploy(factory.address, weth9.address)) as QuoterV2 - - return { - tokens, - nft, - quoter, - } - } - - let nft: Contract - let tokens: [TestERC20, TestERC20, TestERC20] - let quoter: QuoterV2 - - let loadFixture: ReturnType - - before('create fixture loader', async () => { - const wallets = await (ethers as any).getSigners() - ;[wallet, trader] = wallets - loadFixture = waffle.createFixtureLoader(wallets) - }) - - // helper for getting weth and token balances - beforeEach('load fixture', async () => { - ;({ tokens, nft, quoter } = await loadFixture(swapRouterFixture)) - }) - - describe('quotes', () => { - beforeEach(async () => { - await createPool(nft, wallet, tokens[0].address, tokens[1].address) - await createPool(nft, wallet, tokens[1].address, tokens[2].address) - await createPoolWithMultiplePositions(nft, wallet, tokens[0].address, tokens[2].address) - }) - - describe('#quoteExactInput', () => { - it('0 -> 2 cross 2 tick', async () => { - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 10000 - ) - - await snapshotGasCost(gasEstimate) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') - expect(initializedTicksCrossedList[0]).to.eq(2) - expect(amountOut).to.eq(9871) - }) - - it('0 -> 2 cross 2 tick where after is initialized', async () => { - // The swap amount is set such that the active tick after the swap is -120. - // -120 is an initialized tick for this pool. We check that we don't count it. - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 6200 - ) - - await snapshotGasCost(gasEstimate) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('78757224507315167622282810783') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(initializedTicksCrossedList[0]).to.eq(1) - expect(amountOut).to.eq(6143) - }) - - it('0 -> 2 cross 1 tick', async () => { - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 4000 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(1) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('78926452400586371254602774705') - expect(amountOut).to.eq(3971) - }) - - it('0 -> 2 cross 0 tick, starting tick not initialized', async () => { - // Tick before 0, tick after -1. - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 10 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(0) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79227483487511329217250071027') - expect(amountOut).to.eq(8) - }) - - it('0 -> 2 cross 0 tick, starting tick initialized', async () => { - // Tick before 0, tick after -1. Tick 0 initialized. - await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) - - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 10 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(1) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79227817515327498931091950511') - expect(amountOut).to.eq(8) - }) - - it('2 -> 0 cross 2', async () => { - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 10000 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(2) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('80001962924147897865541384515') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(9871) - }) - - it('2 -> 0 cross 2 where tick after is initialized', async () => { - // The swap amount is set such that the active tick after the swap is 120. - // 120 is an initialized tick for this pool. We check we don't count it. - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 6250 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(2) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79705728824507063507279123685') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(6190) - }) - - it('2 -> 0 cross 0 tick, starting tick initialized', async () => { - // Tick 0 initialized. Tick after = 1 - await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) - - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 200 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(0) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79235729830182478001034429156') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(198) - }) - - it('2 -> 0 cross 0 tick, starting tick not initialized', async () => { - // Tick 0 initialized. Tick after = 1 - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 103 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(0) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79235858216754624215638319723') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(amountOut).to.eq(101) - }) - - it('2 -> 1', async () => { - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM]), - 10000 - ) - - await snapshotGasCost(gasEstimate) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('80018067294531553039351583520') - expect(initializedTicksCrossedList[0]).to.eq(0) - expect(amountOut).to.eq(9871) - }) - - it('0 -> 2 -> 1', async () => { - const { - amountOut, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactInput( - encodePath([tokens[0].address, tokens[2].address, tokens[1].address], [FeeAmount.MEDIUM, FeeAmount.MEDIUM]), - 10000 - ) - - await snapshotGasCost(gasEstimate) - expect(sqrtPriceX96AfterList.length).to.eq(2) - expect(sqrtPriceX96AfterList[0]).to.eq('78461846509168490764501028180') - expect(sqrtPriceX96AfterList[1]).to.eq('80007846861567212939802016351') - expect(initializedTicksCrossedList[0]).to.eq(2) - expect(initializedTicksCrossedList[1]).to.eq(0) - expect(amountOut).to.eq(9745) - }) - }) - - describe('#quoteExactInputSingle', () => { - it('0 -> 2', async () => { - const { - amountOut: quote, - sqrtPriceX96After, - initializedTicksCrossed, - gasEstimate, - } = await quoter.callStatic.quoteExactInputSingle({ - tokenIn: tokens[0].address, - tokenOut: tokens[2].address, - fee: FeeAmount.MEDIUM, - amountIn: 10000, - // -2% - sqrtPriceLimitX96: encodePriceSqrt(100, 102), - }) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossed).to.eq(2) - expect(quote).to.eq(9871) - expect(sqrtPriceX96After).to.eq('78461846509168490764501028180') - }) - - it('2 -> 0', async () => { - const { - amountOut: quote, - sqrtPriceX96After, - initializedTicksCrossed, - gasEstimate, - } = await quoter.callStatic.quoteExactInputSingle({ - tokenIn: tokens[2].address, - tokenOut: tokens[0].address, - fee: FeeAmount.MEDIUM, - amountIn: 10000, - // +2% - sqrtPriceLimitX96: encodePriceSqrt(102, 100), - }) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossed).to.eq(2) - expect(quote).to.eq(9871) - expect(sqrtPriceX96After).to.eq('80001962924147897865541384515') - }) - }) - - describe('#quoteExactOutput', () => { - it('0 -> 2 cross 2 tick', async () => { - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 15000 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList.length).to.eq(1) - expect(initializedTicksCrossedList[0]).to.eq(2) - expect(amountIn).to.eq(15273) - - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('78055527257643669242286029831') - }) - - it('0 -> 2 cross 2 where tick after is initialized', async () => { - // The swap amount is set such that the active tick after the swap is -120. - // -120 is an initialized tick for this pool. We check that we count it. - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 6143 - ) - - await snapshotGasCost(gasEstimate) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('78757225449310403327341205211') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(initializedTicksCrossedList[0]).to.eq(1) - expect(amountIn).to.eq(6200) - }) - - it('0 -> 2 cross 1 tick', async () => { - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 4000 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList.length).to.eq(1) - expect(initializedTicksCrossedList[0]).to.eq(1) - expect(amountIn).to.eq(4029) - - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('78924219757724709840818372098') - }) - - it('0 -> 2 cross 0 tick starting tick initialized', async () => { - // Tick before 0, tick after 1. Tick 0 initialized. - await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address) - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 100 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList.length).to.eq(1) - expect(initializedTicksCrossedList[0]).to.eq(1) - expect(amountIn).to.eq(102) - - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79224329176051641448521403903') - }) - - it('0 -> 2 cross 0 tick starting tick not initialized', async () => { - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[2].address, tokens[0].address], [FeeAmount.MEDIUM]), - 10 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList.length).to.eq(1) - expect(initializedTicksCrossedList[0]).to.eq(0) - expect(amountIn).to.eq(12) - - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79227408033628034983534698435') - }) - - it('2 -> 0 cross 2 ticks', async () => { - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 15000 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList.length).to.eq(1) - expect(initializedTicksCrossedList[0]).to.eq(2) - expect(amountIn).to.eq(15273) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('80418414376567919517220409857') - }) - - it('2 -> 0 cross 2 where tick after is initialized', async () => { - // The swap amount is set such that the active tick after the swap is 120. - // 120 is an initialized tick for this pool. We check that we don't count it. - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 6223 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(2) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79708304437530892332449657932') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(amountIn).to.eq(6283) - }) - - it('2 -> 0 cross 1 tick', async () => { - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[0].address, tokens[2].address], [FeeAmount.MEDIUM]), - 6000 - ) - - await snapshotGasCost(gasEstimate) - expect(initializedTicksCrossedList[0]).to.eq(1) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('79690640184021170956740081887') - expect(initializedTicksCrossedList.length).to.eq(1) - expect(amountIn).to.eq(6055) - }) - - it('2 -> 1', async () => { - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[1].address, tokens[2].address], [FeeAmount.MEDIUM]), - 9871 - ) - - await snapshotGasCost(gasEstimate) - expect(sqrtPriceX96AfterList.length).to.eq(1) - expect(sqrtPriceX96AfterList[0]).to.eq('80018020393569259756601362385') - expect(initializedTicksCrossedList[0]).to.eq(0) - expect(amountIn).to.eq(10000) - }) - - it('0 -> 2 -> 1', async () => { - const { - amountIn, - sqrtPriceX96AfterList, - initializedTicksCrossedList, - gasEstimate, - } = await quoter.callStatic.quoteExactOutput( - encodePath([tokens[0].address, tokens[2].address, tokens[1].address].reverse(), [ - FeeAmount.MEDIUM, - FeeAmount.MEDIUM, - ]), - 9745 - ) - - await snapshotGasCost(gasEstimate) - expect(sqrtPriceX96AfterList.length).to.eq(2) - expect(sqrtPriceX96AfterList[0]).to.eq('80007838904387594703933785072') - expect(sqrtPriceX96AfterList[1]).to.eq('78461888503179331029803316753') - expect(initializedTicksCrossedList[0]).to.eq(0) - expect(initializedTicksCrossedList[1]).to.eq(2) - expect(amountIn).to.eq(10000) - }) - }) - - describe('#quoteExactOutputSingle', () => { - it('0 -> 1', async () => { - const { - amountIn, - sqrtPriceX96After, - initializedTicksCrossed, - gasEstimate, - } = await quoter.callStatic.quoteExactOutputSingle({ - tokenIn: tokens[0].address, - tokenOut: tokens[1].address, - fee: FeeAmount.MEDIUM, - amount: MaxUint128, - sqrtPriceLimitX96: encodePriceSqrt(100, 102), - }) - - await snapshotGasCost(gasEstimate) - expect(amountIn).to.eq(9981) - expect(initializedTicksCrossed).to.eq(0) - expect(sqrtPriceX96After).to.eq('78447570448055484695608110440') - }) - - it('1 -> 0', async () => { - const { - amountIn, - sqrtPriceX96After, - initializedTicksCrossed, - gasEstimate, - } = await quoter.callStatic.quoteExactOutputSingle({ - tokenIn: tokens[1].address, - tokenOut: tokens[0].address, - fee: FeeAmount.MEDIUM, - amount: MaxUint128, - sqrtPriceLimitX96: encodePriceSqrt(102, 100), - }) - - await snapshotGasCost(gasEstimate) - expect(amountIn).to.eq(9981) - expect(initializedTicksCrossed).to.eq(0) - expect(sqrtPriceX96After).to.eq('80016521857016594389520272648') - }) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/SwapRouter.gas.spec.ts b/lib/swap-router-contracts/test/SwapRouter.gas.spec.ts deleted file mode 100644 index 7112a22..0000000 --- a/lib/swap-router-contracts/test/SwapRouter.gas.spec.ts +++ /dev/null @@ -1,470 +0,0 @@ -import { defaultAbiCoder } from '@ethersproject/abi' -import { abi as IUniswapV3PoolABI } from '@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json' -import { Fixture } from 'ethereum-waffle' -import { BigNumber, constants, ContractTransaction, Wallet } from 'ethers' -import { solidityPack } from 'ethers/lib/utils' -import { ethers, waffle } from 'hardhat' -import { IUniswapV3Pool, IWETH9, MockTimeSwapRouter02, TestERC20 } from '../typechain' -import completeFixture from './shared/completeFixture' -import { ADDRESS_THIS, FeeAmount, MSG_SENDER, TICK_SPACINGS } from './shared/constants' -import { encodePriceSqrt } from './shared/encodePriceSqrt' -import { expandTo18Decimals } from './shared/expandTo18Decimals' -import { expect } from './shared/expect' -import { encodePath } from './shared/path' -import snapshotGasCost from './shared/snapshotGasCost' -import { getMaxTick, getMinTick } from './shared/ticks' - -describe('SwapRouter gas tests', function () { - this.timeout(40000) - let wallet: Wallet - let trader: Wallet - - const swapRouterFixture: Fixture<{ - weth9: IWETH9 - router: MockTimeSwapRouter02 - tokens: [TestERC20, TestERC20, TestERC20] - pools: [IUniswapV3Pool, IUniswapV3Pool, IUniswapV3Pool] - }> = async (wallets, provider) => { - const { weth9, factory, router, tokens, nft } = await completeFixture(wallets, provider) - - // approve & fund wallets - for (const token of tokens) { - await token.approve(router.address, constants.MaxUint256) - await token.approve(nft.address, constants.MaxUint256) - await token.connect(trader).approve(router.address, constants.MaxUint256) - await token.transfer(trader.address, expandTo18Decimals(1_000_000)) - } - - const liquidity = 1000000 - async function createPool(tokenAddressA: string, tokenAddressB: string) { - if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) - [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] - - await nft.createAndInitializePoolIfNecessary( - tokenAddressA, - tokenAddressB, - FeeAmount.MEDIUM, - encodePriceSqrt(100005, 100000) // we don't want to cross any ticks - ) - - const liquidityParams = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: wallet.address, - amount0Desired: 1000000, - amount1Desired: 1000000, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - return nft.mint(liquidityParams) - } - - async function createPoolWETH9(tokenAddress: string) { - await weth9.deposit({ value: liquidity * 2 }) - await weth9.approve(nft.address, constants.MaxUint256) - return createPool(weth9.address, tokenAddress) - } - - // create pools - await createPool(tokens[0].address, tokens[1].address) - await createPool(tokens[1].address, tokens[2].address) - await createPoolWETH9(tokens[0].address) - - const poolAddresses = await Promise.all([ - factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM), - factory.getPool(tokens[1].address, tokens[2].address, FeeAmount.MEDIUM), - factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM), - ]) - - const pools = poolAddresses.map((poolAddress) => new ethers.Contract(poolAddress, IUniswapV3PoolABI, wallet)) as [ - IUniswapV3Pool, - IUniswapV3Pool, - IUniswapV3Pool - ] - - return { - weth9, - router, - tokens, - pools, - } - } - - let weth9: IWETH9 - let router: MockTimeSwapRouter02 - let tokens: [TestERC20, TestERC20, TestERC20] - let pools: [IUniswapV3Pool, IUniswapV3Pool, IUniswapV3Pool] - - let loadFixture: ReturnType - - function encodeUnwrapWETH9(amount: number) { - return solidityPack( - ['bytes4', 'bytes'], - [router.interface.getSighash('unwrapWETH9(uint256)'), defaultAbiCoder.encode(['uint256'], [amount])] - ) - } - - function encodeSweep(token: string, amount: number) { - const functionSignature = 'sweepToken(address,uint256)' - return solidityPack( - ['bytes4', 'bytes'], - [ - router.interface.getSighash(functionSignature), - defaultAbiCoder.encode((router.interface.functions as any)[functionSignature].inputs, [token, amount]), - ] - ) - } - - before('create fixture loader', async () => { - const wallets = await (ethers as any).getSigners() - ;[wallet, trader] = wallets - - loadFixture = waffle.createFixtureLoader(wallets) - }) - - beforeEach('load fixture', async () => { - ;({ router, weth9, tokens, pools } = await loadFixture(swapRouterFixture)) - }) - - async function exactInput( - tokens: string[], - amountIn: number = 2, - amountOutMinimum: number = 1 - ): Promise { - const inputIsWETH = weth9.address === tokens[0] - const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address - - const value = inputIsWETH ? amountIn : 0 - - const params = { - path: encodePath(tokens, new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountIn, - amountOutMinimum: outputIsWETH9 ? 0 : amountOutMinimum, // save on calldata - } - - const data = [router.interface.encodeFunctionData('exactInput', [params])] - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOutMinimum)) - } - - return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) - } - - async function exactInputSingle( - tokenIn: string, - tokenOut: string, - amountIn: number = 3, - amountOutMinimum: number = 1, - sqrtPriceLimitX96?: BigNumber - ): Promise { - const inputIsWETH = weth9.address === tokenIn - const outputIsWETH9 = tokenOut === weth9.address - - const value = inputIsWETH ? amountIn : 0 - - const params = { - tokenIn, - tokenOut, - fee: FeeAmount.MEDIUM, - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountIn, - amountOutMinimum: outputIsWETH9 ? 0 : amountOutMinimum, // save on calldata - sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, - } - - const data = [router.interface.encodeFunctionData('exactInputSingle', [params])] - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOutMinimum)) - } - - return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) - } - - async function exactOutput(tokens: string[]): Promise { - const amountInMaximum = 10 // we don't care - const amountOut = 1 - - const inputIsWETH9 = tokens[0] === weth9.address - const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address - - const value = inputIsWETH9 ? amountInMaximum : 0 - - const params = { - path: encodePath(tokens.slice().reverse(), new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountOut, - amountInMaximum, - } - - const data = [router.interface.encodeFunctionData('exactOutput', [params])] - if (inputIsWETH9) { - data.push(router.interface.encodeFunctionData('refundETH')) - } - - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOut)) - } - - return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) - } - - async function exactOutputSingle( - tokenIn: string, - tokenOut: string, - amountOut: number = 1, - amountInMaximum: number = 3, - sqrtPriceLimitX96?: BigNumber - ): Promise { - const inputIsWETH9 = tokenIn === weth9.address - const outputIsWETH9 = tokenOut === weth9.address - - const value = inputIsWETH9 ? amountInMaximum : 0 - - const params = { - tokenIn, - tokenOut, - fee: FeeAmount.MEDIUM, - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountOut, - amountInMaximum, - sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, - } - - const data = [router.interface.encodeFunctionData('exactOutputSingle', [params])] - if (inputIsWETH9) { - data.push(router.interface.encodeFunctionData('refundETH')) - } - - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOut)) - } - - return router.connect(trader)['multicall(uint256,bytes[])'](1, data, { value }) - } - - // TODO should really throw this in the fixture - beforeEach('intialize feeGrowthGlobals', async () => { - await exactInput([tokens[0].address, tokens[1].address], 1, 0) - await exactInput([tokens[1].address, tokens[0].address], 1, 0) - await exactInput([tokens[1].address, tokens[2].address], 1, 0) - await exactInput([tokens[2].address, tokens[1].address], 1, 0) - await exactInput([tokens[0].address, weth9.address], 1, 0) - await exactInput([weth9.address, tokens[0].address], 1, 0) - }) - - beforeEach('ensure feeGrowthGlobals are >0', async () => { - const slots = await Promise.all( - pools.map((pool) => - Promise.all([ - pool.feeGrowthGlobal0X128().then((f) => f.toString()), - pool.feeGrowthGlobal1X128().then((f) => f.toString()), - ]) - ) - ) - - expect(slots).to.deep.eq([ - ['340290874192793283295456993856614', '340290874192793283295456993856614'], - ['340290874192793283295456993856614', '340290874192793283295456993856614'], - ['340290874192793283295456993856614', '340290874192793283295456993856614'], - ]) - }) - - beforeEach('ensure ticks are 0 before', async () => { - const slots = await Promise.all(pools.map((pool) => pool.slot0().then(({ tick }) => tick))) - expect(slots).to.deep.eq([0, 0, 0]) - }) - - afterEach('ensure ticks are 0 after', async () => { - const slots = await Promise.all(pools.map((pool) => pool.slot0().then(({ tick }) => tick))) - expect(slots).to.deep.eq([0, 0, 0]) - }) - - describe('#exactInput', () => { - it('0 -> 1', async () => { - await snapshotGasCost(exactInput(tokens.slice(0, 2).map((token) => token.address))) - }) - - it('0 -> 1 minimal', async () => { - const calleeFactory = await ethers.getContractFactory('TestUniswapV3Callee') - const callee = await calleeFactory.deploy() - - await tokens[0].connect(trader).approve(callee.address, constants.MaxUint256) - await snapshotGasCost(callee.connect(trader).swapExact0For1(pools[0].address, 2, trader.address, '4295128740')) - }) - - it('0 -> 1 -> 2', async () => { - await snapshotGasCost( - exactInput( - tokens.map((token) => token.address), - 3 - ) - ) - }) - - it('WETH9 -> 0', async () => { - await snapshotGasCost( - exactInput( - [weth9.address, tokens[0].address], - weth9.address.toLowerCase() < tokens[0].address.toLowerCase() ? 2 : 3 - ) - ) - }) - - it('0 -> WETH9', async () => { - await snapshotGasCost( - exactInput( - [tokens[0].address, weth9.address], - tokens[0].address.toLowerCase() < weth9.address.toLowerCase() ? 2 : 3 - ) - ) - }) - - it('2 trades (via router)', async () => { - await weth9.connect(trader).deposit({ value: 3 }) - await weth9.connect(trader).approve(router.address, constants.MaxUint256) - const swap0 = { - path: encodePath([weth9.address, tokens[0].address], [FeeAmount.MEDIUM]), - recipient: ADDRESS_THIS, - amountIn: 3, - amountOutMinimum: 0, // save on calldata - } - - const swap1 = { - path: encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), - recipient: ADDRESS_THIS, - amountIn: 3, - amountOutMinimum: 0, // save on calldata - } - - const data = [ - router.interface.encodeFunctionData('exactInput', [swap0]), - router.interface.encodeFunctionData('exactInput', [swap1]), - encodeSweep(tokens[0].address, 2), - ] - - await snapshotGasCost(router.connect(trader)['multicall(uint256,bytes[])'](1, data)) - }) - - it('2 trades (directly to sender)', async () => { - await weth9.connect(trader).deposit({ value: 3 }) - await weth9.connect(trader).approve(router.address, constants.MaxUint256) - const swap0 = { - path: encodePath([weth9.address, tokens[0].address], [FeeAmount.MEDIUM]), - recipient: MSG_SENDER, - amountIn: 3, - amountOutMinimum: 1, - } - - const swap1 = { - path: encodePath([tokens[1].address, tokens[0].address], [FeeAmount.MEDIUM]), - recipient: MSG_SENDER, - amountIn: 3, - amountOutMinimum: 1, - } - - const data = [ - router.interface.encodeFunctionData('exactInput', [swap0]), - router.interface.encodeFunctionData('exactInput', [swap1]), - ] - - await snapshotGasCost(router.connect(trader)['multicall(uint256,bytes[])'](1, data)) - }) - - it('3 trades (directly to sender)', async () => { - await weth9.connect(trader).deposit({ value: 3 }) - await weth9.connect(trader).approve(router.address, constants.MaxUint256) - const swap0 = { - path: encodePath([weth9.address, tokens[0].address], [FeeAmount.MEDIUM]), - recipient: MSG_SENDER, - amountIn: 3, - amountOutMinimum: 1, - } - - const swap1 = { - path: encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), - recipient: MSG_SENDER, - amountIn: 3, - amountOutMinimum: 1, - } - - const swap2 = { - path: encodePath([tokens[1].address, tokens[2].address], [FeeAmount.MEDIUM]), - recipient: MSG_SENDER, - amountIn: 3, - amountOutMinimum: 1, - } - - const data = [ - router.interface.encodeFunctionData('exactInput', [swap0]), - router.interface.encodeFunctionData('exactInput', [swap1]), - router.interface.encodeFunctionData('exactInput', [swap2]), - ] - - await snapshotGasCost(router.connect(trader)['multicall(uint256,bytes[])'](1, data)) - }) - }) - - describe('#exactInputSingle', () => { - it('0 -> 1', async () => { - await snapshotGasCost(exactInputSingle(tokens[0].address, tokens[1].address)) - }) - - it('WETH9 -> 0', async () => { - await snapshotGasCost( - exactInputSingle( - weth9.address, - tokens[0].address, - weth9.address.toLowerCase() < tokens[0].address.toLowerCase() ? 2 : 3 - ) - ) - }) - - it('0 -> WETH9', async () => { - await snapshotGasCost( - exactInputSingle( - tokens[0].address, - weth9.address, - tokens[0].address.toLowerCase() < weth9.address.toLowerCase() ? 2 : 3 - ) - ) - }) - }) - - describe('#exactOutput', () => { - it('0 -> 1', async () => { - await snapshotGasCost(exactOutput(tokens.slice(0, 2).map((token) => token.address))) - }) - - it('0 -> 1 -> 2', async () => { - await snapshotGasCost(exactOutput(tokens.map((token) => token.address))) - }) - - it('WETH9 -> 0', async () => { - await snapshotGasCost(exactOutput([weth9.address, tokens[0].address])) - }) - - it('0 -> WETH9', async () => { - await snapshotGasCost(exactOutput([tokens[0].address, weth9.address])) - }) - }) - - describe('#exactOutputSingle', () => { - it('0 -> 1', async () => { - await snapshotGasCost(exactOutputSingle(tokens[0].address, tokens[1].address)) - }) - - it('WETH9 -> 0', async () => { - await snapshotGasCost(exactOutputSingle(weth9.address, tokens[0].address)) - }) - - it('0 -> WETH9', async () => { - await snapshotGasCost(exactOutputSingle(tokens[0].address, weth9.address)) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/SwapRouter.spec.ts b/lib/swap-router-contracts/test/SwapRouter.spec.ts deleted file mode 100644 index 1cdbddf..0000000 --- a/lib/swap-router-contracts/test/SwapRouter.spec.ts +++ /dev/null @@ -1,1623 +0,0 @@ -import { defaultAbiCoder } from '@ethersproject/abi' -import { abi as PAIR_V2_ABI } from '@uniswap/v2-core/build/UniswapV2Pair.json' -import { Fixture } from 'ethereum-waffle' -import { BigNumber, constants, Contract, ContractTransaction, Wallet } from 'ethers' -import { solidityPack } from 'ethers/lib/utils' -import { ethers, waffle } from 'hardhat' -import { IUniswapV2Pair, IWETH9, MockTimeSwapRouter02, MixedRouteQuoterV1, TestERC20 } from '../typechain' -import completeFixture from './shared/completeFixture' -import { computePoolAddress } from './shared/computePoolAddress' -import { - ADDRESS_THIS, - CONTRACT_BALANCE, - FeeAmount, - MSG_SENDER, - TICK_SPACINGS, - V2_FEE_PLACEHOLDER, -} from './shared/constants' -import { encodePriceSqrt } from './shared/encodePriceSqrt' -import { expandTo18Decimals } from './shared/expandTo18Decimals' -import { expect } from './shared/expect' -import { encodePath } from './shared/path' -import { getMaxTick, getMinTick } from './shared/ticks' - -describe('SwapRouter', function () { - this.timeout(40000) - let wallet: Wallet - let trader: Wallet - - const swapRouterFixture: Fixture<{ - weth9: IWETH9 - factory: Contract - factoryV2: Contract - router: MockTimeSwapRouter02 - quoter: MixedRouteQuoterV1 - nft: Contract - tokens: [TestERC20, TestERC20, TestERC20] - }> = async (wallets, provider) => { - const { weth9, factory, factoryV2, router, tokens, nft } = await completeFixture(wallets, provider) - - // approve & fund wallets - for (const token of tokens) { - await token.approve(router.address, constants.MaxUint256) - await token.approve(nft.address, constants.MaxUint256) - await token.connect(trader).approve(router.address, constants.MaxUint256) - await token.transfer(trader.address, expandTo18Decimals(1_000_000)) - } - - const quoterFactory = await ethers.getContractFactory('MixedRouteQuoterV1') - quoter = (await quoterFactory.deploy(factory.address, factoryV2.address, weth9.address)) as MixedRouteQuoterV1 - - return { - weth9, - factory, - factoryV2, - router, - quoter, - tokens, - nft, - } - } - - let factory: Contract - let factoryV2: Contract - let weth9: IWETH9 - let router: MockTimeSwapRouter02 - let quoter: MixedRouteQuoterV1 - let nft: Contract - let tokens: [TestERC20, TestERC20, TestERC20] - let getBalances: ( - who: string - ) => Promise<{ - weth9: BigNumber - token0: BigNumber - token1: BigNumber - token2: BigNumber - }> - - let loadFixture: ReturnType - - function encodeUnwrapWETH9(amount: number) { - const functionSignature = 'unwrapWETH9(uint256,address)' - return solidityPack( - ['bytes4', 'bytes'], - [ - router.interface.getSighash(functionSignature), - defaultAbiCoder.encode(router.interface.functions[functionSignature].inputs, [amount, trader.address]), - ] - ) - } - - function encodeSweep(token: string, amount: number, recipient: string) { - const functionSignature = 'sweepToken(address,uint256,address)' - return solidityPack( - ['bytes4', 'bytes'], - [ - router.interface.getSighash(functionSignature), - defaultAbiCoder.encode(router.interface.functions[functionSignature].inputs, [token, amount, recipient]), - ] - ) - } - - before('create fixture loader', async () => { - ;[wallet, trader] = await (ethers as any).getSigners() - loadFixture = waffle.createFixtureLoader([wallet, trader]) - }) - - // helper for getting weth and token balances - beforeEach('load fixture', async () => { - ;({ router, quoter, weth9, factory, factoryV2, tokens, nft } = await loadFixture(swapRouterFixture)) - - getBalances = async (who: string) => { - const balances = await Promise.all([ - weth9.balanceOf(who), - tokens[0].balanceOf(who), - tokens[1].balanceOf(who), - tokens[2].balanceOf(who), - ]) - return { - weth9: balances[0], - token0: balances[1], - token1: balances[2], - token2: balances[3], - } - } - }) - - // ensure the swap router never ends up with a balance - afterEach('load fixture', async () => { - const balances = await getBalances(router.address) - expect(Object.values(balances).every((b) => b.eq(0))).to.be.eq(true) - const balance = await waffle.provider.getBalance(router.address) - expect(balance.eq(0)).to.be.eq(true) - }) - - it('bytecode size', async () => { - expect(((await router.provider.getCode(router.address)).length - 2) / 2).to.matchSnapshot() - }) - - const liquidity = 1000000 - async function createV3Pool(tokenAddressA: string, tokenAddressB: string) { - if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) - [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] - - await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) - - const liquidityParams = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: wallet.address, - amount0Desired: 1000000, - amount1Desired: 1000000, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - return nft.mint(liquidityParams) - } - describe('swaps - v3', () => { - async function createPoolWETH9(tokenAddress: string) { - await weth9.deposit({ value: liquidity }) - await weth9.approve(nft.address, constants.MaxUint256) - return createV3Pool(weth9.address, tokenAddress) - } - - beforeEach('create 0-1 and 1-2 pools', async () => { - await createV3Pool(tokens[0].address, tokens[1].address) - await createV3Pool(tokens[1].address, tokens[2].address) - }) - - describe('#exactInput', () => { - async function exactInput( - tokens: string[], - amountIn: number = 3, - amountOutMinimum: number = 1 - ): Promise { - const inputIsWETH = weth9.address === tokens[0] - const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address - - const value = inputIsWETH ? amountIn : 0 - - const params = { - path: encodePath(tokens, new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountIn, - amountOutMinimum, - } - - const data = [router.interface.encodeFunctionData('exactInput', [params])] - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOutMinimum)) - } - - // ensure that the swap fails if the limit is any tighter - const amountOut = await router.connect(trader).callStatic.exactInput(params, { value }) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - - return router.connect(trader)['multicall(bytes[])'](data, { value }) - } - - describe('single-pool', () => { - it('0 -> 1', async () => { - const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactInput(tokens.slice(0, 2).map((token) => token.address)) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) - }) - - it('1 -> 0', async () => { - const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactInput( - tokens - .slice(0, 2) - .reverse() - .map((token) => token.address) - ) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) - }) - }) - - describe('multi-pool', () => { - it('0 -> 1 -> 2', async () => { - const traderBefore = await getBalances(trader.address) - - await exactInput( - tokens.map((token) => token.address), - 5, - 1 - ) - - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) - }) - - it('2 -> 1 -> 0', async () => { - const traderBefore = await getBalances(trader.address) - - await exactInput(tokens.map((token) => token.address).reverse(), 5, 1) - - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(5)) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - }) - - it('events', async () => { - await expect( - exactInput( - tokens.map((token) => token.address), - 5, - 1 - ) - ) - .to.emit(tokens[0], 'Transfer') - .withArgs( - trader.address, - computePoolAddress(factory.address, [tokens[0].address, tokens[1].address], FeeAmount.MEDIUM), - 5 - ) - .to.emit(tokens[1], 'Transfer') - .withArgs( - computePoolAddress(factory.address, [tokens[0].address, tokens[1].address], FeeAmount.MEDIUM), - router.address, - 3 - ) - .to.emit(tokens[1], 'Transfer') - .withArgs( - router.address, - computePoolAddress(factory.address, [tokens[1].address, tokens[2].address], FeeAmount.MEDIUM), - 3 - ) - .to.emit(tokens[2], 'Transfer') - .withArgs( - computePoolAddress(factory.address, [tokens[1].address, tokens[2].address], FeeAmount.MEDIUM), - trader.address, - 1 - ) - }) - }) - - describe('ETH input', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - }) - - it('WETH9 -> 0', async () => { - const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactInput([weth9.address, tokens[0].address])) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 3) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - }) - - it('WETH9 -> 0 -> 1', async () => { - const traderBefore = await getBalances(trader.address) - - await expect(exactInput([weth9.address, tokens[0].address, tokens[1].address], 5)) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 5) - - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - }) - }) - }) - - describe('ETH output', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - await createPoolWETH9(tokens[1].address) - }) - - it('0 -> WETH9', async () => { - const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactInput([tokens[0].address, weth9.address])) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - }) - - it('0 -> 1 -> WETH9', async () => { - // get balances before - const traderBefore = await getBalances(trader.address) - - await expect(exactInput([tokens[0].address, tokens[1].address, weth9.address], 5)) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) - }) - }) - }) - }) - - describe('#exactInputSingle', () => { - async function exactInputSingle( - tokenIn: string, - tokenOut: string, - amountIn: number = 3, - amountOutMinimum: number = 1, - sqrtPriceLimitX96?: BigNumber - ): Promise { - const inputIsWETH = weth9.address === tokenIn - const outputIsWETH9 = tokenOut === weth9.address - - const value = inputIsWETH ? amountIn : 0 - - const params = { - tokenIn, - tokenOut, - fee: FeeAmount.MEDIUM, - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountIn, - amountOutMinimum, - sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, - } - - const data = [router.interface.encodeFunctionData('exactInputSingle', [params])] - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOutMinimum)) - } - - // ensure that the swap fails if the limit is any tighter - const amountOut = await router.connect(trader).callStatic.exactInputSingle(params, { value }) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - - // optimized for the gas test - return data.length === 1 - ? router.connect(trader).exactInputSingle(params, { value }) - : router.connect(trader)['multicall(bytes[])'](data, { value }) - } - - it('0 -> 1', async () => { - const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactInputSingle(tokens[0].address, tokens[1].address) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) - }) - - it('1 -> 0', async () => { - const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactInputSingle(tokens[1].address, tokens[0].address) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) - }) - - describe('ETH input', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - }) - - it('WETH9 -> 0', async () => { - const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactInputSingle(weth9.address, tokens[0].address)) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 3) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - }) - }) - }) - - describe('ETH output', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - await createPoolWETH9(tokens[1].address) - }) - - it('0 -> WETH9', async () => { - const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactInputSingle(tokens[0].address, weth9.address)) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - }) - }) - }) - }) - - describe('#exactOutput', () => { - async function exactOutput( - tokens: string[], - amountOut: number = 1, - amountInMaximum: number = 3 - ): Promise { - const inputIsWETH9 = tokens[0] === weth9.address - const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address - - const value = inputIsWETH9 ? amountInMaximum : 0 - - const params = { - path: encodePath(tokens.slice().reverse(), new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountOut, - amountInMaximum, - } - - const data = [router.interface.encodeFunctionData('exactOutput', [params])] - if (inputIsWETH9) { - data.push(router.interface.encodeFunctionData('refundETH')) - } - - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOut)) - } - - // ensure that the swap fails if the limit is any tighter - const amountIn = await router.connect(trader).callStatic.exactOutput(params, { value }) - expect(amountIn.toNumber()).to.be.eq(amountInMaximum) - - return router.connect(trader)['multicall(bytes[])'](data, { value }) - } - - describe('single-pool', () => { - it('0 -> 1', async () => { - const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactOutput(tokens.slice(0, 2).map((token) => token.address)) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) - }) - - it('1 -> 0', async () => { - const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactOutput( - tokens - .slice(0, 2) - .reverse() - .map((token) => token.address) - ) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) - }) - }) - - describe('multi-pool', () => { - it('0 -> 1 -> 2', async () => { - const traderBefore = await getBalances(trader.address) - - await exactOutput( - tokens.map((token) => token.address), - 1, - 5 - ) - - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) - }) - - it('2 -> 1 -> 0', async () => { - const traderBefore = await getBalances(trader.address) - - await exactOutput(tokens.map((token) => token.address).reverse(), 1, 5) - - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(5)) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - }) - - it('events', async () => { - await expect( - exactOutput( - tokens.map((token) => token.address), - 1, - 5 - ) - ) - .to.emit(tokens[2], 'Transfer') - .withArgs( - computePoolAddress(factory.address, [tokens[2].address, tokens[1].address], FeeAmount.MEDIUM), - trader.address, - 1 - ) - .to.emit(tokens[1], 'Transfer') - .withArgs( - computePoolAddress(factory.address, [tokens[1].address, tokens[0].address], FeeAmount.MEDIUM), - computePoolAddress(factory.address, [tokens[2].address, tokens[1].address], FeeAmount.MEDIUM), - 3 - ) - .to.emit(tokens[0], 'Transfer') - .withArgs( - trader.address, - computePoolAddress(factory.address, [tokens[1].address, tokens[0].address], FeeAmount.MEDIUM), - 5 - ) - }) - }) - - describe('ETH input', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - }) - - it('WETH9 -> 0', async () => { - const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactOutput([weth9.address, tokens[0].address])) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 3) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - }) - - it('WETH9 -> 0 -> 1', async () => { - const traderBefore = await getBalances(trader.address) - - await expect(exactOutput([weth9.address, tokens[0].address, tokens[1].address], 1, 5)) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 5) - - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - }) - }) - }) - - describe('ETH output', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - await createPoolWETH9(tokens[1].address) - }) - - it('0 -> WETH9', async () => { - const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactOutput([tokens[0].address, weth9.address])) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - }) - - it('0 -> 1 -> WETH9', async () => { - // get balances before - const traderBefore = await getBalances(trader.address) - - await expect(exactOutput([tokens[0].address, tokens[1].address, weth9.address], 1, 5)) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) - }) - }) - }) - }) - - describe('#exactOutputSingle', () => { - async function exactOutputSingle( - tokenIn: string, - tokenOut: string, - amountOut: number = 1, - amountInMaximum: number = 3, - sqrtPriceLimitX96?: BigNumber - ): Promise { - const inputIsWETH9 = tokenIn === weth9.address - const outputIsWETH9 = tokenOut === weth9.address - - const value = inputIsWETH9 ? amountInMaximum : 0 - - const params = { - tokenIn, - tokenOut, - fee: FeeAmount.MEDIUM, - recipient: outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - amountOut, - amountInMaximum, - sqrtPriceLimitX96: sqrtPriceLimitX96 ?? 0, - } - - const data = [router.interface.encodeFunctionData('exactOutputSingle', [params])] - if (inputIsWETH9) { - data.push(router.interface.encodeFunctionData('refundETH')) - } - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOut)) - } - - // ensure that the swap fails if the limit is any tighter - const amountIn = await router.connect(trader).callStatic.exactOutputSingle(params, { value }) - expect(amountIn.toNumber()).to.be.eq(amountInMaximum) - - return router.connect(trader)['multicall(bytes[])'](data, { value }) - } - - it('0 -> 1', async () => { - const pool = await factory.getPool(tokens[0].address, tokens[1].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactOutputSingle(tokens[0].address, tokens[1].address) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) - }) - - it('1 -> 0', async () => { - const pool = await factory.getPool(tokens[1].address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await exactOutputSingle(tokens[1].address, tokens[0].address) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(3)) - }) - - describe('ETH input', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - }) - - it('WETH9 -> 0', async () => { - const pool = await factory.getPool(weth9.address, tokens[0].address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactOutputSingle(weth9.address, tokens[0].address)) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 3) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(3)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - }) - }) - }) - - describe('ETH output', () => { - describe('WETH9', () => { - beforeEach(async () => { - await createPoolWETH9(tokens[0].address) - await createPoolWETH9(tokens[1].address) - }) - - it('0 -> WETH9', async () => { - const pool = await factory.getPool(tokens[0].address, weth9.address, FeeAmount.MEDIUM) - - // get balances before - const poolBefore = await getBalances(pool) - const traderBefore = await getBalances(trader.address) - - await expect(exactOutputSingle(tokens[0].address, weth9.address)) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const poolAfter = await getBalances(pool) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(3)) - }) - }) - }) - }) - - describe('*WithFee', () => { - const feeRecipient = '0xfEE0000000000000000000000000000000000000' - - it('#sweepTokenWithFee', async () => { - const amountOutMinimum = 100 - const params = { - path: encodePath([tokens[0].address, tokens[1].address], [FeeAmount.MEDIUM]), - recipient: ADDRESS_THIS, - amountIn: 102, - amountOutMinimum: 0, - } - - const functionSignature = 'sweepTokenWithFee(address,uint256,address,uint256,address)' - - const data = [ - router.interface.encodeFunctionData('exactInput', [params]), - solidityPack( - ['bytes4', 'bytes'], - [ - router.interface.getSighash(functionSignature), - defaultAbiCoder.encode( - ['address', 'uint256', 'address', 'uint256', 'address'], - [tokens[1].address, amountOutMinimum, trader.address, 100, feeRecipient] - ), - ] - ), - ] - await router.connect(trader)['multicall(bytes[])'](data) - const balance = await tokens[1].balanceOf(feeRecipient) - expect(balance.eq(1)).to.be.eq(true) - }) - - it('#unwrapWETH9WithFee', async () => { - const startBalance = await waffle.provider.getBalance(feeRecipient) - await createPoolWETH9(tokens[0].address) - const amountOutMinimum = 100 - const params = { - path: encodePath([tokens[0].address, weth9.address], [FeeAmount.MEDIUM]), - recipient: ADDRESS_THIS, - amountIn: 102, - amountOutMinimum: 0, - } - - const functionSignature = 'unwrapWETH9WithFee(uint256,address,uint256,address)' - - const data = [ - router.interface.encodeFunctionData('exactInput', [params]), - solidityPack( - ['bytes4', 'bytes'], - [ - router.interface.getSighash(functionSignature), - defaultAbiCoder.encode( - ['uint256', 'address', 'uint256', 'address'], - [amountOutMinimum, trader.address, 100, feeRecipient] - ), - ] - ), - ] - await router.connect(trader)['multicall(bytes[])'](data) - const endBalance = await waffle.provider.getBalance(feeRecipient) - expect(endBalance.sub(startBalance).eq(1)).to.be.eq(true) - }) - }) - }) - - async function createV2Pool(tokenA: TestERC20, tokenB: TestERC20): Promise { - await factoryV2.createPair(tokenA.address, tokenB.address) - - const pairAddress = await factoryV2.getPair(tokenA.address, tokenB.address) - const pair = new ethers.Contract(pairAddress, PAIR_V2_ABI, wallet) as IUniswapV2Pair - - await tokenA.transfer(pair.address, liquidity) - await tokenB.transfer(pair.address, liquidity) - - await pair.mint(wallet.address) - - return pair - } - - describe('swaps - v2', () => { - let pairs: IUniswapV2Pair[] - let wethPairs: IUniswapV2Pair[] - - async function createPoolWETH9(token: TestERC20) { - await weth9.deposit({ value: liquidity }) - return createV2Pool((weth9 as unknown) as TestERC20, token) - } - - beforeEach('create 0-1 and 1-2 pools', async () => { - const pair01 = await createV2Pool(tokens[0], tokens[1]) - const pair12 = await createV2Pool(tokens[1], tokens[2]) - pairs = [pair01, pair12] - }) - - describe('#swapExactTokensForTokens', () => { - async function exactInput( - tokens: string[], - amountIn: number = 2, - amountOutMinimum: number = 1 - ): Promise { - const inputIsWETH = weth9.address === tokens[0] - const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address - - const value = inputIsWETH ? amountIn : 0 - - const params: [number, number, string[], string] = [ - amountIn, - amountOutMinimum, - tokens, - outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - ] - - const data = [router.interface.encodeFunctionData('swapExactTokensForTokens', params)] - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOutMinimum)) - } - - // ensure that the swap fails if the limit is any tighter - const paramsWithValue: [number, number, string[], string, { value: number }] = [...params, { value }] - const amountOut = await router.connect(trader).callStatic.swapExactTokensForTokens(...paramsWithValue) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - - return router.connect(trader)['multicall(bytes[])'](data, { value }) - } - - describe('single-pool', () => { - it('0 -> 1', async () => { - // get balances before - const poolBefore = await getBalances(pairs[0].address) - const traderBefore = await getBalances(trader.address) - - await exactInput(tokens.slice(0, 2).map((token) => token.address)) - - // get balances after - const poolAfter = await getBalances(pairs[0].address) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) - }) - - it('1 -> 0', async () => { - // get balances before - const poolBefore = await getBalances(pairs[0].address) - const traderBefore = await getBalances(trader.address) - - await exactInput( - tokens - .slice(0, 2) - .reverse() - .map((token) => token.address) - ) - - // get balances after - const poolAfter = await getBalances(pairs[0].address) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(2)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(2)) - }) - }) - - describe('multi-pool', () => { - it('0 -> 1 -> 2', async () => { - const traderBefore = await getBalances(trader.address) - await exactInput( - tokens.map((token) => token.address), - 3, - 1 - ) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) - }) - it('2 -> 1 -> 0', async () => { - const traderBefore = await getBalances(trader.address) - await exactInput(tokens.map((token) => token.address).reverse(), 3, 1) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(3)) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - }) - - it('events', async () => { - await expect( - exactInput( - tokens.map((token) => token.address), - 3, - 1 - ) - ) - .to.emit(tokens[0], 'Transfer') - .withArgs(trader.address, pairs[0].address, 3) - .to.emit(tokens[1], 'Transfer') - .withArgs(pairs[0].address, pairs[1].address, 2) - .to.emit(tokens[2], 'Transfer') - .withArgs(pairs[1].address, trader.address, 1) - }) - }) - - describe('ETH input', () => { - describe('WETH9', () => { - beforeEach(async () => { - const pair = await createPoolWETH9(tokens[0]) - wethPairs = [pair] - }) - - it('WETH9 -> 0', async () => { - // get balances before - const poolBefore = await getBalances(wethPairs[0].address) - const traderBefore = await getBalances(trader.address) - await expect(exactInput([weth9.address, tokens[0].address])) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 2) - // get balances after - const poolAfter = await getBalances(wethPairs[0].address) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(2)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - }) - - it('WETH9 -> 0 -> 1', async () => { - const traderBefore = await getBalances(trader.address) - await expect(exactInput([weth9.address, tokens[0].address, tokens[1].address], 3)) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 3) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - }) - }) - }) - - describe('ETH output', () => { - describe('WETH9', () => { - beforeEach(async () => { - const pair0 = await createPoolWETH9(tokens[0]) - const pair1 = await createPoolWETH9(tokens[1]) - wethPairs = [pair0, pair1] - }) - - it('0 -> WETH9', async () => { - // get balances before - const poolBefore = await getBalances(wethPairs[0].address) - const traderBefore = await getBalances(trader.address) - - await expect(exactInput([tokens[0].address, weth9.address])) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const poolAfter = await getBalances(wethPairs[0].address) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) - }) - - it('0 -> 1 -> WETH9', async () => { - // get balances before - const traderBefore = await getBalances(trader.address) - - await expect(exactInput([tokens[0].address, tokens[1].address, weth9.address], 3)) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - - // get balances after - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - }) - }) - }) - }) - - describe('#swapTokensForExactTokens', () => { - async function exactOutput( - tokens: string[], - amountOut: number = 1, - amountInMaximum: number = 2 - ): Promise { - const inputIsWETH9 = tokens[0] === weth9.address - const outputIsWETH9 = tokens[tokens.length - 1] === weth9.address - - const value = inputIsWETH9 ? amountInMaximum : 0 - - const params: [number, number, string[], string] = [ - amountOut, - amountInMaximum, - tokens, - outputIsWETH9 ? ADDRESS_THIS : MSG_SENDER, - ] - - const data = [router.interface.encodeFunctionData('swapTokensForExactTokens', params)] - if (inputIsWETH9) { - data.push(router.interface.encodeFunctionData('refundETH')) - } - if (outputIsWETH9) { - data.push(encodeUnwrapWETH9(amountOut)) - } - - // ensure that the swap fails if the limit is any tighter - const paramsWithValue: [number, number, string[], string, { value: number }] = [...params, { value }] - const amountIn = await router.connect(trader).callStatic.swapTokensForExactTokens(...paramsWithValue) - expect(amountIn.toNumber()).to.be.eq(amountInMaximum) - - return router.connect(trader)['multicall(bytes[])'](data, { value }) - } - - describe('single-pool', () => { - it('0 -> 1', async () => { - // get balances before - const poolBefore = await getBalances(pairs[0].address) - const traderBefore = await getBalances(trader.address) - - await exactOutput(tokens.slice(0, 2).map((token) => token.address)) - - // get balances after - const poolAfter = await getBalances(pairs[0].address) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.sub(1)) - }) - - it('1 -> 0', async () => { - // get balances before - const poolBefore = await getBalances(pairs[0].address) - const traderBefore = await getBalances(trader.address) - await exactOutput( - tokens - .slice(0, 2) - .reverse() - .map((token) => token.address) - ) - // get balances after - const poolAfter = await getBalances(pairs[0].address) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.sub(2)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - expect(poolAfter.token1).to.be.eq(poolBefore.token1.add(2)) - }) - }) - - describe('multi-pool', () => { - it('0 -> 1 -> 2', async () => { - const traderBefore = await getBalances(trader.address) - await exactOutput( - tokens.map((token) => token.address), - 1, - 3 - ) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(1)) - }) - - it('2 -> 1 -> 0', async () => { - const traderBefore = await getBalances(trader.address) - await exactOutput(tokens.map((token) => token.address).reverse(), 1, 3) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.sub(3)) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - }) - - it('events', async () => { - await expect( - exactOutput( - tokens.map((token) => token.address), - 1, - 3 - ) - ) - .to.emit(tokens[0], 'Transfer') - .withArgs(trader.address, pairs[0].address, 3) - .to.emit(tokens[1], 'Transfer') - .withArgs(pairs[0].address, pairs[1].address, 2) - .to.emit(tokens[2], 'Transfer') - .withArgs(pairs[1].address, trader.address, 1) - }) - }) - - describe('ETH input', () => { - describe('WETH9', () => { - beforeEach(async () => { - const pair = await createPoolWETH9(tokens[0]) - wethPairs = [pair] - }) - - it('WETH9 -> 0', async () => { - // get balances before - const poolBefore = await getBalances(wethPairs[0].address) - const traderBefore = await getBalances(trader.address) - await expect(exactOutput([weth9.address, tokens[0].address])) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 2) - // get balances after - const poolAfter = await getBalances(wethPairs[0].address) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.add(1)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.add(2)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.sub(1)) - }) - - it('WETH9 -> 0 -> 1', async () => { - const traderBefore = await getBalances(trader.address) - await expect(exactOutput([weth9.address, tokens[0].address, tokens[1].address], 1, 3)) - .to.emit(weth9, 'Deposit') - .withArgs(router.address, 3) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(1)) - }) - }) - }) - - describe('ETH output', () => { - describe('WETH9', () => { - beforeEach(async () => { - const pair0 = await createPoolWETH9(tokens[0]) - const pair1 = await createPoolWETH9(tokens[1]) - wethPairs = [pair0, pair1] - }) - - it('0 -> WETH9', async () => { - // get balances before - const poolBefore = await getBalances(wethPairs[0].address) - const traderBefore = await getBalances(trader.address) - await expect(exactOutput([tokens[0].address, weth9.address])) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - // get balances after - const poolAfter = await getBalances(wethPairs[0].address) - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(2)) - expect(poolAfter.weth9).to.be.eq(poolBefore.weth9.sub(1)) - expect(poolAfter.token0).to.be.eq(poolBefore.token0.add(2)) - }) - - it('0 -> 1 -> WETH9', async () => { - // get balances before - const traderBefore = await getBalances(trader.address) - await expect(exactOutput([tokens[0].address, tokens[1].address, weth9.address], 1, 3)) - .to.emit(weth9, 'Withdrawal') - .withArgs(router.address, 1) - // get balances after - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(3)) - }) - }) - }) - }) - }) - - describe('swaps - v2 + v3', () => { - beforeEach('create 0-1 and 1-2 pools', async () => { - await createV3Pool(tokens[0].address, tokens[1].address) - await createV3Pool(tokens[1].address, tokens[2].address) - }) - - beforeEach('create 0-1 and 1-2 pools', async () => { - await createV2Pool(tokens[0], tokens[1]) - await createV2Pool(tokens[1], tokens[2]) - }) - - async function exactInputV3( - tokens: string[], - amountIn: number = 3, - amountOutMinimum: number = 1, - recipient: string, - skipAmountOutMinimumCheck: boolean = false - ): Promise { - const params = { - path: encodePath(tokens, new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), - recipient, - amountIn, - amountOutMinimum, - } - - const data = [router.interface.encodeFunctionData('exactInput', [params])] - - if (!skipAmountOutMinimumCheck) { - // ensure that the swap fails if the limit is any tighter - const amountOut = await router.connect(trader).callStatic.exactInput(params) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - } - - return data - } - - async function exactOutputV3( - tokens: string[], - amountOut: number = 1, - amountInMaximum: number = 3, - recipient: string - ): Promise { - const params = { - path: encodePath(tokens.slice().reverse(), new Array(tokens.length - 1).fill(FeeAmount.MEDIUM)), - recipient, - amountOut, - amountInMaximum, - } - - const data = [router.interface.encodeFunctionData('exactOutput', [params])] - - // ensure that the swap fails if the limit is any tighter - const amountIn = await router.connect(trader).callStatic.exactOutput(params) - expect(amountIn.toNumber()).to.be.eq(amountInMaximum) - - return data - } - - async function exactInputV2( - tokens: string[], - amountIn: number = 2, - amountOutMinimum: number = 1, - recipient: string, - skipAmountOutMinimumCheck: boolean = false - ): Promise { - const params: [number, number, string[], string] = [amountIn, amountOutMinimum, tokens, recipient] - - const data = [router.interface.encodeFunctionData('swapExactTokensForTokens', params)] - - if (!skipAmountOutMinimumCheck) { - // ensure that the swap fails if the limit is any tighter - const amountOut = await router.connect(trader).callStatic.swapExactTokensForTokens(...params) - expect(amountOut.toNumber()).to.be.eq(amountOutMinimum) - } - - return data - } - - async function exactOutputV2( - tokens: string[], - amountOut: number = 1, - amountInMaximum: number = 2, - recipient: string - ): Promise { - const params: [number, number, string[], string] = [amountOut, amountInMaximum, tokens, recipient] - - const data = [router.interface.encodeFunctionData('swapTokensForExactTokens', params)] - - // ensure that the swap fails if the limit is any tighter - const amountIn = await router.connect(trader).callStatic.swapTokensForExactTokens(...params) - expect(amountIn.toNumber()).to.be.eq(amountInMaximum) - - return data - } - - describe('simple split route', async () => { - it('sending directly', async () => { - const swapV3 = await exactInputV3( - tokens.slice(0, 2).map((token) => token.address), - 3, - 1, - MSG_SENDER - ) - const swapV2 = await exactInputV2( - tokens.slice(0, 2).map((token) => token.address), - 2, - 1, - MSG_SENDER - ) - - const traderBefore = await getBalances(trader.address) - - await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2]) - - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(2)) - }) - - it('sending to router and sweeping', async () => { - const swapV3 = await exactInputV3( - tokens.slice(0, 2).map((token) => token.address), - 3, - 1, - ADDRESS_THIS - ) - const swapV2 = await exactInputV2( - tokens.slice(0, 2).map((token) => token.address), - 2, - 1, - ADDRESS_THIS - ) - - const sweep = encodeSweep(tokens[1].address, 2, trader.address) - - const traderBefore = await getBalances(trader.address) - - await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2, sweep]) - - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(5)) - expect(traderAfter.token1).to.be.eq(traderBefore.token1.add(2)) - }) - }) - - describe('merging', () => { - // 0 ↘ - // 0 → 1 → 2 - - it('exactIn x 2 + exactIn', async () => { - const swapV3 = await exactInputV3( - tokens.slice(0, 2).map((token) => token.address), - 3, - 1, - ADDRESS_THIS - ) - const swapV2 = await exactInputV2( - tokens.slice(0, 2).map((token) => token.address), - 3, - 2, - ADDRESS_THIS - ) - - const mergeSwap = await exactInputV3( - tokens.slice(1, 3).map((token) => token.address), - CONTRACT_BALANCE, - 1, - MSG_SENDER, - true - ) - - const traderBefore = await getBalances(trader.address) - - await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2, ...mergeSwap]) - - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(6)) - expect(traderAfter.token2).to.be.eq(traderBefore.token1.add(1)) - }) - - it('exactOut x 2 + exactIn', async () => { - const swapV3 = await exactOutputV3( - tokens.slice(0, 2).map((token) => token.address), - 1, - 3, - ADDRESS_THIS - ) - const swapV2 = await exactOutputV2( - tokens.slice(0, 2).map((token) => token.address), - 2, - 3, - ADDRESS_THIS - ) - - const mergeSwap = await exactInputV3( - tokens.slice(1, 3).map((token) => token.address), - CONTRACT_BALANCE, - 1, - MSG_SENDER, - true - ) - - const traderBefore = await getBalances(trader.address) - - await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2, ...mergeSwap]) - - const traderAfter = await getBalances(trader.address) - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(6)) - expect(traderAfter.token2).to.be.eq(traderBefore.token1.add(1)) - }) - }) - - describe('interleaving', () => { - // 0 -V3-> 1 -V2-> 2 - it('exactIn 0 -V3-> 1 -V2-> 2', async () => { - const swapV3 = await exactInputV3( - tokens.slice(0, 2).map((token) => token.address), - 10, - 8, - ADDRESS_THIS - ) - - const swapV2 = await exactInputV2( - tokens.slice(1, 3).map((token) => token.address), - CONTRACT_BALANCE, - 7, - MSG_SENDER, - true - ) - - const traderBefore = await getBalances(trader.address) - await router.connect(trader)['multicall(bytes[])']([...swapV3, ...swapV2]) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(10)) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(7)) - - const routerAmountOut = traderAfter.token2.sub(traderBefore.token2) - - // expect to equal quoter output - const { amountOut: quoterAmountOut } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[1].address, tokens[2].address], [FeeAmount.MEDIUM, V2_FEE_PLACEHOLDER]), - 10 - ) - - expect(quoterAmountOut.eq(routerAmountOut)).to.be.true - }) - - it('exactIn 0 -V2-> 1 -V3-> 2', async () => { - const swapV2 = await exactInputV2( - tokens.slice(0, 2).map((token) => token.address), - 10, - 9, - ADDRESS_THIS - ) - - const swapV3 = await exactInputV3( - tokens.slice(1, 3).map((token) => token.address), - CONTRACT_BALANCE, - 7, - MSG_SENDER, - true - ) - - const traderBefore = await getBalances(trader.address) - await router.connect(trader)['multicall(bytes[])']([...swapV2, ...swapV3]) - const traderAfter = await getBalances(trader.address) - - expect(traderAfter.token0).to.be.eq(traderBefore.token0.sub(10)) - expect(traderAfter.token2).to.be.eq(traderBefore.token2.add(7)) - - const routerAmountOut = traderAfter.token2.sub(traderBefore.token2) - - // expect to equal quoter output - const { amountOut: quoterAmountOut } = await quoter.callStatic['quoteExactInput(bytes,uint256)']( - encodePath([tokens[0].address, tokens[1].address, tokens[2].address], [V2_FEE_PLACEHOLDER, FeeAmount.MEDIUM]), - 10 - ) - expect(quoterAmountOut.eq(routerAmountOut)).to.be.true - }) - }) - }) -}) diff --git a/lib/swap-router-contracts/test/TokenValidator.spec.ts b/lib/swap-router-contracts/test/TokenValidator.spec.ts deleted file mode 100644 index d6c7353..0000000 --- a/lib/swap-router-contracts/test/TokenValidator.spec.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { expect } from 'chai' -import { constants } from 'ethers' -import hre, { ethers } from 'hardhat' -import { TokenValidator, TestERC20, IUniswapV2Pair__factory } from '../typechain' - -describe('TokenValidator', function () { - let tokenValidator: TokenValidator - let testToken: TestERC20 - - this.timeout(100000) - - enum Status { - UNKN = 0, - FOT = 1, - STF = 2, - } - - // WETH9 and USDC - const BASE_TOKENS = ['0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'] - // Arbitrary amount to flash loan. - const AMOUNT_TO_BORROW = 1000 - - const FOT_TOKENS = [ - '0xa68dd8cb83097765263adad881af6eed479c4a33', // WTF - '0x8B3192f5eEBD8579568A2Ed41E6FEB402f93f73F', // SAITAMA - '0xA2b4C0Af19cC16a6CfAcCe81F192B024d625817D', // KISHU - ] - - const BROKEN_TOKENS = [ - '0xd233d1f6fd11640081abb8db125f722b5dc729dc', // USD - ] - - const NON_FOT_TOKENS = [ - '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC - '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', // UNI - '0xc00e94Cb662C3520282E6f5717214004A7f26888', // COMP - '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH9 - ] - - before(async function () { - // Easiest to test FOT using real world data, so these tests require a hardhat fork. - if (!process.env.ARCHIVE_RPC_URL) { - this.skip() - } - - await hre.network.provider.request({ - method: 'hardhat_reset', - params: [ - { - forking: { - jsonRpcUrl: process.env.ARCHIVE_RPC_URL, - blockNumber: 14024832, - }, - }, - ], - }) - - const factory = await ethers.getContractFactory('TokenValidator') - tokenValidator = (await factory.deploy( - '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', // V2 Factory - '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' // V3 NFT position manager - )) as TokenValidator - - // Deploy a new token for testing. - const tokenFactory = await ethers.getContractFactory('TestERC20') - testToken = (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20 - }) - - after(async () => { - // Disable mainnet forking to avoid effecting other tests. - await hre.network.provider.request({ - method: 'hardhat_reset', - params: [], - }) - }) - - it('succeeds for tokens that cant be transferred', async () => { - for (const token of BROKEN_TOKENS) { - const isFot = await tokenValidator.callStatic.validate(token, BASE_TOKENS, AMOUNT_TO_BORROW) - expect(isFot).to.equal(Status.STF) - } - }) - - it('succeeds to detect fot tokens', async () => { - for (const token of FOT_TOKENS) { - const isFot = await tokenValidator.callStatic.validate(token, [BASE_TOKENS[0]!], AMOUNT_TO_BORROW) - expect(isFot).to.equal(Status.FOT) - } - }) - - it('succeeds to detect fot token when token doesnt have pair with first base token', async () => { - const isFot = await tokenValidator.callStatic.validate( - FOT_TOKENS[0], - [testToken.address, ...BASE_TOKENS], - AMOUNT_TO_BORROW - ) - expect(isFot).to.equal(Status.FOT) - }) - - it('succeeds to return unknown when flash loaning full reserves', async () => { - const pairAddress = '0xab293dce330b92aa52bc2a7cd3816edaa75f890b' // WTF/ETH pair - const pair = IUniswapV2Pair__factory.connect(pairAddress, ethers.provider) - const { reserve0: wtfReserve } = await pair.callStatic.getReserves() - - const isFot1 = await tokenValidator.callStatic.validate( - '0xa68dd8cb83097765263adad881af6eed479c4a33', // WTF - ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'], // WETH - wtfReserve.sub(1).toString() - ) - expect(isFot1).to.equal(Status.FOT) - - const isFot2 = await tokenValidator.callStatic.validate( - '0xa68dd8cb83097765263adad881af6eed479c4a33', // WTF - ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'], // WETH - wtfReserve.toString() - ) - expect(isFot2).to.equal(Status.UNKN) - }) - - it('succeeds to batch detect fot tokens', async () => { - const isFots = await tokenValidator.callStatic.batchValidate(FOT_TOKENS, BASE_TOKENS, AMOUNT_TO_BORROW) - expect(isFots.every((isFot: Status) => isFot == Status.FOT)).to.be.true - }) - - it('succeeds to batch detect fot tokens when dont have pair with first base token', async () => { - const isFots = await tokenValidator.callStatic.batchValidate( - FOT_TOKENS, - [testToken.address, ...BASE_TOKENS], - AMOUNT_TO_BORROW - ) - expect(isFots.every((isFot: Status) => isFot == Status.FOT)).to.be.true - }) - - it('succeeds to detect non fot tokens', async () => { - for (const token of NON_FOT_TOKENS) { - const isFot = await tokenValidator.callStatic.validate(token, BASE_TOKENS, AMOUNT_TO_BORROW) - expect(isFot).to.equal(Status.UNKN) - } - }) - - it('succeeds to batch detect non fot tokens', async () => { - const isFots = await tokenValidator.callStatic.batchValidate(NON_FOT_TOKENS, BASE_TOKENS, AMOUNT_TO_BORROW) - expect(isFots.every((isFot: Status) => isFot == Status.UNKN)).to.be.true - }) - - it('succeeds to batch detect mix of fot tokens and non fot tokens', async () => { - const isFots = await tokenValidator.callStatic.batchValidate( - [NON_FOT_TOKENS[0], FOT_TOKENS[0], BROKEN_TOKENS[0]], - BASE_TOKENS, - 1000 - ) - expect(isFots).to.deep.equal([Status.UNKN, Status.FOT, Status.STF]) - }) - - it('succeeds to return false if token doesnt have a pool with any of the base tokens', async () => { - await tokenValidator.callStatic.validate(testToken.address, BASE_TOKENS, AMOUNT_TO_BORROW) - }) -}) diff --git a/lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap deleted file mode 100644 index 3a9002f..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/ImmutableState.spec.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ImmutableState bytecode size 1`] = `193`; diff --git a/lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap deleted file mode 100644 index df91db3..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/MixedRouteQuoterV1.spec.ts.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 -> 1 1`] = `281505`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 0 tick, starting tick initialized 1`] = `123786`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 0 tick, starting tick not initialized 1`] = `104827`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 1 tick 1`] = `149094`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 2 tick 1`] = `186691`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 0 -> 2 cross 2 tick where after is initialized 1`] = `149132`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 0 tick, starting tick initialized 1`] = `97643`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 0 tick, starting tick not initialized 1`] = `97643`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 2 1`] = `179503`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 0 cross 2 where tick after is initialized 1`] = `179511`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInput V3 only 2 -> 1 1`] = `97318`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInputSingle V3 0 -> 2 1`] = `186673`; - -exports[`MixedRouteQuoterV1 quotes #quoteExactInputSingle V3 2 -> 0 1`] = `179475`; diff --git a/lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap deleted file mode 100644 index 8570516..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/Multicall.spec.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Multicall gas cost of pay w/ multicall 1`] = `45928`; - -exports[`Multicall gas cost of pay w/o multicall 1`] = `43364`; diff --git a/lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap deleted file mode 100644 index e450df9..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/Path.spec.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Path gas cost 1`] = `451`; diff --git a/lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap deleted file mode 100644 index 7471415..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/PoolAddress.spec.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PoolAddress #computeAddress gas cost 1`] = `642`; - -exports[`PoolAddress #computeAddress matches example from core repo 1`] = `"0x03D8bab195A5BC23d249693F53dfA0e358F2650D"`; diff --git a/lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap deleted file mode 100644 index ccb9341..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/QuoterV2.spec.ts.snap +++ /dev/null @@ -1,51 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 -> 1 1`] = `277146`; - -exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 0 tick, starting tick initialized 1`] = `123797`; - -exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 0 tick, starting tick not initialized 1`] = `100962`; - -exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 1 tick 1`] = `144724`; - -exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 2 tick 1`] = `182321`; - -exports[`QuoterV2 quotes #quoteExactInput 0 -> 2 cross 2 tick where after is initialized 1`] = `144762`; - -exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 0 tick, starting tick initialized 1`] = `97654`; - -exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 0 tick, starting tick not initialized 1`] = `93779`; - -exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 2 1`] = `175133`; - -exports[`QuoterV2 quotes #quoteExactInput 2 -> 0 cross 2 where tick after is initialized 1`] = `175141`; - -exports[`QuoterV2 quotes #quoteExactInput 2 -> 1 1`] = `97329`; - -exports[`QuoterV2 quotes #quoteExactInputSingle 0 -> 2 1`] = `182303`; - -exports[`QuoterV2 quotes #quoteExactInputSingle 2 -> 0 1`] = `175105`; - -exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 -> 1 1`] = `276746`; - -exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 0 tick starting tick initialized 1`] = `123352`; - -exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 0 tick starting tick not initialized 1`] = `100537`; - -exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 1 tick 1`] = `144010`; - -exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 2 tick 1`] = `181363`; - -exports[`QuoterV2 quotes #quoteExactOutput 0 -> 2 cross 2 where tick after is initialized 1`] = `144048`; - -exports[`QuoterV2 quotes #quoteExactOutput 2 -> 0 cross 1 tick 1`] = `137858`; - -exports[`QuoterV2 quotes #quoteExactOutput 2 -> 0 cross 2 ticks 1`] = `175203`; - -exports[`QuoterV2 quotes #quoteExactOutput 2 -> 0 cross 2 where tick after is initialized 1`] = `175197`; - -exports[`QuoterV2 quotes #quoteExactOutput 2 -> 1 1`] = `97870`; - -exports[`QuoterV2 quotes #quoteExactOutputSingle 0 -> 1 1`] = `105200`; - -exports[`QuoterV2 quotes #quoteExactOutputSingle 1 -> 0 1`] = `98511`; diff --git a/lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap deleted file mode 100644 index 8600170..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/SwapRouter.gas.spec.ts.snap +++ /dev/null @@ -1,37 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SwapRouter gas tests #exactInput 0 -> 1 -> 2 1`] = `175302`; - -exports[`SwapRouter gas tests #exactInput 0 -> 1 1`] = `110495`; - -exports[`SwapRouter gas tests #exactInput 0 -> 1 minimal 1`] = `98059`; - -exports[`SwapRouter gas tests #exactInput 0 -> WETH9 1`] = `127401`; - -exports[`SwapRouter gas tests #exactInput 2 trades (directly to sender) 1`] = `178981`; - -exports[`SwapRouter gas tests #exactInput 2 trades (via router) 1`] = `188487`; - -exports[`SwapRouter gas tests #exactInput 3 trades (directly to sender) 1`] = `257705`; - -exports[`SwapRouter gas tests #exactInput WETH9 -> 0 1`] = `108832`; - -exports[`SwapRouter gas tests #exactInputSingle 0 -> 1 1`] = `109826`; - -exports[`SwapRouter gas tests #exactInputSingle 0 -> WETH9 1`] = `126732`; - -exports[`SwapRouter gas tests #exactInputSingle WETH9 -> 0 1`] = `108163`; - -exports[`SwapRouter gas tests #exactOutput 0 -> 1 -> 2 1`] = `169268`; - -exports[`SwapRouter gas tests #exactOutput 0 -> 1 1`] = `111692`; - -exports[`SwapRouter gas tests #exactOutput 0 -> WETH9 1`] = `128610`; - -exports[`SwapRouter gas tests #exactOutput WETH9 -> 0 1`] = `119706`; - -exports[`SwapRouter gas tests #exactOutputSingle 0 -> 1 1`] = `111826`; - -exports[`SwapRouter gas tests #exactOutputSingle 0 -> WETH9 1`] = `128744`; - -exports[`SwapRouter gas tests #exactOutputSingle WETH9 -> 0 1`] = `112627`; diff --git a/lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap b/lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap deleted file mode 100644 index e7f484a..0000000 --- a/lib/swap-router-contracts/test/__snapshots__/SwapRouter.spec.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SwapRouter bytecode size 1`] = `24563`; diff --git a/lib/swap-router-contracts/test/contracts/WETH9.json b/lib/swap-router-contracts/test/contracts/WETH9.json deleted file mode 100644 index 68ec24f..0000000 --- a/lib/swap-router-contracts/test/contracts/WETH9.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "bytecode": "60606040526040805190810160405280600d81526020017f57726170706564204574686572000000000000000000000000000000000000008152506000908051906020019061004f9291906100c8565b506040805190810160405280600481526020017f57455448000000000000000000000000000000000000000000000000000000008152506001908051906020019061009b9291906100c8565b506012600260006101000a81548160ff021916908360ff16021790555034156100c357600080fd5b61016d565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061010957805160ff1916838001178555610137565b82800160010185558215610137579182015b8281111561013657825182559160200191906001019061011b565b5b5090506101449190610148565b5090565b61016a91905b8082111561016657600081600090555060010161014e565b5090565b90565b610c348061017c6000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b9578063095ea7b31461014757806318160ddd146101a157806323b872dd146101ca5780632e1a7d4d14610243578063313ce5671461026657806370a082311461029557806395d89b41146102e2578063a9059cbb14610370578063d0e30db0146103ca578063dd62ed3e146103d4575b6100b7610440565b005b34156100c457600080fd5b6100cc6104dd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010c5780820151818401526020810190506100f1565b50505050905090810190601f1680156101395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015257600080fd5b610187600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061057b565b604051808215151515815260200191505060405180910390f35b34156101ac57600080fd5b6101b461066d565b6040518082815260200191505060405180910390f35b34156101d557600080fd5b610229600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061068c565b604051808215151515815260200191505060405180910390f35b341561024e57600080fd5b61026460048080359060200190919050506109d9565b005b341561027157600080fd5b610279610b05565b604051808260ff1660ff16815260200191505060405180910390f35b34156102a057600080fd5b6102cc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b18565b6040518082815260200191505060405180910390f35b34156102ed57600080fd5b6102f5610b30565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561033557808201518184015260208101905061031a565b50505050905090810190601f1680156103625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561037b57600080fd5b6103b0600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610bce565b604051808215151515815260200191505060405180910390f35b6103d2610440565b005b34156103df57600080fd5b61042a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610be3565b6040518082815260200191505060405180910390f35b34600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a2565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105735780601f1061054857610100808354040283529160200191610573565b820191906000526020600020905b81548152906001019060200180831161055657829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b600081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156106dc57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156107b457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156108cf5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084457600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a2757600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501515610ab457600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040518082815260200191505060405180910390a250565b600260009054906101000a900460ff1681565b60036020528060005260406000206000915090505481565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bc65780601f10610b9b57610100808354040283529160200191610bc6565b820191906000526020600020905b815481529060010190602001808311610ba957829003601f168201915b505050505081565b6000610bdb33848461068c565b905092915050565b60046020528160005260406000206020528060005260406000206000915091505054815600a165627a7a72305820deb4c2ccab3c2fdca32ab3f46728389c2fe2c165d5fafa07661e4e004f6c344a0029", - "abi": [ - { - "constant": true, - "inputs": [], - "name": "name", - "outputs": [{ "name": "", "type": "string" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "guy", "type": "address" }, - { "name": "wad", "type": "uint256" } - ], - "name": "approve", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "src", "type": "address" }, - { "name": "dst", "type": "address" }, - { "name": "wad", "type": "uint256" } - ], - "name": "transferFrom", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "wad", "type": "uint256" }], - "name": "withdraw", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "decimals", - "outputs": [{ "name": "", "type": "uint8" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "name": "", "type": "address" }], - "name": "balanceOf", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "symbol", - "outputs": [{ "name": "", "type": "string" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "dst", "type": "address" }, - { "name": "wad", "type": "uint256" } - ], - "name": "transfer", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "deposit", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { "name": "", "type": "address" }, - { "name": "", "type": "address" } - ], - "name": "allowance", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { "payable": true, "stateMutability": "payable", "type": "fallback" }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "src", "type": "address" }, - { "indexed": true, "name": "guy", "type": "address" }, - { "indexed": false, "name": "wad", "type": "uint256" } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "src", "type": "address" }, - { "indexed": true, "name": "dst", "type": "address" }, - { "indexed": false, "name": "wad", "type": "uint256" } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "dst", "type": "address" }, - { "indexed": false, "name": "wad", "type": "uint256" } - ], - "name": "Deposit", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "src", "type": "address" }, - { "indexed": false, "name": "wad", "type": "uint256" } - ], - "name": "Withdrawal", - "type": "event" - } - ] -} diff --git a/lib/swap-router-contracts/test/shared/completeFixture.ts b/lib/swap-router-contracts/test/shared/completeFixture.ts deleted file mode 100644 index 5c44fd2..0000000 --- a/lib/swap-router-contracts/test/shared/completeFixture.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Fixture } from 'ethereum-waffle' -import { ethers, waffle } from 'hardhat' -import { v3RouterFixture } from './externalFixtures' -import { constants, Contract } from 'ethers' -import { IWETH9, MockTimeSwapRouter02, TestERC20 } from '../../typechain' - -const completeFixture: Fixture<{ - weth9: IWETH9 - factoryV2: Contract - factory: Contract - router: MockTimeSwapRouter02 - nft: Contract - tokens: [TestERC20, TestERC20, TestERC20] -}> = async ([wallet], provider) => { - const { weth9, factoryV2, factory, nft, router } = await v3RouterFixture([wallet], provider) - - const tokenFactory = await ethers.getContractFactory('TestERC20') - const tokens: [TestERC20, TestERC20, TestERC20] = [ - (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20, // do not use maxu256 to avoid overflowing - (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20, - (await tokenFactory.deploy(constants.MaxUint256.div(2))) as TestERC20, - ] - - tokens.sort((a, b) => (a.address.toLowerCase() < b.address.toLowerCase() ? -1 : 1)) - - return { - weth9, - factoryV2, - factory, - router, - tokens, - nft, - } -} - -export default completeFixture diff --git a/lib/swap-router-contracts/test/shared/computePoolAddress.ts b/lib/swap-router-contracts/test/shared/computePoolAddress.ts deleted file mode 100644 index fde8c8a..0000000 --- a/lib/swap-router-contracts/test/shared/computePoolAddress.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { bytecode } from '@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json' -import { utils } from 'ethers' - -export const POOL_BYTECODE_HASH = utils.keccak256(bytecode) - -export function computePoolAddress(factoryAddress: string, [tokenA, tokenB]: [string, string], fee: number): string { - const [token0, token1] = tokenA.toLowerCase() < tokenB.toLowerCase() ? [tokenA, tokenB] : [tokenB, tokenA] - const constructorArgumentsEncoded = utils.defaultAbiCoder.encode( - ['address', 'address', 'uint24'], - [token0, token1, fee] - ) - const create2Inputs = [ - '0xff', - factoryAddress, - // salt - utils.keccak256(constructorArgumentsEncoded), - // init code hash - POOL_BYTECODE_HASH, - ] - const sanitizedInputs = `0x${create2Inputs.map((i) => i.slice(2)).join('')}` - return utils.getAddress(`0x${utils.keccak256(sanitizedInputs).slice(-40)}`) -} diff --git a/lib/swap-router-contracts/test/shared/constants.ts b/lib/swap-router-contracts/test/shared/constants.ts deleted file mode 100644 index 15a188a..0000000 --- a/lib/swap-router-contracts/test/shared/constants.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { BigNumber } from 'ethers' - -export const MaxUint128 = BigNumber.from(2).pow(128).sub(1) - -export enum FeeAmount { - LOW = 500, - MEDIUM = 3000, - HIGH = 10000, -} - -export const V2_FEE_PLACEHOLDER = 8388608 // 1 << 23 - -export const TICK_SPACINGS: { [amount in FeeAmount]: number } = { - [FeeAmount.LOW]: 10, - [FeeAmount.MEDIUM]: 60, - [FeeAmount.HIGH]: 200, -} - -export const CONTRACT_BALANCE = 0 -export const MSG_SENDER = '0x0000000000000000000000000000000000000001' -export const ADDRESS_THIS = '0x0000000000000000000000000000000000000002' diff --git a/lib/swap-router-contracts/test/shared/encodePriceSqrt.ts b/lib/swap-router-contracts/test/shared/encodePriceSqrt.ts deleted file mode 100644 index f95cd23..0000000 --- a/lib/swap-router-contracts/test/shared/encodePriceSqrt.ts +++ /dev/null @@ -1,16 +0,0 @@ -import bn from 'bignumber.js' -import { BigNumber, BigNumberish } from 'ethers' - -bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }) - -// returns the sqrt price as a 64x96 -export function encodePriceSqrt(reserve1: BigNumberish, reserve0: BigNumberish): BigNumber { - return BigNumber.from( - new bn(reserve1.toString()) - .div(reserve0.toString()) - .sqrt() - .multipliedBy(new bn(2).pow(96)) - .integerValue(3) - .toString() - ) -} diff --git a/lib/swap-router-contracts/test/shared/expandTo18Decimals.ts b/lib/swap-router-contracts/test/shared/expandTo18Decimals.ts deleted file mode 100644 index cddc9ba..0000000 --- a/lib/swap-router-contracts/test/shared/expandTo18Decimals.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { BigNumber } from 'ethers' - -export function expandTo18Decimals(n: number): BigNumber { - return BigNumber.from(n).mul(BigNumber.from(10).pow(18)) -} - -export function expandToNDecimals(n: number, d: number): BigNumber { - return BigNumber.from(n).mul(BigNumber.from(10).pow(d)) -} diff --git a/lib/swap-router-contracts/test/shared/expect.ts b/lib/swap-router-contracts/test/shared/expect.ts deleted file mode 100644 index ac8f19b..0000000 --- a/lib/swap-router-contracts/test/shared/expect.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { expect, use } from 'chai' -import { solidity } from 'ethereum-waffle' -import { jestSnapshotPlugin } from 'mocha-chai-jest-snapshot' - -use(solidity) -use(jestSnapshotPlugin()) - -export { expect } diff --git a/lib/swap-router-contracts/test/shared/externalFixtures.ts b/lib/swap-router-contracts/test/shared/externalFixtures.ts deleted file mode 100644 index cb02d86..0000000 --- a/lib/swap-router-contracts/test/shared/externalFixtures.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { - abi as FACTORY_ABI, - bytecode as FACTORY_BYTECODE, -} from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json' -import { abi as FACTORY_V2_ABI, bytecode as FACTORY_V2_BYTECODE } from '@uniswap/v2-core/build/UniswapV2Factory.json' -import { Fixture } from 'ethereum-waffle' -import { ethers, waffle } from 'hardhat' -import { IWETH9, MockTimeSwapRouter02 } from '../../typechain' - -import WETH9 from '../contracts/WETH9.json' -import { Contract } from '@ethersproject/contracts' -import { constants } from 'ethers' - -import { - abi as NFT_POSITION_MANAGER_ABI, - bytecode as NFT_POSITION_MANAGER_BYTECODE, -} from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json' - -const wethFixture: Fixture<{ weth9: IWETH9 }> = async ([wallet]) => { - const weth9 = (await waffle.deployContract(wallet, { - bytecode: WETH9.bytecode, - abi: WETH9.abi, - })) as IWETH9 - - return { weth9 } -} - -export const v2FactoryFixture: Fixture<{ factory: Contract }> = async ([wallet]) => { - const factory = await waffle.deployContract( - wallet, - { - bytecode: FACTORY_V2_BYTECODE, - abi: FACTORY_V2_ABI, - }, - [constants.AddressZero] - ) - - return { factory } -} - -const v3CoreFactoryFixture: Fixture = async ([wallet]) => { - return await waffle.deployContract(wallet, { - bytecode: FACTORY_BYTECODE, - abi: FACTORY_ABI, - }) -} - -export const v3RouterFixture: Fixture<{ - weth9: IWETH9 - factoryV2: Contract - factory: Contract - nft: Contract - router: MockTimeSwapRouter02 -}> = async ([wallet], provider) => { - const { weth9 } = await wethFixture([wallet], provider) - const { factory: factoryV2 } = await v2FactoryFixture([wallet], provider) - const factory = await v3CoreFactoryFixture([wallet], provider) - - const nft = await waffle.deployContract( - wallet, - { - bytecode: NFT_POSITION_MANAGER_BYTECODE, - abi: NFT_POSITION_MANAGER_ABI, - }, - [factory.address, weth9.address, constants.AddressZero] - ) - - const router = (await (await ethers.getContractFactory('MockTimeSwapRouter02')).deploy( - factoryV2.address, - factory.address, - nft.address, - weth9.address - )) as MockTimeSwapRouter02 - - return { weth9, factoryV2, factory, nft, router } -} diff --git a/lib/swap-router-contracts/test/shared/path.ts b/lib/swap-router-contracts/test/shared/path.ts deleted file mode 100644 index 99418b1..0000000 --- a/lib/swap-router-contracts/test/shared/path.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { utils } from 'ethers' -import { FeeAmount } from './constants' - -const ADDR_SIZE = 20 -const FEE_SIZE = 3 -const OFFSET = ADDR_SIZE + FEE_SIZE -const DATA_SIZE = OFFSET + ADDR_SIZE - -export function encodePath(path: string[], fees: FeeAmount[]): string { - if (path.length != fees.length + 1) { - throw new Error('path/fee lengths do not match') - } - - let encoded = '0x' - for (let i = 0; i < fees.length; i++) { - // 20 byte encoding of the address - encoded += path[i].slice(2) - // 3 byte encoding of the fee - encoded += fees[i].toString(16).padStart(2 * FEE_SIZE, '0') - } - // encode the final token - encoded += path[path.length - 1].slice(2) - - return encoded.toLowerCase() -} - -function decodeOne(tokenFeeToken: Buffer): [[string, string], number] { - // reads the first 20 bytes for the token address - const tokenABuf = tokenFeeToken.slice(0, ADDR_SIZE) - const tokenA = utils.getAddress('0x' + tokenABuf.toString('hex')) - - // reads the next 2 bytes for the fee - const feeBuf = tokenFeeToken.slice(ADDR_SIZE, OFFSET) - const fee = feeBuf.readUIntBE(0, FEE_SIZE) - - // reads the next 20 bytes for the token address - const tokenBBuf = tokenFeeToken.slice(OFFSET, DATA_SIZE) - const tokenB = utils.getAddress('0x' + tokenBBuf.toString('hex')) - - return [[tokenA, tokenB], fee] -} - -export function decodePath(path: string): [string[], number[]] { - let data = Buffer.from(path.slice(2), 'hex') - - let tokens: string[] = [] - let fees: number[] = [] - let i = 0 - let finalToken: string = '' - while (data.length >= DATA_SIZE) { - const [[tokenA, tokenB], fee] = decodeOne(data) - finalToken = tokenB - tokens = [...tokens, tokenA] - fees = [...fees, fee] - data = data.slice((i + 1) * OFFSET) - i += 1 - } - tokens = [...tokens, finalToken] - - return [tokens, fees] -} diff --git a/lib/swap-router-contracts/test/shared/quoter.ts b/lib/swap-router-contracts/test/shared/quoter.ts deleted file mode 100644 index 2d4afcc..0000000 --- a/lib/swap-router-contracts/test/shared/quoter.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { Wallet, Contract } from 'ethers' -import { FeeAmount, TICK_SPACINGS } from './constants' -import { encodePriceSqrt } from './encodePriceSqrt' -import { getMaxTick, getMinTick } from './ticks' - -export async function createPool(nft: Contract, wallet: Wallet, tokenAddressA: string, tokenAddressB: string) { - if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) - [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] - - await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) - - const liquidityParams = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: wallet.address, - amount0Desired: 1000000, - amount1Desired: 1000000, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - return nft.mint(liquidityParams) -} - -export async function createPoolWithMultiplePositions( - nft: Contract, - wallet: Wallet, - tokenAddressA: string, - tokenAddressB: string -) { - if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) - [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] - - await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) - - const liquidityParams = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: wallet.address, - amount0Desired: 1000000, - amount1Desired: 1000000, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - await nft.mint(liquidityParams) - - const liquidityParams2 = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: -60, - tickUpper: 60, - recipient: wallet.address, - amount0Desired: 100, - amount1Desired: 100, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - await nft.mint(liquidityParams2) - - const liquidityParams3 = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: -120, - tickUpper: 120, - recipient: wallet.address, - amount0Desired: 100, - amount1Desired: 100, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - return nft.mint(liquidityParams3) -} - -export async function createPoolWithZeroTickInitialized( - nft: Contract, - wallet: Wallet, - tokenAddressA: string, - tokenAddressB: string -) { - if (tokenAddressA.toLowerCase() > tokenAddressB.toLowerCase()) - [tokenAddressA, tokenAddressB] = [tokenAddressB, tokenAddressA] - - await nft.createAndInitializePoolIfNecessary(tokenAddressA, tokenAddressB, FeeAmount.MEDIUM, encodePriceSqrt(1, 1)) - - const liquidityParams = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - recipient: wallet.address, - amount0Desired: 1000000, - amount1Desired: 1000000, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - await nft.mint(liquidityParams) - - const liquidityParams2 = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: 0, - tickUpper: 60, - recipient: wallet.address, - amount0Desired: 100, - amount1Desired: 100, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - await nft.mint(liquidityParams2) - - const liquidityParams3 = { - token0: tokenAddressA, - token1: tokenAddressB, - fee: FeeAmount.MEDIUM, - tickLower: -120, - tickUpper: 0, - recipient: wallet.address, - amount0Desired: 100, - amount1Desired: 100, - amount0Min: 0, - amount1Min: 0, - deadline: 2 ** 32, - } - - return nft.mint(liquidityParams3) -} - -/** - * Create V2 pairs for testing with IL routes - */ -export async function createPair(v2Factory: Contract, tokenAddressA: string, tokenAddressB: string): Promise { - // .createPair() sorts the tokens already - const receipt = await (await v2Factory.createPair(tokenAddressA, tokenAddressB)).wait() - // we can extract the pair address from the emitted event - // always the 3rd element: emit PairCreated(token0, token1, pair, allPairs.length); - const pairAddress = receipt.events[0].args[2] - if (!pairAddress) throw new Error('pairAddress not found in txn receipt') - return pairAddress -} diff --git a/lib/swap-router-contracts/test/shared/snapshotGasCost.ts b/lib/swap-router-contracts/test/shared/snapshotGasCost.ts deleted file mode 100644 index 5a606d2..0000000 --- a/lib/swap-router-contracts/test/shared/snapshotGasCost.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider' -import { expect } from './expect' -import { Contract, BigNumber, ContractTransaction } from 'ethers' - -export default async function snapshotGasCost( - x: - | TransactionResponse - | Promise - | ContractTransaction - | Promise - | TransactionReceipt - | Promise - | BigNumber - | Contract - | Promise -): Promise { - const resolved = await x - if ('deployTransaction' in resolved) { - const receipt = await resolved.deployTransaction.wait() - expect(receipt.gasUsed.toNumber()).toMatchSnapshot() - } else if ('wait' in resolved) { - const waited = await resolved.wait() - expect(waited.gasUsed.toNumber()).toMatchSnapshot() - } else if (BigNumber.isBigNumber(resolved)) { - expect(resolved.toNumber()).toMatchSnapshot() - } -} diff --git a/lib/swap-router-contracts/test/shared/ticks.ts b/lib/swap-router-contracts/test/shared/ticks.ts deleted file mode 100644 index b162dfd..0000000 --- a/lib/swap-router-contracts/test/shared/ticks.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const getMinTick = (tickSpacing: number) => Math.ceil(-887272 / tickSpacing) * tickSpacing -export const getMaxTick = (tickSpacing: number) => Math.floor(887272 / tickSpacing) * tickSpacing diff --git a/lib/swap-router-contracts/tsconfig.json b/lib/swap-router-contracts/tsconfig.json deleted file mode 100644 index 69ab585..0000000 --- a/lib/swap-router-contracts/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "es2018", - "module": "commonjs", - "strict": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "outDir": "dist", - "typeRoots": ["./typechain", "./node_modules/@types"], - "types": ["@nomiclabs/hardhat-ethers", "@nomiclabs/hardhat-waffle"] - }, - "include": ["./test"], - "files": ["./hardhat.config.ts"] -} diff --git a/lib/swap-router-contracts/yarn.lock b/lib/swap-router-contracts/yarn.lock deleted file mode 100644 index ac17e7a..0000000 --- a/lib/swap-router-contracts/yarn.lock +++ /dev/null @@ -1,8128 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" - -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/types@^7.0.0", "@babel/types@^7.3.0": - version "7.12.12" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" - dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - -"@ensdomains/ens@^0.4.4": - version "0.4.5" - resolved "https://registry.yarnpkg.com/@ensdomains/ens/-/ens-0.4.5.tgz#e0aebc005afdc066447c6e22feb4eda89a5edbfc" - dependencies: - bluebird "^3.5.2" - eth-ens-namehash "^2.0.8" - solc "^0.4.20" - testrpc "0.0.1" - web3-utils "^1.0.0-beta.31" - -"@ensdomains/resolver@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89" - -"@ethereum-waffle/chai@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.2.1.tgz#5cb542b2a323adf0bc2dda00f48b0eb85944d8ab" - dependencies: - "@ethereum-waffle/provider" "^3.2.1" - ethers "^5.0.0" - -"@ethereum-waffle/compiler@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/compiler/-/compiler-3.2.1.tgz#612a9056285a94ce28eb57b895770ad10e438bf9" - dependencies: - "@resolver-engine/imports" "^0.3.3" - "@resolver-engine/imports-fs" "^0.3.3" - "@types/mkdirp" "^0.5.2" - "@types/node-fetch" "^2.5.5" - ethers "^5.0.1" - mkdirp "^0.5.1" - node-fetch "^2.6.0" - solc "^0.6.3" - -"@ethereum-waffle/ens@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/ens/-/ens-3.2.1.tgz#9f369112d62f7aa88d010be4d133b6d0f5e8c492" - dependencies: - "@ensdomains/ens" "^0.4.4" - "@ensdomains/resolver" "^0.2.4" - ethers "^5.0.1" - -"@ethereum-waffle/mock-contract@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/mock-contract/-/mock-contract-3.2.1.tgz#bf5f63f61c9749eb3270108893a88ff161e68f58" - dependencies: - "@ethersproject/abi" "^5.0.1" - ethers "^5.0.1" - -"@ethereum-waffle/provider@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/provider/-/provider-3.2.1.tgz#d84c0603936f09afa69ecb671d56f527e9818e71" - dependencies: - "@ethereum-waffle/ens" "^3.2.1" - ethers "^5.0.1" - ganache-core "^2.10.2" - patch-package "^6.2.2" - postinstall-postinstall "^2.1.0" - -"@ethereumjs/block@^3.4.0", "@ethereumjs/block@^3.5.0", "@ethereumjs/block@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/block/-/block-3.6.0.tgz#5cf89ea748607597a3f8b038abc986e4ac0b05db" - integrity sha512-dqLo1LtsLG+Oelu5S5tWUDG0pah3QUwV5TJZy2cm19BXDr4ka/S9XBSgao0i09gTcuPlovlHgcs6d7EZ37urjQ== - dependencies: - "@ethereumjs/common" "^2.6.0" - "@ethereumjs/tx" "^3.4.0" - ethereumjs-util "^7.1.3" - merkle-patricia-tree "^4.2.2" - -"@ethereumjs/blockchain@^5.4.0", "@ethereumjs/blockchain@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethereumjs/blockchain/-/blockchain-5.5.1.tgz#60f1f50592c06cc47e1704800b88b7d32f609742" - integrity sha512-JS2jeKxl3tlaa5oXrZ8mGoVBCz6YqsGG350XVNtHAtNZXKk7pU3rH4xzF2ru42fksMMqzFLzKh9l4EQzmNWDqA== - dependencies: - "@ethereumjs/block" "^3.6.0" - "@ethereumjs/common" "^2.6.0" - "@ethereumjs/ethash" "^1.1.0" - debug "^2.2.0" - ethereumjs-util "^7.1.3" - level-mem "^5.0.1" - lru-cache "^5.1.1" - semaphore-async-await "^1.5.1" - -"@ethereumjs/common@^2.4.0", "@ethereumjs/common@^2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.0.tgz#feb96fb154da41ee2cc2c5df667621a440f36348" - integrity sha512-Cq2qS0FTu6O2VU1sgg+WyU9Ps0M6j/BEMHN+hRaECXCV/r0aI78u4N6p52QW/BDVhwWZpCdrvG8X7NJdzlpNUA== - dependencies: - crc-32 "^1.2.0" - ethereumjs-util "^7.1.3" - -"@ethereumjs/ethash@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/ethash/-/ethash-1.1.0.tgz#7c5918ffcaa9cb9c1dc7d12f77ef038c11fb83fb" - integrity sha512-/U7UOKW6BzpA+Vt+kISAoeDie1vAvY4Zy2KF5JJb+So7+1yKmJeJEHOGSnQIj330e9Zyl3L5Nae6VZyh2TJnAA== - dependencies: - "@ethereumjs/block" "^3.5.0" - "@types/levelup" "^4.3.0" - buffer-xor "^2.0.1" - ethereumjs-util "^7.1.1" - miller-rabin "^4.0.0" - -"@ethereumjs/tx@^3.3.0", "@ethereumjs/tx@^3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.4.0.tgz#7eb1947eefa55eb9cf05b3ca116fb7a3dbd0bce7" - integrity sha512-WWUwg1PdjHKZZxPPo274ZuPsJCWV3SqATrEKQP1n2DrVYVP1aZIYpo/mFaA0BDoE0tIQmBeimRCEA0Lgil+yYw== - dependencies: - "@ethereumjs/common" "^2.6.0" - ethereumjs-util "^7.1.3" - -"@ethereumjs/vm@^5.5.2": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/vm/-/vm-5.6.0.tgz#e0ca62af07de820143674c30b776b86c1983a464" - integrity sha512-J2m/OgjjiGdWF2P9bj/4LnZQ1zRoZhY8mRNVw/N3tXliGI8ai1sI1mlDPkLpeUUM4vq54gH6n0ZlSpz8U/qlYQ== - dependencies: - "@ethereumjs/block" "^3.6.0" - "@ethereumjs/blockchain" "^5.5.0" - "@ethereumjs/common" "^2.6.0" - "@ethereumjs/tx" "^3.4.0" - async-eventemitter "^0.2.4" - core-js-pure "^3.0.1" - debug "^2.2.0" - ethereumjs-util "^7.1.3" - functional-red-black-tree "^1.0.1" - mcl-wasm "^0.7.1" - merkle-patricia-tree "^4.2.2" - rustbn.js "~0.2.0" - -"@ethersproject/abi@5.0.0-beta.153": - version "5.0.0-beta.153" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" - dependencies: - "@ethersproject/address" ">=5.0.0-beta.128" - "@ethersproject/bignumber" ">=5.0.0-beta.130" - "@ethersproject/bytes" ">=5.0.0-beta.129" - "@ethersproject/constants" ">=5.0.0-beta.128" - "@ethersproject/hash" ">=5.0.0-beta.128" - "@ethersproject/keccak256" ">=5.0.0-beta.127" - "@ethersproject/logger" ">=5.0.0-beta.129" - "@ethersproject/properties" ">=5.0.0-beta.131" - "@ethersproject/strings" ">=5.0.0-beta.130" - -"@ethersproject/abi@5.0.9", "@ethersproject/abi@^5.0.1", "@ethersproject/abi@^5.0.5": - version "5.0.9" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.9.tgz#738c1c557e56d8f395a5a27caef9b0449bc85a10" - dependencies: - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/abi@^5.1.2": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" - integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/abstract-provider@5.0.7", "@ethersproject/abstract-provider@^5.0.4": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.0.7.tgz#04ee3bfe43323384e7fecf6c774975b8dec4bdc9" - dependencies: - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/networks" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/web" "^5.0.6" - -"@ethersproject/abstract-provider@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" - integrity sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/networks" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/web" "^5.5.0" - -"@ethersproject/abstract-signer@5.0.9", "@ethersproject/abstract-signer@^5.0.4", "@ethersproject/abstract-signer@^5.0.6": - version "5.0.9" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.0.9.tgz#238ddc06031aeb9dfceee2add965292d7dd1acbf" - dependencies: - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - -"@ethersproject/abstract-signer@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" - integrity sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - -"@ethersproject/address@5.0.8", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.0.5": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.8.tgz#0c551659144a5a7643c6bea337149d410825298f" - dependencies: - "@ethersproject/bignumber" "^5.0.10" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/rlp" "^5.0.3" - -"@ethersproject/address@^5.0.2": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.1.0.tgz#3854fd7ebcb6af7597de66f847c3345dae735b58" - integrity sha512-rfWQR12eHn2cpstCFS4RF7oGjfbkZb0oqep+BfrT+gWEGWG2IowJvIsacPOvzyS1jhNF4MQ4BS59B04Mbovteg== - dependencies: - "@ethersproject/bignumber" "^5.1.0" - "@ethersproject/bytes" "^5.1.0" - "@ethersproject/keccak256" "^5.1.0" - "@ethersproject/logger" "^5.1.0" - "@ethersproject/rlp" "^5.1.0" - -"@ethersproject/address@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" - integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - -"@ethersproject/base64@5.0.6", "@ethersproject/base64@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.0.6.tgz#26311ebf29ea3d0b9c300ccf3e1fdc44b7481516" - dependencies: - "@ethersproject/bytes" "^5.0.4" - -"@ethersproject/base64@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090" - integrity sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - -"@ethersproject/basex@5.0.6", "@ethersproject/basex@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.0.6.tgz#ab95c32e48288a3d868726463506641cb1e9fb6b" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/properties" "^5.0.3" - -"@ethersproject/bignumber@5.0.12", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.0.10", "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.0.8": - version "5.0.12" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.12.tgz#fe4a78667d7cb01790f75131147e82d6ea7e7cba" - dependencies: - "@ethersproject/bytes" "^5.0.8" - "@ethersproject/logger" "^5.0.5" - bn.js "^4.4.0" - -"@ethersproject/bignumber@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.1.1.tgz#84812695253ccbc639117f7ac49ee1529b68e637" - integrity sha512-AVz5iqz7+70RIqoQTznsdJ6DOVBYciNlvO+AlQmPTB6ofCvoihI9bQdr6wljsX+d5W7Yc4nyvQvP4JMzg0Agig== - dependencies: - "@ethersproject/bytes" "^5.1.0" - "@ethersproject/logger" "^5.1.0" - bn.js "^4.4.0" - -"@ethersproject/bignumber@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527" - integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - bn.js "^4.11.9" - -"@ethersproject/bytes@5.0.8", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.0.8": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.8.tgz#cf1246a6a386086e590063a4602b1ffb6cc43db1" - dependencies: - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/bytes@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.1.0.tgz#55dfa9c4c21df1b1b538be3accb50fb76d5facfd" - integrity sha512-sGTxb+LVjFxJcJeUswAIK6ncgOrh3D8c192iEJd7mLr95V6du119rRfYT/b87WPkZ5I3gRBUYIYXtdgCWACe8g== - dependencies: - "@ethersproject/logger" "^5.1.0" - -"@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/constants@5.0.7", "@ethersproject/constants@>=5.0.0-beta.128", "@ethersproject/constants@^5.0.4": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.7.tgz#44ff979e5781b17c8c6901266896c3ee745f4e7e" - dependencies: - "@ethersproject/bignumber" "^5.0.7" - -"@ethersproject/constants@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.5.0.tgz#d2a2cd7d94bd1d58377d1d66c4f53c9be4d0a45e" - integrity sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - -"@ethersproject/contracts@5.0.8": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.0.8.tgz#71d3ba16853a1555be2e161a6741df186f81c73b" - dependencies: - "@ethersproject/abi" "^5.0.5" - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - -"@ethersproject/hash@5.0.9", "@ethersproject/hash@>=5.0.0-beta.128", "@ethersproject/hash@^5.0.4": - version "5.0.9" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.0.9.tgz#81252a848185b584aa600db4a1a68cad9229a4d4" - dependencies: - "@ethersproject/abstract-signer" "^5.0.6" - "@ethersproject/address" "^5.0.5" - "@ethersproject/bignumber" "^5.0.8" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.4" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/hash@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" - integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/hdnode@5.0.7", "@ethersproject/hdnode@^5.0.4": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.0.7.tgz#c7bce94a337ea65e37c46bab09a83e1c1a555d99" - dependencies: - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/basex" "^5.0.3" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/pbkdf2" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/sha2" "^5.0.3" - "@ethersproject/signing-key" "^5.0.4" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/wordlists" "^5.0.4" - -"@ethersproject/json-wallets@5.0.9", "@ethersproject/json-wallets@^5.0.6": - version "5.0.9" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.0.9.tgz#2e1708c2854c4ab764e35920bd1f44c948b95434" - dependencies: - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/hdnode" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/pbkdf2" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/random" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@5.0.6", "@ethersproject/keccak256@>=5.0.0-beta.127", "@ethersproject/keccak256@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.0.6.tgz#5b5ba715ef1be86efde5c271f896fa0daf0e1efe" - dependencies: - "@ethersproject/bytes" "^5.0.4" - js-sha3 "0.5.7" - -"@ethersproject/keccak256@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.1.0.tgz#fdcd88fb13bfef4271b225cdd8dec4d315c8e60e" - integrity sha512-vrTB1W6AEYoadww5c9UyVJ2YcSiyIUTNDRccZIgwTmFFoSHwBtcvG1hqy9RzJ1T0bMdATbM9Hfx2mJ6H0i7Hig== - dependencies: - "@ethersproject/bytes" "^5.1.0" - js-sha3 "0.5.7" - -"@ethersproject/keccak256@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492" - integrity sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg== - dependencies: - "@ethersproject/bytes" "^5.5.0" - js-sha3 "0.8.0" - -"@ethersproject/logger@5.0.8", "@ethersproject/logger@>=5.0.0-beta.129", "@ethersproject/logger@^5.0.5": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.8.tgz#135c1903d35c878265f3cbf2b287042c4c20d5d4" - -"@ethersproject/logger@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.1.0.tgz#4cdeeefac029373349d5818f39c31b82cc6d9bbf" - integrity sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw== - -"@ethersproject/logger@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" - integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== - -"@ethersproject/networks@5.0.6", "@ethersproject/networks@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.0.6.tgz#4d6586bbebfde1c027504ebf6dfb783b29c3803a" - dependencies: - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/networks@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.0.tgz#babec47cab892c51f8dd652ce7f2e3e14283981a" - integrity sha512-KWfP3xOnJeF89Uf/FCJdV1a2aDJe5XTN2N52p4fcQ34QhDqQFkgQKZ39VGtiqUgHcLI8DfT0l9azC3KFTunqtA== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/pbkdf2@5.0.6", "@ethersproject/pbkdf2@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.0.6.tgz#105dbfb08cd5fcf33869b42bfdc35a3ebd978cbd" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/sha2" "^5.0.3" - -"@ethersproject/properties@5.0.6", "@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.0.4": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.0.6.tgz#44d82aaa294816fd63333e7def42426cf0e87b3b" - dependencies: - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/properties@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" - integrity sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/providers@5.0.17": - version "5.0.17" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.0.17.tgz#f380e7831149e24e7a1c6c9b5fb1d6dfc729d024" - dependencies: - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/basex" "^5.0.3" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/networks" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/random" "^5.0.3" - "@ethersproject/rlp" "^5.0.3" - "@ethersproject/sha2" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/web" "^5.0.6" - bech32 "1.1.4" - ws "7.2.3" - -"@ethersproject/random@5.0.6", "@ethersproject/random@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.0.6.tgz#9be80a1065f2b8e6f321dccb3ebeb4886cac9ea4" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/rlp@5.0.6", "@ethersproject/rlp@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.0.6.tgz#29f9097348a3c330811997433b7df89ab51cd644" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/rlp@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.1.0.tgz#700f4f071c27fa298d3c1d637485fefe919dd084" - integrity sha512-vDTyHIwNPrecy55gKGZ47eJZhBm8LLBxihzi5ou+zrSvYTpkSTWRcKUlXFDFQVwfWB+P5PGyERAdiDEI76clxw== - dependencies: - "@ethersproject/bytes" "^5.1.0" - "@ethersproject/logger" "^5.1.0" - -"@ethersproject/rlp@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" - integrity sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/sha2@5.0.6", "@ethersproject/sha2@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.0.6.tgz#175116dc10b866a0a381f6316d094bcc510bee3c" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - hash.js "1.1.3" - -"@ethersproject/signing-key@5.0.7", "@ethersproject/signing-key@^5.0.4": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.0.7.tgz#d03bfc5f565efb962bafebf8e6965e70d1c46d31" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - elliptic "6.5.3" - -"@ethersproject/signing-key@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" - integrity sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.7" - -"@ethersproject/solidity@5.0.7": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.0.7.tgz#72a3455f47a454db2dcf363992d42e9045dc7fce" - dependencies: - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/sha2" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/strings@5.0.7", "@ethersproject/strings@>=5.0.0-beta.130", "@ethersproject/strings@^5.0.4": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.0.7.tgz#8dc68f794c9e2901f3b75e53b2afbcb6b6c15037" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/strings@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549" - integrity sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/transactions@5.0.8", "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.0.5": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.0.8.tgz#3b4d7041e13b957a9c4f131e0aea9dae7b6f5a23" - dependencies: - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/rlp" "^5.0.3" - "@ethersproject/signing-key" "^5.0.4" - -"@ethersproject/transactions@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" - integrity sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - -"@ethersproject/units@5.0.8": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.0.8.tgz#563325b20fe1eceff7b61857711d5e2b3f38fd09" - dependencies: - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/wallet@5.0.9": - version "5.0.9" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.0.9.tgz#976c7d950489c40308d676869d24e59ab7b82ad1" - dependencies: - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/hdnode" "^5.0.4" - "@ethersproject/json-wallets" "^5.0.6" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/random" "^5.0.3" - "@ethersproject/signing-key" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/wordlists" "^5.0.4" - -"@ethersproject/web@5.0.11", "@ethersproject/web@^5.0.6": - version "5.0.11" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.0.11.tgz#d47da612b958b4439e415782a53c8f8461522d68" - dependencies: - "@ethersproject/base64" "^5.0.3" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/web@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.0.tgz#0e5bb21a2b58fb4960a705bfc6522a6acf461e28" - integrity sha512-BEgY0eL5oH4mAo37TNYVrFeHsIXLRxggCRG/ksRIxI2X5uj5IsjGmcNiRN/VirQOlBxcUhCgHhaDLG4m6XAVoA== - dependencies: - "@ethersproject/base64" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/wordlists@5.0.7", "@ethersproject/wordlists@^5.0.4": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.0.7.tgz#4e5ad38cfbef746b196a3290c0d41696eb7ab468" - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^26.6.2" - jest-util "^26.6.2" - slash "^3.0.0" - -"@jest/test-result@^26.5.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" - dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - -"@nomiclabs/hardhat-ethers@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.2.tgz#c472abcba0c5185aaa4ad4070146e95213c68511" - integrity sha512-6quxWe8wwS4X5v3Au8q1jOvXYEPkS1Fh+cME5u6AwNdnI4uERvPlVjlgRWzpnb+Rrt1l/cEqiNRH9GlsBMSDQg== - -"@nomiclabs/hardhat-etherscan@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-2.1.8.tgz#e206275e96962cd15e5ba9148b44388bc922d8c2" - integrity sha512-0+rj0SsZotVOcTLyDOxnOc3Gulo8upo0rsw/h+gBPcmtj91YqYJNhdARHoBxOhhE8z+5IUQPx+Dii04lXT14PA== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@ethersproject/address" "^5.0.2" - cbor "^5.0.2" - debug "^4.1.1" - fs-extra "^7.0.1" - node-fetch "^2.6.0" - semver "^6.3.0" - -"@nomiclabs/hardhat-waffle@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.1.tgz#5d43654fba780720c5033dea240fe14f70ef4bd2" - integrity sha512-2YR2V5zTiztSH9n8BYWgtv3Q+EL0N5Ltm1PAr5z20uAY4SkkfylJ98CIqt18XFvxTD5x4K2wKBzddjV9ViDAZQ== - dependencies: - "@types/sinon-chai" "^3.2.3" - "@types/web3" "1.0.19" - -"@openzeppelin/contracts@3.4.2-solc-0.7": - version "3.4.2-solc-0.7" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" - integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== - -"@resolver-engine/core@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.3.3.tgz#590f77d85d45bc7ecc4e06c654f41345db6ca967" - dependencies: - debug "^3.1.0" - is-url "^1.2.4" - request "^2.85.0" - -"@resolver-engine/fs@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@resolver-engine/fs/-/fs-0.3.3.tgz#fbf83fa0c4f60154a82c817d2fe3f3b0c049a973" - dependencies: - "@resolver-engine/core" "^0.3.3" - debug "^3.1.0" - -"@resolver-engine/imports-fs@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@resolver-engine/imports-fs/-/imports-fs-0.3.3.tgz#4085db4b8d3c03feb7a425fbfcf5325c0d1e6c1b" - dependencies: - "@resolver-engine/fs" "^0.3.3" - "@resolver-engine/imports" "^0.3.3" - debug "^3.1.0" - -"@resolver-engine/imports@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@resolver-engine/imports/-/imports-0.3.3.tgz#badfb513bb3ff3c1ee9fd56073e3144245588bcc" - dependencies: - "@resolver-engine/core" "^0.3.3" - debug "^3.1.0" - hosted-git-info "^2.6.0" - path-browserify "^1.0.0" - url "^0.11.0" - -"@sentry/core@5.29.2": - version "5.29.2" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.29.2.tgz#9e05fe197234161d57aabaf52fab336a7c520d81" - dependencies: - "@sentry/hub" "5.29.2" - "@sentry/minimal" "5.29.2" - "@sentry/types" "5.29.2" - "@sentry/utils" "5.29.2" - tslib "^1.9.3" - -"@sentry/hub@5.29.2": - version "5.29.2" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.29.2.tgz#208f10fe6674695575ad74182a1151f71d6df00a" - dependencies: - "@sentry/types" "5.29.2" - "@sentry/utils" "5.29.2" - tslib "^1.9.3" - -"@sentry/minimal@5.29.2": - version "5.29.2" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.29.2.tgz#420bebac8d03d30980fdb05c72d7b253d8aa541b" - dependencies: - "@sentry/hub" "5.29.2" - "@sentry/types" "5.29.2" - tslib "^1.9.3" - -"@sentry/node@^5.18.1": - version "5.29.2" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.29.2.tgz#f0f0b4b2be63c9ddd702729fab998cead271dff1" - dependencies: - "@sentry/core" "5.29.2" - "@sentry/hub" "5.29.2" - "@sentry/tracing" "5.29.2" - "@sentry/types" "5.29.2" - "@sentry/utils" "5.29.2" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" - -"@sentry/tracing@5.29.2": - version "5.29.2" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.29.2.tgz#6012788547d2ab7893799d82c4941bda145dcd47" - dependencies: - "@sentry/hub" "5.29.2" - "@sentry/minimal" "5.29.2" - "@sentry/types" "5.29.2" - "@sentry/utils" "5.29.2" - tslib "^1.9.3" - -"@sentry/types@5.29.2": - version "5.29.2" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.29.2.tgz#ac87383df1222c2d9b9f8f9ed7a6b86ea41a098a" - -"@sentry/utils@5.29.2": - version "5.29.2" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.29.2.tgz#99a5cdda2ea19d34a41932f138d470adcb3ee673" - dependencies: - "@sentry/types" "5.29.2" - tslib "^1.9.3" - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - -"@solidity-parser/parser@^0.12.1": - version "0.12.1" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.12.1.tgz#10ce249890d32ba500e9ce449e60a2b26b11be7a" - integrity sha512-ikxVpwskNxEp2fvYS1BdRImnevHmM97zdPFBa1cVtjtNpoqCm/EmljATTZk0s9G/zsN5ZbPf9OAIAW4gbBJiRA== - -"@solidity-parser/parser@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.0.tgz#d51f074efb0acce0e953ec48133561ed710cebc0" - integrity sha512-cX0JJRcmPtNUJpzD2K7FdA7qQsTOk1UZnFx2k7qAg9ZRvuaH5NBe5IEdBMXGlmf2+FmjhqbygJ26H8l2SV7aKQ== - dependencies: - antlr4ts "^0.5.0-alpha.4" - -"@solidity-parser/parser@^0.8.2": - version "0.8.2" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.8.2.tgz#a6a5e93ac8dca6884a99a532f133beba59b87b69" - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - dependencies: - defer-to-connect "^1.0.1" - -"@typechain/ethers-v5@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-4.0.0.tgz#2a8be5e108d23f3b8e6354d1618fdc2abcb00b07" - -"@types/abstract-leveldown@*": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz#3c7750d0186b954c7f2d2f6acc8c3c7ba0c3412e" - integrity sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ== - -"@types/babel__traverse@^7.0.4": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.11.0.tgz#b9a1efa635201ba9bc850323a8793ee2d36c04a0" - dependencies: - "@babel/types" "^7.3.0" - -"@types/bn.js@*", "@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - dependencies: - "@types/node" "*" - -"@types/bn.js@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" - integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA== - dependencies: - "@types/node" "*" - -"@types/chai@*", "@types/chai@^4.2.6": - version "4.2.14" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.14.tgz#44d2dd0b5de6185089375d976b4ec5caf6861193" - -"@types/graceful-fs@^4.1.2": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/levelup@^4.3.0": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@types/levelup/-/levelup-4.3.1.tgz#7a53b9fd510716e11b2065332790fdf5f9b950b9" - integrity sha512-n//PeTpbHLjMLTIgW5B/g06W/6iuTBHuvUka2nFL9APMSVMNe2r4enADfu3CIE9IyV9E+uquf9OEQQqrDeg24A== - dependencies: - "@types/abstract-leveldown" "*" - "@types/node" "*" - -"@types/lru-cache@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03" - -"@types/mkdirp@^0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" - dependencies: - "@types/node" "*" - -"@types/mocha@^5.2.7": - version "5.2.7" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" - -"@types/node-fetch@^2.5.5": - version "2.5.7" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*": - version "14.14.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.14.tgz#f7fd5f3cc8521301119f63910f0fb965c7d761ae" - -"@types/node@^12.12.6": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - -"@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" - -"@types/pbkdf2@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" - dependencies: - "@types/node" "*" - -"@types/prettier@^2.0.0", "@types/prettier@^2.1.1": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00" - -"@types/resolve@^0.0.8": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" - dependencies: - "@types/node" "*" - -"@types/secp256k1@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.1.tgz#fb3aa61a1848ad97d7425ff9dcba784549fca5a4" - dependencies: - "@types/node" "*" - -"@types/sinon-chai@^3.2.3": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.5.tgz#df21ae57b10757da0b26f512145c065f2ad45c48" - dependencies: - "@types/chai" "*" - "@types/sinon" "*" - -"@types/sinon@*": - version "9.0.10" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.10.tgz#7fb9bcb6794262482859cab66d59132fca18fcf7" - dependencies: - "@types/sinonjs__fake-timers" "*" - -"@types/sinonjs__fake-timers@*": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae" - -"@types/stack-utils@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" - -"@types/underscore@*": - version "1.10.24" - resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.10.24.tgz#dede004deed3b3f99c4db0bdb9ee21cae25befdd" - -"@types/web3@1.0.19": - version "1.0.19" - resolved "https://registry.yarnpkg.com/@types/web3/-/web3-1.0.19.tgz#46b85d91d398ded9ab7c85a5dd57cb33ac558924" - dependencies: - "@types/bn.js" "*" - "@types/underscore" "*" - -"@types/yargs-parser@*": - version "20.2.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" - -"@types/yargs@^15.0.0": - version "15.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.12.tgz#6234ce3e3e3fa32c5db301a170f96a599c960d74" - dependencies: - "@types/yargs-parser" "*" - -"@uniswap/lib@^4.0.1-alpha": - version "4.0.1-alpha" - resolved "https://registry.yarnpkg.com/@uniswap/lib/-/lib-4.0.1-alpha.tgz#2881008e55f075344675b3bca93f020b028fbd02" - integrity sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA== - -"@uniswap/v2-core@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425" - integrity sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q== - -"@uniswap/v3-core@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.1.tgz#b6d2bdc6ba3c3fbd610bdc502395d86cd35264a0" - integrity sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ== - -"@uniswap/v3-periphery@^1.4.4": - version "1.4.4" - resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.4.tgz#d2756c23b69718173c5874f37fd4ad57d2f021b7" - integrity sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw== - dependencies: - "@openzeppelin/contracts" "3.4.2-solc-0.7" - "@uniswap/lib" "^4.0.1-alpha" - "@uniswap/v2-core" "^1.0.1" - "@uniswap/v3-core" "^1.0.0" - base64-sol "1.0.1" - -"@yarnpkg/lockfile@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - dependencies: - event-target-shim "^5.0.0" - -abstract-leveldown@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz#5cb89f958a44f526779d740d1440e743e0c30a57" - dependencies: - xtend "~4.0.0" - -abstract-leveldown@^2.4.1, abstract-leveldown@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" - dependencies: - xtend "~4.0.0" - -abstract-leveldown@^5.0.0, abstract-leveldown@~5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz#f7128e1f86ccabf7d2893077ce5d06d798e386c6" - dependencies: - xtend "~4.0.0" - -abstract-leveldown@^6.2.1: - version "6.3.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" - integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -abstract-leveldown@~2.6.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" - dependencies: - xtend "~4.0.0" - -abstract-leveldown@~6.2.1: - version "6.2.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" - integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -acorn-jsx@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - -acorn@^6.0.7: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - -adm-zip@^0.4.16: - version "0.4.16" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" - -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - -aes-js@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - dependencies: - debug "4" - -ajv@^6.10.2, ajv@^6.12.3, ajv@^6.6.1, ajv@^6.9.1: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-colors@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - -ansi-escapes@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - dependencies: - type-fest "^0.11.0" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - dependencies: - color-convert "^2.0.1" - -antlr4@4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" - -antlr4ts@^0.5.0-alpha.4: - version "0.5.0-alpha.4" - resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" - integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@^3.0.3, anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - -array-back@^1.0.3, array-back@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-1.0.4.tgz#644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b" - dependencies: - typical "^2.6.0" - -array-back@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022" - dependencies: - typical "^2.6.1" - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - -ast-parents@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - -async-eventemitter@^0.2.2, async-eventemitter@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" - dependencies: - async "^2.4.0" - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - -async@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" - dependencies: - lodash "^4.17.11" - -async@^1.4.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - -async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0, async@^2.6.1: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - dependencies: - lodash "^4.17.14" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.0.14, babel-core@^6.26.0: - version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.1" - debug "^2.6.9" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.8" - slash "^1.0.0" - source-map "^0.5.7" - -babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - -babel-plugin-transform-async-to-generator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.23.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-regenerator@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-preset-env@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^3.2.6" - invariant "^2.2.2" - semver "^5.3.0" - -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babelify@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" - dependencies: - babel-core "^6.0.14" - object-assign "^4.0.0" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - -backoff@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" - dependencies: - precond "0.2" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -base-x@^3.0.2, base-x@^3.0.8: - version "3.0.8" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - -base64-sol@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/base64-sol/-/base64-sol-1.0.1.tgz#91317aa341f0bc763811783c5729f1c2574600f6" - integrity sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - dependencies: - tweetnacl "^0.14.3" - -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - -bignumber.js@^9.0.0, bignumber.js@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" - -binary-extensions@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" - -bip39@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.5.0.tgz#51cbd5179460504a63ea3c000db3f787ca051235" - dependencies: - create-hash "^1.1.0" - pbkdf2 "^3.0.9" - randombytes "^2.0.1" - safe-buffer "^5.0.1" - unorm "^1.3.3" - -blakejs@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" - -bluebird@^3.5.0, bluebird@^3.5.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - -bn.js@4.11.6: - version "4.11.6" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.4.0, bn.js@^4.8.0: - version "4.11.9" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" - -bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2: - version "5.1.3" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" - -body-parser@1.19.0, body-parser@^1.16.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - dependencies: - fill-range "^7.0.1" - -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserslist@^3.2.6: - version "3.2.8" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" - dependencies: - caniuse-lite "^1.0.30000844" - electron-to-chromium "^1.3.47" - -bs58@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - dependencies: - base-x "^3.0.2" - -bs58check@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - -buffer-to-arraybuffer@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - -buffer-xor@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-2.0.2.tgz#34f7c64f04c777a1f8aac5e661273bb9dd320289" - dependencies: - safe-buffer "^5.1.1" - -buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -bufferutil@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.2.tgz#79f68631910f6b993d870fc77dc0a2894eb96cd5" - dependencies: - node-gyp-build "^4.2.0" - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - -bytewise-core@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/bytewise-core/-/bytewise-core-1.2.3.tgz#3fb410c7e91558eb1ab22a82834577aa6bd61d42" - dependencies: - typewise-core "^1.2" - -bytewise@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bytewise/-/bytewise-1.1.0.tgz#1d13cbff717ae7158094aa881b35d081b387253e" - dependencies: - bytewise-core "^1.2.2" - typewise "^1.0.3" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -cachedown@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cachedown/-/cachedown-1.0.0.tgz#d43f036e4510696b31246d7db31ebf0f7ac32d15" - dependencies: - abstract-leveldown "^2.4.1" - lru-cache "^3.2.0" - -call-bind@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.0" - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - -caniuse-lite@^1.0.30000844: - version "1.0.30001170" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz#0088bfecc6a14694969e391cc29d7eb6362ca6a7" - -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - dependencies: - rsvp "^4.8.4" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -cbor@^5.0.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c" - integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A== - dependencies: - bignumber.js "^9.0.1" - nofilter "^1.0.4" - -chai@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - pathval "^1.1.0" - type-detect "^4.0.5" - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - -checkpoint-store@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" - dependencies: - functional-red-black-tree "^1.0.1" - -chokidar@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.2.0" - optionalDependencies: - fsevents "~2.1.1" - -chokidar@^3.4.0: - version "3.4.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.1.2" - -chokidar@^3.4.3: - version "3.5.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" - integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.3.1" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - -cids@^0.7.1: - version "0.7.5" - resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" - dependencies: - buffer "^5.5.0" - class-is "^1.1.0" - multibase "~0.6.0" - multicodec "^1.0.0" - multihashes "~0.4.15" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -class-is@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - dependencies: - mimic-response "^1.0.0" - -clone@2.1.2, clone@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - dependencies: - delayed-stream "~1.0.0" - -command-exists@^1.2.8: - version "1.2.9" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" - -command-line-args@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-4.0.7.tgz#f8d1916ecb90e9e121eda6428e41300bfb64cc46" - dependencies: - array-back "^2.0.0" - find-replace "^1.0.3" - typical "^2.6.1" - -commander@2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" - -commander@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -concat-stream@^1.5.1: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - dependencies: - safe-buffer "5.1.2" - -content-hash@^2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" - dependencies: - cids "^0.7.1" - multicodec "^0.5.5" - multihashes "^0.4.15" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - -convert-source-map@^1.5.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - dependencies: - safe-buffer "~5.1.1" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - -cookie@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" - -cookiejar@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - -core-js-pure@^3.0.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.8.1.tgz#23f84048f366fdfcf52d3fd1c68fec349177d119" - -core-js@^2.4.0, core-js@^2.5.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -cors@^2.8.1: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - dependencies: - object-assign "^4" - vary "^1" - -cosmiconfig@^5.0.7: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -crc-32@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" - integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== - dependencies: - exit-on-epipe "~1.0.1" - printj "~1.1.0" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-fetch@^2.1.0, cross-fetch@^2.1.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.3.tgz#e8a0b3c54598136e037f8650f8e823ccdfac198e" - dependencies: - node-fetch "2.1.2" - whatwg-fetch "2.0.4" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -debug@3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - dependencies: - ms "^2.1.1" - -debug@4, debug@^4.0.1, debug@^4.1.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - dependencies: - ms "2.1.2" - -debug@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - dependencies: - ms "^2.1.1" - -decamelize@^1.1.1, decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -decimal.js@^10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - -decompress-response@^3.2.0, decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - dependencies: - mimic-response "^1.0.0" - -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - dependencies: - type-detect "^4.0.0" - -deep-equal@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - -deferred-leveldown@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" - dependencies: - abstract-leveldown "~2.6.0" - -deferred-leveldown@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz#0b0570087827bf480a23494b398f04c128c19a20" - dependencies: - abstract-leveldown "~5.0.0" - inherits "^2.0.3" - -deferred-leveldown@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" - integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== - dependencies: - abstract-leveldown "~6.2.1" - inherits "^2.0.3" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -defined@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" - -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - -diff@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-to-object@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dir-to-object/-/dir-to-object-2.0.0.tgz#29723e9bd1c3e58e4f307bd04ff634c0370c8f8a" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - dependencies: - esutils "^2.0.2" - -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - -dotenv@^14.2.0: - version "14.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.2.0.tgz#7e77fd5dd6cff5942c4496e1acf2d0f37a9e67aa" - integrity sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw== - -dotignore@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" - dependencies: - minimatch "^3.0.4" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - -electron-to-chromium@^1.3.47: - version "1.3.633" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz#16dd5aec9de03894e8d14a1db4cda8a369b9b7fe" - -elliptic@6.5.3, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -elliptic@6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - -encoding-down@5.0.4, encoding-down@~5.0.0: - version "5.0.4" - resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-5.0.4.tgz#1e477da8e9e9d0f7c8293d320044f8b2cd8e9614" - dependencies: - abstract-leveldown "^5.0.0" - inherits "^2.0.3" - level-codec "^9.0.0" - level-errors "^2.0.0" - xtend "^4.0.1" - -encoding-down@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" - integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== - dependencies: - abstract-leveldown "^6.2.1" - inherits "^2.0.3" - level-codec "^9.0.0" - level-errors "^2.0.0" - -encoding@^0.1.11: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - dependencies: - iconv-lite "^0.6.2" - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - dependencies: - once "^1.4.0" - -enquirer@^2.3.0: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - dependencies: - ansi-colors "^4.1.1" - -env-paths@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" - -errno@~0.1.1: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - dependencies: - prr "~1.0.1" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: - version "1.17.7" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.18.0-next.1: - version "1.18.0-next.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - dependencies: - d "^1.0.1" - ext "^1.1.2" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^1.3.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - -eslint@^5.6.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.2.3" - text-table "^0.2.0" - -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - -esquery@^1.0.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - -eth-block-tracker@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz#95cd5e763c7293e0b1b2790a2a39ac2ac188a5e1" - dependencies: - eth-query "^2.1.0" - ethereumjs-tx "^1.3.3" - ethereumjs-util "^5.1.3" - ethjs-util "^0.1.3" - json-rpc-engine "^3.6.0" - pify "^2.3.0" - tape "^4.6.3" - -eth-ens-namehash@2.0.8, eth-ens-namehash@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" - dependencies: - idna-uts46-hx "^2.3.1" - js-sha3 "^0.5.7" - -eth-json-rpc-infura@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.1.tgz#26702a821067862b72d979c016fd611502c6057f" - dependencies: - cross-fetch "^2.1.1" - eth-json-rpc-middleware "^1.5.0" - json-rpc-engine "^3.4.0" - json-rpc-error "^2.0.0" - -eth-json-rpc-middleware@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz#5c9d4c28f745ccb01630f0300ba945f4bef9593f" - dependencies: - async "^2.5.0" - eth-query "^2.1.2" - eth-tx-summary "^3.1.2" - ethereumjs-block "^1.6.0" - ethereumjs-tx "^1.3.3" - ethereumjs-util "^5.1.2" - ethereumjs-vm "^2.1.0" - fetch-ponyfill "^4.0.0" - json-rpc-engine "^3.6.0" - json-rpc-error "^2.0.0" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - tape "^4.6.3" - -eth-lib@0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - xhr-request-promise "^0.1.2" - -eth-lib@^0.1.26: - version "0.1.29" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - nano-json-stream-parser "^0.1.2" - servify "^0.1.12" - ws "^3.0.0" - xhr-request-promise "^0.1.2" - -eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" - dependencies: - json-rpc-random-id "^1.0.0" - xtend "^4.0.1" - -eth-sig-util@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" - dependencies: - ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util "^5.1.1" - -eth-sig-util@^2.0.0, eth-sig-util@^2.5.2: - version "2.5.3" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-2.5.3.tgz#6938308b38226e0b3085435474900b03036abcbe" - dependencies: - buffer "^5.2.1" - elliptic "^6.4.0" - ethereumjs-abi "0.6.5" - ethereumjs-util "^5.1.1" - tweetnacl "^1.0.0" - tweetnacl-util "^0.15.0" - -eth-tx-summary@^3.1.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c" - dependencies: - async "^2.1.2" - clone "^2.0.0" - concat-stream "^1.5.1" - end-of-stream "^1.1.0" - eth-query "^2.0.2" - ethereumjs-block "^1.4.1" - ethereumjs-tx "^1.1.1" - ethereumjs-util "^5.0.1" - ethereumjs-vm "^2.6.0" - through2 "^2.0.3" - -ethashjs@~0.0.7: - version "0.0.8" - resolved "https://registry.yarnpkg.com/ethashjs/-/ethashjs-0.0.8.tgz#227442f1bdee409a548fb04136e24c874f3aa6f9" - dependencies: - async "^2.1.2" - buffer-xor "^2.0.1" - ethereumjs-util "^7.0.2" - miller-rabin "^4.0.0" - -ethereum-bloom-filters@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz#b7b80735e385dbb7f944ce6b4533e24511306060" - dependencies: - js-sha3 "^0.8.0" - -ethereum-common@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" - -ethereum-common@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - -ethereum-cryptography@^0.1.2, ethereum-cryptography@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" - dependencies: - "@types/pbkdf2" "^3.0.0" - "@types/secp256k1" "^4.0.1" - blakejs "^1.1.0" - browserify-aes "^1.2.0" - bs58check "^2.1.2" - create-hash "^1.2.0" - create-hmac "^1.1.7" - hash.js "^1.1.7" - keccak "^3.0.0" - pbkdf2 "^3.0.17" - randombytes "^2.1.0" - safe-buffer "^5.1.2" - scrypt-js "^3.0.0" - secp256k1 "^4.0.1" - setimmediate "^1.0.5" - -ethereum-waffle@^3.0.2: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ethereum-waffle/-/ethereum-waffle-3.2.1.tgz#9d6d6b93484c5e1b77dfdeb646c050ed877e836e" - dependencies: - "@ethereum-waffle/chai" "^3.2.1" - "@ethereum-waffle/compiler" "^3.2.1" - "@ethereum-waffle/mock-contract" "^3.2.1" - "@ethereum-waffle/provider" "^3.2.1" - ethers "^5.0.1" - -ethereumjs-abi@0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz#5a637ef16ab43473fa72a29ad90871405b3f5241" - dependencies: - bn.js "^4.10.0" - ethereumjs-util "^4.3.0" - -ethereumjs-abi@0.6.8, ethereumjs-abi@^0.6.8: - version "0.6.8" - resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": - version "0.6.8" - resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#1ce6a1d64235fabe2aaf827fd606def55693508f" - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-account@3.0.0, ethereumjs-account@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-3.0.0.tgz#728f060c8e0c6e87f1e987f751d3da25422570a9" - dependencies: - ethereumjs-util "^6.0.0" - rlp "^2.2.1" - safe-buffer "^5.1.1" - -ethereumjs-account@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" - dependencies: - ethereumjs-util "^5.0.0" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-block@2.2.2, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.0, ethereumjs-block@~2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" - dependencies: - async "^2.0.1" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0: - version "1.7.1" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" - dependencies: - async "^2.0.1" - ethereum-common "0.2.0" - ethereumjs-tx "^1.2.2" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-blockchain@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.4.tgz#30f2228dc35f6dcf94423692a6902604ae34960f" - dependencies: - async "^2.6.1" - ethashjs "~0.0.7" - ethereumjs-block "~2.2.2" - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.1.0" - flow-stoplight "^1.0.0" - level-mem "^3.0.1" - lru-cache "^5.1.1" - rlp "^2.2.2" - semaphore "^1.1.0" - -ethereumjs-common@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz#d3e82fc7c47c0cef95047f431a99485abc9bb1cd" - -ethereumjs-common@^1.1.0, ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" - -ethereumjs-tx@2.1.2, ethereumjs-tx@^2.1.1, ethereumjs-tx@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - -ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - dependencies: - ethereum-common "^0.0.18" - ethereumjs-util "^5.0.0" - -ethereumjs-util@6.2.1, ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0, ethereumjs-util@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - -ethereumjs-util@^4.3.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.1.tgz#f4bf9b3b515a484e3cc8781d61d9d980f7c83bd0" - dependencies: - bn.js "^4.8.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - rlp "^2.0.0" - -ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.3, ethereumjs-util@^5.1.5, ethereumjs-util@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "^0.1.3" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-util@^7.0.2: - version "7.0.7" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.7.tgz#484fb9c03b766b2ee64821281070616562fb5a59" - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.4" - -ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz#b55d7b64dde3e3e45749e4c41288238edec32d23" - integrity sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - -ethereumjs-vm@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-4.2.0.tgz#e885e861424e373dbc556278f7259ff3fca5edab" - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - core-js-pure "^3.0.1" - ethereumjs-account "^3.0.0" - ethereumjs-block "^2.2.2" - ethereumjs-blockchain "^4.0.3" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.2" - ethereumjs-util "^6.2.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - util.promisify "^1.0.0" - -ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - ethereumjs-account "^2.0.3" - ethereumjs-block "~2.2.0" - ethereumjs-common "^1.1.0" - ethereumjs-util "^6.0.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - -ethereumjs-wallet@0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.5.tgz#685e9091645cee230ad125c007658833991ed474" - dependencies: - aes-js "^3.1.1" - bs58check "^2.1.2" - ethereum-cryptography "^0.1.3" - ethereumjs-util "^6.0.0" - randombytes "^2.0.6" - safe-buffer "^5.1.2" - scryptsy "^1.2.1" - utf8 "^3.0.0" - uuid "^3.3.2" - -ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.8: - version "5.0.24" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.24.tgz#fbb8e4d35070d134f2eb846c07500b8c0eaef6d3" - dependencies: - "@ethersproject/abi" "5.0.9" - "@ethersproject/abstract-provider" "5.0.7" - "@ethersproject/abstract-signer" "5.0.9" - "@ethersproject/address" "5.0.8" - "@ethersproject/base64" "5.0.6" - "@ethersproject/basex" "5.0.6" - "@ethersproject/bignumber" "5.0.12" - "@ethersproject/bytes" "5.0.8" - "@ethersproject/constants" "5.0.7" - "@ethersproject/contracts" "5.0.8" - "@ethersproject/hash" "5.0.9" - "@ethersproject/hdnode" "5.0.7" - "@ethersproject/json-wallets" "5.0.9" - "@ethersproject/keccak256" "5.0.6" - "@ethersproject/logger" "5.0.8" - "@ethersproject/networks" "5.0.6" - "@ethersproject/pbkdf2" "5.0.6" - "@ethersproject/properties" "5.0.6" - "@ethersproject/providers" "5.0.17" - "@ethersproject/random" "5.0.6" - "@ethersproject/rlp" "5.0.6" - "@ethersproject/sha2" "5.0.6" - "@ethersproject/signing-key" "5.0.7" - "@ethersproject/solidity" "5.0.7" - "@ethersproject/strings" "5.0.7" - "@ethersproject/transactions" "5.0.8" - "@ethersproject/units" "5.0.8" - "@ethersproject/wallet" "5.0.9" - "@ethersproject/web" "5.0.11" - "@ethersproject/wordlists" "5.0.7" - -ethjs-unit@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" - dependencies: - bn.js "4.11.6" - number-to-bn "1.7.0" - -ethjs-util@0.1.6, ethjs-util@^0.1.3: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - -eventemitter3@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" - -events@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -exec-sh@^0.3.2: - version "0.3.4" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -exit-on-epipe@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" - integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expect@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" - dependencies: - "@jest/types" "^26.6.2" - ansi-styles "^4.0.0" - jest-get-type "^26.3.0" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - -express@^4.14.0: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - dependencies: - type "^2.0.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fake-merkle-patricia-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" - dependencies: - checkpoint-store "^1.1.0" - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -fast-xml-parser@^3.19.0: - version "3.19.0" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01" - integrity sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg== - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - dependencies: - bser "2.1.1" - -fetch-ponyfill@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" - dependencies: - node-fetch "~1.7.1" - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - dependencies: - flat-cache "^2.0.1" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - dependencies: - to-regex-range "^5.0.1" - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-package-json@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/find-package-json/-/find-package-json-1.2.0.tgz#4057d1b943f82d8445fe52dc9cf456f6b8b58083" - -find-replace@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-1.0.3.tgz#b88e7364d2d9c959559f388c66670d6130441fa0" - dependencies: - array-back "^1.0.4" - test-value "^2.1.0" - -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - dependencies: - locate-path "^3.0.0" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - dependencies: - locate-path "^2.0.0" - -find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-yarn-workspace-root@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db" - dependencies: - fs-extra "^4.0.3" - micromatch "^3.1.4" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flat@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" - dependencies: - is-buffer "~2.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - -flow-stoplight@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" - -follow-redirects@^1.12.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7" - -for-each@~0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - dependencies: - is-callable "^1.1.3" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - -fp-ts@1.19.3: - version "1.19.3" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" - -fp-ts@^1.0.0: - version "1.19.5" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - -fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - -fs-extra@^4.0.2, fs-extra@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^7.0.0, fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - dependencies: - minipass "^2.6.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fsevents@^2.1.2: - version "2.2.1" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.2.1.tgz#1fb02ded2036a8ac288d507a65962bd87b97628d" - -fsevents@~2.1.1, fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - -fsevents@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1, function-bind@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - -functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - -ganache-core@^2.10.2: - version "2.13.1" - resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.13.1.tgz#bf60399a2dd084e1090db91cbbc7ed3885dc01e4" - dependencies: - abstract-leveldown "3.0.0" - async "2.6.2" - bip39 "2.5.0" - cachedown "1.0.0" - clone "2.1.2" - debug "3.2.6" - encoding-down "5.0.4" - eth-sig-util "^2.0.0" - ethereumjs-abi "0.6.8" - ethereumjs-account "3.0.0" - ethereumjs-block "2.2.2" - ethereumjs-common "1.5.0" - ethereumjs-tx "2.1.2" - ethereumjs-util "6.2.1" - ethereumjs-vm "4.2.0" - heap "0.2.6" - keccak "3.0.1" - level-sublevel "6.6.4" - levelup "3.1.1" - lodash "4.17.20" - lru-cache "5.1.1" - merkle-patricia-tree "3.0.0" - patch-package "6.2.2" - seedrandom "3.0.1" - source-map-support "0.5.12" - tmp "0.1.0" - web3-provider-engine "14.2.1" - websocket "1.0.32" - optionalDependencies: - ethereumjs-wallet "0.6.5" - web3 "1.2.11" - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - -get-intrinsic@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49" - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - -get-stream@^4.0.0, get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - dependencies: - pump "^3.0.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - dependencies: - is-glob "^4.0.1" - -glob@7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.2, glob@^7.1.3, glob@~7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - dependencies: - min-document "^2.19.0" - process "^0.11.10" - -globals@^11.7.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -got@9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -got@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -hardhat-typechain@^0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/hardhat-typechain/-/hardhat-typechain-0.3.5.tgz#8e50616a9da348b33bd001168c8fda9c66b7b4af" - integrity sha512-w9lm8sxqTJACY+V7vijiH+NkPExnmtiQEjsV9JKD1KgMdVk2q8y+RhvU/c4B7+7b1+HylRUCxpOIvFuB3rE4+w== - -hardhat-watcher@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/hardhat-watcher/-/hardhat-watcher-2.1.1.tgz#8b05fec429ed45da11808bbf6054a90f3e34c51a" - integrity sha512-zilmvxAYD34IofBrwOliQn4z92UiDmt2c949DW4Gokf0vS0qk4YTfVCi/LmUBICThGygNANE3WfnRTpjCJGtDA== - dependencies: - chokidar "^3.4.3" - -hardhat@^2.6.8: - version "2.6.8" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.6.8.tgz#9ef6f8c16f9044acb95609d15a760b89177b8181" - integrity sha512-iRVd5DgcIVV3rNXMlogOfwlXAhHp7Wy/OjjFiUhTey8Unvo6oq5+Is5ANiKVN+Iw07Pcb/HpkGt7jCB6a4ITgg== - dependencies: - "@ethereumjs/block" "^3.4.0" - "@ethereumjs/blockchain" "^5.4.0" - "@ethereumjs/common" "^2.4.0" - "@ethereumjs/tx" "^3.3.0" - "@ethereumjs/vm" "^5.5.2" - "@ethersproject/abi" "^5.1.2" - "@sentry/node" "^5.18.1" - "@solidity-parser/parser" "^0.14.0" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "^5.1.0" - abort-controller "^3.0.0" - adm-zip "^0.4.16" - ansi-escapes "^4.3.0" - chalk "^2.4.2" - chokidar "^3.4.0" - ci-info "^2.0.0" - debug "^4.1.1" - enquirer "^2.3.0" - env-paths "^2.2.0" - eth-sig-util "^2.5.2" - ethereum-cryptography "^0.1.2" - ethereumjs-abi "^0.6.8" - ethereumjs-util "^7.1.0" - find-up "^2.1.0" - fp-ts "1.19.3" - fs-extra "^7.0.1" - glob "^7.1.3" - https-proxy-agent "^5.0.0" - immutable "^4.0.0-rc.12" - io-ts "1.10.4" - lodash "^4.17.11" - merkle-patricia-tree "^4.2.0" - mnemonist "^0.38.0" - mocha "^7.1.2" - node-fetch "^2.6.0" - qs "^6.7.0" - raw-body "^2.4.1" - resolve "1.17.0" - semver "^6.3.0" - slash "^3.0.0" - solc "0.7.3" - source-map-support "^0.5.13" - stacktrace-parser "^0.1.10" - "true-case-path" "^2.2.1" - tsort "0.0.1" - uuid "^3.3.2" - ws "^7.4.6" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - dependencies: - has-symbol-support-x "^1.4.1" - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.3, has@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - -heap@0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" - -hmac-drbg@^1.0.0, hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - -hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - -http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@1.7.3, http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-https@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - dependencies: - agent-base "6" - debug "4" - -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -idna-uts46-hx@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" - dependencies: - punycode "2.1.0" - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - -immediate@^3.2.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" - -immediate@~3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" - -immutable@^4.0.0-rc.12: - version "4.0.0-rc.12" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-fresh@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -inquirer@^6.2.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - dependencies: - loose-envify "^1.0.0" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - -io-ts@1.10.4: - version "1.10.4" - resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" - dependencies: - fp-ts "^1.0.0" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - dependencies: - kind-of "^6.0.0" - -is-arguments@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" - dependencies: - call-bind "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - dependencies: - binary-extensions "^2.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-buffer@~2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - dependencies: - ci-info "^2.0.0" - -is-core-module@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" - dependencies: - has "^1.0.3" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - -is-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - dependencies: - is-extglob "^2.1.1" - -is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - -is-negative-zero@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - -is-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - dependencies: - isobject "^3.0.1" - -is-regex@^1.0.4, is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" - dependencies: - has-symbols "^1.0.1" - -is-regex@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - dependencies: - has "^1.0.3" - -is-retry-allowed@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - -is-svg@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.3.1.tgz#8c63ec8c67c8c7f0a8de0a71c8c7d58eccf4406b" - integrity sha512-h2CGs+yPUyvkgTJQS9cJzo9lYK06WgRiXUqBBHtglSzVKAuH4/oWsqk7LGfbSa1hGk9QcZ0SyQtVggvBA8LZXA== - dependencies: - fast-xml-parser "^3.19.0" - -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - dependencies: - has-symbols "^1.0.1" - -is-typedarray@^1.0.0, is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -is-url@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -jest-diff@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - -jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" - -jest-matcher-utils@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" - dependencies: - chalk "^4.0.0" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-message-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - pretty-format "^26.6.2" - slash "^3.0.0" - stack-utils "^2.0.2" - -jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - -jest-resolve@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" - dependencies: - "@jest/types" "^26.6.2" - chalk "^4.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.2" - jest-util "^26.6.2" - read-pkg-up "^7.0.1" - resolve "^1.18.1" - slash "^3.0.0" - -jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - -jest-snapshot@^26.5.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.0.0" - chalk "^4.0.0" - expect "^26.6.2" - graceful-fs "^4.2.4" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - jest-haste-map "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - natural-compare "^1.4.0" - pretty-format "^26.6.2" - semver "^7.3.2" - -jest-util@^26.5.2, jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" - -jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - -js-sha3@0.5.7, js-sha3@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - -js-sha3@0.8.0, js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -js-yaml@3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - -json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" - dependencies: - async "^2.0.1" - babel-preset-env "^1.7.0" - babelify "^7.3.0" - json-rpc-error "^2.0.0" - promise-to-callback "^1.0.0" - safe-event-emitter "^1.0.1" - -json-rpc-error@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" - dependencies: - inherits "^2.0.1" - -json-rpc-random-id@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -keccak@3.0.1, keccak@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.1.tgz#ae30a0e94dbe43414f741375cff6d64c8bea0bff" - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - -klaw-sync@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" - dependencies: - graceful-fs "^4.1.11" - -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - optionalDependencies: - graceful-fs "^4.1.9" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - dependencies: - invert-kv "^1.0.0" - -level-codec@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" - dependencies: - buffer "^5.6.0" - -level-codec@~7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" - -level-concat-iterator@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" - integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== - -level-errors@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" - dependencies: - errno "~0.1.1" - -level-errors@^2.0.0, level-errors@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" - dependencies: - errno "~0.1.1" - -level-errors@~1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" - dependencies: - errno "~0.1.1" - -level-iterator-stream@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-2.0.3.tgz#ccfff7c046dcf47955ae9a86f46dfa06a31688b4" - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.5" - xtend "^4.0.0" - -level-iterator-stream@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" - dependencies: - inherits "^2.0.1" - level-errors "^1.0.3" - readable-stream "^1.0.33" - xtend "^4.0.0" - -level-iterator-stream@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-3.0.1.tgz#2c98a4f8820d87cdacab3132506815419077c730" - dependencies: - inherits "^2.0.1" - readable-stream "^2.3.6" - xtend "^4.0.0" - -level-iterator-stream@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" - integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== - dependencies: - inherits "^2.0.4" - readable-stream "^3.4.0" - xtend "^4.0.2" - -level-mem@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-3.0.1.tgz#7ce8cf256eac40f716eb6489654726247f5a89e5" - dependencies: - level-packager "~4.0.0" - memdown "~3.0.0" - -level-mem@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-5.0.1.tgz#c345126b74f5b8aa376dc77d36813a177ef8251d" - integrity sha512-qd+qUJHXsGSFoHTziptAKXoLX87QjR7v2KMbqncDXPxQuCdsQlzmyX+gwrEHhlzn08vkf8TyipYyMmiC6Gobzg== - dependencies: - level-packager "^5.0.3" - memdown "^5.0.0" - -level-packager@^5.0.3: - version "5.1.1" - resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" - integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== - dependencies: - encoding-down "^6.3.0" - levelup "^4.3.2" - -level-packager@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-4.0.1.tgz#7e7d3016af005be0869bc5fa8de93d2a7f56ffe6" - dependencies: - encoding-down "~5.0.0" - levelup "^3.0.0" - -level-post@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/level-post/-/level-post-1.0.7.tgz#19ccca9441a7cc527879a0635000f06d5e8f27d0" - dependencies: - ltgt "^2.1.2" - -level-sublevel@6.6.4: - version "6.6.4" - resolved "https://registry.yarnpkg.com/level-sublevel/-/level-sublevel-6.6.4.tgz#f7844ae893919cd9d69ae19d7159499afd5352ba" - dependencies: - bytewise "~1.1.0" - level-codec "^9.0.0" - level-errors "^2.0.0" - level-iterator-stream "^2.0.3" - ltgt "~2.1.1" - pull-defer "^0.2.2" - pull-level "^2.0.3" - pull-stream "^3.6.8" - typewiselite "~1.0.0" - xtend "~4.0.0" - -level-supports@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" - integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== - dependencies: - xtend "^4.0.2" - -level-ws@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" - dependencies: - readable-stream "~1.0.15" - xtend "~2.1.1" - -level-ws@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-1.0.0.tgz#19a22d2d4ac57b18cc7c6ecc4bd23d899d8f603b" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.8" - xtend "^4.0.1" - -level-ws@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" - integrity sha512-1iv7VXx0G9ec1isqQZ7y5LmoZo/ewAsyDHNA8EFDW5hqH2Kqovm33nSFkSdnLLAK+I5FlT+lo5Cw9itGe+CpQA== - dependencies: - inherits "^2.0.3" - readable-stream "^3.1.0" - xtend "^4.0.1" - -levelup@3.1.1, levelup@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-3.1.1.tgz#c2c0b3be2b4dc316647c53b42e2f559e232d2189" - dependencies: - deferred-leveldown "~4.0.0" - level-errors "~2.0.0" - level-iterator-stream "~3.0.0" - xtend "~4.0.0" - -levelup@^1.2.1: - version "1.3.9" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" - dependencies: - deferred-leveldown "~1.2.1" - level-codec "~7.0.0" - level-errors "~1.0.3" - level-iterator-stream "~1.3.0" - prr "~1.0.1" - semver "~5.4.1" - xtend "~4.0.0" - -levelup@^4.3.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" - integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== - dependencies: - deferred-leveldown "~5.3.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - dependencies: - p-locate "^4.1.0" - -lodash.assign@^4.0.3, lodash.assign@^4.0.6: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - -lodash@4.17.20, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - -log-symbols@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - dependencies: - chalk "^2.0.1" - -log-symbols@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" - dependencies: - chalk "^2.4.2" - -looper@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" - -looper@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/looper/-/looper-3.0.0.tgz#2efa54c3b1cbaba9b94aee2e5914b0be57fbb749" - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - -lru-cache@5.1.1, lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - dependencies: - yallist "^3.0.2" - -lru-cache@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" - dependencies: - pseudomap "^1.0.1" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - dependencies: - yallist "^4.0.0" - -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - -ltgt@^2.1.2, ltgt@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - -ltgt@~2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - dependencies: - tmpl "1.0.x" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - dependencies: - object-visit "^1.0.0" - -mcl-wasm@^0.7.1: - version "0.7.6" - resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.6.tgz#c1789ebda5565d49b77d2ee195ff3e4d282f1554" - integrity sha512-cbRl3sUOkBeRY2hsM4t1EIln2TIdQBkSiTOqNTv/4Hu5KOECnMWCgjIf+a9Ebunyn22VKqkMF3zj6ejRzz7YBw== - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - -memdown@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" - dependencies: - abstract-leveldown "~2.7.1" - functional-red-black-tree "^1.0.1" - immediate "^3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.1.1" - -memdown@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb" - integrity sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw== - dependencies: - abstract-leveldown "~6.2.1" - functional-red-black-tree "~1.0.1" - immediate "~3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.2.0" - -memdown@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-3.0.0.tgz#93aca055d743b20efc37492e9e399784f2958309" - dependencies: - abstract-leveldown "~5.0.0" - functional-red-black-tree "~1.0.1" - immediate "~3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.1.1" - -memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - -merkle-patricia-tree@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-3.0.0.tgz#448d85415565df72febc33ca362b8b614f5a58f8" - dependencies: - async "^2.6.1" - ethereumjs-util "^5.2.0" - level-mem "^3.0.1" - level-ws "^1.0.0" - readable-stream "^3.0.6" - rlp "^2.0.0" - semaphore ">=1.0.1" - -merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" - dependencies: - async "^1.4.2" - ethereumjs-util "^5.0.0" - level-ws "0.0.0" - levelup "^1.2.1" - memdown "^1.0.0" - readable-stream "^2.0.0" - rlp "^2.0.0" - semaphore ">=1.0.1" - -merkle-patricia-tree@^4.2.0, merkle-patricia-tree@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-4.2.2.tgz#6dec17855370172458244c2f42c989dd60b773a3" - integrity sha512-eqZYNTshcYx9aESkSPr71EqwsR/QmpnObDEV4iLxkt/x/IoLYZYjJvKY72voP/27Vy61iMOrfOG6jrn7ttXD+Q== - dependencies: - "@types/levelup" "^4.3.0" - ethereumjs-util "^7.1.2" - level-mem "^5.0.1" - level-ws "^2.0.0" - readable-stream "^3.6.0" - rlp "^2.2.4" - semaphore-async-await "^1.5.1" - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - -micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - -mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - dependencies: - mime-db "1.44.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - dependencies: - dom-walk "^0.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - dependencies: - minipass "^2.9.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - dependencies: - mkdirp "*" - -mkdirp@*: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - -mkdirp@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" - dependencies: - minimist "^1.2.5" - -mkdirp@0.5.5, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - dependencies: - minimist "^1.2.5" - -mnemonist@^0.38.0: - version "0.38.3" - resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.3.tgz#35ec79c1c1f4357cfda2fe264659c2775ccd7d9d" - integrity sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw== - dependencies: - obliterator "^1.6.1" - -mocha-chai-jest-snapshot@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/mocha-chai-jest-snapshot/-/mocha-chai-jest-snapshot-1.1.1.tgz#7e49f20d0c12e6792d7f7da2e4ee0c38950571cc" - dependencies: - "@jest/test-result" "^26.5.2" - chalk "^4.1.0" - find-package-json "^1.2.0" - jest-snapshot "^26.5.2" - jest-util "^26.5.2" - slash "^3.0.0" - yargs "^16.0.3" - -mocha@^6.2.2: - version "6.2.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.3.tgz#e648432181d8b99393410212664450a4c1e31912" - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "2.2.0" - minimatch "3.0.4" - mkdirp "0.5.4" - ms "2.1.1" - node-environment-flags "1.0.5" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" - -mocha@^7.1.2: - version "7.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - chokidar "3.3.0" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "3.0.0" - minimatch "3.0.4" - mkdirp "0.5.5" - ms "2.1.1" - node-environment-flags "1.0.6" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" - -mock-fs@^4.1.0: - version "4.13.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.13.0.tgz#31c02263673ec3789f90eb7b6963676aa407a598" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - -multibase@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multibase@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multicodec@^0.5.5: - version "0.5.7" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" - dependencies: - varint "^5.0.0" - -multicodec@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" - dependencies: - buffer "^5.6.0" - varint "^5.0.0" - -multihashes@^0.4.15, multihashes@~0.4.15: - version "0.4.21" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" - dependencies: - buffer "^5.5.0" - multibase "^0.7.0" - varint "^5.0.0" - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - -nano-json-stream-parser@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - -node-environment-flags@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - -node-environment-flags@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - -node-fetch@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" - -node-fetch@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - -node-fetch@~1.7.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - -node-gyp-build@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - -nofilter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e" - integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA== - -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - -normalize-url@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - dependencies: - path-key "^2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -number-to-bn@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - dependencies: - bn.js "4.11.6" - strip-hex-prefix "1.0.0" - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - -object-assign@^4, object-assign@^4.0.0, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.8.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" - -object-inspect@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" - -object-is@^1.0.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.4.tgz#63d6c83c00a43f4cbc9434eb9757c8a5b8565068" - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - dependencies: - isobject "^3.0.0" - -object.assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.assign@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz#0dfda8d108074d9c563e80490c883b6661091544" - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - dependencies: - isobject "^3.0.1" - -obliterator@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3" - integrity sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig== - -oboe@2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" - dependencies: - http-https "^1.0.0" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - dependencies: - ee-first "1.1.1" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - dependencies: - mimic-fn "^1.0.0" - -optionator@^0.8.2: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - dependencies: - lcid "^1.0.0" - -os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - dependencies: - p-try "^2.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - dependencies: - p-limit "^2.2.0" - -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-headers@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646" - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - -patch-package@6.2.2, patch-package@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.2.2.tgz#71d170d650c65c26556f0d0fbbb48d92b6cc5f39" - dependencies: - "@yarnpkg/lockfile" "^1.1.0" - chalk "^2.4.2" - cross-spawn "^6.0.5" - find-yarn-workspace-root "^1.2.1" - fs-extra "^7.0.1" - is-ci "^2.0.0" - klaw-sync "^6.0.0" - minimist "^1.2.0" - rimraf "^2.6.3" - semver "^5.6.0" - slash "^2.0.0" - tmp "^0.0.33" - -path-browserify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -pathval@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - -pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - -postinstall-postinstall@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" - -precond@0.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - dependencies: - fast-diff "^1.1.2" - -prettier-plugin-solidity@^1.0.0-beta.10: - version "1.0.0-beta.10" - resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.10.tgz#f2a249002733826b08d981b599335ddb7e93af8d" - integrity sha512-55UsEbeJfqYKB3RFR7Nvpi+ApEoUfgdKHVg2ZybrbOkRW4RTblyONLL3mEr8Vrxpo7wBbObVLbWodGg4YXIQ7g== - dependencies: - "@solidity-parser/parser" "^0.12.1" - dir-to-object "^2.0.0" - emoji-regex "^9.2.2" - escape-string-regexp "^4.0.0" - prettier "^2.2.1" - semver "^7.3.5" - solidity-comments-extractor "^0.0.7" - string-width "^4.2.2" - -prettier@^1.14.3: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - -prettier@^2.0.5, prettier@^2.1.2, prettier@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" - -pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -printj@~1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" - integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== - -private@^0.1.6, private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - -promise-to-callback@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" - dependencies: - is-fn "^1.0.0" - set-immediate-shim "^1.0.1" - -proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.9.1" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - -pseudomap@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pull-cat@^1.1.9: - version "1.1.11" - resolved "https://registry.yarnpkg.com/pull-cat/-/pull-cat-1.1.11.tgz#b642dd1255da376a706b6db4fa962f5fdb74c31b" - -pull-defer@^0.2.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/pull-defer/-/pull-defer-0.2.3.tgz#4ee09c6d9e227bede9938db80391c3dac489d113" - -pull-level@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pull-level/-/pull-level-2.0.4.tgz#4822e61757c10bdcc7cf4a03af04c92734c9afac" - dependencies: - level-post "^1.0.7" - pull-cat "^1.1.9" - pull-live "^1.0.1" - pull-pushable "^2.0.0" - pull-stream "^3.4.0" - pull-window "^2.1.4" - stream-to-pull-stream "^1.7.1" - -pull-live@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pull-live/-/pull-live-1.0.1.tgz#a4ecee01e330155e9124bbbcf4761f21b38f51f5" - dependencies: - pull-cat "^1.1.9" - pull-stream "^3.4.0" - -pull-pushable@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/pull-pushable/-/pull-pushable-2.2.0.tgz#5f2f3aed47ad86919f01b12a2e99d6f1bd776581" - -pull-stream@^3.2.3, pull-stream@^3.4.0, pull-stream@^3.6.8: - version "3.6.14" - resolved "https://registry.yarnpkg.com/pull-stream/-/pull-stream-3.6.14.tgz#529dbd5b86131f4a5ed636fdf7f6af00781357ee" - -pull-window@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/pull-window/-/pull-window-2.1.4.tgz#fc3b86feebd1920c7ae297691e23f705f88552f0" - dependencies: - looper "^2.0.0" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - -punycode@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - -qs@^6.7.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -raw-body@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" - dependencies: - bytes "3.1.0" - http-errors "1.7.3" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-is@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -readable-stream@^1.0.33: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.6, readable-stream@^3.1.0, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~1.0.15: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readdirp@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" - dependencies: - picomatch "^2.0.4" - -readdirp@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" - dependencies: - picomatch "^2.2.1" - -regenerate@^1.2.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexp.prototype.flags@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -request@^2.79.0, request@^2.85.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - -require-from-string@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" - -require-from-string@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - -resolve@1.17.0, resolve@~1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - dependencies: - path-parse "^1.0.6" - -resolve@^1.10.0, resolve@^1.18.1, resolve@^1.8.1: - version "1.19.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" - dependencies: - is-core-module "^2.1.0" - path-parse "^1.0.6" - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - dependencies: - lowercase-keys "^1.0.0" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -resumer@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" - dependencies: - through "~2.3.4" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - dependencies: - glob "^7.1.3" - -rimraf@^2.2.8, rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3, rlp@^2.2.4: - version "2.2.6" - resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.6.tgz#c80ba6266ac7a483ef1e69e8e2f056656de2fb2c" - dependencies: - bn.js "^4.11.1" - -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - -rustbn.js@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - -rxjs@^6.4.0: - version "6.6.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" - dependencies: - tslib "^1.9.0" - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - -safe-event-emitter@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" - dependencies: - events "^3.0.0" - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - -scryptsy@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" - dependencies: - pbkdf2 "^3.0.3" - -secp256k1@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.2.tgz#15dd57d0f0b9fdb54ac1fa1694f40e5e9a54f4a1" - dependencies: - elliptic "^6.5.2" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -seedrandom@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.1.tgz#eb3dde015bcf55df05a233514e5df44ef9dce083" - -semaphore-async-await@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz#857bef5e3644601ca4b9570b87e9df5ca12974fa" - integrity sha1-hXvvXjZEYBykuVcLh+nfXKEpdPo= - -semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - -semver@^7.3.2: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - dependencies: - lru-cache "^6.0.0" - -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -semver@~5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -servify@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" - dependencies: - body-parser "^1.16.0" - cors "^2.8.1" - express "^4.14.0" - request "^2.79.0" - xhr "^2.3.3" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - -simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - -simple-get@^2.7.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" - dependencies: - decompress-response "^3.3.0" - once "^1.3.1" - simple-concat "^1.0.0" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -solc@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" - dependencies: - command-exists "^1.2.8" - commander "3.0.2" - follow-redirects "^1.12.1" - fs-extra "^0.30.0" - js-sha3 "0.8.0" - memorystream "^0.3.1" - require-from-string "^2.0.0" - semver "^5.5.0" - tmp "0.0.33" - -solc@^0.4.20: - version "0.4.26" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.26.tgz#5390a62a99f40806b86258c737c1cf653cc35cb5" - dependencies: - fs-extra "^0.30.0" - memorystream "^0.3.1" - require-from-string "^1.1.0" - semver "^5.3.0" - yargs "^4.7.1" - -solc@^0.6.3: - version "0.6.12" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.6.12.tgz#48ac854e0c729361b22a7483645077f58cba080e" - dependencies: - command-exists "^1.2.8" - commander "3.0.2" - fs-extra "^0.30.0" - js-sha3 "0.8.0" - memorystream "^0.3.1" - require-from-string "^2.0.0" - semver "^5.5.0" - tmp "0.0.33" - -solhint-plugin-prettier@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz#e3b22800ba435cd640a9eca805a7f8bc3e3e6a6b" - dependencies: - prettier-linter-helpers "^1.0.0" - -solhint@^3.2.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.3.2.tgz#ebd7270bb50fd378b427d7a6fc9f2a7fd00216c0" - dependencies: - "@solidity-parser/parser" "^0.8.2" - ajv "^6.6.1" - antlr4 "4.7.1" - ast-parents "0.0.1" - chalk "^2.4.2" - commander "2.18.0" - cosmiconfig "^5.0.7" - eslint "^5.6.0" - fast-diff "^1.1.2" - glob "^7.1.3" - ignore "^4.0.6" - js-yaml "^3.12.0" - lodash "^4.17.11" - semver "^6.3.0" - optionalDependencies: - prettier "^1.14.3" - -solidity-comments-extractor@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" - integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@0.5.12: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - dependencies: - source-map "^0.5.6" - -source-map-support@^0.5.13, source-map-support@^0.5.17: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - -source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.7" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stack-utils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277" - dependencies: - escape-string-regexp "^2.0.0" - -stacktrace-parser@^0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" - dependencies: - type-fest "^0.7.1" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - -stream-to-pull-stream@^1.7.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz#4161aa2d2eb9964de60bfa1af7feaf917e874ece" - dependencies: - looper "^3.0.0" - pull-stream "^3.2.3" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string-width@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.trim@~1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.3.tgz#d23a22fde01c1e6571a7fadcb9be11decd8061a7" - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - -string.prototype.trimend@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - dependencies: - ansi-regex "^5.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - -strip-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - dependencies: - is-hex-prefixed "1.0.0" - -strip-json-comments@2.0.1, strip-json-comments@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -supports-color@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" - dependencies: - has-flag "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - dependencies: - has-flag "^4.0.0" - -swarm-js@^0.1.40: - version "0.1.40" - resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" - dependencies: - bluebird "^3.5.0" - buffer "^5.0.5" - eth-lib "^0.1.26" - fs-extra "^4.0.2" - got "^7.1.0" - mime-types "^2.1.16" - mkdirp-promise "^5.0.1" - mock-fs "^4.1.0" - setimmediate "^1.0.5" - tar "^4.0.2" - xhr-request "^1.0.1" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -tape@^4.6.3: - version "4.13.3" - resolved "https://registry.yarnpkg.com/tape/-/tape-4.13.3.tgz#51b3d91c83668c7a45b1a594b607dee0a0b46278" - dependencies: - deep-equal "~1.1.1" - defined "~1.0.0" - dotignore "~0.1.2" - for-each "~0.3.3" - function-bind "~1.1.1" - glob "~7.1.6" - has "~1.0.3" - inherits "~2.0.4" - is-regex "~1.0.5" - minimist "~1.2.5" - object-inspect "~1.7.0" - resolve "~1.17.0" - resumer "~0.0.0" - string.prototype.trim "~1.2.1" - through "~2.3.8" - -tar@^4.0.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - -test-value@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/test-value/-/test-value-2.1.0.tgz#11da6ff670f3471a73b625ca4f3fdcf7bb748291" - dependencies: - array-back "^1.0.3" - typical "^2.6.0" - -testrpc@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/testrpc/-/testrpc-0.0.1.tgz#83e2195b1f5873aec7be1af8cbe6dcf39edb7aed" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - -through2@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@^2.3.6, through@~2.3.4, through@~2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - -tmp@0.0.33, tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - dependencies: - os-tmpdir "~1.0.2" - -tmp@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" - dependencies: - rimraf "^2.6.3" - -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - dependencies: - kind-of "^3.0.2" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - -"true-case-path@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-2.2.1.tgz#c5bf04a5bbec3fd118be4084461b3a27c4d796bf" - -ts-essentials@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a" - -ts-essentials@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.1.tgz#d205508cae0cdadfb73c89503140cf2228389e2d" - -ts-generator@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ts-generator/-/ts-generator-0.1.1.tgz#af46f2fb88a6db1f9785977e9590e7bcd79220ab" - dependencies: - "@types/mkdirp" "^0.5.2" - "@types/prettier" "^2.1.1" - "@types/resolve" "^0.0.8" - chalk "^2.4.1" - glob "^7.1.2" - mkdirp "^0.5.1" - prettier "^2.1.2" - resolve "^1.8.1" - ts-essentials "^1.0.0" - -ts-node@^8.5.4: - version "8.10.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" - dependencies: - arg "^4.1.0" - diff "^4.0.1" - make-error "^1.1.1" - source-map-support "^0.5.17" - yn "3.1.1" - -tslib@^1.9.0, tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - -tsort@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl-util@^0.15.0: - version "0.15.1" - resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -tweetnacl@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - -type-fest@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - -type@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f" - -typechain@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-4.0.1.tgz#b40eaf5ede15588d97a4b9a5f85120f7ea1cf262" - dependencies: - command-line-args "^4.0.7" - debug "^4.1.1" - fs-extra "^7.0.0" - js-sha3 "^0.8.0" - lodash "^4.17.15" - ts-essentials "^7.0.1" - ts-generator "^0.1.1" - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - dependencies: - is-typedarray "^1.0.0" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - -typescript@^3.7.3: - version "3.9.7" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" - -typewise-core@^1.2, typewise-core@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/typewise-core/-/typewise-core-1.2.0.tgz#97eb91805c7f55d2f941748fa50d315d991ef195" - -typewise@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/typewise/-/typewise-1.0.3.tgz#1067936540af97937cc5dcf9922486e9fa284651" - dependencies: - typewise-core "^1.2.0" - -typewiselite@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typewiselite/-/typewiselite-1.0.0.tgz#c8882fa1bb1092c06005a97f34ef5c8508e3664e" - -typical@^2.6.0, typical@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" - -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - -underscore@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - -unorm@^1.3.3: - version "1.6.0" - resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -uri-js@^4.2.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - dependencies: - prepend-http "^1.0.1" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - dependencies: - prepend-http "^2.0.0" - -url-set-query@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" - -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - -utf-8-validate@^5.0.2: - version "5.0.3" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.3.tgz#3b64e418ad2ff829809025fdfef595eab2f03a27" - dependencies: - node-gyp-build "^4.2.0" - -utf8@3.0.0, utf8@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -util.promisify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -varint@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - dependencies: - makeerror "1.0.x" - -web3-bzz@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.11.tgz#41bc19a77444bd5365744596d778b811880f707f" - dependencies: - "@types/node" "^12.12.6" - got "9.6.0" - swarm-js "^0.1.40" - underscore "1.9.1" - -web3-core-helpers@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.11.tgz#84c681ed0b942c0203f3b324a245a127e8c67a99" - dependencies: - underscore "1.9.1" - web3-eth-iban "1.2.11" - web3-utils "1.2.11" - -web3-core-method@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.11.tgz#f880137d1507a0124912bf052534f168b8d8fbb6" - dependencies: - "@ethersproject/transactions" "^5.0.0-beta.135" - underscore "1.9.1" - web3-core-helpers "1.2.11" - web3-core-promievent "1.2.11" - web3-core-subscriptions "1.2.11" - web3-utils "1.2.11" - -web3-core-promievent@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.11.tgz#51fe97ca0ddec2f99bf8c3306a7a8e4b094ea3cf" - dependencies: - eventemitter3 "4.0.4" - -web3-core-requestmanager@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.11.tgz#fe6eb603fbaee18530293a91f8cf26d8ae28c45a" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.11" - web3-providers-http "1.2.11" - web3-providers-ipc "1.2.11" - web3-providers-ws "1.2.11" - -web3-core-subscriptions@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.11.tgz#beca908fbfcb050c16f45f3f0f4c205e8505accd" - dependencies: - eventemitter3 "4.0.4" - underscore "1.9.1" - web3-core-helpers "1.2.11" - -web3-core@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.11.tgz#1043cacc1becb80638453cc5b2a14be9050288a7" - dependencies: - "@types/bn.js" "^4.11.5" - "@types/node" "^12.12.6" - bignumber.js "^9.0.0" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-core-requestmanager "1.2.11" - web3-utils "1.2.11" - -web3-eth-abi@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.11.tgz#a887494e5d447c2926d557a3834edd66e17af9b0" - dependencies: - "@ethersproject/abi" "5.0.0-beta.153" - underscore "1.9.1" - web3-utils "1.2.11" - -web3-eth-accounts@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.11.tgz#a9e3044da442d31903a7ce035a86d8fa33f90520" - dependencies: - crypto-browserify "3.12.0" - eth-lib "0.2.8" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" - scrypt-js "^3.0.1" - underscore "1.9.1" - uuid "3.3.2" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-utils "1.2.11" - -web3-eth-contract@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.11.tgz#917065902bc27ce89da9a1da26e62ef663663b90" - dependencies: - "@types/bn.js" "^4.11.5" - underscore "1.9.1" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-core-promievent "1.2.11" - web3-core-subscriptions "1.2.11" - web3-eth-abi "1.2.11" - web3-utils "1.2.11" - -web3-eth-ens@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.11.tgz#26d4d7f16d6cbcfff918e39832b939edc3162532" - dependencies: - content-hash "^2.5.2" - eth-ens-namehash "2.0.8" - underscore "1.9.1" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-promievent "1.2.11" - web3-eth-abi "1.2.11" - web3-eth-contract "1.2.11" - web3-utils "1.2.11" - -web3-eth-iban@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.11.tgz#f5f73298305bc7392e2f188bf38a7362b42144ef" - dependencies: - bn.js "^4.11.9" - web3-utils "1.2.11" - -web3-eth-personal@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.11.tgz#a38b3942a1d87a62070ce0622a941553c3d5aa70" - dependencies: - "@types/node" "^12.12.6" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-net "1.2.11" - web3-utils "1.2.11" - -web3-eth@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.11.tgz#4c81fcb6285b8caf544058fba3ae802968fdc793" - dependencies: - underscore "1.9.1" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-core-subscriptions "1.2.11" - web3-eth-abi "1.2.11" - web3-eth-accounts "1.2.11" - web3-eth-contract "1.2.11" - web3-eth-ens "1.2.11" - web3-eth-iban "1.2.11" - web3-eth-personal "1.2.11" - web3-net "1.2.11" - web3-utils "1.2.11" - -web3-net@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.11.tgz#eda68ef25e5cdb64c96c39085cdb74669aabbe1b" - dependencies: - web3-core "1.2.11" - web3-core-method "1.2.11" - web3-utils "1.2.11" - -web3-provider-engine@14.2.1: - version "14.2.1" - resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.2.1.tgz#ef351578797bf170e08d529cb5b02f8751329b95" - dependencies: - async "^2.5.0" - backoff "^2.5.0" - clone "^2.0.0" - cross-fetch "^2.1.0" - eth-block-tracker "^3.0.0" - eth-json-rpc-infura "^3.1.0" - eth-sig-util "^1.4.2" - ethereumjs-block "^1.2.2" - ethereumjs-tx "^1.2.0" - ethereumjs-util "^5.1.5" - ethereumjs-vm "^2.3.4" - json-rpc-error "^2.0.0" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - readable-stream "^2.2.9" - request "^2.85.0" - semaphore "^1.0.3" - ws "^5.1.1" - xhr "^2.2.0" - xtend "^4.0.1" - -web3-providers-http@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.11.tgz#1cd03442c61670572d40e4dcdf1faff8bd91e7c6" - dependencies: - web3-core-helpers "1.2.11" - xhr2-cookies "1.1.0" - -web3-providers-ipc@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.11.tgz#d16d6c9be1be6e0b4f4536c4acc16b0f4f27ef21" - dependencies: - oboe "2.1.4" - underscore "1.9.1" - web3-core-helpers "1.2.11" - -web3-providers-ws@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.11.tgz#a1dfd6d9778d840561d9ec13dd453046451a96bb" - dependencies: - eventemitter3 "4.0.4" - underscore "1.9.1" - web3-core-helpers "1.2.11" - websocket "^1.0.31" - -web3-shh@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.11.tgz#f5d086f9621c9a47e98d438010385b5f059fd88f" - dependencies: - web3-core "1.2.11" - web3-core-method "1.2.11" - web3-core-subscriptions "1.2.11" - web3-net "1.2.11" - -web3-utils@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.11.tgz#af1942aead3fb166ae851a985bed8ef2c2d95a82" - dependencies: - bn.js "^4.11.9" - eth-lib "0.2.8" - ethereum-bloom-filters "^1.0.6" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - underscore "1.9.1" - utf8 "3.0.0" - -web3-utils@^1.0.0-beta.31: - version "1.3.1" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.3.1.tgz#9aa880dd8c9463fe5c099107889f86a085370c2e" - dependencies: - bn.js "^4.11.9" - eth-lib "0.2.8" - ethereum-bloom-filters "^1.0.6" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - underscore "1.9.1" - utf8 "3.0.0" - -web3@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.11.tgz#50f458b2e8b11aa37302071c170ed61cff332975" - dependencies: - web3-bzz "1.2.11" - web3-core "1.2.11" - web3-eth "1.2.11" - web3-eth-personal "1.2.11" - web3-net "1.2.11" - web3-shh "1.2.11" - web3-utils "1.2.11" - -websocket@1.0.32: - version "1.0.32" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.32.tgz#1f16ddab3a21a2d929dec1687ab21cfdc6d3dbb1" - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - -websocket@^1.0.31: - version "1.0.33" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.33.tgz#407f763fc58e74a3fa41ca3ae5d78d3f5e3b82a5" - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - -whatwg-fetch@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - -which@1.3.1, which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - dependencies: - isexe "^2.0.0" - -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - dependencies: - string-width "^1.0.2 || 2" - -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - dependencies: - mkdirp "^0.5.1" - -ws@7.2.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" - -ws@^3.0.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - -ws@^5.1.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" - dependencies: - async-limiter "~1.0.0" - -ws@^7.4.6: - version "7.5.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" - integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== - -xhr-request-promise@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" - dependencies: - xhr-request "^1.1.0" - -xhr-request@^1.0.1, xhr-request@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" - dependencies: - buffer-to-arraybuffer "^0.0.5" - object-assign "^4.1.1" - query-string "^5.0.1" - simple-get "^2.7.0" - timed-out "^4.0.1" - url-set-query "^1.0.0" - xhr "^2.0.4" - -xhr2-cookies@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" - dependencies: - cookiejar "^2.1.1" - -xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" - dependencies: - global "~4.4.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - dependencies: - object-keys "~0.4.0" - -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - -y18n@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" - -y18n@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" - -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - -yargs-parser@13.1.2, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.0.6" - -yargs-parser@^20.2.2: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - -yargs-unparser@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" - dependencies: - flat "^4.1.0" - lodash "^4.17.15" - yargs "^13.3.0" - -yargs@13.3.2, yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^16.0.3: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@^4.7.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" - dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - lodash.assign "^4.0.3" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.1" - which-module "^1.0.0" - window-size "^0.2.0" - y18n "^3.2.1" - yargs-parser "^2.4.1" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" diff --git a/remappings.txt b/remappings.txt index dc7d2c1..6fdbafd 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,3 +1 @@ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ -@uniswap/v3-periphery/contracts/=lib/v3-periphery/contracts -@uniswap/v3-core/contracts/=lib/v3-core/contracts diff --git a/src/Constants.sol b/src/Constants.sol index 0b65467..58237ff 100644 --- a/src/Constants.sol +++ b/src/Constants.sol @@ -6,5 +6,5 @@ contract Constants { address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8; address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926; address public constant WETH = 0x4200000000000000000000000000000000000006; - address public constant SWAP_ROUTER = 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD; + address public constant SWAP_ROUTER = 0x2626664c2603336E57B271c5C0b26F421741e481; } diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 802da7c..01c1869 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -3,14 +3,12 @@ pragma solidity ^0.8.13; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; -import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol'; -import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol'; + import {RaidGeldUtils} from "../src/RaidGeldUtils.sol"; import {Army, Player, Raider} from "../src/RaidGeldStructs.sol"; import "../src/Constants.sol"; contract RaidGeld is ERC20, Ownable, Constants { - uint256 public constant MANTISSA = 1e4; uint256 public constant BUY_IN_AMOUNT = 0.0005 ether; uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT; @@ -19,13 +17,13 @@ contract RaidGeld is ERC20, Ownable, Constants { mapping(address => Army) private armies; // WETH - IERC20 public immutable weth = IERC20(WETH); + IWETH public immutable weth = IWETH(WETH); // RGCVII token ERC20 public daoToken; // RGCVII pool address public pool; // Uniswap - ISwapRouter private constant router = ISwapRouter(SWAP_ROUTER); + ISwapRouter02 private constant router = ISwapRouter02(SWAP_ROUTER); // Modifier for functions that should only be available to registered players modifier onlyPlayer() { @@ -33,6 +31,7 @@ contract RaidGeld is ERC20, Ownable, Constants { _; } // Modifier for functions that should only be available to non initialized players + modifier newPlayer() { require(players[msg.sender].created_at == 0, "Whoops, player already exists :)"); _; @@ -61,14 +60,14 @@ contract RaidGeld is ERC20, Ownable, Constants { // New player want to register with ETH function register_eth() external payable newPlayer { - require(weth.transferFrom(msg.sender, address(this), BUY_IN_AMOUNT), "Make sure to send exactly 0.0005 eth"); - TransferHelper.safeApprove(WETH, address(router), BUY_IN_AMOUNT); - ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({ + require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount"); + weth.deposit{value: BUY_IN_AMOUNT}(); + weth.approve(address(router), BUY_IN_AMOUNT); + ISwapRouter02.ExactInputSingleParams memory params = ISwapRouter02.ExactInputSingleParams({ tokenIn: WETH, tokenOut: DAO_TOKEN, fee: 10000, recipient: address(this), - deadline: block.timestamp, amountIn: BUY_IN_AMOUNT, amountOutMinimum: 0, sqrtPriceLimitX96: 0 @@ -82,8 +81,7 @@ contract RaidGeld is ERC20, Ownable, Constants { //@notice this is not safe for arbitrary tokens, which may not follow the interface eg. USDT //@notice but should be fine for the DAO token require( - daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), - "Failed to transfer DAO tokens" + daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), "Failed to transfer DAO tokens" ); // Init player init_player(msg.sender); @@ -94,13 +92,8 @@ contract RaidGeld is ERC20, Ownable, Constants { return 4; } - // Allows the owner to withdraw - function withdraw() external onlyOwner { - payable(owner()).transfer(address(this).balance); - } - // Allows the owner to withdraw DAO tokens - function withdraw_dao() external onlyOwner { + function withdraw() external onlyOwner { uint256 amount = daoToken.balanceOf(address(this)); daoToken.approve(address(this), amount); daoToken.transferFrom(address(this), owner(), amount); @@ -200,3 +193,40 @@ contract RaidGeld is ERC20, Ownable, Constants { revert("No fallback calls accepted"); } } + +interface ISwapRouter02 { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + function exactInputSingle(ExactInputSingleParams calldata params) + external + payable + returns (uint256 amountOut); + + struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } + + function exactOutputSingle(ExactOutputSingleParams calldata params) + external + payable + returns (uint256 amountIn); +} + +interface IWETH is IERC20 { + function deposit() external payable; + function withdraw(uint256 amount) external; +} diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 8084e7c..c0b2a4b 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -6,10 +6,8 @@ import {stdStorage, StdStorage} from "forge-std/Test.sol"; import {RaidGeld, Army, Player} from "../src/RaidGeld.sol"; import "../src/RaidGeldUtils.sol"; import {Constants} from "../src/Constants.sol"; -import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; contract raid_geldTest is Test, Constants { - using stdStorage for StdStorage; RaidGeld public raid_geld; @@ -24,24 +22,16 @@ contract raid_geldTest is Test, Constants { fundAccount(player1); vm.prank(owner); raid_geld = new RaidGeld(DAO_TOKEN, POOL); - raid_geld.weth().deposit{ value: 5 ether }(); + raid_geld.weth().deposit{value: 5 ether}(); } function fundAccount(address _acc) private { vm.deal(_acc, 10 ether); stdstore.target(DAO_TOKEN).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether); - stdstore.target(WETH).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether); - } - - function getPoolLiquidity() public view { - IUniswapV3Pool pool = IUniswapV3Pool(POOL); - console.log(pool.liquidity()); } function registerPlayer() private { - getPoolLiquidity(); - raid_geld.weth().approve(address(raid_geld), raid_geld.BUY_IN_AMOUNT()); - raid_geld.register_eth(); + raid_geld.register_eth{value: raid_geld.BUY_IN_AMOUNT()}(); } function registerPlayerWithDaoToken() private { @@ -64,7 +54,8 @@ contract raid_geldTest is Test, Constants { function test_02_1_registrationWithEth() public { vm.startPrank(player1); - uint256 initialBalance = address(raid_geld).balance; + uint256 contractBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); + uint256 userBalance = address(player1).balance; // Send registration fee ETH to the contract registerPlayer(); @@ -73,7 +64,13 @@ contract raid_geldTest is Test, Constants { assertEq(raid_geld.balanceOf(player1), raid_geld.INITIAL_GELD()); // Verify the contract balance is updated - assertEq(address(raid_geld).balance, initialBalance + raid_geld.BUY_IN_AMOUNT()); + uint256 contractBalance2 = raid_geld.daoToken().balanceOf(address(raid_geld)); + uint256 userBalance2 = address(player1).balance; + + // Contract should get DAO tokens + assertLt(contractBalance, contractBalance2); + // Player should lose ETH + assertEq(userBalance2, userBalance - raid_geld.BUY_IN_AMOUNT()); // Verify player is set initially Player memory player = raid_geld.getPlayer(player1); @@ -117,28 +114,9 @@ contract raid_geldTest is Test, Constants { assertEq(army.apprentice.level, 0); assertEq(army.anointed.level, 0); assertEq(army.champion.level, 0); - } + } - function test_03_01_ETH_funds_can_be_withdrawn() public { - uint256 initialBalance = owner.balance; - - // Switch to Player 1 and register it - vm.startPrank(player1); - registerPlayer(); - - // Switch back to owner and withdraw funds - vm.startPrank(owner); - raid_geld.withdraw(); - uint256 newBalance = owner.balance; - uint256 newContractBalance = address(raid_geld).balance; - - // contract balance should be empty - assertEq(newContractBalance, 0); - // owner should have the extra funds - assertEq(newBalance, initialBalance + raid_geld.BUY_IN_AMOUNT()); - } - - function test_03_02_RGCVII_funds_can_be_withdrawn() public { + function test_dao_token_can_be_withdrawn() public { uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); // Switch to Player 1 and register it @@ -147,7 +125,7 @@ contract raid_geldTest is Test, Constants { // Switch back to owner and withdraw funds vm.startPrank(owner); - raid_geld.withdraw_dao(); + raid_geld.withdraw(); uint256 newBalance = raid_geld.daoToken().balanceOf(address(owner)); uint256 newContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); From bd1f418e11d1db112b155ef28571e333fcef8247 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Mon, 28 Oct 2024 10:08:35 +0100 Subject: [PATCH 12/19] Test naming fix --- test/RaidGeld.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index c0b2a4b..915fd99 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -116,7 +116,7 @@ contract raid_geldTest is Test, Constants { assertEq(army.champion.level, 0); } - function test_dao_token_can_be_withdrawn() public { + function test_03_dao_token_can_be_withdrawn() public { uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); // Switch to Player 1 and register it From 8c8ca58607adcc2258166877aed294c18ac1ff0f Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Mon, 28 Oct 2024 18:31:41 +0100 Subject: [PATCH 13/19] Enables registrations with RGCVII and ETH --- .gitignore | 1 + README.md | 25 +++++-- app/contract_address.ts | 8 ++- app/public/loader/hamster.png | Bin 0 -> 35376 bytes app/public/loader/hamster_stand.png | Bin 0 -> 8679 bytes app/public/loader/hamster_wheel.png | Bin 0 -> 53859 bytes app/src/components/Header.tsx | 8 ++- app/src/components/RegistrationModal.tsx | 26 +++++++ app/src/components/WaitingForTxModal.tsx | 31 ++++++++ app/src/pages/_app.tsx | 7 +- app/src/providers/ModalProvider.tsx | 33 +++++++++ app/src/providers/PlayerProvider.tsx | 64 +++++++++++++---- app/src/styles/Modal.module.css | 67 +++++++++++++++++ app/src/styles/globals.css | 6 +- .../RaidGeld.s.sol/8453/run-1729970220.json | 68 ------------------ broadcast/RaidGeld.s.sol/8453/run-latest.json | 68 ------------------ .../RaidGeld.s.sol/84532/run-1729696549.json | 68 ------------------ .../RaidGeld.s.sol/84532/run-1729773387.json | 68 ------------------ .../RaidGeld.s.sol/84532/run-latest.json | 68 ------------------ deploy_contract.sh | 27 +++++-- 20 files changed, 272 insertions(+), 371 deletions(-) create mode 100644 app/public/loader/hamster.png create mode 100644 app/public/loader/hamster_stand.png create mode 100644 app/public/loader/hamster_wheel.png create mode 100644 app/src/components/RegistrationModal.tsx create mode 100644 app/src/components/WaitingForTxModal.tsx create mode 100644 app/src/providers/ModalProvider.tsx create mode 100644 app/src/styles/Modal.module.css delete mode 100644 broadcast/RaidGeld.s.sol/8453/run-1729970220.json delete mode 100644 broadcast/RaidGeld.s.sol/8453/run-latest.json delete mode 100644 broadcast/RaidGeld.s.sol/84532/run-1729696549.json delete mode 100644 broadcast/RaidGeld.s.sol/84532/run-1729773387.json delete mode 100644 broadcast/RaidGeld.s.sol/84532/run-latest.json diff --git a/.gitignore b/.gitignore index 482352c..53107fa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ # Compiler files cache/ out/ +broadcast/* # Ignores development broadcast logs !/broadcast diff --git a/README.md b/README.md index f044f0b..9552e4d 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,22 @@ Idle game & shitcoin advanture dedicated to cohort VII of Raid Guild. ### 1. Run `anvil` to setup local RPC as a fork of base mainnet -`anvil --block-time 5 --rpc-url ` +`anvil --fork-url --block-time 10 --chain-id 31337` -You can get a free rpc url by registering with https://alchemy.com and creating and app +You can get a free rpc url by registering with https://alchemy.com and creating an app + +Be sure to set --chain-id to 31337 if you are forking mainnet base, otherwise it will deploy with Base chain id and metamask will glitch out. ### 2. Deploy contract -Either use `./deploy_contract.sh` script (!! change contract values and set private key to $DEV_PRIVATE_KEY for it to work) or call those things by hand. +Use `./deploy_contract.sh` script + +This will deploy the contract and give you ETH and DAO Token (RGCVII) funds. + +1. Make sure to change `DEV_WALLET` var to your own. +2. Make sure you have your private key on `DEV_PRIVATE_KEY` environment variable + +Alternatively, check the script and run the steps as you see fit. ### 3. Run dev app @@ -20,8 +29,16 @@ Move to `app` dir, install deps via `npm install` and run `npm run dev` to start #### 3. 1. Point Metamask to Anvil network for local dev +Add network `http://127.0.0.1:8545` with chain id `31337` + #### 3. 2. Change `app/contract_address.ts` to match your program address if needed +#### 3. 3. Reset metamask transaction history between anvil deployments + +If u re-run `anvil` and redeploy the contract, do clear your history in Metamask under Advanced Settings, otherwise Metamask glitches because of its cache (?) + ### 4. Fork tests -forge test --rpc-url +Run `forge test --rpc-url ` + +You can get a free rpc url by registering with https://alchemy.com and creating an app diff --git a/app/contract_address.ts b/app/contract_address.ts index 5eaa84e..620cb43 100644 --- a/app/contract_address.ts +++ b/app/contract_address.ts @@ -1,4 +1,8 @@ -const contractAddress = "0xb2fc8F28aD37290245241C6cb0E411c9fff6A1d7"; +import { Address } from "viem" +const contracts: Record = { + contractAddress: "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66", + daoTokenAddress: "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8" +} -export default contractAddress +export default contracts diff --git a/app/public/loader/hamster.png b/app/public/loader/hamster.png new file mode 100644 index 0000000000000000000000000000000000000000..77667641220e7d4520b4604bb5da30e7eabb065e GIT binary patch literal 35376 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 R?^y#+Lq$g!tY{nc{{VI(UlafU literal 0 HcmV?d00001 diff --git a/app/public/loader/hamster_wheel.png b/app/public/loader/hamster_wheel.png new file mode 100644 index 0000000000000000000000000000000000000000..67874569d3e9902419f3bde0c38ac4ff8aa99060 GIT binary patch literal 53859 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 M07*qoM6N<$f<*(6>i_@% literal 0 HcmV?d00001 diff --git a/app/src/components/Header.tsx b/app/src/components/Header.tsx index cf88274..60eecdf 100644 --- a/app/src/components/Header.tsx +++ b/app/src/components/Header.tsx @@ -5,10 +5,12 @@ import { usePlayer } from "../providers/PlayerProvider"; import { useAccount } from 'wagmi'; import dynamic from "next/dynamic"; import Counter, { toReadable } from "./Counter"; +import { useModal } from "../providers/ModalProvider"; const Header = () => { const { isConnected } = useAccount(); - const { isRegistered, register, army } = usePlayer(); + const { isRegistered, army } = usePlayer(); + const { openRegistrationModal } = useModal(); const title = useMemo(() => { return isRegistered ? `SLAY THE MOLOCH` : @@ -33,8 +35,8 @@ const Header = () => { const onRegister = useCallback(() => { if (isRegistered) return - register(); - }, [isRegistered, register]) + openRegistrationModal() + }, [isRegistered, openRegistrationModal]) return

{title}

diff --git a/app/src/components/RegistrationModal.tsx b/app/src/components/RegistrationModal.tsx new file mode 100644 index 0000000..0161a9e --- /dev/null +++ b/app/src/components/RegistrationModal.tsx @@ -0,0 +1,26 @@ +import { useCallback } from "react"; +import { usePlayer } from "../providers/PlayerProvider"; +import styles from "../styles/Modal.module.css"; + +interface RegistrationModalProps { + isOpen: boolean; + setIsOpen: (val: boolean) => void +} + +const RegistrationModal = ({ isOpen, setIsOpen }: RegistrationModalProps) => { + const { register } = usePlayer() + const onRegister = useCallback((mode: "ETH" | "RGCVII") => { + register(mode); + setIsOpen(false); + }, [register, setIsOpen]) + if (!isOpen) return null; + return
+

Insert coins to continue

+
+ + +
+
+} + +export default RegistrationModal diff --git a/app/src/components/WaitingForTxModal.tsx b/app/src/components/WaitingForTxModal.tsx new file mode 100644 index 0000000..be8ccde --- /dev/null +++ b/app/src/components/WaitingForTxModal.tsx @@ -0,0 +1,31 @@ +import { useEffect } from "react"; +import { Hash } from "viem" +import { useWaitForTransactionReceipt } from "wagmi"; +import styles from "../styles/Modal.module.css" + +interface WaitingForTxModalProps { + hash: Hash, + callbackFn: () => void; +} + +const WaitingForTxModal = ({ + hash, + callbackFn +}: WaitingForTxModalProps) => { + const { isFetched } = useWaitForTransactionReceipt({ hash }) + useEffect(() => { + if (isFetched) { + callbackFn() + } + }, [isFetched, callbackFn]) + return
+
+
+
+
+
+

Writing contract ...

+
+} + +export default WaitingForTxModal diff --git a/app/src/pages/_app.tsx b/app/src/pages/_app.tsx index 1f69bf4..6340077 100644 --- a/app/src/pages/_app.tsx +++ b/app/src/pages/_app.tsx @@ -7,6 +7,7 @@ import { RainbowKitProvider, midnightTheme } from '@rainbow-me/rainbowkit'; import { config } from '../wagmi'; import { Texturina } from 'next/font/google' import PlayerProvider from '../providers/PlayerProvider'; +import ModalProvider from '../providers/ModalProvider'; const client = new QueryClient(); const font = Texturina({ weight: ['400'], subsets: ["latin"] }) @@ -17,7 +18,7 @@ function MyApp({ Component, pageProps }: AppProps) { - + + + diff --git a/app/src/providers/ModalProvider.tsx b/app/src/providers/ModalProvider.tsx new file mode 100644 index 0000000..058ae10 --- /dev/null +++ b/app/src/providers/ModalProvider.tsx @@ -0,0 +1,33 @@ +import React, { createContext, ReactNode, useCallback, useContext, useState } from 'react' +import RegistrationModal from '../components/RegistrationModal'; + + +export interface PlayerContextType { + openRegistrationModal: () => void +} + +const ModalContext = createContext({ + openRegistrationModal: () => { } +}); + +const ModalProvider = ({ children }: { children: ReactNode }) => { + const [registrationModalOpen, setIsRegistrationModalOpen] = useState(false) + const openRegistrationModal = useCallback(() => { + setIsRegistrationModalOpen(true) + }, []) + return ( + + {children} + + + ); +} + +export const useModal = () => { + return useContext(ModalContext); +} + +export default ModalProvider + diff --git a/app/src/providers/PlayerProvider.tsx b/app/src/providers/PlayerProvider.tsx index 824cce3..f0d38f3 100644 --- a/app/src/providers/PlayerProvider.tsx +++ b/app/src/providers/PlayerProvider.tsx @@ -1,9 +1,11 @@ -import React, { createContext, ReactNode, useCallback, useContext, useEffect } from 'react' +import React, { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react' import { useAccount, useReadContract, useWriteContract } from 'wagmi' import contractAbi from "../../../out/RaidGeld.sol/RaidGeld.json" -import { parseEther } from 'viem' -import contractAddress from '../../contract_address' +import { Hash, parseEther } from 'viem' +import contracts from '../../contract_address' +import WaitingForTxModal from '../components/WaitingForTxModal' +const { contractAddress, daoTokenAddress } = contracts const abi = contractAbi.abi export type UnitType = 0 | 1 | 2 | 3 @@ -26,7 +28,7 @@ export interface PlayerContextType { player: null | Player, army: null | Army, balance: bigint, - register: () => void, + register: (arg: "ETH" | "RGCVII") => void, raid: () => void, addUnit: (unit: UnitType) => void } @@ -44,11 +46,16 @@ const PlayerContext = createContext({ const PlayerProvider = ({ children }: { children: ReactNode }) => { const { address, isConnected } = useAccount(); const { writeContract, error } = useWriteContract(); + const [[txHash, callbackFn], setHashAndCallback] = useState<[Hash | null, () => void]>([null, () => { }]) useEffect(() => { console.warn(error) }, [error]) + const resetHashAndCallback = useCallback(() => { + setHashAndCallback([null, () => { }]) + }, []) + const { data: isRegistered } = useReadContract({ address: contractAddress, abi, @@ -56,7 +63,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { args: [address], query: { enabled: isConnected, - refetchInterval: 5, + refetchInterval: 15, } }); @@ -66,7 +73,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { functionName: 'balanceOf', args: [address], query: { - refetchInterval: 5, + refetchInterval: 15, enabled: isConnected } }); @@ -95,14 +102,42 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { console.log(balance, player, army) - const register = useCallback(() => { - writeContract({ - abi, - address: contractAddress, - functionName: 'register', - value: parseEther("0.0005"), - }) - }, [writeContract]) + const register = useCallback((arg: "RGCVII" | "ETH") => { + if (arg === 'ETH') { + writeContract({ + abi, + address: contractAddress, + functionName: 'register_eth', + value: parseEther("0.0005"), + }, { + onSuccess: (hash) => { + setHashAndCallback([hash, resetHashAndCallback]) + } + }) + } else if (arg === "RGCVII") { + writeContract({ + abi, + address: daoTokenAddress, + functionName: 'approve', + args: [contractAddress, parseEther("50")], + }, { + onSuccess: (hash) => { + setHashAndCallback([ + hash, + () => writeContract({ + abi, + address: contractAddress, + functionName: 'register_dao', + }, { + onSuccess: (hash) => { + setHashAndCallback([hash, resetHashAndCallback]) + } + }) + ]) + } + }); + } + }, [writeContract, resetHashAndCallback]) const raid = useCallback(() => { writeContract({ @@ -132,6 +167,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { addUnit }}> {children} + {txHash && } ); } diff --git a/app/src/styles/Modal.module.css b/app/src/styles/Modal.module.css new file mode 100644 index 0000000..a1ec842 --- /dev/null +++ b/app/src/styles/Modal.module.css @@ -0,0 +1,67 @@ +.modal { + position: fixed; + margin: 0 auto; + height: auto; + background: var(--bg-color); + border-width: 8px; + border-image: url("/background/frame.png") 22 fill / auto space; + padding: 44px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + & button { + font-size: 1.4rem; + margin: 0 11px; + } + & h2 { + margin-top: 0; + } + .loadingImage { + position: relative; + width: 240px; + height: 240px; + } + .loadingHamster { + position: absolute; + background-image: url("/loader/hamster.png"); + width: 240px; + height: 240px; + animation: jump 0.2s ease infinite; + } + .loadingHamsterWheel { + position: absolute; + background-image: url("/loader/hamster_wheel.png"); + width: 240px; + height: 240px; + animation: spin 3.5s linear infinite; + } + .loadingHamsterWheelStand { + position: absolute; + background-image: url("/loader/hamster_stand.png"); + width: 240px; + height: 240px; + } + .loadingText { + text-align: center; + font-size: 1.1rem; + margin-bottom: 0; + } +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +@keyframes jump { + 0%, + 100% { + transform: translate(0, 0); + } + 50% { + transform: translate(0, -10px); + } +} diff --git a/app/src/styles/globals.css b/app/src/styles/globals.css index 8da1309..ad4aa7a 100644 --- a/app/src/styles/globals.css +++ b/app/src/styles/globals.css @@ -1,5 +1,6 @@ :root { --bg-color: #1a1a1a; + --bg-color-button: #000; --text-color: #ffffff; --accent-color: #f00000; --border-color: #800000; @@ -40,8 +41,8 @@ a:hover { } button { - background-color: var(--accent-color); - color: var(--bg-color); + background-color: var(--bg-color-button); + color: var(--text-color); border: 2px solid var(--border-color); padding: 10px; cursor: pointer; @@ -49,6 +50,7 @@ button { button:hover { background-color: var(--hover-color); + color: var(--bg-color-button); } header, diff --git a/broadcast/RaidGeld.s.sol/8453/run-1729970220.json b/broadcast/RaidGeld.s.sol/8453/run-1729970220.json deleted file mode 100644 index da935d1..0000000 --- a/broadcast/RaidGeld.s.sol/8453/run-1729970220.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "transactions": [ - { - "hash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", - "transactionType": "CREATE", - "contractName": "RaidGeld", - "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", - "function": null, - "arguments": [ - "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8", - "0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926" - ], - "transaction": { - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "gas": "0x1e142b", - "value": "0x0", - "input": "0x60a060405234801561001057600080fd5b50604051611ccd380380611ccd83398101604081905261002f916101e2565b336040518060400160405280600981526020016814985a590811d95b1960ba1b8152506040518060400160405280600481526020016311d1531160e21b815250816003908161007e91906102b4565b50600461008b82826102b4565b5050506001600160a01b0381166100bc57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100c581610174565b50600880546001600160a01b038085166001600160a01b0319928316811790935560098054918516919092161790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801561012f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101539190610372565b61015e90600a61049b565b6101699060326104aa565b608052506104c19050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146101dd57600080fd5b919050565b600080604083850312156101f557600080fd5b6101fe836101c6565b915061020c602084016101c6565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061023f57607f821691505b60208210810361025f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102af57806000526020600020601f840160051c8101602085101561028c5750805b601f840160051c820191505b818110156102ac5760008155600101610298565b50505b505050565b81516001600160401b038111156102cd576102cd610215565b6102e1816102db845461022b565b84610265565b6020601f82116001811461031557600083156102fd5750848201515b600019600385901b1c1916600184901b1784556102ac565b600084815260208120601f198516915b828110156103455787850151825560209485019460019092019101610325565b50848210156103635786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b60006020828403121561038457600080fd5b815160ff8116811461039557600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b6001815b60018411156103ed578085048111156103d1576103d161039c565b60018416156103df57908102905b60019390931c9280026103b6565b935093915050565b60008261040457506001610495565b8161041157506000610495565b816001811461042757600281146104315761044d565b6001915050610495565b60ff8411156104425761044261039c565b50506001821b610495565b5060208310610133831016604e8410600b8410161715610470575081810a610495565b61047d60001984846103b2565b80600019048211156104915761049161039c565b0290505b92915050565b600061039560ff8416836103f5565b80820281158282048414176104955761049561039c565b6080516117ea6104e360003960008181610677015261088901526117ea6000f3fe6080604052600436106101855760003560e01c80635c12cd4b116100d1578063a7db742f1161008a578063c861dcb111610064578063c861dcb114610650578063db4d0d2714610665578063dd62ed3e14610699578063f2fde38b146106df576101fd565b8063a7db742f146105e0578063a9059cbb146105f5578063c3c5a54714610615576101fd565b80635c12cd4b1461050057806370a0823114610542578063715018a61461057857806385ed706d1461058d5780638da5cb5b146105ad57806395d89b41146105cb576101fd565b806323b872dd1161013e5780633ccfd60b116101185780633ccfd60b1461036c57806347d1e46e146103815780634914b0301461039b57806353d7da60146103bb576101fd565b806323b872dd1461031a5780632703984c1461033a578063313ce56714610350576101fd565b806306fdde0314610245578063095ea7b31461027057806313820ba7146102a057806316f0115b146102c357806318160ddd146102fb5780631aa3a00814610310576101fd565b366101fd5760405162461bcd60e51b815260206004820152603f60248201527f4e6f20706c61696e2045746865722061636365707465642c207573652072656760448201527f697374657228292066756e6374696f6e20746f20636865636b20696e203a290060648201526084015b60405180910390fd5b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2066616c6c6261636b2063616c6c7320616363657074656400000000000060448201526064016101f4565b34801561025157600080fd5b5061025a6106ff565b6040516102679190611544565b60405180910390f35b34801561027c57600080fd5b5061029061028b3660046115ae565b610791565b6040519015158152602001610267565b3480156102ac57600080fd5b506102b5600f81565b604051908152602001610267565b3480156102cf57600080fd5b506009546102e3906001600160a01b031681565b6040516001600160a01b039091168152602001610267565b34801561030757600080fd5b506002546102b5565b6103186107ab565b005b34801561032657600080fd5b506102906103353660046115d8565b610a6c565b34801561034657600080fd5b506102b561271081565b34801561035c57600080fd5b5060405160048152602001610267565b34801561037857600080fd5b50610318610a90565b34801561038d57600080fd5b506102b5652d79883d200081565b3480156103a757600080fd5b506008546102e3906001600160a01b031681565b3480156103c757600080fd5b506104aa6103d6366004611615565b6040805160c081018252600060a082018181528252825160208082018552828252808401919091528351808201855282815283850152835190810190935280835260608201929092526080810191909152506001600160a01b0316600090815260076020908152604091829020825160c081018452815461ffff90811660a08301908152825284518085018652600184015482168152828501528451808501865260028401548216815282860152845193840190945260038201549093168252606083019190915260040154608082015290565b6040516102679190600060a08201905061ffff83515116825261ffff60208401515116602083015261ffff60408401515116604083015261ffff6060840151511660608301526080830151608083015292915050565b34801561050c57600080fd5b5061052061051b366004611615565b610ad4565b6040805182518152602080840151908201529181015190820152606001610267565b34801561054e57600080fd5b506102b561055d366004611615565b6001600160a01b031660009081526020819052604090205490565b34801561058457600080fd5b50610318610b3a565b34801561059957600080fd5b506103186105a8366004611637565b610b4e565b3480156105b957600080fd5b506005546001600160a01b03166102e3565b3480156105d757600080fd5b5061025a610e2d565b3480156105ec57600080fd5b50610318610e3c565b34801561060157600080fd5b506102906106103660046115ae565b610f07565b34801561062157600080fd5b50610290610630366004611615565b6001600160a01b0316600090815260066020526040902060010154151590565b34801561065c57600080fd5b506102b5610f15565b34801561067157600080fd5b506102b57f000000000000000000000000000000000000000000000000000000000000000081565b3480156106a557600080fd5b506102b56106b436600461167d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156106eb57600080fd5b506103186106fa366004611615565b610f25565b60606003805461070e906116b0565b80601f016020809104026020016040519081016040528092919081815260200182805461073a906116b0565b80156107875780601f1061075c57610100808354040283529160200191610787565b820191906000526020600020905b81548152906001019060200180831161076a57829003601f168201915b5050505050905090565b60003361079f818585610f60565b60019150505b92915050565b336000908152600660205260409020600101541561080b5760405162461bcd60e51b815260206004820181905260248201527f57686f6f70732c20706c6179657220616c726561647920657869737473203a2960448201526064016101f4565b341561086b57652d79883d200034146108665760405162461bcd60e51b815260206004820152601760248201527f496e636f72726563742062757920696e20616d6f756e7400000000000000000060448201526064016101f4565b610951565b6008546040516323b872dd60e01b81523360048201523060248201527f000000000000000000000000000000000000000000000000000000000000000060448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090591906116ea565b6109515760405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f207472616e736665722044414f20746f6b656e7300000060448201526064016101f4565b610967336109626127106032611722565b610f72565b604051806060016040528061271060326109819190611722565b815242602080830182905260409283019190915233600081815260068352838120855181558584015160018083019190915595850151600291820155845160c08101865260a0810183815281528551808601875283815281860190815286518087018852848152828801908152875180880189528581526060840190815260808401868152968652600790975296909320905151815461ffff1990811661ffff92831617835593515197820180548516988216989098179097559451519085018054831691871691909117905591515160038401805490931694169390931790559051600490910155565b600033610a7a858285610fac565b610a8585858561102a565b506001949350505050565b610a98611089565b6005546040516001600160a01b03909116904780156108fc02916000818181858888f19350505050158015610ad1573d6000803e3d6000fd5b50565b610af860405180606001604052806000815260200160008152602001600081525090565b506001600160a01b0316600090815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b610b42611089565b610b4c60006110b6565b565b336000908152600660205260408120600101549003610ba95760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b60038260ff161115610bec5760405162461bcd60e51b815260206004820152600c60248201526b155b9adb9bdddb881d5b9a5d60a21b60448201526064016101f4565b3360009081526007602052604081209060ff84168103610c125750805461ffff16610c5c565b8360ff16600103610c2c5750600181015461ffff16610c5c565b8360ff16600203610c465750600281015461ffff16610c5c565b8360ff16600303610c5c5750600381015461ffff165b6000610c69858386611108565b9050610c74336111d5565b336000908152602081905260409020548110610cd25760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682047454c4420746f206164642074686973206d75636860448201526064016101f4565b610cdc3382611258565b8460ff16600003610d1e57825484908490600090610cff90849061ffff16611739565b92506101000a81548161ffff021916908361ffff160217905550610dab565b8460ff16600103610d4457600183018054859190600090610cff90849061ffff16611739565b8460ff16600203610d6a57600283018054859190600090610cff90849061ffff16611739565b8460ff16600303610dab57600383018054859190600090610d9090849061ffff16611739565b92506101000a81548161ffff021916908361ffff1602179055505b6040805160c081018252845461ffff90811660a08301908152825282516020818101855260018801548316825280840191909152835180820185526002880154831681528385015283519081019093526003860154168252606081019190915260048401546080820152610e1e9061128e565b83600401819055505050505050565b60606004805461070e906116b0565b336000908152600660205260408120600101549003610e975760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b33600090815260066020526040902060020154610eb690600f90611753565b421015610efe5760405162461bcd60e51b81526020600482015260166024820152752a3934b2b21036b4b73a34b733903a37b79039b7b7b760511b60448201526064016101f4565b610b4c336111d5565b60003361079f81858561102a565b610f226127106032611722565b81565b610f2d611089565b6001600160a01b038116610f5757604051631e4fbdf760e01b8152600060048201526024016101f4565b610ad1816110b6565b610f6d8383836001611345565b505050565b6001600160a01b038216610f9c5760405163ec442f0560e01b8152600060048201526024016101f4565b610fa86000838361141a565b5050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611024578181101561101557604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016101f4565b61102484848484036000611345565b50505050565b6001600160a01b03831661105457604051634b637e8f60e11b8152600060048201526024016101f4565b6001600160a01b03821661107e5760405163ec442f0560e01b8152600060048201526024016101f4565b610f6d83838361141a565b6005546001600160a01b03163314610b4c5760405163118cdaa760e01b81523360048201526024016101f4565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060038460ff1611156111575760405162461bcd60e51b8152602060048201526016602482015275139bc81b585d18da1a5b99c81d5b9a5d08199bdd5b9960521b60448201526064016101f4565b60006205cc60611168866001611766565b60ff166111759190611722565b90508060015b6111858587611739565b61ffff168110156111cb5761271061119f612cec85611722565b6111a9919061177f565b92508561ffff1681106111c3576111c08383611753565b91505b60010161117b565b5095945050505050565b6001600160a01b0381166000908152600660205260408120600201546111fb90426117a1565b6001600160a01b03831660009081526007602052604081206004015491925090611226908390611722565b90506112328382610f72565b6001600160a01b0390921660009081526006602052604090204260028201559190915550565b6001600160a01b03821661128257604051634b637e8f60e11b8152600060048201526024016101f4565b610fa88260008361141a565b80515160009081906112a7906127109061ffff16611722565b9050600061ee4884602001516000015161ffff166112c59190611722565b905060006205dc0085604001516000015161ffff166112e49190611722565b905060006127106112fb8165ede50bb9800061177f565b611305919061177f565b606087015151611319919061ffff16611722565b905080826113278587611753565b6113319190611753565b61133b9190611753565b9695505050505050565b6001600160a01b03841661136f5760405163e602df0560e01b8152600060048201526024016101f4565b6001600160a01b03831661139957604051634a1406b160e11b8152600060048201526024016101f4565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561102457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161140c91815260200190565b60405180910390a350505050565b6001600160a01b03831661144557806002600082825461143a9190611753565b909155506114b79050565b6001600160a01b038316600090815260208190526040902054818110156114985760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016101f4565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166114d3576002805482900390556114f2565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161153791815260200190565b60405180910390a3505050565b602081526000825180602084015260005b818110156115725760208186018101516040868401015201611555565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b03811681146115a957600080fd5b919050565b600080604083850312156115c157600080fd5b6115ca83611592565b946020939093013593505050565b6000806000606084860312156115ed57600080fd5b6115f684611592565b925061160460208501611592565b929592945050506040919091013590565b60006020828403121561162757600080fd5b61163082611592565b9392505050565b6000806040838503121561164a57600080fd5b823560ff8116811461165b57600080fd5b9150602083013561ffff8116811461167257600080fd5b809150509250929050565b6000806040838503121561169057600080fd5b61169983611592565b91506116a760208401611592565b90509250929050565b600181811c908216806116c457607f821691505b6020821081036116e457634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156116fc57600080fd5b8151801515811461163057600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176107a5576107a561170c565b61ffff81811683821601908111156107a5576107a561170c565b808201808211156107a5576107a561170c565b60ff81811683821601908111156107a5576107a561170c565b60008261179c57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156107a5576107a561170c56fea2646970667358221220e6bad70680fdee5fb985ae5e884c4471f46d5febec4efc3ccebe2e1ee82de75764736f6c634300081c003300000000000000000000000011dc980faf34a1d082ae8a6a883db3a950a3c6e800000000000000000000000027004f6d0c1bb7979367d32ba9d6df6d61a18926", - "nonce": "0x1", - "chainId": "0x2105" - }, - "additionalContracts": [], - "isFixedGasLimit": false - } - ], - "receipts": [ - { - "status": "0x1", - "cumulativeGasUsed": "0x172507", - "logs": [ - { - "address": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", - "topics": [ - "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000003295cca2d922c637d35b258fc6c9c7e471803b45" - ], - "data": "0x", - "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", - "blockNumber": "0x1497119", - "blockTimestamp": "0x671d402a", - "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", - "transactionIndex": "0x0", - "logIndex": "0x0", - "removed": false - } - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000008000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000010000000000000001000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "type": "0x2", - "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", - "transactionIndex": "0x0", - "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", - "blockNumber": "0x1497119", - "gasUsed": "0x172507", - "effectiveGasPrice": "0x2b", - "blobGasPrice": "0x1", - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "to": null, - "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", - "root": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - ], - "libraries": [], - "pending": [], - "returns": {}, - "timestamp": 1729970220, - "chain": 8453, - "commit": "5b0d24c" -} \ No newline at end of file diff --git a/broadcast/RaidGeld.s.sol/8453/run-latest.json b/broadcast/RaidGeld.s.sol/8453/run-latest.json deleted file mode 100644 index da935d1..0000000 --- a/broadcast/RaidGeld.s.sol/8453/run-latest.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "transactions": [ - { - "hash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", - "transactionType": "CREATE", - "contractName": "RaidGeld", - "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", - "function": null, - "arguments": [ - "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8", - "0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926" - ], - "transaction": { - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "gas": "0x1e142b", - "value": "0x0", - "input": "0x60a060405234801561001057600080fd5b50604051611ccd380380611ccd83398101604081905261002f916101e2565b336040518060400160405280600981526020016814985a590811d95b1960ba1b8152506040518060400160405280600481526020016311d1531160e21b815250816003908161007e91906102b4565b50600461008b82826102b4565b5050506001600160a01b0381166100bc57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100c581610174565b50600880546001600160a01b038085166001600160a01b0319928316811790935560098054918516919092161790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801561012f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101539190610372565b61015e90600a61049b565b6101699060326104aa565b608052506104c19050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146101dd57600080fd5b919050565b600080604083850312156101f557600080fd5b6101fe836101c6565b915061020c602084016101c6565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061023f57607f821691505b60208210810361025f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102af57806000526020600020601f840160051c8101602085101561028c5750805b601f840160051c820191505b818110156102ac5760008155600101610298565b50505b505050565b81516001600160401b038111156102cd576102cd610215565b6102e1816102db845461022b565b84610265565b6020601f82116001811461031557600083156102fd5750848201515b600019600385901b1c1916600184901b1784556102ac565b600084815260208120601f198516915b828110156103455787850151825560209485019460019092019101610325565b50848210156103635786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b60006020828403121561038457600080fd5b815160ff8116811461039557600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b6001815b60018411156103ed578085048111156103d1576103d161039c565b60018416156103df57908102905b60019390931c9280026103b6565b935093915050565b60008261040457506001610495565b8161041157506000610495565b816001811461042757600281146104315761044d565b6001915050610495565b60ff8411156104425761044261039c565b50506001821b610495565b5060208310610133831016604e8410600b8410161715610470575081810a610495565b61047d60001984846103b2565b80600019048211156104915761049161039c565b0290505b92915050565b600061039560ff8416836103f5565b80820281158282048414176104955761049561039c565b6080516117ea6104e360003960008181610677015261088901526117ea6000f3fe6080604052600436106101855760003560e01c80635c12cd4b116100d1578063a7db742f1161008a578063c861dcb111610064578063c861dcb114610650578063db4d0d2714610665578063dd62ed3e14610699578063f2fde38b146106df576101fd565b8063a7db742f146105e0578063a9059cbb146105f5578063c3c5a54714610615576101fd565b80635c12cd4b1461050057806370a0823114610542578063715018a61461057857806385ed706d1461058d5780638da5cb5b146105ad57806395d89b41146105cb576101fd565b806323b872dd1161013e5780633ccfd60b116101185780633ccfd60b1461036c57806347d1e46e146103815780634914b0301461039b57806353d7da60146103bb576101fd565b806323b872dd1461031a5780632703984c1461033a578063313ce56714610350576101fd565b806306fdde0314610245578063095ea7b31461027057806313820ba7146102a057806316f0115b146102c357806318160ddd146102fb5780631aa3a00814610310576101fd565b366101fd5760405162461bcd60e51b815260206004820152603f60248201527f4e6f20706c61696e2045746865722061636365707465642c207573652072656760448201527f697374657228292066756e6374696f6e20746f20636865636b20696e203a290060648201526084015b60405180910390fd5b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2066616c6c6261636b2063616c6c7320616363657074656400000000000060448201526064016101f4565b34801561025157600080fd5b5061025a6106ff565b6040516102679190611544565b60405180910390f35b34801561027c57600080fd5b5061029061028b3660046115ae565b610791565b6040519015158152602001610267565b3480156102ac57600080fd5b506102b5600f81565b604051908152602001610267565b3480156102cf57600080fd5b506009546102e3906001600160a01b031681565b6040516001600160a01b039091168152602001610267565b34801561030757600080fd5b506002546102b5565b6103186107ab565b005b34801561032657600080fd5b506102906103353660046115d8565b610a6c565b34801561034657600080fd5b506102b561271081565b34801561035c57600080fd5b5060405160048152602001610267565b34801561037857600080fd5b50610318610a90565b34801561038d57600080fd5b506102b5652d79883d200081565b3480156103a757600080fd5b506008546102e3906001600160a01b031681565b3480156103c757600080fd5b506104aa6103d6366004611615565b6040805160c081018252600060a082018181528252825160208082018552828252808401919091528351808201855282815283850152835190810190935280835260608201929092526080810191909152506001600160a01b0316600090815260076020908152604091829020825160c081018452815461ffff90811660a08301908152825284518085018652600184015482168152828501528451808501865260028401548216815282860152845193840190945260038201549093168252606083019190915260040154608082015290565b6040516102679190600060a08201905061ffff83515116825261ffff60208401515116602083015261ffff60408401515116604083015261ffff6060840151511660608301526080830151608083015292915050565b34801561050c57600080fd5b5061052061051b366004611615565b610ad4565b6040805182518152602080840151908201529181015190820152606001610267565b34801561054e57600080fd5b506102b561055d366004611615565b6001600160a01b031660009081526020819052604090205490565b34801561058457600080fd5b50610318610b3a565b34801561059957600080fd5b506103186105a8366004611637565b610b4e565b3480156105b957600080fd5b506005546001600160a01b03166102e3565b3480156105d757600080fd5b5061025a610e2d565b3480156105ec57600080fd5b50610318610e3c565b34801561060157600080fd5b506102906106103660046115ae565b610f07565b34801561062157600080fd5b50610290610630366004611615565b6001600160a01b0316600090815260066020526040902060010154151590565b34801561065c57600080fd5b506102b5610f15565b34801561067157600080fd5b506102b57f000000000000000000000000000000000000000000000000000000000000000081565b3480156106a557600080fd5b506102b56106b436600461167d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156106eb57600080fd5b506103186106fa366004611615565b610f25565b60606003805461070e906116b0565b80601f016020809104026020016040519081016040528092919081815260200182805461073a906116b0565b80156107875780601f1061075c57610100808354040283529160200191610787565b820191906000526020600020905b81548152906001019060200180831161076a57829003601f168201915b5050505050905090565b60003361079f818585610f60565b60019150505b92915050565b336000908152600660205260409020600101541561080b5760405162461bcd60e51b815260206004820181905260248201527f57686f6f70732c20706c6179657220616c726561647920657869737473203a2960448201526064016101f4565b341561086b57652d79883d200034146108665760405162461bcd60e51b815260206004820152601760248201527f496e636f72726563742062757920696e20616d6f756e7400000000000000000060448201526064016101f4565b610951565b6008546040516323b872dd60e01b81523360048201523060248201527f000000000000000000000000000000000000000000000000000000000000000060448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090591906116ea565b6109515760405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f207472616e736665722044414f20746f6b656e7300000060448201526064016101f4565b610967336109626127106032611722565b610f72565b604051806060016040528061271060326109819190611722565b815242602080830182905260409283019190915233600081815260068352838120855181558584015160018083019190915595850151600291820155845160c08101865260a0810183815281528551808601875283815281860190815286518087018852848152828801908152875180880189528581526060840190815260808401868152968652600790975296909320905151815461ffff1990811661ffff92831617835593515197820180548516988216989098179097559451519085018054831691871691909117905591515160038401805490931694169390931790559051600490910155565b600033610a7a858285610fac565b610a8585858561102a565b506001949350505050565b610a98611089565b6005546040516001600160a01b03909116904780156108fc02916000818181858888f19350505050158015610ad1573d6000803e3d6000fd5b50565b610af860405180606001604052806000815260200160008152602001600081525090565b506001600160a01b0316600090815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b610b42611089565b610b4c60006110b6565b565b336000908152600660205260408120600101549003610ba95760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b60038260ff161115610bec5760405162461bcd60e51b815260206004820152600c60248201526b155b9adb9bdddb881d5b9a5d60a21b60448201526064016101f4565b3360009081526007602052604081209060ff84168103610c125750805461ffff16610c5c565b8360ff16600103610c2c5750600181015461ffff16610c5c565b8360ff16600203610c465750600281015461ffff16610c5c565b8360ff16600303610c5c5750600381015461ffff165b6000610c69858386611108565b9050610c74336111d5565b336000908152602081905260409020548110610cd25760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682047454c4420746f206164642074686973206d75636860448201526064016101f4565b610cdc3382611258565b8460ff16600003610d1e57825484908490600090610cff90849061ffff16611739565b92506101000a81548161ffff021916908361ffff160217905550610dab565b8460ff16600103610d4457600183018054859190600090610cff90849061ffff16611739565b8460ff16600203610d6a57600283018054859190600090610cff90849061ffff16611739565b8460ff16600303610dab57600383018054859190600090610d9090849061ffff16611739565b92506101000a81548161ffff021916908361ffff1602179055505b6040805160c081018252845461ffff90811660a08301908152825282516020818101855260018801548316825280840191909152835180820185526002880154831681528385015283519081019093526003860154168252606081019190915260048401546080820152610e1e9061128e565b83600401819055505050505050565b60606004805461070e906116b0565b336000908152600660205260408120600101549003610e975760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101f4565b33600090815260066020526040902060020154610eb690600f90611753565b421015610efe5760405162461bcd60e51b81526020600482015260166024820152752a3934b2b21036b4b73a34b733903a37b79039b7b7b760511b60448201526064016101f4565b610b4c336111d5565b60003361079f81858561102a565b610f226127106032611722565b81565b610f2d611089565b6001600160a01b038116610f5757604051631e4fbdf760e01b8152600060048201526024016101f4565b610ad1816110b6565b610f6d8383836001611345565b505050565b6001600160a01b038216610f9c5760405163ec442f0560e01b8152600060048201526024016101f4565b610fa86000838361141a565b5050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611024578181101561101557604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016101f4565b61102484848484036000611345565b50505050565b6001600160a01b03831661105457604051634b637e8f60e11b8152600060048201526024016101f4565b6001600160a01b03821661107e5760405163ec442f0560e01b8152600060048201526024016101f4565b610f6d83838361141a565b6005546001600160a01b03163314610b4c5760405163118cdaa760e01b81523360048201526024016101f4565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060038460ff1611156111575760405162461bcd60e51b8152602060048201526016602482015275139bc81b585d18da1a5b99c81d5b9a5d08199bdd5b9960521b60448201526064016101f4565b60006205cc60611168866001611766565b60ff166111759190611722565b90508060015b6111858587611739565b61ffff168110156111cb5761271061119f612cec85611722565b6111a9919061177f565b92508561ffff1681106111c3576111c08383611753565b91505b60010161117b565b5095945050505050565b6001600160a01b0381166000908152600660205260408120600201546111fb90426117a1565b6001600160a01b03831660009081526007602052604081206004015491925090611226908390611722565b90506112328382610f72565b6001600160a01b0390921660009081526006602052604090204260028201559190915550565b6001600160a01b03821661128257604051634b637e8f60e11b8152600060048201526024016101f4565b610fa88260008361141a565b80515160009081906112a7906127109061ffff16611722565b9050600061ee4884602001516000015161ffff166112c59190611722565b905060006205dc0085604001516000015161ffff166112e49190611722565b905060006127106112fb8165ede50bb9800061177f565b611305919061177f565b606087015151611319919061ffff16611722565b905080826113278587611753565b6113319190611753565b61133b9190611753565b9695505050505050565b6001600160a01b03841661136f5760405163e602df0560e01b8152600060048201526024016101f4565b6001600160a01b03831661139957604051634a1406b160e11b8152600060048201526024016101f4565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561102457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161140c91815260200190565b60405180910390a350505050565b6001600160a01b03831661144557806002600082825461143a9190611753565b909155506114b79050565b6001600160a01b038316600090815260208190526040902054818110156114985760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016101f4565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166114d3576002805482900390556114f2565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161153791815260200190565b60405180910390a3505050565b602081526000825180602084015260005b818110156115725760208186018101516040868401015201611555565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b03811681146115a957600080fd5b919050565b600080604083850312156115c157600080fd5b6115ca83611592565b946020939093013593505050565b6000806000606084860312156115ed57600080fd5b6115f684611592565b925061160460208501611592565b929592945050506040919091013590565b60006020828403121561162757600080fd5b61163082611592565b9392505050565b6000806040838503121561164a57600080fd5b823560ff8116811461165b57600080fd5b9150602083013561ffff8116811461167257600080fd5b809150509250929050565b6000806040838503121561169057600080fd5b61169983611592565b91506116a760208401611592565b90509250929050565b600181811c908216806116c457607f821691505b6020821081036116e457634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156116fc57600080fd5b8151801515811461163057600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176107a5576107a561170c565b61ffff81811683821601908111156107a5576107a561170c565b808201808211156107a5576107a561170c565b60ff81811683821601908111156107a5576107a561170c565b60008261179c57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156107a5576107a561170c56fea2646970667358221220e6bad70680fdee5fb985ae5e884c4471f46d5febec4efc3ccebe2e1ee82de75764736f6c634300081c003300000000000000000000000011dc980faf34a1d082ae8a6a883db3a950a3c6e800000000000000000000000027004f6d0c1bb7979367d32ba9d6df6d61a18926", - "nonce": "0x1", - "chainId": "0x2105" - }, - "additionalContracts": [], - "isFixedGasLimit": false - } - ], - "receipts": [ - { - "status": "0x1", - "cumulativeGasUsed": "0x172507", - "logs": [ - { - "address": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", - "topics": [ - "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000003295cca2d922c637d35b258fc6c9c7e471803b45" - ], - "data": "0x", - "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", - "blockNumber": "0x1497119", - "blockTimestamp": "0x671d402a", - "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", - "transactionIndex": "0x0", - "logIndex": "0x0", - "removed": false - } - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000008000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000010000000000000001000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "type": "0x2", - "transactionHash": "0xf4278a9fce11d0c2cead03215a7b1a659835ee9c34eaef5d77414746e08df39e", - "transactionIndex": "0x0", - "blockHash": "0xe8f062660de56b3a4a6ee42c5abb2b43d7cee37c911822eff46c6dead0783edd", - "blockNumber": "0x1497119", - "gasUsed": "0x172507", - "effectiveGasPrice": "0x2b", - "blobGasPrice": "0x1", - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "to": null, - "contractAddress": "0xb2fc8f28ad37290245241c6cb0e411c9fff6a1d7", - "root": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - ], - "libraries": [], - "pending": [], - "returns": {}, - "timestamp": 1729970220, - "chain": 8453, - "commit": "5b0d24c" -} \ No newline at end of file diff --git a/broadcast/RaidGeld.s.sol/84532/run-1729696549.json b/broadcast/RaidGeld.s.sol/84532/run-1729696549.json deleted file mode 100644 index 0a1ec0c..0000000 --- a/broadcast/RaidGeld.s.sol/84532/run-1729696549.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "transactions": [ - { - "hash": "0x9d39df7a47137565fa4dfd579c92e4a90db9ae54490630585e878d7313ce15a7", - "transactionType": "CREATE", - "contractName": "RaidGeld", - "contractAddress": "0xbd06b0878888bf4c6895704fa603a5adf7e65c66", - "function": null, - "arguments": null, - "transaction": { - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "gas": "0x1c21ce", - "value": "0x0", - "input": "0x608060405234801561001057600080fd5b50336040518060400160405280600981526020016814985a590811d95b1960ba1b8152506040518060400160405280600481526020016311d1531160e21b8152508160039081610060919061019e565b50600461006d828261019e565b5050506001600160a01b03811661009e57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100a7816100ad565b5061025c565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061012957607f821691505b60208210810361014957634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561019957806000526020600020601f840160051c810160208510156101765750805b601f840160051c820191505b818110156101965760008155600101610182565b50505b505050565b81516001600160401b038111156101b7576101b76100ff565b6101cb816101c58454610115565b8461014f565b6020601f8211600181146101ff57600083156101e75750848201515b600019600385901b1c1916600184901b178455610196565b600084815260208120601f198516915b8281101561022f578785015182556020948501946001909201910161020f565b508482101561024d5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b6117478061026b6000396000f3fe6080604052600436106101395760003560e01c806370a08231116100ab578063a7db742f1161006f578063a7db742f14610530578063a9059cbb14610545578063c3c5a54714610565578063c861dcb1146105a0578063dd62ed3e146105b5578063f2fde38b146105fb576101b1565b806370a0823114610488578063715018a6146104be57806385ed706d146104d35780638da5cb5b146104f357806395d89b411461051b576101b1565b806323b872dd116100fd57806323b872dd14610296578063313ce567146102b65780633ccfd60b146102d257806347d1e46e146102e757806353d7da60146103015780635c12cd4b14610446576101b1565b806306fdde03146101f9578063095ea7b31461022457806313820ba71461025457806318160ddd146102775780631aa3a0081461028c576101b1565b366101b15760405162461bcd60e51b815260206004820152603f60248201527f4e6f20706c61696e2045746865722061636365707465642c207573652072656760448201527f697374657228292066756e6374696f6e20746f20636865636b20696e203a290060648201526084015b60405180910390fd5b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2066616c6c6261636b2063616c6c7320616363657074656400000000000060448201526064016101a8565b34801561020557600080fd5b5061020e61061b565b60405161021b9190611396565b60405180910390f35b34801561023057600080fd5b5061024461023f366004611400565b6106ad565b604051901515815260200161021b565b34801561026057600080fd5b50610269600f81565b60405190815260200161021b565b34801561028357600080fd5b50600254610269565b6102946106c7565b005b3480156102a257600080fd5b506102446102b136600461142a565b6108ab565b3480156102c257600080fd5b506040516004815260200161021b565b3480156102de57600080fd5b506102946108cf565b3480156102f357600080fd5b50610269652d79883d200081565b34801561030d57600080fd5b506103f061031c366004611467565b6040805160c081018252600060a082018181528252825160208082018552828252808401919091528351808201855282815283850152835190810190935280835260608201929092526080810191909152506001600160a01b0316600090815260076020908152604091829020825160c081018452815461ffff90811660a08301908152825284518085018652600184015482168152828501528451808501865260028401548216815282860152845193840190945260038201549093168252606083019190915260040154608082015290565b60405161021b9190600060a08201905061ffff83515116825261ffff60208401515116602083015261ffff60408401515116604083015261ffff6060840151511660608301526080830151608083015292915050565b34801561045257600080fd5b50610466610461366004611467565b610913565b604080518251815260208084015190820152918101519082015260600161021b565b34801561049457600080fd5b506102696104a3366004611467565b6001600160a01b031660009081526020819052604090205490565b3480156104ca57600080fd5b50610294610979565b3480156104df57600080fd5b506102946104ee366004611489565b61098d565b3480156104ff57600080fd5b506005546040516001600160a01b03909116815260200161021b565b34801561052757600080fd5b5061020e610c64565b34801561053c57600080fd5b50610294610c73565b34801561055157600080fd5b50610244610560366004611400565b610daf565b34801561057157600080fd5b50610244610580366004611467565b6001600160a01b0316600090815260066020526040902060010154151590565b3480156105ac57600080fd5b50610269610dbd565b3480156105c157600080fd5b506102696105d03660046114cf565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b34801561060757600080fd5b50610294610616366004611467565b610dd7565b60606003805461062a90611502565b80601f016020809104026020016040519081016040528092919081815260200182805461065690611502565b80156106a35780601f10610678576101008083540402835291602001916106a3565b820191906000526020600020905b81548152906001019060200180831161068657829003601f168201915b5050505050905090565b6000336106bb818585610e12565b60019150505b92915050565b33600090815260066020526040902060010154156107275760405162461bcd60e51b815260206004820181905260248201527f57686f6f70732c20706c6179657220616c726561647920657869737473203a2960448201526064016101a8565b652d79883d2000341461077c5760405162461bcd60e51b815260206004820152601760248201527f496e636f72726563742062757920696e20616d6f756e7400000000000000000060448201526064016101a8565b61079c3361078c6004600a611639565b610797906032611648565b610e24565b60405180606001604052806004600a6107b59190611639565b6107c0906032611648565b815242602080830182905260409283019190915233600081815260068352838120855181558584015160018083019190915595850151600291820155845160c08101865260a0810183815281528551808601875283815281860190815286518087018852848152828801908152875180880189528581526060840190815260808401868152968652600790975296909320905151815461ffff1990811661ffff92831617835593515197820180548516988216989098179097559451519085018054831691871691909117905591515160038401805490931694169390931790559051600490910155565b6000336108b9858285610e5e565b6108c4858585610edc565b506001949350505050565b6108d7610f3b565b6005546040516001600160a01b03909116904780156108fc02916000818181858888f19350505050158015610910573d6000803e3d6000fd5b50565b61093760405180606001604052806000815260200160008152602001600081525090565b506001600160a01b0316600090815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b610981610f3b565b61098b6000610f68565b565b3360009081526006602052604081206001015490036109e85760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101a8565b60038260ff161115610a2b5760405162461bcd60e51b815260206004820152600c60248201526b155b9adb9bdddb881d5b9a5d60a21b60448201526064016101a8565b3360009081526007602052604081209060ff84168103610a515750805461ffff16610a9b565b8360ff16600103610a6b5750600181015461ffff16610a9b565b8360ff16600203610a855750600281015461ffff16610a9b565b8360ff16600303610a9b5750600381015461ffff165b6000610aa8858386610fba565b336000908152602081905260409020549091508110610b095760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682047454c4420746f206164642074686973206d75636860448201526064016101a8565b610b13338261107c565b8460ff16600003610b5557825484908490600090610b3690849061ffff1661165f565b92506101000a81548161ffff021916908361ffff160217905550610be2565b8460ff16600103610b7b57600183018054859190600090610b3690849061ffff1661165f565b8460ff16600203610ba157600283018054859190600090610b3690849061ffff1661165f565b8460ff16600303610be257600383018054859190600090610bc790849061ffff1661165f565b92506101000a81548161ffff021916908361ffff1602179055505b6040805160c081018252845461ffff90811660a08301908152825282516020818101855260018801548316825280840191909152835180820185526002880154831681528385015283519081019093526003860154168252606081019190915260048401546080820152610c55906110b2565b83600401819055505050505050565b60606004805461062a90611502565b336000908152600660205260408120600101549003610cce5760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101a8565b33600090815260066020526040902060020154610ced90600f90611679565b421015610d355760405162461bcd60e51b81526020600482015260166024820152752a3934b2b21036b4b73a34b733903a37b79039b7b7b760511b60448201526064016101a8565b33600090815260066020526040812060020154610d52904261168c565b90506000610d626004600a611639565b33600090815260076020526040902060040154610d80908490611648565b610d8a9190611648565b9050610d963382610e24565b3360009081526006602052604090204260028201555550565b6000336106bb818585610edc565b610dc96004600a611639565b610dd4906032611648565b81565b610ddf610f3b565b6001600160a01b038116610e0957604051631e4fbdf760e01b8152600060048201526024016101a8565b61091081610f68565b610e1f8383836001611197565b505050565b6001600160a01b038216610e4e5760405163ec442f0560e01b8152600060048201526024016101a8565b610e5a6000838361126c565b5050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610ed65781811015610ec757604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016101a8565b610ed684848484036000611197565b50505050565b6001600160a01b038316610f0657604051634b637e8f60e11b8152600060048201526024016101a8565b6001600160a01b038216610f305760405163ec442f0560e01b8152600060048201526024016101a8565b610e1f83838361126c565b6005546001600160a01b0316331461098b5760405163118cdaa760e01b81523360048201526024016101a8565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060038460ff1611156110095760405162461bcd60e51b8152602060048201526016602482015275139bc81b585d18da1a5b99c81d5b9a5d08199bdd5b9960521b60448201526064016101a8565b600061101960ff86166026611648565b90506000607360015b61102c868861165f565b61ffff168110156110705760646110438386611648565b61104d91906116b5565b93508661ffff16811115611068576110658484611679565b92505b600101611022565b50909695505050505050565b6001600160a01b0382166110a657604051634b637e8f60e11b8152600060048201526024016101a8565b610e5a8260008361126c565b80515160208201515160009161ffff16908290600a906110d390603d6116c9565b6110dd91906116ed565b61ffff1690506000600a85604001516000015160066110fc91906116c9565b6111079060406116c9565b61111191906116ed565b61ffff1690506000600a80600a886060015160000151603d61113391906116c9565b61113d91906116ed565b6111489060406116c9565b61115291906116ed565b61115d9060436116c9565b61116791906116ed565b61ffff16905080826111798587611679565b6111839190611679565b61118d9190611679565b9695505050505050565b6001600160a01b0384166111c15760405163e602df0560e01b8152600060048201526024016101a8565b6001600160a01b0383166111eb57604051634a1406b160e11b8152600060048201526024016101a8565b6001600160a01b0380851660009081526001602090815260408083209387168352929052208290558015610ed657826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161125e91815260200190565b60405180910390a350505050565b6001600160a01b03831661129757806002600082825461128c9190611679565b909155506113099050565b6001600160a01b038316600090815260208190526040902054818110156112ea5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016101a8565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661132557600280548290039055611344565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161138991815260200190565b60405180910390a3505050565b602081526000825180602084015260005b818110156113c457602081860181015160408684010152016113a7565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b03811681146113fb57600080fd5b919050565b6000806040838503121561141357600080fd5b61141c836113e4565b946020939093013593505050565b60008060006060848603121561143f57600080fd5b611448846113e4565b9250611456602085016113e4565b929592945050506040919091013590565b60006020828403121561147957600080fd5b611482826113e4565b9392505050565b6000806040838503121561149c57600080fd5b823560ff811681146114ad57600080fd5b9150602083013561ffff811681146114c457600080fd5b809150509250929050565b600080604083850312156114e257600080fd5b6114eb836113e4565b91506114f9602084016113e4565b90509250929050565b600181811c9082168061151657607f821691505b60208210810361153657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b6001815b600184111561158d578085048111156115715761157161153c565b600184161561157f57908102905b60019390931c928002611556565b935093915050565b6000826115a4575060016106c1565b816115b1575060006106c1565b81600181146115c757600281146115d1576115ed565b60019150506106c1565b60ff8411156115e2576115e261153c565b50506001821b6106c1565b5060208310610133831016604e8410600b8410161715611610575081810a6106c1565b61161d6000198484611552565b80600019048211156116315761163161153c565b029392505050565b600061148260ff841683611595565b80820281158282048414176106c1576106c161153c565b61ffff81811683821601908111156106c1576106c161153c565b808201808211156106c1576106c161153c565b818103818111156106c1576106c161153c565b634e487b7160e01b600052601260045260246000fd5b6000826116c4576116c461169f565b500490565b61ffff81811683821602908116908181146116e6576116e661153c565b5092915050565b600061ffff8316806117015761170161169f565b8061ffff8416049150509291505056fea2646970667358221220061f190eb2f6fddd15161a6db096edf6e4a5b06217867d89e6792c032ada56e764736f6c634300081c0033", - "nonce": "0x0", - "chainId": "0x14a34" - }, - "additionalContracts": [], - "isFixedGasLimit": false - } - ], - "receipts": [ - { - "status": "0x1", - "cumulativeGasUsed": "0x3dfdcd", - "logs": [ - { - "address": "0xbd06b0878888bf4c6895704fa603a5adf7e65c66", - "topics": [ - "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000003295cca2d922c637d35b258fc6c9c7e471803b45" - ], - "data": "0x", - "blockHash": "0xe82c2fd01054c42c857cd623a9f0bd0486c97c47b55d8504798371063e4a1614", - "blockNumber": "0x102da20", - "transactionHash": "0x9d39df7a47137565fa4dfd579c92e4a90db9ae54490630585e878d7313ce15a7", - "transactionIndex": "0xe", - "logIndex": "0x19", - "removed": false - } - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000800008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000020000000000000000000800000000000004000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000010000000000000001000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "type": "0x2", - "transactionHash": "0x9d39df7a47137565fa4dfd579c92e4a90db9ae54490630585e878d7313ce15a7", - "transactionIndex": "0xe", - "blockHash": "0xe82c2fd01054c42c857cd623a9f0bd0486c97c47b55d8504798371063e4a1614", - "blockNumber": "0x102da20", - "gasUsed": "0x15a576", - "effectiveGasPrice": "0xa0f5edca", - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "to": null, - "contractAddress": "0xbd06b0878888bf4c6895704fa603a5adf7e65c66", - "l1BaseFeeScalar": "0x44d", - "l1BlobBaseFee": "0x3", - "l1BlobBaseFeeScalar": "0xa118b", - "l1Fee": "0x22c9f9127e", - "l1GasPrice": "0x84641d16", - "l1GasUsed": "0xeeab" - } - ], - "libraries": [], - "pending": [], - "returns": {}, - "timestamp": 1729696549, - "chain": 84532, - "commit": "830beab" -} \ No newline at end of file diff --git a/broadcast/RaidGeld.s.sol/84532/run-1729773387.json b/broadcast/RaidGeld.s.sol/84532/run-1729773387.json deleted file mode 100644 index 76fb6d9..0000000 --- a/broadcast/RaidGeld.s.sol/84532/run-1729773387.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "transactions": [ - { - "hash": "0xd4fa77c04f44634b166b7ae80cabe097cf35d8d38ea569e499b73310623501d9", - "transactionType": "CREATE", - "contractName": "RaidGeld", - "contractAddress": "0x3572a80eb8df722c98814290f86be29141859660", - "function": null, - "arguments": null, - "transaction": { - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "gas": "0x1c9543", - "value": "0x0", - "input": "0x608060405234801561001057600080fd5b50336040518060400160405280600981526020016814985a590811d95b1960ba1b8152506040518060400160405280600481526020016311d1531160e21b8152508160039081610060919061019e565b50600461006d828261019e565b5050506001600160a01b03811661009e57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100a7816100ad565b5061025c565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061012957607f821691505b60208210810361014957634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561019957806000526020600020601f840160051c810160208510156101765750805b601f840160051c820191505b818110156101965760008155600101610182565b50505b505050565b81516001600160401b038111156101b7576101b76100ff565b6101cb816101c58454610115565b8461014f565b6020601f8211600181146101ff57600083156101e75750848201515b600019600385901b1c1916600184901b178455610196565b600084815260208120601f198516915b8281101561022f578785015182556020948501946001909201910161020f565b508482101561024d5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b6117b08061026b6000396000f3fe6080604052600436106101395760003560e01c806370a08231116100ab578063a7db742f1161006f578063a7db742f14610530578063a9059cbb14610545578063c3c5a54714610565578063c861dcb1146105a0578063dd62ed3e146105b5578063f2fde38b146105fb576101b1565b806370a0823114610488578063715018a6146104be57806385ed706d146104d35780638da5cb5b146104f357806395d89b411461051b576101b1565b806323b872dd116100fd57806323b872dd14610296578063313ce567146102b65780633ccfd60b146102d257806347d1e46e146102e757806353d7da60146103015780635c12cd4b14610446576101b1565b806306fdde03146101f9578063095ea7b31461022457806313820ba71461025457806318160ddd146102775780631aa3a0081461028c576101b1565b366101b15760405162461bcd60e51b815260206004820152603f60248201527f4e6f20706c61696e2045746865722061636365707465642c207573652072656760448201527f697374657228292066756e6374696f6e20746f20636865636b20696e203a290060648201526084015b60405180910390fd5b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2066616c6c6261636b2063616c6c7320616363657074656400000000000060448201526064016101a8565b34801561020557600080fd5b5061020e61061b565b60405161021b91906113e6565b60405180910390f35b34801561023057600080fd5b5061024461023f366004611450565b6106ad565b604051901515815260200161021b565b34801561026057600080fd5b50610269600f81565b60405190815260200161021b565b34801561028357600080fd5b50600254610269565b6102946106c7565b005b3480156102a257600080fd5b506102446102b136600461147a565b6108ab565b3480156102c257600080fd5b506040516004815260200161021b565b3480156102de57600080fd5b506102946108cf565b3480156102f357600080fd5b50610269652d79883d200081565b34801561030d57600080fd5b506103f061031c3660046114b7565b6040805160c081018252600060a082018181528252825160208082018552828252808401919091528351808201855282815283850152835190810190935280835260608201929092526080810191909152506001600160a01b0316600090815260076020908152604091829020825160c081018452815461ffff90811660a08301908152825284518085018652600184015482168152828501528451808501865260028401548216815282860152845193840190945260038201549093168252606083019190915260040154608082015290565b60405161021b9190600060a08201905061ffff83515116825261ffff60208401515116602083015261ffff60408401515116604083015261ffff6060840151511660608301526080830151608083015292915050565b34801561045257600080fd5b506104666104613660046114b7565b610913565b604080518251815260208084015190820152918101519082015260600161021b565b34801561049457600080fd5b506102696104a33660046114b7565b6001600160a01b031660009081526020819052604090205490565b3480156104ca57600080fd5b50610294610979565b3480156104df57600080fd5b506102946104ee3660046114d9565b61098d565b3480156104ff57600080fd5b506005546040516001600160a01b03909116815260200161021b565b34801561052757600080fd5b5061020e610c83565b34801561053c57600080fd5b50610294610c92565b34801561055157600080fd5b50610244610560366004611450565b610d5d565b34801561057157600080fd5b506102446105803660046114b7565b6001600160a01b0316600090815260066020526040902060010154151590565b3480156105ac57600080fd5b50610269610d6b565b3480156105c157600080fd5b506102696105d036600461151f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b34801561060757600080fd5b506102946106163660046114b7565b610d85565b60606003805461062a90611552565b80601f016020809104026020016040519081016040528092919081815260200182805461065690611552565b80156106a35780601f10610678576101008083540402835291602001916106a3565b820191906000526020600020905b81548152906001019060200180831161068657829003601f168201915b5050505050905090565b6000336106bb818585610dc0565b60019150505b92915050565b33600090815260066020526040902060010154156107275760405162461bcd60e51b815260206004820181905260248201527f57686f6f70732c20706c6179657220616c726561647920657869737473203a2960448201526064016101a8565b652d79883d2000341461077c5760405162461bcd60e51b815260206004820152601760248201527f496e636f72726563742062757920696e20616d6f756e7400000000000000000060448201526064016101a8565b61079c3361078c6004600a611689565b610797906032611698565b610dd2565b60405180606001604052806004600a6107b59190611689565b6107c0906032611698565b815242602080830182905260409283019190915233600081815260068352838120855181558584015160018083019190915595850151600291820155845160c08101865260a0810183815281528551808601875283815281860190815286518087018852848152828801908152875180880189528581526060840190815260808401868152968652600790975296909320905151815461ffff1990811661ffff92831617835593515197820180548516988216989098179097559451519085018054831691871691909117905591515160038401805490931694169390931790559051600490910155565b6000336108b9858285610e0c565b6108c4858585610e8a565b506001949350505050565b6108d7610ee9565b6005546040516001600160a01b03909116904780156108fc02916000818181858888f19350505050158015610910573d6000803e3d6000fd5b50565b61093760405180606001604052806000815260200160008152602001600081525090565b506001600160a01b0316600090815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b610981610ee9565b61098b6000610f16565b565b3360009081526006602052604081206001015490036109e85760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101a8565b60038260ff161115610a2b5760405162461bcd60e51b815260206004820152600c60248201526b155b9adb9bdddb881d5b9a5d60a21b60448201526064016101a8565b3360009081526007602052604081209060ff84168103610a515750805461ffff16610a9b565b8360ff16600103610a6b5750600181015461ffff16610a9b565b8360ff16600203610a855750600281015461ffff16610a9b565b8360ff16600303610a9b5750600381015461ffff165b6000610aa96004600a611689565b610ab4868487610f68565b610abe9190611698565b336000908152602081905260409020549091508110610b1f5760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682047454c4420746f206164642074686973206d75636860448201526064016101a8565b610b2833611033565b610b3233826110cc565b8460ff16600003610b7457825484908490600090610b5590849061ffff166116af565b92506101000a81548161ffff021916908361ffff160217905550610c01565b8460ff16600103610b9a57600183018054859190600090610b5590849061ffff166116af565b8460ff16600203610bc057600283018054859190600090610b5590849061ffff166116af565b8460ff16600303610c0157600383018054859190600090610be690849061ffff166116af565b92506101000a81548161ffff021916908361ffff1602179055505b6040805160c081018252845461ffff90811660a08301908152825282516020818101855260018801548316825280840191909152835180820185526002880154831681528385015283519081019093526003860154168252606081019190915260048401546080820152610c7490611102565b83600401819055505050505050565b60606004805461062a90611552565b336000908152600660205260408120600101549003610ced5760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101a8565b33600090815260066020526040902060020154610d0c90600f906116c9565b421015610d545760405162461bcd60e51b81526020600482015260166024820152752a3934b2b21036b4b73a34b733903a37b79039b7b7b760511b60448201526064016101a8565b61098b33611033565b6000336106bb818585610e8a565b610d776004600a611689565b610d82906032611698565b81565b610d8d610ee9565b6001600160a01b038116610db757604051631e4fbdf760e01b8152600060048201526024016101a8565b61091081610f16565b610dcd83838360016111e7565b505050565b6001600160a01b038216610dfc5760405163ec442f0560e01b8152600060048201526024016101a8565b610e08600083836112bc565b5050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610e845781811015610e7557604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016101a8565b610e84848484840360006111e7565b50505050565b6001600160a01b038316610eb457604051634b637e8f60e11b8152600060048201526024016101a8565b6001600160a01b038216610ede5760405163ec442f0560e01b8152600060048201526024016101a8565b610dcd8383836112bc565b6005546001600160a01b0316331461098b5760405163118cdaa760e01b81523360048201526024016101a8565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060038460ff161115610fb75760405162461bcd60e51b8152602060048201526016602482015275139bc81b585d18da1a5b99c81d5b9a5d08199bdd5b9960521b60448201526064016101a8565b6000610fc48560016116dc565b610fd29060ff166026611698565b905080607360015b610fe486886116af565b61ffff16811015611027576064610ffb8386611698565b611005919061170b565b93508661ffff16811061101f5761101c84846116c9565b92505b600101610fda565b50909695505050505050565b6001600160a01b038116600090815260066020526040812060020154611059904261171f565b905060006110696004600a611689565b6001600160a01b038416600090815260076020526040902060040154611090908490611698565b61109a9190611698565b90506110a68382610dd2565b6001600160a01b0390921660009081526006602052604090204260028201559190915550565b6001600160a01b0382166110f657604051634b637e8f60e11b8152600060048201526024016101a8565b610e08826000836112bc565b80515160208201515160009161ffff16908290600a9061112390603d611732565b61112d9190611756565b61ffff1690506000600a856040015160000151600661114c9190611732565b611157906040611732565b6111619190611756565b61ffff1690506000600a80600a886060015160000151603d6111839190611732565b61118d9190611756565b611198906040611732565b6111a29190611756565b6111ad906043611732565b6111b79190611756565b61ffff16905080826111c985876116c9565b6111d391906116c9565b6111dd91906116c9565b9695505050505050565b6001600160a01b0384166112115760405163e602df0560e01b8152600060048201526024016101a8565b6001600160a01b03831661123b57604051634a1406b160e11b8152600060048201526024016101a8565b6001600160a01b0380851660009081526001602090815260408083209387168352929052208290558015610e8457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516112ae91815260200190565b60405180910390a350505050565b6001600160a01b0383166112e75780600260008282546112dc91906116c9565b909155506113599050565b6001600160a01b0383166000908152602081905260409020548181101561133a5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016101a8565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661137557600280548290039055611394565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516113d991815260200190565b60405180910390a3505050565b602081526000825180602084015260005b8181101561141457602081860181015160408684010152016113f7565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b038116811461144b57600080fd5b919050565b6000806040838503121561146357600080fd5b61146c83611434565b946020939093013593505050565b60008060006060848603121561148f57600080fd5b61149884611434565b92506114a660208501611434565b929592945050506040919091013590565b6000602082840312156114c957600080fd5b6114d282611434565b9392505050565b600080604083850312156114ec57600080fd5b823560ff811681146114fd57600080fd5b9150602083013561ffff8116811461151457600080fd5b809150509250929050565b6000806040838503121561153257600080fd5b61153b83611434565b915061154960208401611434565b90509250929050565b600181811c9082168061156657607f821691505b60208210810361158657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b6001815b60018411156115dd578085048111156115c1576115c161158c565b60018416156115cf57908102905b60019390931c9280026115a6565b935093915050565b6000826115f4575060016106c1565b81611601575060006106c1565b816001811461161757600281146116215761163d565b60019150506106c1565b60ff8411156116325761163261158c565b50506001821b6106c1565b5060208310610133831016604e8410600b8410161715611660575081810a6106c1565b61166d60001984846115a2565b80600019048211156116815761168161158c565b029392505050565b60006114d260ff8416836115e5565b80820281158282048414176106c1576106c161158c565b61ffff81811683821601908111156106c1576106c161158c565b808201808211156106c1576106c161158c565b60ff81811683821601908111156106c1576106c161158c565b634e487b7160e01b600052601260045260246000fd5b60008261171a5761171a6116f5565b500490565b818103818111156106c1576106c161158c565b61ffff818116838216029081169081811461174f5761174f61158c565b5092915050565b600061ffff83168061176a5761176a6116f5565b8061ffff8416049150509291505056fea2646970667358221220313cc1e5e86bbb7d3c3ded2bd7a034c1d5ffeb6733733567e3c8f6b4f041b55864736f6c634300081c0033", - "nonce": "0x7", - "chainId": "0x14a34" - }, - "additionalContracts": [], - "isFixedGasLimit": false - } - ], - "receipts": [ - { - "status": "0x1", - "cumulativeGasUsed": "0x1f8453", - "logs": [ - { - "address": "0x3572a80eb8df722c98814290f86be29141859660", - "topics": [ - "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000003295cca2d922c637d35b258fc6c9c7e471803b45" - ], - "data": "0x", - "blockHash": "0x9708bb1125f0e43dc1ffc445a674ebbf03f5e0c95bf8f803027fe0b8a64492dd", - "blockNumber": "0x1037033", - "transactionHash": "0xd4fa77c04f44634b166b7ae80cabe097cf35d8d38ea569e499b73310623501d9", - "transactionIndex": "0x7", - "logIndex": "0x7", - "removed": false - } - ], - "logsBloom": "0x00000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "type": "0x2", - "transactionHash": "0xd4fa77c04f44634b166b7ae80cabe097cf35d8d38ea569e499b73310623501d9", - "transactionIndex": "0x7", - "blockHash": "0x9708bb1125f0e43dc1ffc445a674ebbf03f5e0c95bf8f803027fe0b8a64492dd", - "blockNumber": "0x1037033", - "gasUsed": "0x15fe4c", - "effectiveGasPrice": "0x13b3f9", - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "to": null, - "contractAddress": "0x3572a80eb8df722c98814290f86be29141859660", - "l1BaseFeeScalar": "0x44d", - "l1BlobBaseFee": "0x1", - "l1BlobBaseFeeScalar": "0xa118b", - "l1Fee": "0x664fcff1ad", - "l1GasPrice": "0x17fe2ef41", - "l1GasUsed": "0xf211" - } - ], - "libraries": [], - "pending": [], - "returns": {}, - "timestamp": 1729773387, - "chain": 84532, - "commit": "cb12c77" -} \ No newline at end of file diff --git a/broadcast/RaidGeld.s.sol/84532/run-latest.json b/broadcast/RaidGeld.s.sol/84532/run-latest.json deleted file mode 100644 index 76fb6d9..0000000 --- a/broadcast/RaidGeld.s.sol/84532/run-latest.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "transactions": [ - { - "hash": "0xd4fa77c04f44634b166b7ae80cabe097cf35d8d38ea569e499b73310623501d9", - "transactionType": "CREATE", - "contractName": "RaidGeld", - "contractAddress": "0x3572a80eb8df722c98814290f86be29141859660", - "function": null, - "arguments": null, - "transaction": { - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "gas": "0x1c9543", - "value": "0x0", - "input": "0x608060405234801561001057600080fd5b50336040518060400160405280600981526020016814985a590811d95b1960ba1b8152506040518060400160405280600481526020016311d1531160e21b8152508160039081610060919061019e565b50600461006d828261019e565b5050506001600160a01b03811661009e57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100a7816100ad565b5061025c565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061012957607f821691505b60208210810361014957634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561019957806000526020600020601f840160051c810160208510156101765750805b601f840160051c820191505b818110156101965760008155600101610182565b50505b505050565b81516001600160401b038111156101b7576101b76100ff565b6101cb816101c58454610115565b8461014f565b6020601f8211600181146101ff57600083156101e75750848201515b600019600385901b1c1916600184901b178455610196565b600084815260208120601f198516915b8281101561022f578785015182556020948501946001909201910161020f565b508482101561024d5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b6117b08061026b6000396000f3fe6080604052600436106101395760003560e01c806370a08231116100ab578063a7db742f1161006f578063a7db742f14610530578063a9059cbb14610545578063c3c5a54714610565578063c861dcb1146105a0578063dd62ed3e146105b5578063f2fde38b146105fb576101b1565b806370a0823114610488578063715018a6146104be57806385ed706d146104d35780638da5cb5b146104f357806395d89b411461051b576101b1565b806323b872dd116100fd57806323b872dd14610296578063313ce567146102b65780633ccfd60b146102d257806347d1e46e146102e757806353d7da60146103015780635c12cd4b14610446576101b1565b806306fdde03146101f9578063095ea7b31461022457806313820ba71461025457806318160ddd146102775780631aa3a0081461028c576101b1565b366101b15760405162461bcd60e51b815260206004820152603f60248201527f4e6f20706c61696e2045746865722061636365707465642c207573652072656760448201527f697374657228292066756e6374696f6e20746f20636865636b20696e203a290060648201526084015b60405180910390fd5b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2066616c6c6261636b2063616c6c7320616363657074656400000000000060448201526064016101a8565b34801561020557600080fd5b5061020e61061b565b60405161021b91906113e6565b60405180910390f35b34801561023057600080fd5b5061024461023f366004611450565b6106ad565b604051901515815260200161021b565b34801561026057600080fd5b50610269600f81565b60405190815260200161021b565b34801561028357600080fd5b50600254610269565b6102946106c7565b005b3480156102a257600080fd5b506102446102b136600461147a565b6108ab565b3480156102c257600080fd5b506040516004815260200161021b565b3480156102de57600080fd5b506102946108cf565b3480156102f357600080fd5b50610269652d79883d200081565b34801561030d57600080fd5b506103f061031c3660046114b7565b6040805160c081018252600060a082018181528252825160208082018552828252808401919091528351808201855282815283850152835190810190935280835260608201929092526080810191909152506001600160a01b0316600090815260076020908152604091829020825160c081018452815461ffff90811660a08301908152825284518085018652600184015482168152828501528451808501865260028401548216815282860152845193840190945260038201549093168252606083019190915260040154608082015290565b60405161021b9190600060a08201905061ffff83515116825261ffff60208401515116602083015261ffff60408401515116604083015261ffff6060840151511660608301526080830151608083015292915050565b34801561045257600080fd5b506104666104613660046114b7565b610913565b604080518251815260208084015190820152918101519082015260600161021b565b34801561049457600080fd5b506102696104a33660046114b7565b6001600160a01b031660009081526020819052604090205490565b3480156104ca57600080fd5b50610294610979565b3480156104df57600080fd5b506102946104ee3660046114d9565b61098d565b3480156104ff57600080fd5b506005546040516001600160a01b03909116815260200161021b565b34801561052757600080fd5b5061020e610c83565b34801561053c57600080fd5b50610294610c92565b34801561055157600080fd5b50610244610560366004611450565b610d5d565b34801561057157600080fd5b506102446105803660046114b7565b6001600160a01b0316600090815260066020526040902060010154151590565b3480156105ac57600080fd5b50610269610d6b565b3480156105c157600080fd5b506102696105d036600461151f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b34801561060757600080fd5b506102946106163660046114b7565b610d85565b60606003805461062a90611552565b80601f016020809104026020016040519081016040528092919081815260200182805461065690611552565b80156106a35780601f10610678576101008083540402835291602001916106a3565b820191906000526020600020905b81548152906001019060200180831161068657829003601f168201915b5050505050905090565b6000336106bb818585610dc0565b60019150505b92915050565b33600090815260066020526040902060010154156107275760405162461bcd60e51b815260206004820181905260248201527f57686f6f70732c20706c6179657220616c726561647920657869737473203a2960448201526064016101a8565b652d79883d2000341461077c5760405162461bcd60e51b815260206004820152601760248201527f496e636f72726563742062757920696e20616d6f756e7400000000000000000060448201526064016101a8565b61079c3361078c6004600a611689565b610797906032611698565b610dd2565b60405180606001604052806004600a6107b59190611689565b6107c0906032611698565b815242602080830182905260409283019190915233600081815260068352838120855181558584015160018083019190915595850151600291820155845160c08101865260a0810183815281528551808601875283815281860190815286518087018852848152828801908152875180880189528581526060840190815260808401868152968652600790975296909320905151815461ffff1990811661ffff92831617835593515197820180548516988216989098179097559451519085018054831691871691909117905591515160038401805490931694169390931790559051600490910155565b6000336108b9858285610e0c565b6108c4858585610e8a565b506001949350505050565b6108d7610ee9565b6005546040516001600160a01b03909116904780156108fc02916000818181858888f19350505050158015610910573d6000803e3d6000fd5b50565b61093760405180606001604052806000815260200160008152602001600081525090565b506001600160a01b0316600090815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b610981610ee9565b61098b6000610f16565b565b3360009081526006602052604081206001015490036109e85760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101a8565b60038260ff161115610a2b5760405162461bcd60e51b815260206004820152600c60248201526b155b9adb9bdddb881d5b9a5d60a21b60448201526064016101a8565b3360009081526007602052604081209060ff84168103610a515750805461ffff16610a9b565b8360ff16600103610a6b5750600181015461ffff16610a9b565b8360ff16600203610a855750600281015461ffff16610a9b565b8360ff16600303610a9b5750600381015461ffff165b6000610aa96004600a611689565b610ab4868487610f68565b610abe9190611698565b336000908152602081905260409020549091508110610b1f5760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682047454c4420746f206164642074686973206d75636860448201526064016101a8565b610b2833611033565b610b3233826110cc565b8460ff16600003610b7457825484908490600090610b5590849061ffff166116af565b92506101000a81548161ffff021916908361ffff160217905550610c01565b8460ff16600103610b9a57600183018054859190600090610b5590849061ffff166116af565b8460ff16600203610bc057600283018054859190600090610b5590849061ffff166116af565b8460ff16600303610c0157600383018054859190600090610be690849061ffff166116af565b92506101000a81548161ffff021916908361ffff1602179055505b6040805160c081018252845461ffff90811660a08301908152825282516020818101855260018801548316825280840191909152835180820185526002880154831681528385015283519081019093526003860154168252606081019190915260048401546080820152610c7490611102565b83600401819055505050505050565b60606004805461062a90611552565b336000908152600660205260408120600101549003610ced5760405162461bcd60e51b81526020600482015260176024820152762737ba1030b71034b734ba34b0ba32b210383630bcb2b960491b60448201526064016101a8565b33600090815260066020526040902060020154610d0c90600f906116c9565b421015610d545760405162461bcd60e51b81526020600482015260166024820152752a3934b2b21036b4b73a34b733903a37b79039b7b7b760511b60448201526064016101a8565b61098b33611033565b6000336106bb818585610e8a565b610d776004600a611689565b610d82906032611698565b81565b610d8d610ee9565b6001600160a01b038116610db757604051631e4fbdf760e01b8152600060048201526024016101a8565b61091081610f16565b610dcd83838360016111e7565b505050565b6001600160a01b038216610dfc5760405163ec442f0560e01b8152600060048201526024016101a8565b610e08600083836112bc565b5050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610e845781811015610e7557604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016101a8565b610e84848484840360006111e7565b50505050565b6001600160a01b038316610eb457604051634b637e8f60e11b8152600060048201526024016101a8565b6001600160a01b038216610ede5760405163ec442f0560e01b8152600060048201526024016101a8565b610dcd8383836112bc565b6005546001600160a01b0316331461098b5760405163118cdaa760e01b81523360048201526024016101a8565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060038460ff161115610fb75760405162461bcd60e51b8152602060048201526016602482015275139bc81b585d18da1a5b99c81d5b9a5d08199bdd5b9960521b60448201526064016101a8565b6000610fc48560016116dc565b610fd29060ff166026611698565b905080607360015b610fe486886116af565b61ffff16811015611027576064610ffb8386611698565b611005919061170b565b93508661ffff16811061101f5761101c84846116c9565b92505b600101610fda565b50909695505050505050565b6001600160a01b038116600090815260066020526040812060020154611059904261171f565b905060006110696004600a611689565b6001600160a01b038416600090815260076020526040902060040154611090908490611698565b61109a9190611698565b90506110a68382610dd2565b6001600160a01b0390921660009081526006602052604090204260028201559190915550565b6001600160a01b0382166110f657604051634b637e8f60e11b8152600060048201526024016101a8565b610e08826000836112bc565b80515160208201515160009161ffff16908290600a9061112390603d611732565b61112d9190611756565b61ffff1690506000600a856040015160000151600661114c9190611732565b611157906040611732565b6111619190611756565b61ffff1690506000600a80600a886060015160000151603d6111839190611732565b61118d9190611756565b611198906040611732565b6111a29190611756565b6111ad906043611732565b6111b79190611756565b61ffff16905080826111c985876116c9565b6111d391906116c9565b6111dd91906116c9565b9695505050505050565b6001600160a01b0384166112115760405163e602df0560e01b8152600060048201526024016101a8565b6001600160a01b03831661123b57604051634a1406b160e11b8152600060048201526024016101a8565b6001600160a01b0380851660009081526001602090815260408083209387168352929052208290558015610e8457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516112ae91815260200190565b60405180910390a350505050565b6001600160a01b0383166112e75780600260008282546112dc91906116c9565b909155506113599050565b6001600160a01b0383166000908152602081905260409020548181101561133a5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016101a8565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661137557600280548290039055611394565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516113d991815260200190565b60405180910390a3505050565b602081526000825180602084015260005b8181101561141457602081860181015160408684010152016113f7565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b038116811461144b57600080fd5b919050565b6000806040838503121561146357600080fd5b61146c83611434565b946020939093013593505050565b60008060006060848603121561148f57600080fd5b61149884611434565b92506114a660208501611434565b929592945050506040919091013590565b6000602082840312156114c957600080fd5b6114d282611434565b9392505050565b600080604083850312156114ec57600080fd5b823560ff811681146114fd57600080fd5b9150602083013561ffff8116811461151457600080fd5b809150509250929050565b6000806040838503121561153257600080fd5b61153b83611434565b915061154960208401611434565b90509250929050565b600181811c9082168061156657607f821691505b60208210810361158657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b6001815b60018411156115dd578085048111156115c1576115c161158c565b60018416156115cf57908102905b60019390931c9280026115a6565b935093915050565b6000826115f4575060016106c1565b81611601575060006106c1565b816001811461161757600281146116215761163d565b60019150506106c1565b60ff8411156116325761163261158c565b50506001821b6106c1565b5060208310610133831016604e8410600b8410161715611660575081810a6106c1565b61166d60001984846115a2565b80600019048211156116815761168161158c565b029392505050565b60006114d260ff8416836115e5565b80820281158282048414176106c1576106c161158c565b61ffff81811683821601908111156106c1576106c161158c565b808201808211156106c1576106c161158c565b60ff81811683821601908111156106c1576106c161158c565b634e487b7160e01b600052601260045260246000fd5b60008261171a5761171a6116f5565b500490565b818103818111156106c1576106c161158c565b61ffff818116838216029081169081811461174f5761174f61158c565b5092915050565b600061ffff83168061176a5761176a6116f5565b8061ffff8416049150509291505056fea2646970667358221220313cc1e5e86bbb7d3c3ded2bd7a034c1d5ffeb6733733567e3c8f6b4f041b55864736f6c634300081c0033", - "nonce": "0x7", - "chainId": "0x14a34" - }, - "additionalContracts": [], - "isFixedGasLimit": false - } - ], - "receipts": [ - { - "status": "0x1", - "cumulativeGasUsed": "0x1f8453", - "logs": [ - { - "address": "0x3572a80eb8df722c98814290f86be29141859660", - "topics": [ - "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000003295cca2d922c637d35b258fc6c9c7e471803b45" - ], - "data": "0x", - "blockHash": "0x9708bb1125f0e43dc1ffc445a674ebbf03f5e0c95bf8f803027fe0b8a64492dd", - "blockNumber": "0x1037033", - "transactionHash": "0xd4fa77c04f44634b166b7ae80cabe097cf35d8d38ea569e499b73310623501d9", - "transactionIndex": "0x7", - "logIndex": "0x7", - "removed": false - } - ], - "logsBloom": "0x00000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "type": "0x2", - "transactionHash": "0xd4fa77c04f44634b166b7ae80cabe097cf35d8d38ea569e499b73310623501d9", - "transactionIndex": "0x7", - "blockHash": "0x9708bb1125f0e43dc1ffc445a674ebbf03f5e0c95bf8f803027fe0b8a64492dd", - "blockNumber": "0x1037033", - "gasUsed": "0x15fe4c", - "effectiveGasPrice": "0x13b3f9", - "from": "0x3295cca2d922c637d35b258fc6c9c7e471803b45", - "to": null, - "contractAddress": "0x3572a80eb8df722c98814290f86be29141859660", - "l1BaseFeeScalar": "0x44d", - "l1BlobBaseFee": "0x1", - "l1BlobBaseFeeScalar": "0xa118b", - "l1Fee": "0x664fcff1ad", - "l1GasPrice": "0x17fe2ef41", - "l1GasUsed": "0xf211" - } - ], - "libraries": [], - "pending": [], - "returns": {}, - "timestamp": 1729773387, - "chain": 84532, - "commit": "cb12c77" -} \ No newline at end of file diff --git a/deploy_contract.sh b/deploy_contract.sh index 8dc4b9a..667fc86 100755 --- a/deploy_contract.sh +++ b/deploy_contract.sh @@ -1,4 +1,23 @@ -#!/bin/sh -cast rpc anvil_setBalance 0x3295CCA2d922c637d35b258fc6c9C7e471803b45 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8545 -forge script script/RaidGeld.s.sol:RaidGeldScript --rpc-url 127.0.0.1:8545 --broadcast --private-key $DEV_PRIVATE_KEY -cast rpc anvil_mine +#!/bin/bash + +# YOUR WALLET, change to you account below: +DEV_WALLET="0x3295CCA2d922c637d35b258fc6c9C7e471803b45" + +DAO_OWNER="0x4d5A5B4a679b10038e1677C84Cb675d10d29fFFD" +DAO_CONTRACT="0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8" + +# Set balance for the dev wallet (1eth) +cast rpc anvil_setBalance $DEV_WALLET 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8545 +cast rpc anvil_setBalance $DAO_OWNER 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8545 + +# Deploy RaidGeld +forge script script/RaidGeld.s.sol:RaidGeldScript --rpc-url http://127.0.0.1:8545 --broadcast --private-key $DEV_PRIVATE_KEY + +# Impersonate the DAO owner account +cast rpc anvil_impersonateAccount $DAO_OWNER + +# Send the mint transaction as the impersonated owner +cast send $DAO_CONTRACT "mint(address,uint256)" $DEV_WALLET 0x00000000000000000000000000000000000000000000003635c9adc5dea00000 --from $DAO_OWNER --rpc-url http://127.0.0.1:8545 --unlocked --gas-limit 300000 + +# Stop impersonating the DAO owner +cast rpc anvil_stopImpersonatingAccount $DAO_OWNER From 6e0012e9d6369dd3353e5598b49be4f9f8adb440 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Mon, 28 Oct 2024 18:32:43 +0100 Subject: [PATCH 14/19] 31337 chain id is already in gitignore, whoops --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 53107fa..482352c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ # Compiler files cache/ out/ -broadcast/* # Ignores development broadcast logs !/broadcast From b584399d91d93a2dbadbb6e4bcd10c2269015390 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Mon, 28 Oct 2024 18:45:14 +0100 Subject: [PATCH 15/19] Makes the sprockets of the loading wheel a bit nicer color --- app/public/loader/hamster_wheel.png | Bin 53859 -> 52643 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/public/loader/hamster_wheel.png b/app/public/loader/hamster_wheel.png index 67874569d3e9902419f3bde0c38ac4ff8aa99060..e74c5551185197bdb36cec23a60a5ffc84161705 100644 GIT binary patch literal 52643 zcmV)ZK&!urP)1^@s6fgSkQ00001b5ch_0olnc ze*gdg32;bRa{vGf6951U69E94oEQKA%}7Z^K~#90?0pAVTSpe|W^1Zr(>tOgKp>&s zKn+j_AtWJ*B6{!5U}M1D1{?QYaPPfWa7&yxv7PD^JJ?PfJ5F(uEy-@O?|%dPvM;-v zWbKU|CpQ20oo_CeduQg1=AU!U+>2MDM7 z_C9i|Z_gtqkM4S8-`16Zn|kI*R?O{`ET7jYS+jViWK++4$>yH#; zTd;@c_yLLV^P9{F4VlIY51keh%qs-p>w?=#L2qd5Iqx-J8f0^r}Uo-ej?;S1%Iwss%h!7PmKn%kEXhi+c|4+&$uc zx7iSe@Uy_RORxS$#ALwdsp0T>^65eGdvXLQPdOuSm@|ThxghjuSA-3BL)ZvcggOm~ z3qnRXBV@QMf`|l?{|Auk{GW0f6rU%C!0e6tk=W*draStzk*4@$Ak zfnvLZ96L~!m4ou^Jk%DHpsBP1qbjR0rnVO2o0~DEy$zl19q4FkhA@(a7{3TG17pAo zWk4Lsfr1qegG`IeR2xdO%hA<7c3nxfIk7OqC@FH7C51T_iGv(#RZ>Z1XTRt#{0N&<2}6p{$6-~RSB`THw!{1sj}a~2UkK_IR<{D=g)c_G-t2ccg6i0}=7 zl+8hXd13qgZu21w;kK}CN*@;toHsaLYO@rx)o$GOY=UVh`U4>&i*5dfC^*FkH4UTSGP0p{!iQVM7 zeOriZ#YrM3_H04l&P_P7eLW6sS&ai5SK#1=9voahAj`46XCB^p;}uee*GbtI@b0Bc zxOVvpuD^Q~A6&mi27v20-g^uou7QItIMv-B4F3@D!XhDvAQqb%O|ZyJ(z|`-Q}_FK8p0616U!HNx^n5%we;}NzL>C(K5h){`2?}xotUuT_X0gV z5a8~K05^B6oY{@TTi0Xfy5-oqdNDREUw}<3mSD^3WjJ%}AnFUO=x(dU-0@9VGG!E& zOdXA7U9DI#y$$PUbznww3EB%RXw5ZYR8AV2vr^Gu*Q4H^j5@0hwdp!knKh^$I40-n zGYx3WHew{XzB$K?#>_NSS#&5#NkWl60r_eP90_7%$@oYYv0&uVAqfdUM`a)hPL8-bT!su(fC%ZnlTyc7Ib6ftWL}s+k)0S z3u<(-*Q&K~eWNl{`(`v$%h{z>#FHEck{Fui z>kD>J5MurPKcoBjen@q5yAtN=+8^rd+#lxV`VVn&xf1Zy2zWg?3|_;A!Jiz5I=Ori z(fv5@w(vt#N&M=F7FL;^?L8=-#m(8zx_R){@oui z;?c+8^w{GV{@4?E>i3V~DU!O8fniQt4fZbTz@7zd*uQWb4lSOH5cv7SAmZOFwWrC))D}~g&zVHI-@oY)9zfVq z)tpR|p->}_Gg}Rsyn;;27`sv1ZdNL$Ng|^mrqLjdrsCk{9^AO{7OwTbitF#3$Bj!b z;r)v*;@ZV$aq-+C%p6mVY~s3R>JwpA%Agl8V3Kl>rHn_uN(y_T6sc0hMuSAQ#iUT| zwN)8z8rREext%@^zrb9Qal@^}r|sswpmhFMZ>)G^A_w9zVhc%Yt3qofMy6kCFT zlBJ5Hn5CS+P-5){A4@&;G(w2=6^93(9aE9d*YKHvdLE0CpRA^|l;lw6Pimv=S+~UF z^ucX|`YKth#hyg=$u)&Ix@jf)wyi+l_GLJ^dnJj>*JAsMML2zA z@83)blB;5BXul{jtX~{U>m^>t43&`6u9u543+-tk_xa}^!Y>`{sIXb#6bizL#i06A zK=q>_k`hQ<+8|788Hts1CSgHm3pOvEfoqpu!8%!OD~cQ0`KeKEEsA9u6f1J8ARhYg1xA#fORjrqYry|;6p zmd~cqyuA|n)NpCKGEv%5TPj&FwL`LJ!wSZU13P{_aE;xV+UYsm89~l22qx}&&%oohNVp)m&~)+ESdsR(p)g6mVm;P&{F#Qhyc z;?Us;b@zlUmWlF=3>c&`ggd!`;}?MG%{5p#z5T8dILK`v)^$Q4iESgDJRl8^x-A0V z4p@=l?Y<-25bog(3L&v4(bM(uC*V%Rn+zBO=lq>Uz<2mCgpqi+B1MML7Ae}(<(S}5 zV@=mcoISZ0r;qJMi9wCxBpLFgVq}T=u<_Zj@rcC5Ll7CUDkjLUT`lIdt3)iBAe!>% z-O^zQ4=6sl{+6>;!1yRCn9?5=I|B*O*9%8v#KW1<^j92yrC@B9@6VVgx8ouJ9S*4ia;sz+}Yf{kzayTukCp zHzd*-*u1a{Yv+!;s|03{IGMz{#6r3t%Gne0NZMT^a8{bCx}~Dv{mJ#^*V{^SzbZ&h zK#oR&rkphBISgWv|1lxvLk5r#GLWRlabT0gB2&sjsZN54l@4@|sln8i3e0RS$1|Ij z;?(9vcy8AUym(+e&L7^4dE;6^^Y=rPyDPX9Ut}m12R8RCre1#Ie>Q+Uv(~YfA!30HWY-jI;cr7_ihVTnV zXGbHw#9@-gv1r?UoJYWG_|q_Il5q0yZXDjZ0W+txbCE zT8|@J)&KxHh-B>Bn6Bjhhl?*Iy9-w=8K^zg*pDc@SHzy{vXPflxdFiR`CE4li)rFa@ zW{u3mqEci@@l0(+k*#>s>V;v4cW-bzux&MM`?>{^b<3tnW=(36G*@OyENY=-Tw`hY zx9jrEj)mg~V%)=PyU}Dz2Fu$QFCKYVtiQv>acmMMuIg^WZg@{%>k)2orGQotk?K^`3iVQ2_A#5HCI4oEQA zK_TD%Ci+#GTr+Qh0Ff zJlzWi*1WQ-rwhv`)uTKm32a|KuqhO-zav|c@wKv&YRxK$B z^>F{x^RdU^`S|1Teey|^STyL{z7%^lEkxge9XNC9DEjtoMRBGP^`&_j+ti4G8Fo3B z1AaKESD-JpEu9y6&pXQyeqLC!e5zMvf$?CZzdIr+o``2gqGw(gc5hsUbxUWWXYORQ zH0+1VmpJG+&!d)ZW%?<;Hj+7&CG zIdlltq$DWlbYhtpIDKRvUVZL3+6oW1p}9jG}4*VNNVD-NXkMgI~GZiRB(xv<9PW(6CH_kAqQ3> zb`cMDAs1Ew8y0fCnM2AV<)ty1NFkzU#*(tQun_NJKx_gbxkro)F_Abv3X?>bTAB0r z`po1vs&omL+A{Um&K_Fz_XBHZ!@#4F`o%y%1{jk>e9oqdx0TtGeZQ|=A_FNwL2j;Z z`93}D-C#Gj&wYmtgOnDEQcDu@4H6WlsnAqp#;8&oHY}TgYwx^@&u-p;S)~G%40bFM zBg+E)&@*k4WFWsio0mVbWcI`-??HDN!p{Mt8w)*Z%IuDUY<-78EqFn}qkhE*^hRum zFN!k^c=wIx@$Oq^aQ))*c=hyNWE+*B66-Y}VZL4n@%8{A?(;GZoi?&OH*o6cs@s|s zy>;_)*%zOEh%!qCq>*%RLPD{B>qeYBxC2G08kktou<>J&FAd7_rY8e_xj9RB8byAZ1lH_oZ zcwQM52^xuE=_K~INqKnX_(mMrumECW5#z(DkVi$JAXVM>+~JLn{7}1C^qNQYaw%QG zV+R-6ZK6nTFT{9yAlAo=v{M*NaxSuy#V90%ZY^=skpRWHr2OJ%8A%;cY4bZes)L{#!8vt{s?w+2E}zIXZj?9V>BhWgwhD59C5 z6IV4!z#*=&kXX}b7+DPD%EYK3mcB|WLtSbTMp_6lZG@m1$rw!t+(Jk@KmZL}+j~wD5*hMU2Rf%$G5eJPMf zL_$g0MIFZho5b-n;)-*L>uunZd~}MJw)D*SUa#ce@y>;Fe_#ZW!P3nIp{^s~@AMRc zNE+laeDK)g$;VJrWXDUV_h4hsWSl*|1vf99$H(uSCvJB#{D(gU->07dD>U%po%f6( z{H!5lgg_-`K}$NMI64$H#EQ-6s6b;uDh_O1j5EDkacJujNSRUaA@MCOIN&c~zMfb8 z+@8Lyk@MFro;k_9Z~L0T$&wdO?5NtXe43@euC}gOF!{DDa8#Ev3^il3ydM9ci>(lfvL@x5mV_XVk1(PN1cdVs|s z50bK?KBZH9NJsNPo>76`jk9t7=t>;lu?RXb8%iM)Tw-Mhp5I0hv8AYYjBTn5<*oiA^oxVTKa^4w71WStOVbUa z<+G+x)-UX)^ln}4_spJ6?$00H{pgwAJ^#_kEs0WtBqHpJl0okmhJ~CIg@*PjVracq zsi?QjVgFPU9RoUvubBhyWt044ef>fA@f)06GYEKOu!$oir$fVKepzNzKUZ(nc6St| zx6f!UE}cKN#`W7}Rpyvo3ry-+%>}0GqpNKHoCs7)Sso!iP87E%eotwwt|%RtIP`k@ zX?Q#}3<2(LD6(5IaZD4MtMbr$Xe&OtaS4aFuR?)QMO=A*sF{JEo5j=oG!18oRD zGiVdJ0w&GxG9%LWYOYm_ma=R#E4HQBQ)E5ytcaer+C0g(|2K7XNoYr1&d%2A>;oBk#VcyQ z07j`Cc6Ac$B>v1-6L*)myoDsT%t;UvD;f)ZOc<18@X$qvW5%e;`W(HMk}j1{3X^q_ zBXhGA)fTh1#%@i2>-F=@i*LR1*u^(q`N6pI8}K8j5^-=aB*co#!h-sgEE?r@+l~wp zkI!yx4&1wTIpvvyJO8B}a#e9>SUw(vyxvd^%$O@AP{zhUPK!iROf>Aon?iV^c~oYoA1AjT^kqR*+bjVQC|Uipbsd-^-f>~;gfgI zdtbZs;%|1YUo^Ci*DnFKGzE8Tb5%cc;4{1sZ_Jp~gx8+ihu2PR!Ye1%B111lNrnMz z;{JIK8wT&E9!E=c$?Dt5d+)ZTetWkqH?3RVo&Vg4opm!Nk4)OMY})pN+ZOjvA6@b1 z6mBd`B)+xA3y`BqM7~aq98DrJ662697Y)t?r?O*^8XJWyx$sO~hGAk?T}fqEO`-O{ z_7xs?s|||MQnF;k^;U$15^_=dQX~S(-N^Ukp-sb29NhBHdJ5>Ff&9>rD?Bn##D#|< zg~LE530LwYY!XZJQIaS`r6vw_DH1fNt1+QEzj|@^1W9A5L!#o*Bx7p}0&b_=V+S|> z;hWR^-Ya@~L|>Lv@aCk7g5rDC29ug=dlZCF>ZnL!A*1^;^+}X_Q4XIG5g?{f zPfKH>`qdmpzfH;|F+H0Qn2SP%5XA{Xl&M6hP>W&WMne?rkND64$Rk3K6defzCmQW# zna`d&xZ$_ATW0T`t<)_m7QU2YQh%uy#zMu3fs}YMBg=BIc0niRPHn_{S1#c5Pd~(% z=0=43_#oWZ3+tB6N9VX!ji<|#K84wa+b(YiKLN5V>XdkXWVeVNwpYZa_DcjYsIRbN z-I+~>5wwQ5#j9t2|enwyfn?i{x_b#Etm8g^uP7|BU-H_VD+knWpie9 zffqu7jvfhX92>c$!xoSZJCJ6{c(96MkxSxRhaw(!65~!ESv~W})>STNdUyS5?}lYw zecRUEvzPNHjI8NNilPz%Q=w(Y^kt_gDfgnBaic4LyK>=lp95Q0Q?@Oi6WWxQz9C;3 z_gtA?e!9l0-)-d6|D=izgEpFqRAMnxm^2tkY9^%17BP`8;h-ih>5Cby6~PO~*Hfm} zMsE-FiyxdThYsR*6CtmGSd(;Og)0n6pL92umCtA{uI{YQY2Uo8%kN(4{X>}8 zRMV}Ep+Qf?B;xkf<=QAebscPa8O10Uj489GmCYO9CK*$dbJoIV!o-Op);J7C;tiRY zRHU)OVPJ&8PF(C<8TUq^UY>fVWo=qLKXSpWi3SBPW@Ut%3#cCMpaps%KQk5MCXB|G zZ5v3RcnKAGS>T0v!Y&QJHMcF_aSzlU!tG#mV_vW>k-vh+2=6T`OuHQ5Jseq`Qv->-dnG1+Pz_^+wGK-myzsaNs&=($+B#- zQuIZ!S%q?&9@SZCsLC)RJ6Q=CmwAgD9nr63({B}|DF1Y5>jw6{*8jg@WT7M1A{=nz zd2l32`|7gODfgouCk}4^=j4-BE!)To_60k@3!Ff2B+x=(CtgbqvBWtE0^}wMkgpWp zUAdJKD1!lnktEt)?0wmw$qJG}m}*;7Zg5v#vAiB5%Z@cFb4qKUVqCIf7DR|k$C z*@NYa7Ghj$6H3i-w=A;QjTQx?*C>fTI_X9qjj2q@U*(#hC`wi9S zQ<uIT&<(qq%hO@z(sVw)^(mJru~br})Kjqn79rc`Fm+S;sihAxKY+$H}8xP*z|WjDMN5 z&|9%lp?xv|qf5%7?u%#AkV!g;Ng9iJlWOqkhi~rw_=8s@-&e-Y^@}{Vu302GdSHv7 zYfJ+ingrw$OPfEirWNUANwEuZQ7$^6BC)Y7Dhx?65rfOy<|J@Xtm32EqQdjNdvR>f=C@Al-xBvj zc^%xcc(^rDcupQ33LPgJW)fqE5&{Q0IU#7oF!&F99Kj?$?wZ(+voAi2w_bY*XO161 zhFObdG3b@@~;WyfJlbGhTi11a@p%h$&;6 zkfu+7hs#r-hWPe;b5B9KE+;C;6O)??;Yb!hBMd_viI~+ zf6hu)7iAt(3z*P|xyVV?pfbaR3cC?y>3TF2*}k@`rOVBU@!QG&dj7MPKMxELmPr54 znZN^(a-*4IMx<<1Rq;%{M7U4Ijz*DAg39E0I1+h?Aue!;hZ}4u+BXkuTNCqLdCZyG zq_%1V$TKA&nNNpR5{n{@2)oxV!P05tFU}p;@?MR@awg2n`AcpL4eW>@)RyMp;_EM> zrX&wX5AFbm3?3pz6t=FKoiV-RU*8rR!d<|-#Ihuc*cX^#f!B;0=@*m7)?@vOxp?#C z=P+(m4FWu!VALeOZ_p{Hi3Lo@H}_3xuk(+M@c&vPV!*28qtvc~P8^NannIj7w0qUm zNiE^qcdW1+Il3cnOhehY`m&sP9V4s%n4y%wst~~>k3%wvBU8j|q>*^7sW_v5^@1+? z+9fkR#$ z{(Rrw4KXM7Z)ElDUL7gt&{l})F^KTJ+ z+9YHp@=1RJe|56D2Z7iHVF{rJw z%)$)xeL2MGDM+J&kgJJxaJ$qhk1KA1AG0Tw+6ubqDeXHK7l zMa)1UvEExI*SvFhPKV%rw8I01F^#4E>3aDQ87~?RixN{iYOr?s3_O2oALdMNN07G@ ztSQP>moJ=sY}e)<&pq2$|KYpxnKHVvNX`iR!m5>_&}Kp@>DW3FZ*?>lV*JQLwAJS# zXJES#T^uS+3gX6zVV84|7#oI$0(-+xt@n?`FOk3l=o;Jf=!DU=^aWkxG*d@aZM7wd zP?VO0a+4CqI3`l#1?X;X`Fc!MJ_&CUP?4F8RACJ4A|^%_W_+D*)V+}^i|d>_ebRRh zvgyY3nJR@9d3n_+DkuXtCKPoQR`ea&i47appmS6U8N>xJbAqt2DPQsvtN&o3tu9+) zPzm>^Bni<}m5n9y$70Xsr5Igb3R|icaXbd%`HahSs(b9-h_GX50$-c9^c3H)u8 zXQvfYeVqIGw2)hB;u@P1MNo3-Na8Y(#EgcL8HFT9I0`fpl#t)7%%VJZ>D9AA|1IB( z7q8m4Z{Ipuo2dMozncdFJY12cQ((uY9^ANg6^*5NP!p?OUy!wd9uXqROIK5V0(BoO z*er=&`RVG(Iw|8ueW?Wtr?)^A&%ojtlc6VZsh`^jGa;^=D1Jy7i@!Gl0xlREART|9@fcf$&< zLcoB547x@c4_ZDUFe?fM;x?X?RN7nFU<2YY4siY1Z7!WasCB4 z83X=n{mV zr6~AVGNTREg=X~3n}7w=+7RLE1a72%|NoNryH}q3%?H&L z#B*Si^RQ*{GP5_7|lm6RRsmo=%SZWEpaFLQHOO zT$#~acw0;I{yWOj4RkF#_LeBzAH_Bu3hjDgb=7$3`I8`JLP{)tsLu#wXvMqlwq6em zmMoa?XiHOxe{5t}H-j3Ag3J_jj4ZyEafhCyd$z2^{FxotylOu2 z`WTQh!=ANh#S{U}=Yi=bcMU6+PV-*~6>yO_K7glx=0{S~Qf|Fs3>eIZ1ppICRgJro>aGkE(p2UZH!C z37ne5_b5zP6&ITl`byFgkR|6LR~?6vL?)_LygyIMR!-kEv+=eU)cXcE`rmM;1$ciM z6X*+OSOCf$Cajn@5l8o|#*X!iz>f+2BGlcfKQ_p1#=X$%7mc~IC(sk(n9oKAd1L&T zdQ56>hBa9UAw2*(SuDmjmW(OOF;+M%${$=L?Yl6l%8`+!lftfxN1iDGB~~S}v;)?c zd9KE)Tz@b0x!-t@3H%M@{Ah+vC+~L{R3tV|Kn@{tnwW{nRn~W&-M#2L-`e_b&`Y^9 zEGo$=t(enK8Sx}qDje9ec`>@i)}p1h0?`2;D9<(AvxOLbk>JOMI%q*&NE9(3V1%P2 z-;9%ocfhJwLd*z8Wo|0wPHm>#X}$|*wLjK9u3l1?XIYz(AVPU^JSvScl<4J9GD5D+ z9orCk57hZt;9(%}H^@jcUzxd3_6;thD(JEd2vp9eKaBP z*iltjws<<0FPw^+qD&0zrK62wU_oc||FqU`ZkC2sXjAtW8xuayQi%s&&ZsdbqH|=; z$r4j?_qgg}@4Kzj&jk+?fg37IC1aZEx8&IjC^00WOd}ygjz?392=nUG^Zu7SO)BZQ zcozLK#p!7TxeiA~ZaSt-Y{kMEQ!sH#8hTO~)w6;{jVb()Nj{+|=2r7OwsvIdNjEOAz!tPQ2x0Cm#)$@nP zb0Q_y6j?!ehVEuXngWGd8EVtDe`?H7Uuh{a@vrv(G%I7=FFZ^H9>B<&JbzoN`a-ci z4OJ#3s!6C+YfeI@Qn05`D^H(RnG?Qy!-CsdM(5bkjlb_byvaLRE}oE{B!|D#Fhux! zqP3wExg`HLUOh{U%q$3K0a&(h_6KWME>4Z0I6qu_7bnDV>I)oM=ku(#FG4(=(LH%I zOv!R^=^;?XaRv!2iU@;}Lq~i}FdB-@mrZK!(%Z?K5STLX;9n_@MQ*AL6(%XF(^WXI zVMWjOWwRBVmP~!1Cak^-4;z68U{J@WCMO7b3R03#J+R%3T?biI5R&QPm{e--+qrK3 zZOtAZKf2N9MBmmqxvARudZ`$JZq5iG!ix?;b#X4vo;i*az5CGF-h^U@4MiDg@64Vu z`UgLEeBh8})U^k@xk4EyMm`zUM9e5m8`p|VgBDaj4}|-AAXO$qRC-GQ+6^sO3kRxGrU-qWw@i2Cx6L!7zsQ8heg%i zP?UAEF+1(=mBbR485A(YhNC`B_59WI$8Ku^bo%JZ#%ZnPU*?y}Hth^sro-8>QQ z?gj~)fud{^PWJ7>XP(iR60@+6X0MamTO-7;d?Lths%;@ z(J50DqW;Vj)%E&9JH}UMV^pCTQ%4paCUJDwszsd-#7i2tgNK#CRfXx4@~pIi9JS>A zk=bdewP=wo;lL5k{f)(tK)I>4nb$1Y#x*SLL?0{Ly`br+;alI%(vS?vr?E~-K{YnrM-mBoo4lceu zeN+X~baKp`Isp-WUMRF1K3KV+YjDeqBz7b;tT5Qb(U@3I{*EEX5+AD}5{X$U?k};Y zpva&^xjqra34G+sSg0cH@#hcUoBiSCH~(b~teVQaVTF0d3Dd_^T_2Tc_}UOjg*GA- zitu2>1qVV9lfY&(wC82p zu4E*uznn})uhAvx7+qk7h!u^Dv=q<+J>f`GuROMY!~Uat)}m+TIHZW^Na04IIX@kR z`UF@dEL0d1QC^U-F)5K(-`-L*OdZcm5s>&KMaoC9)qp~?j>Nu7jBhBJU1HNnCo~j3 z_@m;#;bA850JTvk!)XOE=&UQm>Zv0!DlZK} z($E?a>xiK6%Zdwz*>w#$sEla9|AKXG6$V$7X65i8d&#gSu&aHRJD@~o-v#rin+sv^DT z-w%E7I&NHj`B#kZn-kGiU_zN$gT~^V?w>%lpEZUE{QvRHu|2=e)har& zr2`w5v!RO&f{I2YCK&qIFr=`;kjf5+O&o(_ZT!HB933wm-t%Z%Mdo+Dsn>U4Uv_?G z4hl(M4)^y&d2t4wedZ7@y!A42N#BfddJGNb#0x*Qo_8H{yGCge`0VS<;9#h^Y-DQ_ zP?2rHxQYxy;#55KhetsV4tVj|gS&2P@ouexd#biL8nv~X#Nmlt@EVVE&_B37+gHu%ZwhPe~5Z~a^{5QuKoWSc*) zFUh;(4{&}K7~4<)VH6dd&>+~AGRzy-gx0DOjIYXuO)Y}wuqVI>rres}IsUd@JYT+W zs$tpO&iA!qE@FJVi3<}9lUe~`WH51q$Ve)RmcIPVj$gg}?6y1p;Nd~T5P|;{JGLyQ z?ccG&zJGHMhvnk}X{av}BmY6*1Zn`J5kbgO%W?J1bLaPNUXge^dA8P7)zkdEAc+Y_ zK8dlH%E z8Vi0z2qJwvQEX3ZN)W`B*O%n{*WKs_@Y30%zdp8a`{H7|6%smqzh?nm#x^_`o$|2xuCl*V{g^s&s;teQI($968kh11($q547+ z=mC|0A-Tuu-F=)mwCmS2Lf&W}e>ezvN0vA+b9^fnbWTE;rw2LjgFDT$#9=a26=c0x zTa*vGPK&r08u-*8B*jJ|ow!F!r#AetqgeS-sa-kqUg-2o!VrP~6BFCZMkes7$dEE& zNQV)vSvnlq z*bPm97X+SeD0f(Ue4U?^m~OAeiIhU{Xktz+)lXY=TLZfHiZcU}8fN95N=#EQv4Q z3*CN67$We$qIFb-y0fElm0m_eRZarRt(rfUn37PQB1LHe6BS7uWXDBg-SoOY?O8r9 z@8;Xj-S!tof&QU#KhHpLqv&YPvY^(Wz{CmzPVC%_3ooBTrX>wtPdo;VR8(>=b-XKJ z1XIVycvBD`9*&|E9VF3_sK_#7%d%NWV8$TQ>1pI@5+Yicgd zw7sola$$)R!z2~Ks#D^PH(tfgt()GNGIk_d>q?N9nur>EBD$M%c1~-|+P8nhyn>sT z-?%N8=t05|f&V|AJ-Yk%qS(;mW@S9gdIeI{ywA!Dj2(w}ud%F|HEvgpo{RcqA?i}4 zNEJmv&J4ZMUXyp*VOX$#j5sosb4x8#U*tv6K8ueIMMt3ymtH%It5^GxtVlrMlTTvP zvW3&iY$~67sq2qMf;l z{(f@D(oZ+c9sAHNf%32u_|~U4{XY8OCbcNXb~q!=a9kZH{A^%Xj=JI;96Pvs-@I9! zw1MmPt(xoKY*T*Km?}n{DFHc3KC+aezs?xfyr#^ilif~P;XyHvjjS8Zc>csG|G4PL zW5SRC)Mg~$;_EM9!@4!7D64~Bq99>p&R5I;&(Zf*^B)PBOgcR(Bn&Dx9o6Z2OdVB) zRD}e7!=8YGO}kWN)r`zcmEO^!V1=owc70SNEQG)|Wg>F4QkbPYq$m=;>h7E&`u4TU z=1!@sv}sUnmZ8ZaMTwG)QoVG~-PQ8vkB6DSSKoc*k=2`5FTQZ;;>*Q34mi{@VnC8G zchVT-*-~#^zx>+2YyvR8JmZ-nH5WEH2Sv$ogv3H{Ln$Oo<7_{7Wan?bubl6KhRf_t zjG`i4!N!&~bI{tEq}%MM zv&oTR5MkZQ*&o09%9;Pz*nM0}wQ*Wo+r$E!`9hA8i<~4OG^|KC^zkRQ&TM;Q^~8px z+buVl9ouV&Wgspr1e_pWba#%!$A9??#*Au#@36-piU~h<>+0)I{OSES?|9L@dy0__ zWol}G?_YEx0SZ#npyja8kd+RjLWG)v3}hrLZ^qGSpWjKIS`lxLFgOTiiI|8G`hhJ! ziDj2Wgy6uI)%D+Z-#c%;9D4lduA{j*8DCWwq*XR6ZMVp&_3O0{k(uG#l@J^Z`l=a`k=n4 zAoq~aF94~09xBp}q(P-f<1&#z2)wmtk^P76?V2*i>CmD5%lGfxf_$SCc?JO*N-dw} zYPgrWM%VoOr}KX#9!3J6JNKe!(ZVHHP1*!x8WgBXGhl2I2lK|)-8}j1QPITq)T9S|aR2{;+ zJfRYC&-U(E<9oY#PH3;Ar&~0Vw#u?g0{;Lg8Fb|9RnT*2sLL?g7K|S)dG6rO|2oY- zX+p;cyEV0=qp56ro<)xI1Qx9PXcVQXQ_nuLm-3?&|C!@qB=G3=#?4cvPJ%T>jUsb0 ziY=))-*;fun)%ZuZ(cb6gHIwNg8d)OG#MGWsoF)BI5u(=JY>sQ(8UB|Oit>1MN0l_ z+gHrK?U`wtM%5nS<^@5ZHwqJ?QEAuU{i_#HoN0z2$PF)_>v#3? z`QNEz!mX^pVCcA9SmPvc$mFnz_^=3Lk*AK6+-V)Jzk9)NV090pgh57ECPw9(QInbS z(Tw)y2X_D0hmF9OFTeRjo=tzUBr_FdS-B|B$^JagZrFLJ`7{>iI4m;$Eqi<{=__0q zxzS*GyQ5emxvlw|l3dH9bGpXyMwS&W3?uzN!r28;ZX-~huEM6CE}TAb09#fr0mFGX zY6QW^SMX-Ock$Kxx2k2jK3Njt^iuI>$s9MtXnn*fBNKOu)?VD9pQvPH@87c z92???6?3O5e<;5zmtOw8S|T1D7s-H8Ac9RCj|^cP@{;6l*IJVgHf9^|_{H#xmtK6N zv97py;<%A7GQ@P`g9%=nj@Gubg*0nc&{qc>f!FlDS%T3t@ zr*sMO&j!97wsl13I;{^wO#CN!0$CvzCkF{mg?6rfZk8eFBrDq+9W zT#_An=E#okU7psSs*DVDcfAts;R``nBtnP<4j3^4rX(@;ZCi{DD`()P7y58$%QjFR ze+-e{u6^&m^YZ;$;&|cAX%bchwLj3)3uS2vY@9V3RXJ8jxNHOytD7PKw?Ih05o2sc zAsVu*F!I=l3-E_%Q2Zbc@P(A(jar+o=eeVs9w~QNB+}@Zehr<6H2#3~<-^R1MOt(; zvL&KrKen!;M^z6i$g$+t7w3IgVo;#g7>CLACCEu+buO;S{J}}FUm6|;0*`I0n_X2| zg!+-?s4mS!Wt#Yl=eKo?`?2}9SCj|x{Q|BC{e4lTm7~m zc++COO&Qmx=Cf|enb8o^!XbX)(cp!KBgT({AQDQlDDKEq39)nC z61;l)G<^T?JFr9iesHDLdxrADTn~zurzF#4+8Yxb@+U@6D2Xd|IJ|B)sOu2>z;Ja*?A@ zKuRTXuz+_Vj^bY^3-P~eGsm@M4w+dgzFcZcLSvqm{78HpTF~+8Ysc3uWK83bvV{QqZBYlMj|RC95N;w5(X2IbO!i= z!H`jd&|Z*%!@GCl!^68l8#)A8#<;8Vr%##}qn4MnH#hKm!*;i%-QHBrqq7j~6##=$ zjfFF2V9r=O-re#H+A51cC-HxrR0UPI2wJHeI;9ke3NgmmGB7UHj0ve0OwLHd^z3wG z%ET~Bg)mAah#^m|Y%K|$qgBv`hM^?Y+;R1!`xDFEk?k8+4|;LcGW)jm&;B(%Mu7@z z9L83p|FbSD=IaGh#x(Wjx%x})M}YS_w>^C5z)sI8j>hweI??AP)_61*rFL3XoIS_( zY!+QQ_n(J}Zdcyi^2*S4&nyow&d&Oahydt{9?SGvg!uVDM5jT;W+RrzLuv#cHklB4 zsz?+@%TT0MK*?s3&^QR;{(%T1k!hHpKf(h7!6&aKi3pWeBbH5S!#g|Qz_U-S!0MnrWEGD#C5-`eQK$cXD!dM;hVstReWT>o%4UHdHg_n&`qPv^z=Bf#}F zxn(VNg-@?oKKUO;4SCSVt1z-Gd%=l=@7!^}$bXYFA0B=vDL(P{yg&x>RSML_stJsq zkTV%DgoPp@JPgS~J~AW%WD+oQl@b(b6i5_=!X%4Ca+Kn`1gZFF$Fg#@})UsH;*w8ZIsd2YEte3k1@hlMzn6tMu2 zlt37TVZ`YOk-`r}aySoGArG0tP*lZ8Fgi09b851&W#z1|_w9N`d8lL4p!Yg9|K`w} zn}1W9lnCnZAxMs(V`XDL{`lnuY~8RHLmwRkil6UUnMiPVLTDkE`E}q3Ptbh)5U*9i z92bRGR;|F|Su+qYY&aA`!S6eEy)L-g z(W8naC*OT_L|>o3FXVm#c+GQ58k%Z~(NI-@$~+^AlQoz(sb&A=Pfm!ge)54^_0;ZE zIDwRE(*=C|*9$iy|Onb0B3?ksqV_-xLwAvocop!Tj31J)57JI)BfWC##RW zy_S9a-AzAQ1ks$C^*PJi8)B*t+A6b=9NqY*|S?eqiI^ zeLJ7rl&g^-j>SMG$$K-@DnzqG5EIJ9*XKXDqfMG`SHAh;e8AD;@6RtTZ-C93f&6qU z$>X!JZQYV@cdVYZ>+{aDZm(S)C~~g>{N<%{KkDb$vGrx)j&19fZr||I?~9V-QAX~w z@lE;1rrHY}W9thkm(LvS^Wm3sCyqRF<=lxOd=~u>!`BDam^dVBv=EUnS|b*`|H{%C z^gUai_58rO@s_KW9QC#Hgh3RzLg^e;1opkP9?NG>#=;p6ys~lyL^L{lhYrQ%Pfqvk z1S4s9$m$?ZPehVXclyLpSWJv~W5bJhe)%#44fjN_kN3gfy}D)4t=bt?pQWrTGQXD? z#zs;Y4;j&}*;Z<3IbqQ8*!b+s;k%ZHzOj2x!sI8{{C(<@=P-5Fax|8tVsuL>=C+kw z+qwP4A3R8|Ts}SE3k2M20DpD)lOGgAzk2cPuocVZ&(6&v_Lmi*sW1h(Ng6a1rL4Z& zw!OCLrNJCZ;9)jN7j1?_q((dY!k)Xf@OYVDUQ8XufJ_ON62^7sPX``(@13;K&6WQeW3R=?l3bJ}CtPhP zNME-8x%tEU!>*^7%=C*A^PO6;u+wHRe4D0@LW)d*M4=e50zQfjF=uwHULw9#J98$q z1htkGwC5(qXDj(3$63DKnAA)F{^knCw=^Juw99AGQIT(Zt+~3a_QL6ty}LzAmf7s^ z`0Wq`d;22OXhH;+3Fn(z@Y1R$K=Bv>5sP#6cG}YjLmUb=6KYB@M%l8F6d^!{N`d;E zOkJ-Uew%XY#LR^w44#h;#>Dovx4yb^sdv||a{_}* zo{xES4IR}N=VQFR8VB~ihF8`+1?mV-L`O((E9^B#%N)_6JSc)`7?W#7np}!B0&qiq zj=on7zXLh@(XmI`TNMOn-(@=wvxv76!Fuv)@{kB<$QeVsGo^|oj(2i9mcaW>J=@Oa3Kmi^zVsVx(4ryZR{`j6n@ z9!SwCFt4o)Z?1m^m(HDnS{MnhM~7l`vwhB`k9)ZoBcI98c|SfJtN<6l*%(!mk5fmT zSUhzCs2<(~VA*W}oMVZ1==cIigD4oAlZ+f)EDRA5sJ3OM^s3=MLr$JPqS?N2-B&4* z5pU&b6hd-yZ6#XV-*(+f?j?YUZ6cz_x^4YOLx!cJCf&fFH@ZhFG27kl}D8^YukpXs<26GRJ6=yG9~th!-Nc{4Z|R#`KA;!;5UG4Q093 z(W9zMJ~YWykOWguX^g?-hK9MBv6>xvak#A4jlV-V_0jwE1(U`!CPxY@UEp@#WG*n8 ziT298+rE%{0bpX&uZZRoJ>aslIV;12PDMW;X4R9@14t2P$Tn!*%uIhVso8+BP( zsLRZQl*xiYD8kq0PjQya82c-i_PX&uL*`Cw^GQ)ec#xY+*A2uCb@aDw|4HrD^LtQ`6W=k#N3FCfh9_C*TDJVa7N+ zUU+5!EK((CLq|ZsU>e@g2JC6g|6i?k(pI3>2|f7EFrfagZLZMP+(6@x+l( z&;wDDq^Wl2_?=tV%H~ZTpDm;^zu*&RHmR;0PtTo-Y-23!fYPGFGE-S)UaflgNlQITv!b8ZIY z!~=^dOmv<&aZgNJBsUxDrW>Nq zNQ=^-D#HegM2g5@AJnF6-*LB%ob(KtkR|vF!#fyR8YS#mCTw4`6o2~tr!Xj@G33|3 zg~yN~>wdPeI=M{83J5}=rx$86vN68822(~hVRUUJBD@2@^YVq1%hkEl))$?pej^JH z-50^)pvV{xd#)8K77yYe23}dYazKYqJ%!wKgNZ&#^twD}^yY5t~a;y#|ivf!|3RTu@q)26u1_vQiCHU~j&ed)?qRiwpeFRqo zrZ)wN5q#9A#dHDu$N#yCB%L0E3BU%O{=&~TRwWYYSi}Pdd-atBijS3E)7@W1%!L8ZRxGfoor1BmnEW0M;s0Cx4cq(l8!PFA=Y#dHZ#( zK5EL(!%I&*ffVwDVEVYKZgAZGN2EkcpbO)nIMD)|+5jUz4EeF@*Hfc3Gt5fGw)|9+ z;%6D#PeN`+TlYh%5+wpisZ;`OJo2LAU<%`+ z(Q4Xx_0)U)SJbPQq&qL}>~W*+?9UsuzX9&fcYF3SUmGaVNpHxSrE{1sEL*VrskyT+ zCP?H+Avthek`d8t4kG-0k*!rZ+-XNIkD!H7sU1{LZ)n0o(2$pkFE4!nt0@sffBRd6 zQ)!rxn{nrkjp^&{a24b-h$B#+la7Ux+VI^UzCx)r6G6jX*XZ{ROc7`q*w<_XF%kN7dnh)IZRhvSQw> z*-@e4Fo}d{PESUhAPkWK0kFs=j{kJbx@Q+ZT2qvxFsP+Evp#xED3x;21#ol-7xw&A zT>a!dR2LOs#GuE(cx(uk7H7=9V*}~lo({H`ch~BRru+;%J#QNRa_uV=r)MB=m*<2-!q!3i7i;3^{`aF`bTVjT*U1IZQk@N!&H} z6~Hd(4j+r{KkT$AzRNb;Re*bR=-s&HYu!Ue19rArZ%BetVUn{r1mG}?A`z;AF93x& zHYu0gnW9y9B*?}4vl4WFG)GGjA0dFAq@e~u2xJrr;U*YT8UvvLf&T`$ttb`ePVB~1 z*KUS{J2r`OXXTnZ?$|(>*!t>x14#r_s!q;kcMSuz<)#rhg$Nox9HBn`hzO)0 zGKc~tg9SB z_3*^>JX6OV8yFKQS;Hd$>-l_)ApmbA0RQppt4NKD?V9psRf^G;ZoufwIE>9QU|e=0 z#%CvCY-SS5baE6&%Tb-EL$yhdVto`z_9IZHjY7Vw@_iTyp_5|Q_TJYy@PypR=9_w` z7v2qs?-szWjw$=~G4LCncfOV z*@ligHZW1C*cayOOWeN@<0=cVZslTp^LgjL0gew3LB3j!f+#tPv})w3WXS9C$TE}? zVCxfOQESklCQgg$7%lQ#7sU@pT6ieZNZ3(kjBW03#pdyjhHDnJ$)u#!2D`6zZY~kOE|p`@fJxphbj^{7(BgTEZ*3%0S#F}Mu@ae@fuo~hKIK%_OpkS!!Y(&%8h+&5yjuVQ+ z5E34cTp)#n6PEBWB=SOGAc?+)Mkk-6K^;tmmP#jKw)#+8u8rMC-|c`C`wu65T4GpM z6L?LbL`f)}Lc-__sTdhiDkzvNk{dHnpQOi*Ra0={z&7mOvKC1M@+3jnu}KvL?mzVH z6(x~LO2wa&6_F@QibHE&DrPj6;CNSr##iKAsxZe~HiU+Jl_cPUyh2GXNJ*0RBw}h7Ul z*ds4?<%+K5biKa%sxJWUk=NhoWxkOT45)eF{UKT&&mklLt2rUihJ=Cd7YNtS3Uc2Y z3BaWq>33tZ%$Mg>=AT&DShjcNq>=AFH*56XwF@ThS-*VRo^?;o`;%EIC*adyrcv<9 z+|fAp?k2pw`FX_BnTQGu>dcLj(A+jCFEP$2XD|^b3`ccx0w$DaWA4aGRHP)KA}t-! zJRVGn2psI#{LrD@n*!c*Ze$#MX9MHlTdy$o?|g}|X0d~5&q@v(Ut-g(n9@3_Cd1NI zI>%KI+e{$Vx@!N#$4t9=;&A`%joJ^=Jx*%t;k~}?iw>VY0{F?BLgssVI%IE(lErj{ z1qHz*C+TED97F*Ws8~$QYN))hps~1i-Q00e?{0jWdF+jsy^g)L{#Wn6x$f78-&*&p z!*9Rx$a`$6iw2GrW$yCvP@rPq4E@LVsq-)jKdf4qdUU&givvdCyOM_6DmEOI4Ej0sRN zIRs*Vq{t##-8p`8b8Va^gnLOv^59tVAXwa5iKDyMJ>&6NNd0hYm-w zQUynCCAO_zj&)0BA=JkY;gsNuwZ(aE13aa%dWLJ|QL0FQYyz+;EEGBp3+=Xy9JdX+ zkHvm{ZSkZYp7>`^{Qo%s+pjOoIMKtN0avhKph-+zWe(?38;Yt;1Nhx zsWG{(2F@*Ov1a~Mg!uTn0Pbw7tERczR%?N6i;+N^CKez^CWbLI1bQwLwPr)C+Xnpt zq`Qar^Bxf2vB$epfV*w@LEW$33hVDz+4ts-hjLBw~nULkQ5Pm z{`J+%+^+AOp^2Z&_XTHfqowalMp&Z z9fhe4bvU?d3!a%d0inKK9=LPD$Of9bMpYOSoQWYJuu8?qQ%Ji8vE#T5JTbP#;BFhg z6tVws=GF~>ZhO+l?E-ASKEyS%$9Y{LbMc*C$1hDr7Uec4N2~vwDpw$17mZv^6k=E` z82P-;=?!HxciR#A(~HAB1G-A=Olv8^#Hw5@AKi=@<;AFu)1W*~bLy6j=tW_vA$~re zQ-*mWQ>Vuadp(XhU&T|?#v;U(0~3I!jd3p?-?wYa!&ZrOcRYuOLQOP^)G8QwY}l0I z%ez)Bx#t&l_qKEoGx2)#`hM4)7vGi_yd8k;*O&kGJl~E7z09{Ko7Oz#QDiYKOO{Gu zRZ5Ysk47AigM?7_25pXU{*1Ign!q%;>O%$jIS!dwJ)yXt@Rrq9N`Pm2=80h zUbiL0I$YDbTma|B8@d4gaL-OGpWNOBuz*JCTrhPa%^ic@-uChct6cU$9EXFlm>3kh zHilv|kSQ1KcK4!wiDLg@vGcBBrrXIw-38cweZ|n{H=XA}$b1Kq9jA8~#bP8!MxZ1< z1_@zYq(t)n+?bXmb+?TuZdezC~~As7p*lF$pbn zj387PV-C7|QNL8NU!VEZbMnOJ?)FgM3gGULd0mgTPd^Bmf1c!;VjYPQk%$i$pwg5G zV;B#~qA(Q2MeE#cBO@lZICO*$B7y=?ksgcDWoh`s*Pmj;s;9vvDXr8m=+*!$xNHa4 z&mZ&=UMMyvVs={-&K%i;MPo-H+{Ygh7US&Z7oQDq$DnDWn`q`pVW*Y=+-NqTSgR(< zeE`Z5v>onV)Gt}OL2JHwILD3S{v*Kl>yt=&Ru0+Q9Y#MGBKjF(GwK}%Q3PT`!%=H7 zBPl$DK+HvQgnPx_T~d>6D-I=|RzMtRS&ANG3BcFBx{T+SF9p}b6EZ)_tpVl-1v=Q? zK3xEpCYvyKOcTx>dlz#@Hi7T$2N{dCd-u+5ZcTx#Ey$$B^TRr$7<9CzC8LNW=PrON zlVUsEy{HHB@8WPh^Hj$z^4cE(Y`;ES)olNM2H3au2NN@TO>&cB2*4s}xjZzbrNA5> zh6El9^(hIt?zS8@>7VBj*bU}UY^yIMXu zYi?H#%qNj`uZ5IUM0g0}3;u0=cX96F}gm92KSjWx@bb>+Z3Z(o!pYB8lU3s=s6 zfYr+ufkQm7B*={rIy@+F9^KQst4>di%}M|siStMIV?tF0m>wfgmYU)=z-cimnvzB# z00)ta%0RI`8fsb~O3iT(Jn$Wg{rkdsJ(nd)>^+tx-UM*Zl}}GT=w zQHr-{qyfqZ*Ir0g%x!DNg<}UWrlJhAp&lr(B)#OWLCMi_nu1E{l#>&;*)mW-LTEKD z0A-f=4tLvlAU~Gw9_sNo!D;UC_nQHBd1~{6j;g+sa%++!He3KHory7dc_ar8g`N=% zdrs&pf>xGi!3tdHM)e%$?Q6o?8Ix#KI0LX~b1%t05=73*gQV z4q|L&1t>#?B52r<3U>|CgmY;!3Z+x#0yvidtWiQmLg?bem=1T_cpyJ5_U|_fyU{7- zdR^4r%iJ?p?sRwf>4Dt2RAweS^kD)>Xbg-d02{+X5KRq4O=`kwciVV<>xM>_=Lpa} zh9gTY!;Gq2d~)(Io?0*$)WIHIRV;7Wh$4*JLGALuUT7i!&ueQU03SkYX-OBrK7$4o zyK4|Xz?&ux47?}{rlLLH<$)DY1`~h{x(;{Scp(2>>_09nceCELy3oBLXHOh{=k<2-WGKS~0F(VCxztf)v5LI z^j+-HwJdj0i-L6<)M;IVG~^-s0;$>}2xU+FwKojt|rJbQfTg|kP0OI`;Pef-=<@BiwP z)9*h_{s+JAJbUbMqOR}%2Sp(+e02EX^QRA!&m8{u@6Me({1DNfUHzr=%=-@!{q@DO zM;^KPZ>4uoSOwLkJ~jIBxSKa*9s$?T2Z7kPAYdMDwIwm(FD2Nsf&nk zMhW;%MM#JY)1;iySBU#rSUan{+a&bG3`eG_WS4@|17cz05L#U4j}<=%;P zmHWug`zF>_?3q|o;hbDw<(%4BvwOO|e($vAy4};8YMd^eVXt$}ve!Fjx70gllK0oO z);XiO);XoV(&?xzcTTJ>?HFHGyn9S}!S1$_+}*83w!QYe%)L#y8GD1+ zZRrOZveORMW+We~$*>%%OiOyVB014{vzA#BcGqMizh9r7dbA-cWp7hfO1u4fA@}~$ z(YNrxu31*Cy?DMpohLo2xSVd!EBJeLTKcDXhPb1)IQ{t_{VMioSd#6K8Zuj_L#Ql$|DU>nY#Jc^f}SqaMHL%Zs1 z-5OvHtAj=wVfy=C2Y5mYE`4+iEyYD7ksc0h2oE-;422psDq}RLj@5R(R_LQpsf$86 z0kteji6U|ld9M1nVhPfOVi-cgpl7m?CW-t{H`)VzpnayzSt(uGl z(xgzKAW>(WYr7Q=7v``qqzDB_7YUF_G%G@Y>t-;C^Nb91VE28)Ewu4?gWVrVom zR7*l*JqZF_r{jwE|}F^ z{mPQD_B|^mww<0gvTon(rfTQx<|-$7?_AJY-$U!13rE%OUfkYzXkJULb8d6>?wR#v z&S^Cz&Z$*J&dC)8PDgqEb#=Y(*2$HH&MDQ!&Z#w}&gpe7EhAd)oK{=b^}EUB*a_sA zaizJ=F(o+C1JF)#Xt9{7pR9QcXP-O$s$ zXp5_IN9Vn!&9>A_GpYrBG3+ zaE-pm$-OTNA|Z5803<>FB*hFM8u$Yh2KYnZ=SNrx1k=kOG%sIRB*HF$FP`}T9k0Dg z03Oj*H~N+U$I7K$0Mop@P@j1n;PWTmN3AUjtRcf)YZXsxSey zp$FdH%slYcX5qo#ZTzoua*yrV@~h*!w|I5G|4}Ex{Vw(&4;#4veZu||3;yjtJ(1&v zZn5{$u#)}y+GX9nrnPzLv5h%t`rAFOH7_H!tspC|HP;%`{kwnn2jrR!j%ebbG%PNP zG&;!XG>9p|Py_};O9>*OH0$r_k;3;)g3#SYe%PLbu#k>89=Ai!W_9Q|oDQQ<)R7Ub zenZUQz%>uU6cL6grJ1<&@d@mCQ=J+^br zZ`^5zPr!FMPa{7B6ADss<=jVjYx`C(hj>6iW8E6ylvv$$fV~O8X$0Wb>aGyl1#s|? zp_n|n)#2_%8RSx(j3oC8ItvquZAc{CxBzDHP#tH0l1Yb%06ev!^zf~Z{$9BL0ib(& zAxRL5@dYWkdj1UF*!T*VgNJo-bjt>Gk&$a$0MlGkDXkU)a4kAd9YrMpIB@U~OlluF z)m>wZN`+3%4M8*~1e442kRlOv0i2f*^I$QX#<=>lnM3b+0!WlMu~iLlhi<`n=RPZ>JruzdtxWKFE+uNZOf-FRymuwGHdt2bksS z?O^!&g68enHH@@m!pJUw%Lu@MLx-WUthmu#W6Wx$P8S*qLufdrxd4{(p<+>yql;lt5?&?A5o^4u=3NAfb1TMuGN%G<@~h6}-A(BN#4#-3g&x0Mp46fbQdoF{L?p za_ShIKXI4o?!dMg0<_M~->} zyc-oWZhQHky8w58*7eXR?#_pMc9Jze$c^0>7r-hG4{@OajI<;}AHsu(8Vs{4VyC-p zY*_QOFPntWQaTkS1|8Z9)A7|8pJCg&S3rAwDC9IZdZ9JK@TVEx-e3?9Jgu%2&(5BJ zv&Z(MI6V~j7uSL^Xb2=!Hx@Hkv{4;&FK@7XyfDXJi`DZc z;lqP(BPS^l3@x)%=hPO!7OjAs9t>Mdbcefb-0xz)z7V1F zChtf4nQh)Sz&(z2)!#bZ!=4A_cifOPy~d#?04MMx2*4?b=Z6yyOhI9yZi~BZJiTac zF@1z5^n4!b(h@O}c;G+&>09D~HzMfK#}P@P-5TI{xuk>U=?RvvCuX0aXw?n{my0;Q2=-(%0XPJaj9`?d#Fe|- z#^RZii-SD~z+oY1$VkGd(k%S>yYKM&mMsYQ?PCxJyD^ngD+=!dnB(V-87;M#Lc-`L zXOAaOgRHJuCCM_`nU(XV`MYCKW1)?v=Y@9a=xi*sm!jMlOFS?IX&PCFyBBpoO7~EX zvj-rqabEMChRi?F{?7uqM?0?Qpl1nMmuDXT0OTKwNv&|m*c=!mA~7;883sWplspDf z)gqlc$A5C_z^}(N)=Y2#9Lox)U% z#Tc2FhG(XY#MWgF=qXGj@kMR}yk_xynwHJ$R0UA5U}Pn#lM|p~(2*n;b-3Hc{USX= z<{Mu3T3_|__9nnR+PrzY7nl96Qne5ExFQlQ40nhb45TTPXh}ya6gNU>lQQxRDU0zB5rz7X ziZnACZ5F&RXEZh~n+zTCq^S~#+W>D`{S-yZ<(-!W1Y&km8L9}tN&;}YPH}DWs1|Fv zEmP)hTlcbb_cHgq`8)eE4DAbmd$c|7rU=5dv%}BY&-h-JUBBD$$o8!-`&bPz+aydD zvNRerBpZ<^5<(NkxnzxwaBDB^&NGL-t?{~(!5&`7)T*%QsX54q(?ZS@Kuo3ogYD^g zC4x!6HG7p=CSGH{RjUXU9A^6X!K#VGi}Tv?`s#&Yp*;0@w(^rLlULBSbLE!atp1FXgz?&V`Q-57vmn57CCZ zYOm|?_NJGhA^CLhpy6N+_Pk<<5JxqY+1&qrg>0VF&%=X&#=`S+Td{rRJQ(R*WGNN9 zKkNKx&}SDkzIS#!@~(5oBk4LNbX+z{jB%(mC3LN<5K^f3JHS0>Io+rl+2@lZ z`V!zC=XfxSi^$~GMxiY+{(?yqi8QGcd73B`Y8A-W%8;iQU)ZpG2K82L)RpJSOKd6e zg5ZD;=pNoEOp3?*Z@q?i5{?HxHVl4)JUWLw^eFAN3}gETIsH9`L&2tD;h1WyTRaX6 zCrw6XQu4J34(se{OZEX=RS0+Dq|{%>t%E%s?CXLNHs%20FH?ep6l4QHt4nt z8^F>XUfO!(h^`*ng?Br&yqf^`IA`%qx$)=S-$kzsjSWz3AX^cM zBtZx!ROZCF+lEP}`;6w{M*yZ`YI6maPieu0~016aB{s+RT03ta$Z*!yAkzy1KY`@F86>Zf~vd?V+-Z}(!FKH9F! zHyaVdbrpMzM21|9I35$LW{-690Esa3KrF6;e*5b(cUzMc;FETrP1)kg%fU-w)yh(FscxcGIoJ~UKG^q&DObT9DHZ5+)ODh6aFQ2AcK4+|M)sktttuL;iy}j+FE{Ava z#NJ0fKKX9f`w@=~a|C<%LPP+b+g^hev)Xa?*j}t&vIK!ceZlez`Zm>IaNp6*nly&S z3l8q&_yxckCCAjVEX=LV!Lj{&F@NS<_&q+n3*efp^!>?7*`6#-)Q6R6=6{xx{I(=1 z0fmWi$c>Ldt|1P2#zYia%;5R>f*;^Va^M6srJErOrVyn=MQ7>y=BvFs(j7YXT>iJH zzw^KT1h|I{H;;SYn2vehfPB#T`eVyyPoABuRw9}~N47iyCVnWS#8K(PIM9c35EI5D zPAUvZV)8eU2uYGiSX6T4nG9FQHq}m<*luqZu(+>NhWjGI*B`T5s`1pUaX52iFV;S_ z5_FFsP>1<+1`qY5xoy~#v8{s=H0qd9^>u4QC;>1;hNCe%3GeNG8++b<6MCr}0UjPu zF(|MQ51lO*qC_o2Wvm*tiCQ!z6EB;RNYq4f-UL*d4M-)qL0*g!GiwSkCf^DPxky*l zN;RFK>!a_tPi1Ub-iU5kdsfVtO4O^rZ5s#xciSPpL3alHZ%MWrK!Pn?`li?-BQj5O;p${d4HNik?k zibcCQ7UPm*Fy5jkud$eDO~e#y0$O6DAg9nk8xaT&37=C{GF)~9%L`B8(@Uo@f9eEKygXqRg`+(^9+NT>F*VzSNtp?l znrFeR;tY(-GNC?6io?kFYR~5K& z{w&_y`Z|;x0Vu;gV33RTcWhvm#i*kU9{~}CiX!6ro5+`b{`C8JapkhE&Ceo;7d3{k zkQ%~8dRQpZ!$Xl87J?L_N#u9290m*|EHHAIh$AZS^MRNg6UAV<>Pth%<)R|lXzRuA zv`=L9szoD4HC0sGt4p8D&}%-bOfsN0&4e7iYJz)qD;G{a{Kv1a&_DX{ zkf6TMw$YXti}8(B|6DY_{d`rLsUt5zd*@$nAId!du&bv!&VGF!^>;nIaeZ@E3NcG7p!(wZ;c^frila)1yP76^+&!bX+;b_%%Nt}C#NVQ78e*atII6$ zYbV#1ottH^`+8P;9Y*D*Ab~hKCh@=&*Cv61!6-09Boc3(DVLGga9H>}>{`7{cgIHdp^O{VXqq;@?c$_S&6i8kQ~pw(VZyk& zqGS8tew}_`&+7v=#2e@U-w;=apZ)q=@t#W+FO;SxoLo6`)XW8=N(S^KpGpF7@UY>C zrqhv1ys0>tf>7d7n~IAj-u&73-rVr;`)_RtI=E{CfA5=Xov$pNge_0r`eS`7wu*kC+0f12)&4cxZzrJyL02>Q@4WJfD7u`(Z9Us#T}wy#53 zW;(?F{z#EVu6DOQjWBeziNyVS4jUOH2S^MJL1G9UuRlHCaK}dWfpm6$@X%LZUya$c z_W5tDae7qQ((uBH#orZYB)*fKsGfXq_l^MzuS@O~fNzNXrlpGQ#VMFnlz=IvN#_2x z?Wbhv+^NcEmdu+_Q&jXJ+vj>pXc2^UEx6|qCMt8X9slk4L%TOU^6CrAA}XzEI~czH z5Ywn#L#wkJO7Y35!&p3ZDnh*c!1eZobNeekKg-zJ6GrV!6onCY&qIwd2J`JzIN0$j zW=$Lok&iDioWJ|aGwyG4oo7jONCE?qt(0O^UK%D<Xs$bCl_a#4Q_R6X2t0oEN^ef zNe(@^G#lHO&O$87jiYE3m?H##ElkvW^s|j!HE*gRGfMe)4LL~_38UxLm157EoAAWK zSrC(iUC(6f`|9K4Ke?OzPf2>LHb25Y05+8z6H9HFSyzIDP!>c1-n#`szHY6Z>`VFl z(gzP!<|kW9GZWEXm4jJh8!pXrj7+R4Opfnw+uW6V5#U36wmaV`ItIot8uH_1j@xM`Rik#$ zy*#1hGO?hs6z@F091-N_Si)LsPI}#vi4DF#+t{totz_3{W?WT~INt^E{Musde&ZE9 zw_-8m#QiILeQ#??AU`NrCk~_#4@>|qvtbS~+(5$Um{881inNq|1$eBzoYvM@G`YQ@ za94ePDq71kQB{!Mxnj`_T7TMgyK;{L{Of~zwki(p-ZuXEWz*1-XF|J8hly2bIIwFI zRxcjEcFWpj17d}fH9_YPQUhVt#v&&+5xKfpnD}(0t3n;O(@wfpvykfLg{TlVo*vtX z_cp%(&d?!<_no#%_N8$w%k5w>BpLu|Q702!z)pzJXnZ?WT=x#1jjqL*qv- zLdgHLAusb8jWBFhQC8|L%ZIerRyF8D`G2v>WpGsFVopN|;@}7Ni&M9lWl7w&ujIPeU_RPG=>QB#~e7HYs`Z;nh0^C!!ZF=T~@%1H7 zmsw)|x?*At8q+nH*H-$kFFH@!zy0F0u)pmq$xdk(Py%3$)}t`NjNN%(QwH%L~D%TW9!oCI89Ph>d?V3N+Qviou%tFgZJ&+{HySQz?sy? zhk@hii;7$uDv9oXV<#@0`3M3g7ejtM2yHDRD{s}-vy0}@GIg2`i&%ikl{U<4D1??7 z1TBxgl+OxaWv3*ldd+Y*ep3j`@>XP?KjxX6c{Eo-KK_VMwDGxS;r0|Q}*6rhzvp^a$?cz5F}Tt5CTf(Ji_XddrUvC$aO zt42qKhC8T3h9kt!4|RpPsLs#E;eC5?_T))~(pY$$0Q~B<9ksV==XV=l2x`mA+}UDF z|3h=W^LZ zL{q8d5AVM9>e8JXH?;ogv-57}_5(@o7l6l(9woMA=N@dcHy#+UbOAOJsP z5Q`DwLmmKHC1#IlAdzSuj=#MLpPhOSl)*#59q!p7^z*0ns_{mp(m@&Q0X}(h*h>pg zo1cmI54=kNK7kM#6OaAsQM|VO)vQ~!vvJK*zbSR4t#7Pzo!hh9>IyNcHXk#_HIc}|bg44O)LC7WM!Os5?<=`q06w_y z?Oz`_{O*X7nue(rl|>j`YsJJ`6BbXY!@~0Te{Gr7^wiz7$6iyiTE=C-s!<_Dtw1sX zxYQKi*Yu*3+BxIvE1x{xs~6ENv!;#oZ>i3myK>o#|8ulfBG0TL z4~}?zdg08l3uix+biBFao~|NszW{tgmaSMqTlv(o;`Y|MKUC%?puN(9l~aoF%%U-; z$Fc#Af=SrAD3gNelbC22{p#%gf%@P2%F_#ncWEQB!F zSTcX!+Po}lRZV5FTTc(IOy=YS2cSADy$j$(aX1Q+6HuIzinREcKaXu`OzYK)AoBTV zr+;($rZUII0TMCyoDGOG9lvX_jg3 zw6SCT^F9R`mQlHBNi9h#eI8KeW3=_0$8q_=vs`9cEdh;4)O&jIc-deeDx})`KV@Vb=bqY*u ztom}#Yn$D&_g<0v5nz|hpY5P^y!H0_U9ayz2}$8H(-V&#!!S^E%7?S(C(l zao%`!q*KbF!8I$-79Wf3*l1+vqmZmppf)>WhdXVofBqS%Qpo=c-P;@0IoWu6?rf}C zIuq|~eI6#Y8j;i>)Mcj}`rXDgLl#YGqfKZo@0&$3G`N?t-|}K zPvhdn3mE$NRY6{UMuNeqWHV8jpvIVNGZa*Rh^YaW!>C@p zmIr)x_3Wd^4!t8YY9weZ$;9~PO7h@HUp=zA{A*WAxZI9Qp7pE}c7v;e#FnJD75b`ONW$@=^^QLM9C{5(!fOKYQ;1-sE+@jeq&2{WZ;C<2~dpS+@4xvSbZw*zz9o z-g{wV8w|#P0o#Bv7z~)bH)d~}y*Ek7bP}?ghO}v#+1~#n_n+@;+N6Od1PI*M^<0u{ z>74hR_uS{XpYxtUNNf>sux?@7pFVi~;_p6u?c(q5B%QU(=F=oh+WR41?kLSp!_DjG zF}Vh8Pk~5F{cgPMto3=PzHzsAr!; zh_Bx#3p!@XKfLwwk4k{PL))_V>|FazXUljL#+YE{(qUjyVdT;fE#)G`poT>zL`Jk_ z`hR=9hqf$qS-EIhdu>6=#|c^?nyT{A-9G77j!irMgImu((2ElOTRaK`K6UcIlYNJG z#m$&H?z5(`d8p1Zf0AXBT;I?$W!BN%OMaH;_Yo@5Hm!i$AI|4~A_xkAip@flRE#)@ z0JA1koP2-a{2jHQ+|)=)^SDZpI5g-DCdCtF+39%s`AeAESP$nR&w}bU`m1=2WMNsN z>E2Id+PrRu;OhD3V=IfxFS?SLmq%yf+{Fvnw|5s@hYW*^#rh^MC-bI3t~mYnOE-UT z7SqWiy}w`CGjs3c+Cr4Z>ye|AAW6nSyoiBB85{O65v)S);9045vu@IVd%YWaT2_uL zibt%11uKV&imZg&{RelL-+twVUnO}RcoYciz=@-KpE-7DU-H)Vs}XNjp|Knk=16-%Po03DhX+D^{Xq!)axtA*5}17%8N7cS1+D>PaaP_D0ox|?7-QR`+w8bF~wkyHyyLb=#d{M#k_Ix*uQjK z?N3Sf*6Y`P6RDKnkOvY)$YLQytAsj~3T+4tu@XM)8ZlChijSjIyua&sG^m&XuqxQ- zm{Rqf1HC_f`$ZQz#cLqI*#$*uY1p`W1y(HV!qNSE(bYBs-ou8%$PekCURzB0NfmK7 z*tc)f|4B}aHU)Wje$J(aBEzOfLw+(o`Sdo9^&Nqyi!)?w&gYKrUOc_K^8AUNU!FO- z9cTNuV&>Qa6q%JMwWnX28|sscNY^Qdj1~-f;Y2MT3#U{J z>{{1#M}@q8@hE@#gt94ONZJIogm_*Z3a!NZCPyOI zq=6#P4+^RuR5X8tGiXTGO23>~ksaMVYvSOHtoL8L^hE2#au-gJ?*+$B9kE6O4)5QC zRoz|iCC)F<$?0n;o%)_K)OUSeoZ*+-yud-=Su-cQS;90s*#SX+OCnx$OinyL{p2GY z-m@EiPR@{oh71&^#m~)-w_GaCNcggXc<6D3Y3QiUM^{w_W|!JADKiT7$wt&A>5--3 zBU#QsG(Q9p%pjOZJRB<%z#c9mlA3|lt)+iFxNaun$FA+qe|Ssr^0fkrPl5ZwARP1V*Q1hd||25!IBd`PK&K~mEykW`u{KUv>=?32CH3@Pon^N$}?$y(` zfBfDx!5`i_c2{ePr6K;L4YCm>5kbochAhw*LO(A^1AL&OIu(zB_E3=?3(%EjoK(Si`iW|6Kg@5P3P zWvEyIE;cp)m!CY8laf45976xIO)Eh`f(bqIW}_lE6G~PnlFfRENblrWDiy|{BSJtb zgT%Mx(P5ZVVaI|o8R#fWMr(d7W)!D5$oh>YgnU2169OMs$o##C2j&lMGm;=-V$0l0 z^lfUh{HN=A?~UufU9o(@-d#JkqO2elWkq%*+O)WM?$}%JzVXTfx$oA!z@tduGv|(s zAeKL&wlKURUO6x>NsihC6?&IW!^gKypMU?Ay>~TlS{51rGna)pg%mmx#tHqr!Srwj z$IEq)#A)FQ)Ti1oA;U&Oz$jD@MHwq(5KkP42qLwu9OmH0bu1Srh)8>`%ZbF~x;*UM zyc#X_wO|ke2Rl36j*y8m?opNeIFv$(%AyRrtS02lh_)hGABO$C>#=|D4z#sQfsRK< zquqr0HJMmFtsHBnm!df@hEzx}F*;)Sp-7Q2Q5>)P{GZcJjJ0;qJe**Y@sMdyAe(d$ z8A>)*&u!d)_TbJR9NqrQ$8W^6woOH0mL1tCktoSdfZb-k{nCv~)9!t3JUDn13H&W8 z3X@Z^t&$ImqNOO0QJ^G>kG298t{zzQZ`;@YD>kp3N3n$om&a(tN7cmZ+9W(AX^2;4 zQXSJCUzt5^qH6hqcEyoh8w0WS z;ozZOOmCimcp@nZ6ZEJhac$d}bj%-@g|7NSOe-lmmSWWRnb?dzO^{EYhUwS0eZ$h= zZ_`Xli0)$e1t3}>LpG7;xq1l-^-?aaAft|lHFJgNjfcV_>SXHMUY)B=RV*Jlv2TrAK3FI?kLrgzC~lh&?=r45z%ba^8gd zvi|)$Fsg(mDVzRMgj#t!RVPJGj2;JfuEVP3OVPV|D|jJv__;bk66`5kbB$I8rzt%42-MJM{bJc z%gkuq8!H#gnsv_#{s7}qC9nghPwm$eTYlj}|4Ri~v7eS@#iJ_SjFr=Kv3q&*;*0&O zzjv@`>xwx~jVny$#mIP9;^YD(5s7Rh3Ng`fUTzRp+L66emGP=d3^kKo-m--cGAfRD2?3ha@`(j(L}OoGrR z8O>YupVAz7qb({`|xArXGx1npeNr@D57)~7MeS2d{EoKi z2dnc^zRa;nv2s=oUO2U(_2!ukL;v+RHHFEl@+9j!Sr#24WqhO%LPiRiNY+TPbk_9h zt(#W-;6BwIGp9Hw+l)k5*oj5H|9Nx1L^<#<<>h27>%P0~) z()#ml>biSd3wMbCkI^cM^C&njK1nOU+{t6mw|6g=bj`(d(({Pu6dXUW<&K}fo;ZHs ze2aY}>)y!ygLY+SJb42lz4 z##jBvQRII`%lMk7%2MMer^q?T4&%Tsq$5+o#`sJdGEMTo*5xK$npRi*mrRWqg;o`I zt?6FSIb$M~L-l&-Prmypcue5`hZW1`hD;h?y11q=?n-rr9+L|ru&cX%rQ?4WPHcH% z+W5Rt7B#~!LdoiKNM{3&j$$HrvxsyipO?pliDXr|DR`0?N%QwXtU-*1yco1KmE*lz*KzjP zUZj{*nAbXXXGwFfLLAA;=9Apdyk~u80YJXaJH_0%RH$NKmq| zct&H-y(-(ogvSK_F3z1j^2FKGhlg)i+r72DAqBk)>-)|h-4J-;*m~W}i3O7^(%?6f zb&^kWts2yln7JlB5*b<@gp&Jrti_cx zN8veq2s}m%MQTh`(>*TgPea>;26L#7&pV<}D)OTvpy33fX>2}TfB6FDwKPB-;D+&8 zQM=CXS#`(f-W)%^`>Cy~x-v+70vjs`u^cLL6ar+ZB#09*5hrBeyFHL+Y5iXu+q>ttI;mujRjq{kv(G_J_d`vw9a}dqLEo;8XfDn}f{HUZ)h!`h zyl(%-Wp{iM!~C|16*hh-%pn1T&yN$O9At*^QDBmzr8dWYFU$3?;W2@~AG>z0T9O+j zLHC4AoZQxdp5`2sC+HDR!m=@T6AElf;ghRdSAZG@{Yv^-`HmLuor1`H@(0%V{neBZ=L0WQf+oXmjn!6jAK5m%Q zP=+m=dT?y-W?VgX5My#uKpFNF1R=iDcduV`$J5(pPOMf$@fn{-1p6VL5I9-Ff?du= zrdEg*bDHLS_VFu^blm&Tcue5$M{ncXi8LJ_ zjRncoMTs_1*YpX)?t#F%py_l%*$sPU4O3dtIi7 z0gnm%{Wx`Y&u?eWsEaR7Fujqe5gW6aoGi$WAc8~`77oe-I3$C`6GX`j9*h|^>J z{HD2UI>+D90Bb>N%u-$u1rkOOW;WNOX>1vKx@Y0q<&!X~6d3*V(_r{f7ToJH-BZLE zH0{2lhTYPJ_vK@bb0em^pDQ+MDXX4)7RpiyKUNr>-LV2hUY%sm-S> zZmpM3uPwM4FXbRzCr6f1iX4Lk*;)}YH49NI=>Y3By8BnPeCoz!Lb3gp%R?NmuK*o(;=p#eH8|mAMH`7D9YA zj|#n`?IlED%bIQ++`bknE`!MDVMtGkULGBxqI9&5fA}{|eCy^5PlgKxQ|TV=D2&w- zxy!sEA06K&cJQ3mDfDHb_$tuo}ACCD+$kggXZSw5zPa&c?pP7FtDL#I?f;6ynSYK zrL&kB^opO`NJNovt)-y^yEZPxnx46+D#!%W-;?~#cc6VjHRXPn`<`I=qAo>{x7*uX zn*Y~2IUkMHndslY0k_|O0}I-xK@u8-oOmlr6QhoY@k9E;C9GpQQRtr&^b+*6HDGLZ zG;CrjkwA2GPHDuzOE=O#{NS}A@4k8ciL$(`*@^lv*wq5$JNDWlRv4o}Q*kmjub6x3 z=$56v_q+VRBp!7FpE}iuTQX@^5>WZ?y9$%3UtCWjEo0eGE;FQjHUb?*b%RjvJvu*bMpyN>{@QJ?Or%s*R zGi1a1McX2jd}KOS7iGkuC@}(w1|jB7uik#CZ`0rzSQn0Nb)M5)x_*3NTz^fv>1tt& z3>8UX$RZ(FE|J(Onm2g9?qGSkfa){~S{WOgR?o-0_GZjz9!m(k7^2_+NEiV~jlJ{J z2_I@`<&s>rR01}gj>gI~ThM4iL4P4-RU#hJ43y&g!CyptnI@=0{6P0|#{Ah+(9=B!)0=8w)2k3;P@^I@{c{D6 zc6{IV<<7rkSsw`KRPseq0sDQ2lunBdLv?-ODrW>EUdaX1%Ly!BH?WD6p4B!9 z>(?$pQ(Yy(C1SWe_Z+%gr%tIWOs5~&z3S1Mb5NX{Nm;RYeurKm0^P?QnQ=zc--n&^*TbzXyqZ-kK zz(zh7Stb$2#7WUyobui`UwnK=^ROQ_JZc0UUzxk#rV=74A`DqZ8In{CL~w&}VC$A6 zuibq9t~PYf$%-*Df+_t9cJSw1Uk^mFU0@$#xBw?cWoV3 zl${n{nUk_jFJQtbU?D}rN3KS5obLm9y{of(*XTqaE;FEpZ zf}87#=9?v~zC@$)FLt8}cD)=aIw>ZWWWFA+=FOZ^S94bfw_iB6?Kg2228g^Z-ys41-0@-)N7G5cO{9`Sm_7x?3z?-sL7@hMZB0m|yckeIRD} zVP$sAIYtX ze-y91bmNKa^n@;dLRPAu2dWF>FneMNo+t9<(y;?5&QAK05#;uzFx2n%-KM>6#XR|e z-i;gL^ePy6!HAV{kf;&Cz@vdr@(Okti8)j1UU~baD^K5xvi;KdH52&Y-nC9qS^?s9 zGGxc-2A}okT9ruBicpiEdc$rCtIUisQ0_L}7^AY7=Ie%Vr4aSig&1F3hW*<&AuT2n zUL&4Egpzk@W>Y1lu_EKK=lvn*w2G4OFzwfoMjax<1sIbbiz{dLqq}_ybaDao8ae9A z^KSE~6eEk`Dy`2;y5q{US=25`v4*&Lf-eelj}53QvBH4=EshVG}blTD(EtXNi-EgW$&Hj=_f8%eXGu`p?Tc5K*t z9nBSYJ*JV8VxgAgryNg9u$-s+xg#M`i&H1}WBsEFz zQVSU1)BR!5Nicgx1Ln*%{qWtS9VQ8BGKm?;G%C@Un=-g9kK^zv z$8n}sVF(K2jL1tcew}609eqsT2LtJGxjqw)#V~gfj7N)-+&Iy4wGyri@He!g3c8pLM{6Fc0j|7AqoOR%`ZouGtCOOS*QUllbc;F43lfJ_WXCtopFVDjMMj89 z)R9fbfkna|>~Qs*V8o~du$$$WFsA50L2^__LrM0J?m7PPJJ0{`N4IV~{l=@;o@}Tp z`6D|h5HVH*8cEE1WZzcIX_){s>Bx0VZ-|54n|^_!{(6xa8)py%(vIt;g3m*}U6C1Y z#>z$QIJ9#u*7wZA&JC+kQfg) zuGOF-1jfVafp=}{a#}NgYIQ??^5-RqCX~b*Q5dTuo>zjZ3>%V(e2yYSj!_9wnrwj} z&8Mb7N7Lm>c*v2F(`+rI?rqdwSR6^0|YU*FG665(hg5#gXoxt*E1i!PQx6dg{k ztY4Kz8<1;KBF7{{u0;l$gof(;#7X5@aj$8(G-x?Alq4DGmUb=A7!jiMCsLV97TF)?-rQDB}j@2he^tKRm1fD zx^-OPWAgr7c>9&>PY`mxDWC;_6G*|-+B_`n81FcR5bKt9Lnjj=Dbffw`Cnp``rv`y zl|%MySvq)-TBcF3Azn&HqLMSX7gBMe8Ide1@~nDnU%Qs_Z5|)IcJ;S;u@Na2F)KsQ zp?wl1X2UT#pfKKq(gX|2iTBSiE0AtgYVKP_+#zN))>l7_1Wt-lbBZ#eGZRhf&tgeu zTbp7*WuhJxNd}}EM5Hqf!RD1+X>HA8qQ+I`zOP~hBTm6Y>)2w9%}#=r8-fV25KCrM zcWvmd{|*7StnLbzFayD-`a#B|qbNNE%NBOx#pf?z*Y>sGhdBQ3hwAK@+GL}sE;ms( z;(pb`uM+Junge>eIu6d7GT{xgj0-)9iHu&N;^KA`LSP60g zvcu&lk5;4DD#MK0{98x&Y}PHA+phZd`)w@~+NC_sZBYmf8WQ@9D@+_*I#`iPI@}aJ zrq*TO{_@ig8^8MV`}P?V%O)%N)WvEc^R|k|aLg&d>0^6w<*DUYr$Kuzwq0425$OKtS(6x)BGSNa+*adecsF#jH@Zdrj?7aYs*Gd7H5MW z?1xZqH_*LY5GCcJB;AIrR0}dwBH`mY8u5{lE2Mq_VQc4i{@dEn@wFwtU$Ll5G-J{P zac)xdtJ#(?6xnnrk0o)KS&dAs2-!v%vLjTN70jS%R<)>M>AbcFYGK683H1*Jfy*-E zL+obtPLn9K&m;;tm#h(eY1fc2#~?#tgq)C9^--Zkeyc7!cIDyT)!#YIeoE7LuPGB6 zljpXzej#O0k!qHsFeV&nCNZp}1Bg^gFt#B7o0|NrKZXk!A30VP$(dA)EzQA}wM(#e zWjFTru7@bZA58aAP|-Xt|ume{p-^(g8w?h;&o_ovKKp0TyD{D4C;g-iLUDb2&; zj%J)ac^J0_UIEMB7a~R|f_*)(u%i{5)-HucE`*Tu)&`Y$ew;<8eEsF;|KmiB{$qQd ztSZi#kZe#j6~$X;jLC?*o@@3p+^r2msU1 z0~s+9o1&GRaYn9h#xGd>$JnxVPJv@*O19@HSmYc`ER4gF&SqS>cnUhX9G$b~K&O-< zJ<$dciw=Lc(NL3{`QPNVVb$DGld7`U6-5zA=NJh!6B$l={5+iu@nH&N#K*m;6>v_+ z8@0$yO;G*JMZIe@SC>6-1QrDQG{r|~>db19p}sUnl@@2boMcqMDqtX9%0re;j$Bfo zIpJay=!M8Mh~F$pF#hP{uZw36{buQ+nVH#Xv0o_oAN|ipUws*cDTxSlb%7wr9}FKa=wu>?m(Hm!%}XfEN{J=1{K+5B=^r?G zXoJ(5j`1%wr<>879F8UuXVoU?2S>9tOgi)|CiEiipX95Prpxlq^_-E+(%-8tj9`Gn0V0*cN>*s}7Id?E5$qAPb@=9PQ zswO`|fi*K~=Jrgh5Z`IqM-FZsdtlc(EbVN8^Rv&wZTL|5y12p|CdST9OVB*N0&`m@ zp`oGx0YolSMm-A!oBC?+`h`z*v^I!V_Ow5q-+aH&w|mty70KcK+8|dbgWVA)4Mcf* zBv$v#LwZyMy4xq=#Qtr_Nsa^6%M;-u-X~07kN1sI-g|wAcii#urVgCgyK>#u1yiwl zS|w%{Cm@O!0waq?rNR&rgm^;W=E_3KFPXmsIq{~xG;8>3t5Ps6K3v{r;4?l|(gVmn3WAJus3Ly~ zVk9g=U;(nULgWxN)l!jrpe)f+ad2Jd@bib(-%&nur<9LuuFcFX#pe-4n?}-XcvtfHZB86Bqq1ZNsO!%AX_a$ij;%0IPT2^xf~_An`I zA_fxVY^11o$Tusodd`%ByUDA4a&2&$MRv_3ppg#26QUq*Eb5qymoA^d%}b}yR9}M5 z_9kQ}M8;q(#p(O4)0QQ=;=;yLjq9dgF^Hdw+B8=++O<_HDxE zIdv#BN)gEoMXE}OJcA6`4jHH=@f&$9BvwG)7db|(N#iWCgbmo0+@@3&XKI02v9KmL zvEyFWLu~;eFo^+m4gxF1{Zp!oDfc2D9*d^pvqEkMdb#)Oq=NoLv#!4=GyZaZM)XMo zJD7B8QWDQ9k#A6tPEJaQDnYVRgd_zq@|t1RUdfF%>>QI3f4x301uMH|MBhoi`*$pl z+OVu`-lXd6mv}y-QI!#k`EBC~d7E(V*dDxg<04+YatiGetD#`{Lq?~7PxX189YAT) zidc1p8L_TEp37tW;t2E^9?&vz?BPju<$nqBaT*+D403Y9>`B!)uzfMPx$AKA;x3%n zw+6}PF!&Nr?B_Hbl8^wjHde0rPibE~vHj^Yee2P;xeL?MBakLxVti&4T1yjOnN?{& zIj1JGzr8H=a#4f?c|;cGX#~h8maFC=T@s39;w9pFfk@y5p(4q$!;xnH{_Rii+Om?e zZh04F*S0l3+dxWvVfJ!Opg%NJf5gay{gWyRC_h)){|sM`kt&Z-Bj7WN)U}&8L_YqI zlYF%yfk;tsQDRY`!lpvCO+z|7C6UV#WDr%7KG^B0K558HVLQ@U&_1bY(d;HH@1AjS zcrZg}D16jE-A01fV-g9QpQok3DZ~Wiu$2UDunH8zZGb_GKSMlD?){5S< z%UH-#@rh>^A!l%~Mo2z$U|4EMn#yxjb@^#`eZEs;Y5sDBuMd=dKClYe{k6GilsoP6Km3WROjbVcC24I z^4!rq|MTtt@=~LwTEh4XQX(}?6}icEtN_o7Ko@5)JiJIa5sWBiC}K$%5zl8LK}bx* zLL#wL84o3d#FdH0iUPAzm2Xn2%3} z`rCZR6=#;$=GmKaVhl}LvDzzK(m9)n{O+7okE8oG;rO8~xOuf77fx(PuHA+p4>$Ob zj+x^09Bg_;!IYXJN^X3_U5$4<#(hN7xUx|>sVR(}dGj)C2K{C4(WA%>9fim+3F=ET zv2sZ}>dP|l^3@Y~<=SzqS=ff)(Ien7^lA9H4mtYAx1aa>=)IS?uU$QowS3OFjyJ9x zRc~B2rDXm5iD)fPK|@9amd+THdiucf=l(h0nxe#E6H3w~b?I>dQ_Hfb8G0#V_;e)8 zID;OjfJp7EFd?)-UQkfnq4x8FJ~#l;q`_xOB_t-~!N_Mp$7Ot>=du27U@;IYmz=xX z@{cdcUoP?>F`=g?vWeih`>aaQ zUt}ci7yA2v=Sv~p%^N&#FQ@_okR)UyLqf<(h-;w-5by6p%IPo)bi|SzBg{6f`up;n zSen_NNMd6%A$pNfhDjNQ{#CQ<2d{bOin&1wsyAdrP04)S!S{B8hUJg4)F^CP+J$5L zw_)$r64FrS>CxUf@?nR9&0xt`A&cX5Vf`9bFa-YY z5C(X{Mq;q%FZAKn>qoGC^&HF^SAn^c#zGYAi?pb4q{kSM6=O!CmXJ^_fq}d5SR3#5Ngv>=I6)GZisEX2| zfLxE(-wy(cH-r=lMBWsLy(kEy(UGJL{~|G5iv&#=;?-(I$|TV9*-(ZCBZ8=iB%5BP zlW^227DG&7Mp9F(KI}5r)g4?n4+uTo2VxYm-t4HzzD%pRKhqk~pB-iC&x^6`i&4mD z8@Svii%8rQqgFO0n+#1kiLvttc|Q&H@B@e953a921OY*ihlC=6kisGn!YURJ6T&Ru z!^mX7NDo2`HyBA`ChT%9W{t`J+y3>7RO>rhRIQbHsxc{6RfbWl%862aZ=H3ujHN_r z1ramG6x;|8^g%=@_2U%1yjH{US7k=Xw#a=wNGCyoHrNj(31+-<{S02XdK#P8EP;&0 zB1CmXfV&d{J&3uFhA@bL||wdHpEfxN?Xz250!XxPap93eVA_;p65yXfz)RqIG&)K79(e-+N=u-Q<0` zZ_|?{spj=&0quH@%L zoe5P42kH78tV+f$-aG~e%K!^w(lL-Zt3Z9quAbGhi?hv@UK}Ni>%-tIb zFJCBq0*D1c;};A~KnTLAOyVsW2&WSwGTAVaJe4HmkoX5e5)cR(NiQrU1V%0gky0U| zh#9#|XhUh_+UT$dxJV?|t_li(jCg!?kUwVB6o2&J+@t2A^m2W05Q3dt2h9<~CyH6H zI}}W8IK~#mV{%V`n}$rYYEV)-2D?gi5|j~d zTpFQ4d87$dF&0$E8BrBW%w{AWT8|P-IPun66h?%jz^FyOL4!Pf80i2UrXsRjfefV_ zb|S;$`2uJHgTNu35YO3#5S2o_BLfLM7E*{rPm>Cep%5ZlB|=`9W57+0LcI#b#;`#v zGN_TSS0XoDj%(oU4hapR+M6{HPa8iaa29CyG*%uxM5rx@Js8q)Gvrhb!oW_&zS9 zpyY?B?k3LzdsjW9;Rp8{ICLD_wGJ_&P^2l?$W(GsX4RmOkRwMSMXp+o;&2s82|+6e zp{mRpR9m#DB39{mwT2H`1$kc@p+*TITw%Bpc`6cLOGU5?1SGch1)IeDToU_h34v1x z>9SNpn&ngp&?JBSo@W@|P67 za$T%a&}0^|o1&Hc^~n*6&lj~#L`h;4A+SGm4C>o;@iQ$NG!~{{X-hdach+I+ygIbjWDds2-lImrW26&NN5n>v`{y)b@qg6_9^>H! zBf!hWW5kfTZbOED>iXOWkXLvP9R}~=L(x=~i%Um0;L5RWIN!e$D|_Z*+?XnG0;mY} z^o58T0=-BEmLFxC*QgOqL0;}{dZqNBjK%B^p?LR;Xo3CdQO1mK^U9A8A4W{Id&2@s zR-EBvb43nzt?xo%oO$KMg2d+i8)kD}yL#ZoMB*6@frJ1=HX5h_h@b_*5*&<3B42Hx zj6sVcaj4_7g-$2`r@=@XyFQRgNE!fzw-4k*It$&sKqC#DK72GnN$13Mc7|g_IxN5s z+5nP%U;y+%fh3P07->{kNE~ft(20c*3xzq9$Ypx)pczPBh7dZ8b8q}R^4*Sl^9vLgJBV5esS8_s@ zgp1jmnZ6#kNj;Lf^aaB)C`RIKWiTC^yT;@ArVgCkG7G1-&BCeP4pgLB5J<`*B=I=k zKk(yFZ{Jz|F7CWvu-QDug9ZhiPLa`q4oLz7{^Ug(yX&ywh$P<0M!X@{L0G>)?A*2+ zySDGdxf4h6=a1eWv`;_$5G-HEsdW_4NZc3b?hZd^clZ|J@gdJMyT` zOf*IC*^p3ukwiRQYhyX)PA$jT1FK7RuW4<$c5LIg*RCG<&?;emp$+!CstFD3ixhME z5|pC8Or5GP$Drv;Rm=L4<&wT6nfM>3koKjh<$ZRIvM*Vy9<+2rcwe^3*q39qp7kF# z0>Q&afJ!WQ~qRZ(0TH zH_6`yEJF4`w1htpCl?GPC`1D>GTw_iMo?d2ob~vEmI>dPqnv8hWC?@Z#NMsz@ctV&@zzUMaOK27 z9N)bOCwHwzPNV@E7M;|aA6VXQL@f>fyXT0ZZ;NO_GyR4SdnAsDeT+MRE;RVra0XrN z=j^i9W0ccJok6=I)toPm z?_7f2t2@70K4-$Gn|fy2xAn{!{!`0ybjLb(zhOfNd504liC|I=6PI)O>WKqB%etmf zI;Pb6PHQOfol;xq-`-dm*j$z8JE=0qhj>!o_VJaz?TuBGxl;G?z8SFkry_y6<5rGJb^79dl!>aTwy_Gf(Y`JagW5%0Wt9j$d$ z2qs>c?&Sjp@z9|})&{$IgYMythSFRt?`lPDeg@`E84Dsoab)8n$4(L#f39+DTQOfo z8S*TsBOC-C1v-(_MmFp6hp$}w$#Z}AZd^2c=A;VlKNDEZ2~{zDJi+nzfu6&HgvfNh zH&G|99;DoE2zGaaW4wXk^b!D4mXc+7dYL&{RtT}w8>`#@y0|N`#QP7XVj=c zavEe(Y+BxfgT3oxPQIwX6s@wvYv1Dkd6gO{%j`Kf6y zn>|$}X9nL81_$=o)Z&709!(P=<5uu#{-lmZf=%j1Nb!Y$gcn?j7ot?+!4dt!BpWh` zB(_IrFu!#YuAMuE3&#&)-i%3z)X1RZh7yvyfk8qMx{K@IX``KYszQRb@4tTij+c8r z#$)^&lx&tR$l3FJkc;Q%fi51TkvhSP#FRwJAx0%fj>Ujns~*MCddweRiv5Jd7xr(& z^XK~T*2^#8{Wo93A8);h>Ej#W??lM!>_t419|D}b;5UlIb;DiZJ#;kcvr}^ZIo~a- z=DE$DI+jwH5ks+tizwAaDYCJp>6C#NPyXoRk=AilD&HYPNeoN~JZvOrBSt|TOgr}O zip4K!}(3r~b~P27+9j-g9(LexpZ&L)3eYU{aQ+~!o!*1X{X5WDT7X!C76NJjsBSK#Q*!~;+2t=ZXP1N2(at5*QO<6m zPA-qh`xrkRbT`TnC4-faXfX5?rzK5Hh|pzJ=B9VW%jL+{tC43^BPU#n=IlhYm1ba4 zULq!D#bZigI=ZJfVAjMjFiGVw3neIwBXP6cj)J&Y)aGQ9MqYxh$>X8t^Dc7(eft;` z&px`Rd!Lw2dr3$Q8sG;64RHMf2DCiRHxWYqjk@d%|JN>^{ErQLR%5NoZ^#e?4;=y8 zP!afulwsh)7BL=ur?7IXQW36{glypguPX=k{#D^`kp*?PxFYLfdfl=yqH`-iuey z?fplrNTfB}%OO4eAr7EI8c2g8hz1q$XsX~4sDkK_`%@7X%z%!?gOMi~>=eZQ0WbLv z8{Y3fe0aa_(4qaI?yk@K4;_vGLf)XE4lg_k5*qC@W0?G;m=)a54-V{S2m1DhP&~-1 z&lSg$=@84D(FQ1(_EafaY+|0^zX;DGl%ff zrDJ&Y%5l7Y^*CNUy$>gMuEHh~)3%Q(Kt^QP;F@bLiH#Y)UZ8ms1>)fXf0xmqy1PKl zq<@?fZDpO`x9xu4%Ex#V5u;Yt%R)nzs5zY7EHAImX--52j&erO$k7NMH5wAqaNEaK zy;fijN25I&N7l?j?}7$wol}E73&!E_l4kU+YQd#FOA)J-V{A?uX4F++c2g~S+9zXe z_e^YG*@b2V>-iC|BTVL$oPX4wI>*mkIlC~*WGHV7Fcg)6;&be4R zcRm((F2ll(rIckGTG`3^fw>F_2Gn(4b);trlrp`uJ`#f}a zbYaE99&A~)8hbXZ$I(4IaO&`WoI0`}Cl2k!$%DIb>d+pXBCjX*?ZEDht5K4bf}G?i zRAwciESY6odQFp%7Bo4;)3aF+;NN7HiJRheVPiOc z6k(8y)9>#0{dm_PX(;4tEysLrlP zwVE({dMMNn%{TZPvA=)wxBuVB`>($uuV0bBe?`9YB|iJh zpYYDR0~mPi1w4P{G|nH}g_C>M;^?;J=eyhE+|ON{8T3pAk$(XQd$a|OoS+j z2v#8qRHL)8ihL&WyrB%OV+t{?G8dCe(=fTjj>!dyXwHenr2ntI`}t`ih~faA zsEG%~Ep6HEw%w9a3oVV^Qj4^-g)MDiQ=ovs(uye<3IWmdSx>|tC})aaY++b{nx3G4D;Xmyjwo}b!UA# z*6iCAwYpz4Xrhtm*V#;;W}O}-+B??Lo?4=H<>!kgi-g@xE*zqZY9tcCQM$--iB=p> zglNJz)u&+oY!t7iIPhnW1|ocwcp4MXWy!A zk;h$OWj1#{`#wK$=|^GmGMOA5BiU4jq`H%2uuCQVib8t)0n#bUBxJXf(`FO#h(;m{ zm5BQhMdCKnh{9e@2?pXa@Wjd2(D1~;8)yX5Xb^~OmWbb8Phwsl=?S)x!D#2tR9yX* z3@STnbL&dGOP*^v+3+CZ@yx`VeQfjy!~ChZ_?lZ@TJ)Eei$~X2R*#fdOWy5`^4Pnr z?fm9O8P-)?~u+rLAT>}kz0i3)MWTONfE;rtYcQjfDO8@`>07*qoM6N<$g1=4vD*ylh literal 53859 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 M07*qoM6N<$f<*(6>i_@% From d64f98c0d424db18f4e651858c0fc4a04802beda Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Mon, 28 Oct 2024 22:10:07 +0100 Subject: [PATCH 16/19] Fixes botched merge --- app/src/pages/_app.tsx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/app/src/pages/_app.tsx b/app/src/pages/_app.tsx index b4ea6d0..533f4e8 100644 --- a/app/src/pages/_app.tsx +++ b/app/src/pages/_app.tsx @@ -1,15 +1,3 @@ -<<<<<<< HEAD -import '../styles/globals.css'; -import '@rainbow-me/rainbowkit/styles.css'; -import type { AppProps } from 'next/app'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { WagmiProvider } from 'wagmi'; -import { RainbowKitProvider, midnightTheme } from '@rainbow-me/rainbowkit'; -import { config } from '../wagmi'; -import { Texturina } from 'next/font/google' -import PlayerProvider from '../providers/PlayerProvider'; -import ModalProvider from '../providers/ModalProvider'; -======= import "../styles/globals.css"; import "../styles/pixelatedBorders.scss"; import "@rainbow-me/rainbowkit/styles.css"; @@ -20,7 +8,8 @@ import { RainbowKitProvider, midnightTheme } from "@rainbow-me/rainbowkit"; import { config } from "../wagmi"; import { Press_Start_2P, Texturina } from "next/font/google"; import PlayerProvider from "../providers/PlayerProvider"; ->>>>>>> main +import ModalProvider from '../providers/ModalProvider'; + const client = new QueryClient(); const font = Texturina({ weight: ["400"], subsets: ["latin"] }); From 52aec1ae9d10cc5ca2cfbe73f0b81c074b731587 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Tue, 29 Oct 2024 12:14:30 +0100 Subject: [PATCH 17/19] Raises RGCVII for entry to 500 --- app/src/providers/PlayerProvider.tsx | 2 +- src/RaidGeld.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/providers/PlayerProvider.tsx b/app/src/providers/PlayerProvider.tsx index f0d38f3..c64434b 100644 --- a/app/src/providers/PlayerProvider.tsx +++ b/app/src/providers/PlayerProvider.tsx @@ -119,7 +119,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { abi, address: daoTokenAddress, functionName: 'approve', - args: [contractAddress, parseEther("50")], + args: [contractAddress, parseEther("500")], }, { onSuccess: (hash) => { setHashAndCallback([ diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index ecc332a..83ef9e4 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -12,7 +12,7 @@ contract RaidGeld is ERC20, Ownable, Constants { uint256 public constant MANTISSA = 1e4; uint256 public constant BUY_IN_AMOUNT = 0.0005 ether; uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT; - uint256 public constant INITIAL_GELD = 50 * MANTISSA; + uint256 public constant INITIAL_GELD = 500 * MANTISSA; mapping(address => Player) private players; mapping(address => Army) private armies; From 81170fd8ec91d10af314aa79a2ca73799e2b0c61 Mon Sep 17 00:00:00 2001 From: yellow <8539006+yellowBirdy@users.noreply.github.com> Date: Tue, 29 Oct 2024 19:35:26 +0100 Subject: [PATCH 18/19] reg price aligned, withdraw refactor --- src/RaidGeld.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 83ef9e4..a592dd9 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -10,7 +10,7 @@ import "../src/Constants.sol"; contract RaidGeld is ERC20, Ownable, Constants { uint256 public constant MANTISSA = 1e4; - uint256 public constant BUY_IN_AMOUNT = 0.0005 ether; + uint256 public constant BUY_IN_AMOUNT = 0.00005 ether; uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT; uint256 public constant INITIAL_GELD = 500 * MANTISSA; mapping(address => Player) private players; @@ -118,8 +118,7 @@ contract RaidGeld is ERC20, Ownable, Constants { // Allows the owner to withdraw DAO tokens function withdraw() external onlyOwner { uint256 amount = daoToken.balanceOf(address(this)); - daoToken.approve(address(this), amount); - daoToken.transferFrom(address(this), owner(), amount); + daoToken.transfer(owner(), amount); } // Manual minting for itchy fingers From ee6c9ec7100b6389d1ba686c0cd98cef951ce759 Mon Sep 17 00:00:00 2001 From: Mitja Belak Date: Wed, 30 Oct 2024 00:31:06 +0100 Subject: [PATCH 19/19] Changed the buy in amounts in client as well --- app/src/providers/PlayerProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/providers/PlayerProvider.tsx b/app/src/providers/PlayerProvider.tsx index c64434b..0aec1a4 100644 --- a/app/src/providers/PlayerProvider.tsx +++ b/app/src/providers/PlayerProvider.tsx @@ -108,7 +108,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { abi, address: contractAddress, functionName: 'register_eth', - value: parseEther("0.0005"), + value: parseEther("0.00005"), }, { onSuccess: (hash) => { setHashAndCallback([hash, resetHashAndCallback]) @@ -119,7 +119,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => { abi, address: daoTokenAddress, functionName: 'approve', - args: [contractAddress, parseEther("500")], + args: [contractAddress, parseEther("50")], }, { onSuccess: (hash) => { setHashAndCallback([